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