]> source.dussan.org Git - archiva.git/blob
985c646c5bdd621b369857a300fd4e3f75409033
[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.Date;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.LinkedHashSet;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Properties;
37 import java.util.Set;
38 import java.util.StringTokenizer;
39
40 import org.apache.archiva.metadata.model.ArtifactMetadata;
41 import org.apache.archiva.metadata.model.CiManagement;
42 import org.apache.archiva.metadata.model.Dependency;
43 import org.apache.archiva.metadata.model.IssueManagement;
44 import org.apache.archiva.metadata.model.License;
45 import org.apache.archiva.metadata.model.MailingList;
46 import org.apache.archiva.metadata.model.MetadataFacet;
47 import org.apache.archiva.metadata.model.MetadataFacetFactory;
48 import org.apache.archiva.metadata.model.Organization;
49 import org.apache.archiva.metadata.model.ProjectMetadata;
50 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
51 import org.apache.archiva.metadata.model.ProjectVersionReference;
52 import org.apache.archiva.metadata.model.Scm;
53 import org.apache.archiva.metadata.repository.MetadataRepository;
54 import org.apache.commons.io.FileUtils;
55 import org.apache.commons.io.IOUtils;
56 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 /**
61  * @plexus.component role="org.apache.archiva.metadata.repository.MetadataRepository"
62  */
63 public class FileMetadataRepository
64     implements MetadataRepository
65 {
66     /**
67      * @plexus.requirement role="org.apache.archiva.metadata.model.MetadataFacetFactory"
68      */
69     private Map<String, MetadataFacetFactory> metadataFacetFactories;
70
71     /**
72      * @plexus.requirement
73      */
74     private ArchivaConfiguration configuration;
75
76     private static final Logger log = LoggerFactory.getLogger( FileMetadataRepository.class );
77
78     private static final String PROJECT_METADATA_KEY = "project-metadata";
79
80     private static final String PROJECT_VERSION_METADATA_KEY = "version-metadata";
81
82     private static final String NAMESPACE_METADATA_KEY = "namespace-metadata";
83
84     private static final String METADATA_KEY = "metadata";
85
86     private File getBaseDirectory( String repoId )
87     {
88         // TODO: should be configurable, like the index
89         String basedir = configuration.getConfiguration().getManagedRepositoriesAsMap().get( repoId ).getLocation();
90         File dir = new File( basedir, ".archiva" );
91         return dir;
92     }
93
94     private File getDirectory( String repoId )
95     {
96         return new File( getBaseDirectory( repoId ), "content" );
97     }
98
99     public void updateProject( String repoId, ProjectMetadata project )
100     {
101         updateProject( repoId, project.getNamespace(), project.getId() );
102     }
103
104     private void updateProject( String repoId, String namespace, String id )
105     {
106         // TODO: this is a more braindead implementation than we would normally expect, for prototyping purposes
107         updateNamespace( repoId, namespace );
108
109         try
110         {
111             File namespaceDirectory = new File( getDirectory( repoId ), namespace );
112             Properties properties = new Properties();
113             properties.setProperty( "namespace", namespace );
114             properties.setProperty( "id", id );
115             writeProperties( properties, new File( namespaceDirectory, id ), PROJECT_METADATA_KEY );
116         }
117         catch ( IOException e )
118         {
119             // TODO!
120             e.printStackTrace();
121         }
122     }
123
124     public void updateProjectVersion( String repoId, String namespace, String projectId,
125                                       ProjectVersionMetadata versionMetadata )
126     {
127         updateProject( repoId, namespace, projectId );
128
129         File directory =
130             new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + versionMetadata.getId() );
131
132         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
133         // remove properties that are not references or artifacts
134         for ( Object key : new ArrayList( properties.keySet() ) )
135         {
136             String name = (String) key;
137             if ( !name.contains( ":" ) && !name.equals( "facetIds" ) )
138             {
139                 properties.remove( name );
140             }
141         }
142         properties.setProperty( "id", versionMetadata.getId() );
143         setProperty( properties, "name", versionMetadata.getName() );
144         setProperty( properties, "description", versionMetadata.getDescription() );
145         setProperty( properties, "url", versionMetadata.getUrl() );
146         setProperty( properties, "incomplete", String.valueOf( versionMetadata.isIncomplete() ) );
147         if ( versionMetadata.getScm() != null )
148         {
149             setProperty( properties, "scm.connection", versionMetadata.getScm().getConnection() );
150             setProperty( properties, "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
151             setProperty( properties, "scm.url", versionMetadata.getScm().getUrl() );
152         }
153         if ( versionMetadata.getCiManagement() != null )
154         {
155             setProperty( properties, "ci.system", versionMetadata.getCiManagement().getSystem() );
156             setProperty( properties, "ci.url", versionMetadata.getCiManagement().getUrl() );
157         }
158         if ( versionMetadata.getIssueManagement() != null )
159         {
160             setProperty( properties, "issue.system", versionMetadata.getIssueManagement().getSystem() );
161             setProperty( properties, "issue.url", versionMetadata.getIssueManagement().getUrl() );
162         }
163         if ( versionMetadata.getOrganization() != null )
164         {
165             setProperty( properties, "org.name", versionMetadata.getOrganization().getName() );
166             setProperty( properties, "org.url", versionMetadata.getOrganization().getUrl() );
167         }
168         int i = 0;
169         for ( License license : versionMetadata.getLicenses() )
170         {
171             setProperty( properties, "license." + i + ".name", license.getName() );
172             setProperty( properties, "license." + i + ".url", license.getUrl() );
173             i++;
174         }
175         i = 0;
176         for ( MailingList mailingList : versionMetadata.getMailingLists() )
177         {
178             setProperty( properties, "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
179             setProperty( properties, "mailingList." + i + ".name", mailingList.getName() );
180             setProperty( properties, "mailingList." + i + ".post", mailingList.getPostAddress() );
181             setProperty( properties, "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
182             setProperty( properties, "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
183             setProperty( properties, "mailingList." + i + ".otherArchives", join( mailingList.getOtherArchives() ) );
184             i++;
185         }
186         i = 0;
187         for ( Dependency dependency : versionMetadata.getDependencies() )
188         {
189             setProperty( properties, "dependency." + i + ".classifier", dependency.getClassifier() );
190             setProperty( properties, "dependency." + i + ".scope", dependency.getScope() );
191             setProperty( properties, "dependency." + i + ".systemPath", dependency.getSystemPath() );
192             setProperty( properties, "dependency." + i + ".artifactId", dependency.getArtifactId() );
193             setProperty( properties, "dependency." + i + ".groupId", dependency.getGroupId() );
194             setProperty( properties, "dependency." + i + ".version", dependency.getVersion() );
195             setProperty( properties, "dependency." + i + ".type", dependency.getType() );
196             i++;
197         }
198         Set<String> facetIds = new LinkedHashSet<String>( versionMetadata.getFacetIds() );
199         facetIds.addAll( Arrays.asList( properties.getProperty( "facetIds", "" ).split( "," ) ) );
200         properties.setProperty( "facetIds", join( facetIds ) );
201
202         for ( MetadataFacet facet : versionMetadata.getFacetList() )
203         {
204             properties.putAll( facet.toProperties() );
205         }
206
207         try
208         {
209             writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
210         }
211         catch ( IOException e )
212         {
213             // TODO
214             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
215         }
216     }
217
218     public void updateProjectReference( String repoId, String namespace, String projectId, String projectVersion,
219                                         ProjectVersionReference reference )
220     {
221         File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
222
223         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
224         int i = Integer.valueOf( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
225         setProperty( properties, "ref:lastReferenceNum", Integer.toString( i ) );
226         setProperty( properties, "ref:reference." + i + ".namespace", reference.getNamespace() );
227         setProperty( properties, "ref:reference." + i + ".projectId", reference.getProjectId() );
228         setProperty( properties, "ref:reference." + i + ".projectVersion", reference.getProjectVersion() );
229         setProperty( properties, "ref:reference." + i + ".referenceType", reference.getReferenceType().toString() );
230
231         try
232         {
233             writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
234         }
235         catch ( IOException e )
236         {
237             // TODO
238             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
239         }
240     }
241
242     public void updateNamespace( String repoId, String namespace )
243     {
244         try
245         {
246             File namespaceDirectory = new File( getDirectory( repoId ), namespace );
247             Properties properties = new Properties();
248             properties.setProperty( "namespace", namespace );
249             writeProperties( properties, namespaceDirectory, NAMESPACE_METADATA_KEY );
250
251         }
252         catch ( IOException e )
253         {
254             // TODO!
255             e.printStackTrace();
256         }
257     }
258
259     public List<String> getMetadataFacets( String repoId, String facetId )
260     {
261         File directory = getMetadataDirectory( repoId, facetId );
262         List<String> facets = new ArrayList<String>();
263         recurse( facets, "", directory );
264         return facets;
265     }
266
267     private void recurse( List<String> facets, String prefix, File directory )
268     {
269         File[] list = directory.listFiles();
270         if ( list != null )
271         {
272             for ( File dir : list )
273             {
274                 if ( dir.isDirectory() )
275                 {
276                     recurse( facets, prefix + "/" + dir.getName(), dir );
277                 }
278                 else if ( dir.getName().equals( METADATA_KEY + ".properties" ) )
279                 {
280                     facets.add( prefix.substring( 1 ) );
281                 }
282             }
283         }
284     }
285
286     public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
287     {
288         Properties properties;
289         try
290         {
291             properties =
292                 readProperties( new File( getMetadataDirectory( repositoryId, facetId ), name ), METADATA_KEY );
293         }
294         catch ( FileNotFoundException e )
295         {
296             return null;
297         }
298         catch ( IOException e )
299         {
300             // TODO
301             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
302             return null;
303         }
304         MetadataFacet metadataFacet = null;
305         MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
306         if ( metadataFacetFactory != null )
307         {
308             metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
309             Map<String, String> map = new HashMap<String, String>();
310             for ( Object key : new ArrayList( properties.keySet() ) )
311             {
312                 String property = (String) key;
313                 map.put( property, properties.getProperty( property ) );
314             }
315             metadataFacet.fromProperties( map );
316         }
317         return metadataFacet;
318     }
319
320     public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
321     {
322         Properties properties = new Properties();
323         properties.putAll( metadataFacet.toProperties() );
324
325         try
326         {
327             File directory =
328                 new File( getMetadataDirectory( repositoryId, metadataFacet.getFacetId() ), metadataFacet.getName() );
329             writeProperties( properties, directory, METADATA_KEY );
330         }
331         catch ( IOException e )
332         {
333             // TODO!
334             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
335         }
336     }
337
338     public void removeMetadataFacets( String repositoryId, String facetId )
339     {
340         try
341         {
342             FileUtils.deleteDirectory( getMetadataDirectory( repositoryId, facetId ) );
343         }
344         catch ( IOException e )
345         {
346             // TODO!
347             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
348         }
349     }
350
351     public void removeMetadataFacet( String repoId, String facetId, String name )
352     {
353         File dir = new File( getMetadataDirectory( repoId, facetId ), name );
354         try
355         {
356             FileUtils.deleteDirectory( dir );
357         }
358         catch ( IOException e )
359         {
360             // TODO
361             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
362         }
363     }
364
365     public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
366     {
367         // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
368         //  of this information (eg. in Lucene, as before)
369
370         List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
371         for ( String ns : getRootNamespaces( repoId ) )
372         {
373             getArtifactsByDateRange( artifacts, repoId, ns, startTime, endTime );
374         }
375         return artifacts;
376     }
377
378     private void getArtifactsByDateRange( List<ArtifactMetadata> artifacts, String repoId, String ns, Date startTime,
379                                           Date endTime )
380     {
381         for ( String namespace : getNamespaces( repoId, ns ) )
382         {
383             getArtifactsByDateRange( artifacts, repoId, ns + "." + namespace, startTime, endTime );
384         }
385
386         for ( String project : getProjects( repoId, ns ) )
387         {
388             for ( String version : getProjectVersions( repoId, ns, project ) )
389             {
390                 for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
391                 {
392                     if ( startTime == null || startTime.before( artifact.getWhenGathered() ) )
393                     {
394                         if ( endTime == null || endTime.after( artifact.getWhenGathered() ) )
395                         {
396                             artifacts.add( artifact );
397                         }
398                     }
399                 }
400             }
401         }
402     }
403
404     public Collection<ArtifactMetadata> getArtifacts( String repoId, String namespace, String projectId,
405                                                       String projectVersion )
406     {
407         Map<String, ArtifactMetadata> artifacts = new HashMap<String, ArtifactMetadata>();
408
409         File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
410
411         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
412
413         for ( Map.Entry entry : properties.entrySet() )
414         {
415             String name = (String) entry.getKey();
416             StringTokenizer tok = new StringTokenizer( name, ":" );
417             if ( tok.hasMoreTokens() && "artifact".equals( tok.nextToken() ) )
418             {
419                 String field = tok.nextToken();
420                 String id = tok.nextToken();
421
422                 ArtifactMetadata artifact = artifacts.get( id );
423                 if ( artifact == null )
424                 {
425                     artifact = new ArtifactMetadata();
426                     artifact.setRepositoryId( repoId );
427                     artifact.setNamespace( namespace );
428                     artifact.setProject( projectId );
429                     artifact.setVersion( projectVersion );
430                     artifact.setId( id );
431                     artifacts.put( id, artifact );
432                 }
433
434                 String value = (String) entry.getValue();
435                 if ( "updated".equals( field ) )
436                 {
437                     artifact.setFileLastModified( Long.valueOf( value ) );
438                 }
439                 else if ( "size".equals( field ) )
440                 {
441                     artifact.setSize( Long.valueOf( value ) );
442                 }
443                 else if ( "whenGathered".equals( field ) )
444                 {
445                     artifact.setWhenGathered( new Date( Long.valueOf( value ) ) );
446                 }
447                 else if ( "version".equals( field ) )
448                 {
449                     artifact.setVersion( value );
450                 }
451                 else if ( "md5".equals( field ) )
452                 {
453                     artifact.setMd5( value );
454                 }
455                 else if ( "sha1".equals( field ) )
456                 {
457                     artifact.setSha1( value );
458                 }
459             }
460         }
461         return artifacts.values();
462     }
463
464     public Collection<String> getRepositories()
465     {
466         return configuration.getConfiguration().getManagedRepositoriesAsMap().keySet();
467     }
468
469     public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
470     {
471         // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
472         //  of this information (eg. in Lucene, as before)
473         // alternatively, we could build a referential tree in the content repository, however it would need some levels
474         // of depth to avoid being too broad to be useful (eg. /repository/checksums/a/ab/abcdef1234567)
475
476         List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
477         for ( String ns : getRootNamespaces( repositoryId ) )
478         {
479             getArtifactsByChecksum( artifacts, repositoryId, ns, checksum );
480         }
481         return artifacts;
482     }
483
484     public void deleteArtifact( String repoId, String namespace, String project, String version, String id )
485     {
486         File directory = new File( getDirectory( repoId ), namespace + "/" + project + "/" + version );
487
488         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
489
490         properties.remove( "artifact:updated:" + id );
491         properties.remove( "artifact:whenGathered:" + id );
492         properties.remove( "artifact:size:" + id );
493         properties.remove( "artifact:md5:" + id );
494         properties.remove( "artifact:sha1:" + id );
495         properties.remove( "artifact:version:" + id );
496
497         try
498         {
499             writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
500         }
501         catch ( IOException e )
502         {
503             // TODO
504             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
505         }
506     }
507
508     public void deleteRepository( String repoId )
509     {
510         try
511         {
512             FileUtils.deleteDirectory( getDirectory( repoId ) );
513         }
514         catch ( IOException e )
515         {
516             // TODO
517             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
518         }
519     }
520
521     private void getArtifactsByChecksum( List<ArtifactMetadata> artifacts, String repositoryId, String ns,
522                                          String checksum )
523     {
524         for ( String namespace : getNamespaces( repositoryId, ns ) )
525         {
526             getArtifactsByChecksum( artifacts, repositoryId, ns + "." + namespace, checksum );
527         }
528
529         for ( String project : getProjects( repositoryId, ns ) )
530         {
531             for ( String version : getProjectVersions( repositoryId, ns, project ) )
532             {
533                 for ( ArtifactMetadata artifact : getArtifacts( repositoryId, ns, project, version ) )
534                 {
535                     if ( checksum.equals( artifact.getMd5() ) || checksum.equals( artifact.getSha1() ) )
536                     {
537                         artifacts.add( artifact );
538                     }
539                 }
540             }
541         }
542     }
543
544     private File getMetadataDirectory( String repoId, String facetId )
545     {
546         return new File( getBaseDirectory( repoId ), "facets/" + facetId );
547     }
548
549     private String join( Collection<String> ids )
550     {
551         if ( !ids.isEmpty() )
552         {
553             StringBuilder s = new StringBuilder();
554             for ( String id : ids )
555             {
556                 s.append( id );
557                 s.append( "," );
558             }
559             return s.substring( 0, s.length() - 1 );
560         }
561         return "";
562     }
563
564     private void setProperty( Properties properties, String name, String value )
565     {
566         if ( value != null )
567         {
568             properties.setProperty( name, value );
569         }
570     }
571
572     public void updateArtifact( String repoId, String namespace, String projectId, String projectVersion,
573                                 ArtifactMetadata artifact )
574     {
575         File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
576
577         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
578
579         properties.setProperty( "artifact:updated:" + artifact.getId(),
580                                 Long.toString( artifact.getFileLastModified().getTime() ) );
581         properties.setProperty( "artifact:whenGathered:" + artifact.getId(),
582                                 Long.toString( artifact.getWhenGathered().getTime() ) );
583         properties.setProperty( "artifact:size:" + artifact.getId(), Long.toString( artifact.getSize() ) );
584         if ( artifact.getMd5() != null )
585         {
586             properties.setProperty( "artifact:md5:" + artifact.getId(), artifact.getMd5() );
587         }
588         if ( artifact.getSha1() != null )
589         {
590             properties.setProperty( "artifact:sha1:" + artifact.getId(), artifact.getSha1() );
591         }
592         properties.setProperty( "artifact:version:" + artifact.getId(), artifact.getVersion() );
593
594         try
595         {
596             writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
597         }
598         catch ( IOException e )
599         {
600             // TODO
601             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
602         }
603     }
604
605     private Properties readOrCreateProperties( File directory, String propertiesKey )
606     {
607         try
608         {
609             return readProperties( directory, propertiesKey );
610         }
611         catch ( FileNotFoundException e )
612         {
613             // ignore and return new properties
614         }
615         catch ( IOException e )
616         {
617             // TODO
618             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
619         }
620         return new Properties();
621     }
622
623     private Properties readProperties( File directory, String propertiesKey )
624         throws IOException
625     {
626         Properties properties = new Properties();
627         FileInputStream in = null;
628         try
629         {
630             in = new FileInputStream( new File( directory, propertiesKey + ".properties" ) );
631             properties.load( in );
632         }
633         finally
634         {
635             IOUtils.closeQuietly( in );
636         }
637         return properties;
638     }
639
640     public ProjectMetadata getProject( String repoId, String namespace, String projectId )
641     {
642         File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
643
644         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
645
646         ProjectMetadata project = new ProjectMetadata();
647         project.setNamespace( properties.getProperty( "namespace" ) );
648         project.setId( properties.getProperty( "id" ) );
649         return project;
650     }
651
652     public ProjectVersionMetadata getProjectVersion( String repoId, String namespace, String projectId,
653                                                      String projectVersion )
654     {
655         File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
656
657         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
658         String id = properties.getProperty( "id" );
659         ProjectVersionMetadata versionMetadata = null;
660         if ( id != null )
661         {
662             versionMetadata = new ProjectVersionMetadata();
663             versionMetadata.setId( id );
664             versionMetadata.setName( properties.getProperty( "name" ) );
665             versionMetadata.setDescription( properties.getProperty( "description" ) );
666             versionMetadata.setUrl( properties.getProperty( "url" ) );
667             versionMetadata.setIncomplete( Boolean.valueOf( properties.getProperty( "incomplete", "false" ) ) );
668
669             String scmConnection = properties.getProperty( "scm.connection" );
670             String scmDeveloperConnection = properties.getProperty( "scm.developerConnection" );
671             String scmUrl = properties.getProperty( "scm.url" );
672             if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
673             {
674                 Scm scm = new Scm();
675                 scm.setConnection( scmConnection );
676                 scm.setDeveloperConnection( scmDeveloperConnection );
677                 scm.setUrl( scmUrl );
678                 versionMetadata.setScm( scm );
679             }
680
681             String ciSystem = properties.getProperty( "ci.system" );
682             String ciUrl = properties.getProperty( "ci.url" );
683             if ( ciSystem != null || ciUrl != null )
684             {
685                 CiManagement ci = new CiManagement();
686                 ci.setSystem( ciSystem );
687                 ci.setUrl( ciUrl );
688                 versionMetadata.setCiManagement( ci );
689             }
690
691             String issueSystem = properties.getProperty( "issue.system" );
692             String issueUrl = properties.getProperty( "issue.url" );
693             if ( issueSystem != null || issueUrl != null )
694             {
695                 IssueManagement issueManagement = new IssueManagement();
696                 issueManagement.setSystem( issueSystem );
697                 issueManagement.setUrl( issueUrl );
698                 versionMetadata.setIssueManagement( issueManagement );
699             }
700
701             String orgName = properties.getProperty( "org.name" );
702             String orgUrl = properties.getProperty( "org.url" );
703             if ( orgName != null || orgUrl != null )
704             {
705                 Organization org = new Organization();
706                 org.setName( orgName );
707                 org.setUrl( orgUrl );
708                 versionMetadata.setOrganization( org );
709             }
710
711             boolean done = false;
712             int i = 0;
713             while ( !done )
714             {
715                 String licenseName = properties.getProperty( "license." + i + ".name" );
716                 String licenseUrl = properties.getProperty( "license." + i + ".url" );
717                 if ( licenseName != null || licenseUrl != null )
718                 {
719                     License license = new License();
720                     license.setName( licenseName );
721                     license.setUrl( licenseUrl );
722                     versionMetadata.addLicense( license );
723                 }
724                 else
725                 {
726                     done = true;
727                 }
728                 i++;
729             }
730
731             done = false;
732             i = 0;
733             while ( !done )
734             {
735                 String mailingListName = properties.getProperty( "mailingList." + i + ".name" );
736                 if ( mailingListName != null )
737                 {
738                     MailingList mailingList = new MailingList();
739                     mailingList.setName( mailingListName );
740                     mailingList.setMainArchiveUrl( properties.getProperty( "mailingList." + i + ".archive" ) );
741                     mailingList.setOtherArchives(
742                         Arrays.asList( properties.getProperty( "mailingList." + i + ".otherArchives" ).split( "," ) ) );
743                     mailingList.setPostAddress( properties.getProperty( "mailingList." + i + ".post" ) );
744                     mailingList.setSubscribeAddress( properties.getProperty( "mailingList." + i + ".subscribe" ) );
745                     mailingList.setUnsubscribeAddress( properties.getProperty( "mailingList." + i + ".unsubscribe" ) );
746                     versionMetadata.addMailingList( mailingList );
747                 }
748                 else
749                 {
750                     done = true;
751                 }
752                 i++;
753             }
754
755             done = false;
756             i = 0;
757             while ( !done )
758             {
759                 String dependencyArtifactId = properties.getProperty( "dependency." + i + ".artifactId" );
760                 if ( dependencyArtifactId != null )
761                 {
762                     Dependency dependency = new Dependency();
763                     dependency.setArtifactId( dependencyArtifactId );
764                     dependency.setGroupId( properties.getProperty( "dependency." + i + ".groupId" ) );
765                     dependency.setClassifier( properties.getProperty( "dependency." + i + ".classifier" ) );
766                     dependency.setOptional(
767                         Boolean.valueOf( properties.getProperty( "dependency." + i + ".optional" ) ) );
768                     dependency.setScope( properties.getProperty( "dependency." + i + ".scope" ) );
769                     dependency.setSystemPath( properties.getProperty( "dependency." + i + ".systemPath" ) );
770                     dependency.setType( properties.getProperty( "dependency." + i + ".type" ) );
771                     dependency.setVersion( properties.getProperty( "dependency." + i + ".version" ) );
772                     versionMetadata.addDependency( dependency );
773                 }
774                 else
775                 {
776                     done = true;
777                 }
778                 i++;
779             }
780
781             String facetIds = properties.getProperty( "facetIds", "" );
782             if ( facetIds.length() > 0 )
783             {
784                 for ( String facetId : facetIds.split( "," ) )
785                 {
786                     MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
787                     if ( factory == null )
788                     {
789                         log.error( "Attempted to load unknown metadata facet: " + facetId );
790                     }
791                     else
792                     {
793                         MetadataFacet facet = factory.createMetadataFacet();
794                         Map<String, String> map = new HashMap<String, String>();
795                         for ( Object key : new ArrayList( properties.keySet() ) )
796                         {
797                             String property = (String) key;
798                             if ( property.startsWith( facet.getFacetId() ) )
799                             {
800                                 map.put( property, properties.getProperty( property ) );
801                             }
802                         }
803                         facet.fromProperties( map );
804                         versionMetadata.addFacet( facet );
805                     }
806                 }
807             }
808
809             for ( MetadataFacet facet : versionMetadata.getFacetList() )
810             {
811                 properties.putAll( facet.toProperties() );
812             }
813         }
814         return versionMetadata;
815     }
816
817     public Collection<String> getArtifactVersions( String repoId, String namespace, String projectId,
818                                                    String projectVersion )
819     {
820         File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
821
822         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
823
824         Set<String> versions = new HashSet<String>();
825         for ( Map.Entry entry : properties.entrySet() )
826         {
827             String name = (String) entry.getKey();
828             if ( name.startsWith( "artifact:version:" ) )
829             {
830                 versions.add( (String) entry.getValue() );
831             }
832         }
833         return versions;
834     }
835
836     public Collection<ProjectVersionReference> getProjectReferences( String repoId, String namespace, String projectId,
837                                                                      String projectVersion )
838     {
839         File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
840
841         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
842         int numberOfRefs = Integer.valueOf( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
843
844         List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
845         for ( int i = 0; i < numberOfRefs; i++ )
846         {
847             ProjectVersionReference reference = new ProjectVersionReference();
848             reference.setProjectId( properties.getProperty( "ref:reference." + i + ".projectId" ) );
849             reference.setNamespace( properties.getProperty( "ref:reference." + i + ".namespace" ) );
850             reference.setProjectVersion( properties.getProperty( "ref:reference." + i + ".projectVersion" ) );
851             reference.setReferenceType( ProjectVersionReference.ReferenceType.valueOf(
852                 properties.getProperty( "ref:reference." + i + ".referenceType" ) ) );
853             references.add( reference );
854         }
855         return references;
856     }
857
858     public Collection<String> getRootNamespaces( String repoId )
859     {
860         return getNamespaces( repoId, null );
861     }
862
863     public Collection<String> getNamespaces( String repoId, String baseNamespace )
864     {
865         List<String> allNamespaces = new ArrayList<String>();
866         File directory = getDirectory( repoId );
867         File[] files = directory.listFiles();
868         if ( files != null )
869         {
870             for ( File namespace : files )
871             {
872                 if ( new File( namespace, NAMESPACE_METADATA_KEY + ".properties" ).exists() )
873                 {
874                     allNamespaces.add( namespace.getName() );
875                 }
876             }
877         }
878
879         Set<String> namespaces = new LinkedHashSet<String>();
880         int fromIndex = baseNamespace != null ? baseNamespace.length() + 1 : 0;
881         for ( String namespace : allNamespaces )
882         {
883             if ( baseNamespace == null || namespace.startsWith( baseNamespace + "." ) )
884             {
885                 int i = namespace.indexOf( '.', fromIndex );
886                 if ( i >= 0 )
887                 {
888                     namespaces.add( namespace.substring( fromIndex, i ) );
889                 }
890                 else
891                 {
892                     namespaces.add( namespace.substring( fromIndex ) );
893                 }
894             }
895         }
896         return new ArrayList<String>( namespaces );
897     }
898
899     public Collection<String> getProjects( String repoId, String namespace )
900     {
901         List<String> projects = new ArrayList<String>();
902         File directory = new File( getDirectory( repoId ), namespace );
903         File[] files = directory.listFiles();
904         if ( files != null )
905         {
906             for ( File project : files )
907             {
908                 if ( new File( project, PROJECT_METADATA_KEY + ".properties" ).exists() )
909                 {
910                     projects.add( project.getName() );
911                 }
912             }
913         }
914         return projects;
915     }
916
917     public Collection<String> getProjectVersions( String repoId, String namespace, String projectId )
918     {
919         List<String> projectVersions = new ArrayList<String>();
920         File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
921         File[] files = directory.listFiles();
922         if ( files != null )
923         {
924             for ( File projectVersion : files )
925             {
926                 if ( new File( projectVersion, PROJECT_VERSION_METADATA_KEY + ".properties" ).exists() )
927                 {
928                     projectVersions.add( projectVersion.getName() );
929                 }
930             }
931         }
932         return projectVersions;
933     }
934
935     private void writeProperties( Properties properties, File directory, String propertiesKey )
936         throws IOException
937     {
938         directory.mkdirs();
939         FileOutputStream os = new FileOutputStream( new File( directory, propertiesKey + ".properties" ) );
940         try
941         {
942             properties.store( os, null );
943         }
944         finally
945         {
946             IOUtils.closeQuietly( os );
947         }
948     }
949
950     public void setMetadataFacetFactories( Map<String, MetadataFacetFactory> metadataFacetFactories )
951     {
952         this.metadataFacetFactories = metadataFacetFactories;
953     }
954
955     public void setConfiguration( ArchivaConfiguration configuration )
956     {
957         this.configuration = configuration;
958     }
959 }