1 package org.apache.archiva.metadata.repository.file;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
22 import org.apache.archiva.configuration.ArchivaConfiguration;
23 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
24 import org.apache.archiva.metadata.model.ArtifactMetadata;
25 import org.apache.archiva.metadata.model.CiManagement;
26 import org.apache.archiva.metadata.model.Dependency;
27 import org.apache.archiva.metadata.model.IssueManagement;
28 import org.apache.archiva.metadata.model.License;
29 import org.apache.archiva.metadata.model.MailingList;
30 import org.apache.archiva.metadata.model.MetadataFacet;
31 import org.apache.archiva.metadata.model.MetadataFacetFactory;
32 import org.apache.archiva.metadata.model.Organization;
33 import org.apache.archiva.metadata.model.ProjectMetadata;
34 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
35 import org.apache.archiva.metadata.model.ProjectVersionReference;
36 import org.apache.archiva.metadata.model.Scm;
37 import org.apache.archiva.metadata.repository.MetadataRepository;
38 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
39 import org.apache.commons.io.FileUtils;
40 import org.apache.commons.io.IOUtils;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 import java.io.FileInputStream;
46 import java.io.FileNotFoundException;
47 import java.io.FileOutputStream;
48 import java.io.IOException;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.Collection;
52 import java.util.Collections;
53 import java.util.Comparator;
54 import java.util.Date;
55 import java.util.HashMap;
56 import java.util.HashSet;
57 import java.util.LinkedHashSet;
58 import java.util.List;
60 import java.util.Properties;
62 import java.util.StringTokenizer;
64 public class FileMetadataRepository
65 implements MetadataRepository
67 private final Map<String, MetadataFacetFactory> metadataFacetFactories;
69 private final ArchivaConfiguration configuration;
71 private Logger log = LoggerFactory.getLogger( FileMetadataRepository.class );
73 private static final String PROJECT_METADATA_KEY = "project-metadata";
75 private static final String PROJECT_VERSION_METADATA_KEY = "version-metadata";
77 private static final String NAMESPACE_METADATA_KEY = "namespace-metadata";
79 private static final String METADATA_KEY = "metadata";
81 public FileMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories,
82 ArchivaConfiguration configuration )
84 this.metadataFacetFactories = metadataFacetFactories;
85 this.configuration = configuration;
88 private File getBaseDirectory( String repoId )
90 // TODO: should be configurable, like the index
91 String basedir = configuration.getConfiguration().getManagedRepositoriesAsMap().get( repoId ).getLocation();
92 File dir = new File( basedir, ".archiva" );
96 private File getDirectory( String repoId )
98 return new File( getBaseDirectory( repoId ), "content" );
101 public void updateProject( String repoId, ProjectMetadata project )
103 updateProject( repoId, project.getNamespace(), project.getId() );
106 private void updateProject( String repoId, String namespace, String id )
108 // TODO: this is a more braindead implementation than we would normally expect, for prototyping purposes
109 updateNamespace( repoId, namespace );
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 );
119 catch ( IOException e )
122 log.error( e.getMessage(), e );
126 public void updateProjectVersion( String repoId, String namespace, String projectId,
127 ProjectVersionMetadata versionMetadata )
129 updateProject( repoId, namespace, projectId );
132 new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + versionMetadata.getId() );
134 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
135 // remove properties that are not references or artifacts
136 for ( Object key : new ArrayList<Object>( properties.keySet() ) )
138 String name = (String) key;
139 if ( !name.contains( ":" ) && !name.equals( "facetIds" ) )
141 properties.remove( name );
144 // clear the facet contents so old properties are no longer written
145 clearMetadataFacetProperties( versionMetadata.getFacetList(), properties, "" );
147 properties.setProperty( "id", versionMetadata.getId() );
148 setProperty( properties, "name", versionMetadata.getName() );
149 setProperty( properties, "description", versionMetadata.getDescription() );
150 setProperty( properties, "url", versionMetadata.getUrl() );
151 setProperty( properties, "incomplete", String.valueOf( versionMetadata.isIncomplete() ) );
152 if ( versionMetadata.getScm() != null )
154 setProperty( properties, "scm.connection", versionMetadata.getScm().getConnection() );
155 setProperty( properties, "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
156 setProperty( properties, "scm.url", versionMetadata.getScm().getUrl() );
158 if ( versionMetadata.getCiManagement() != null )
160 setProperty( properties, "ci.system", versionMetadata.getCiManagement().getSystem() );
161 setProperty( properties, "ci.url", versionMetadata.getCiManagement().getUrl() );
163 if ( versionMetadata.getIssueManagement() != null )
165 setProperty( properties, "issue.system", versionMetadata.getIssueManagement().getSystem() );
166 setProperty( properties, "issue.url", versionMetadata.getIssueManagement().getUrl() );
168 if ( versionMetadata.getOrganization() != null )
170 setProperty( properties, "org.name", versionMetadata.getOrganization().getName() );
171 setProperty( properties, "org.url", versionMetadata.getOrganization().getUrl() );
174 for ( License license : versionMetadata.getLicenses() )
176 setProperty( properties, "license." + i + ".name", license.getName() );
177 setProperty( properties, "license." + i + ".url", license.getUrl() );
181 for ( MailingList mailingList : versionMetadata.getMailingLists() )
183 setProperty( properties, "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
184 setProperty( properties, "mailingList." + i + ".name", mailingList.getName() );
185 setProperty( properties, "mailingList." + i + ".post", mailingList.getPostAddress() );
186 setProperty( properties, "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
187 setProperty( properties, "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
188 setProperty( properties, "mailingList." + i + ".otherArchives", join( mailingList.getOtherArchives() ) );
192 ProjectVersionReference reference = new ProjectVersionReference();
193 reference.setNamespace( namespace );
194 reference.setProjectId( projectId );
195 reference.setProjectVersion( versionMetadata.getId() );
196 reference.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
197 for ( Dependency dependency : versionMetadata.getDependencies() )
199 setProperty( properties, "dependency." + i + ".classifier", dependency.getClassifier() );
200 setProperty( properties, "dependency." + i + ".scope", dependency.getScope() );
201 setProperty( properties, "dependency." + i + ".systemPath", dependency.getSystemPath() );
202 setProperty( properties, "dependency." + i + ".artifactId", dependency.getArtifactId() );
203 setProperty( properties, "dependency." + i + ".groupId", dependency.getGroupId() );
204 setProperty( properties, "dependency." + i + ".version", dependency.getVersion() );
205 setProperty( properties, "dependency." + i + ".type", dependency.getType() );
206 setProperty( properties, "dependency." + i + ".optional", String.valueOf( dependency.isOptional() ) );
208 updateProjectReference( repoId, dependency.getGroupId(), dependency.getArtifactId(),
209 dependency.getVersion(), reference );
213 Set<String> facetIds = new LinkedHashSet<String>( versionMetadata.getFacetIds() );
214 facetIds.addAll( Arrays.asList( properties.getProperty( "facetIds", "" ).split( "," ) ) );
215 properties.setProperty( "facetIds", join( facetIds ) );
217 updateProjectVersionFacets( versionMetadata, properties );
221 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
223 catch ( IOException e )
226 log.error( e.getMessage(), e );
230 private void updateProjectVersionFacets( ProjectVersionMetadata versionMetadata, Properties properties )
232 for ( MetadataFacet facet : versionMetadata.getFacetList() )
234 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
236 properties.setProperty( facet.getFacetId() + ":" + entry.getKey(), entry.getValue() );
241 private static void clearMetadataFacetProperties( Collection<MetadataFacet> facetList, Properties properties,
244 List<Object> propsToRemove = new ArrayList<Object>();
245 for ( MetadataFacet facet : facetList )
247 for ( Object key : properties.keySet() )
249 String keyString = (String) key;
250 if ( keyString.startsWith( prefix + facet.getFacetId() + ":" ) )
252 propsToRemove.add( key );
257 for ( Object key : propsToRemove )
259 properties.remove( key );
263 private void updateProjectReference( String repoId, String namespace, String projectId, String projectVersion,
264 ProjectVersionReference reference )
266 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
268 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
269 int i = Integer.parseInt( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
270 setProperty( properties, "ref:lastReferenceNum", Integer.toString( i ) );
271 setProperty( properties, "ref:reference." + i + ".namespace", reference.getNamespace() );
272 setProperty( properties, "ref:reference." + i + ".projectId", reference.getProjectId() );
273 setProperty( properties, "ref:reference." + i + ".projectVersion", reference.getProjectVersion() );
274 setProperty( properties, "ref:reference." + i + ".referenceType", reference.getReferenceType().toString() );
278 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
280 catch ( IOException e )
283 log.error( e.getMessage(), e );
287 public void updateNamespace( String repoId, String namespace )
291 File namespaceDirectory = new File( getDirectory( repoId ), namespace );
292 Properties properties = new Properties();
293 properties.setProperty( "namespace", namespace );
294 writeProperties( properties, namespaceDirectory, NAMESPACE_METADATA_KEY );
297 catch ( IOException e )
300 log.error( e.getMessage(), e );
304 public List<String> getMetadataFacets( String repoId, String facetId )
306 File directory = getMetadataDirectory( repoId, facetId );
307 List<String> facets = new ArrayList<String>();
308 recurse( facets, "", directory );
312 public boolean hasMetadataFacet( String repositoryId, String facetId )
313 throws MetadataRepositoryException
315 // TODO could be improved a bit
316 return !getMetadataFacets( repositoryId, facetId ).isEmpty();
319 private void recurse( List<String> facets, String prefix, File directory )
321 File[] list = directory.listFiles();
324 for ( File dir : list )
326 if ( dir.isDirectory() )
328 recurse( facets, prefix + "/" + dir.getName(), dir );
330 else if ( dir.getName().equals( METADATA_KEY + ".properties" ) )
332 facets.add( prefix.substring( 1 ) );
338 public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
340 Properties properties;
344 readProperties( new File( getMetadataDirectory( repositoryId, facetId ), name ), METADATA_KEY );
346 catch ( FileNotFoundException e )
350 catch ( IOException e )
353 log.error( e.getMessage(), e );
356 MetadataFacet metadataFacet = null;
357 MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
358 if ( metadataFacetFactory != null )
360 metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
361 Map<String, String> map = new HashMap<String, String>();
362 for ( Object key : new ArrayList( properties.keySet() ) )
364 String property = (String) key;
365 map.put( property, properties.getProperty( property ) );
367 metadataFacet.fromProperties( map );
369 return metadataFacet;
372 public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
374 Properties properties = new Properties();
375 properties.putAll( metadataFacet.toProperties() );
380 new File( getMetadataDirectory( repositoryId, metadataFacet.getFacetId() ), metadataFacet.getName() );
381 writeProperties( properties, directory, METADATA_KEY );
383 catch ( IOException e )
386 log.error( e.getMessage(), e );
390 public void removeMetadataFacets( String repositoryId, String facetId )
392 File dir = getMetadataDirectory( repositoryId, facetId );
393 if ( !FileUtils.deleteQuietly( dir ) )
395 log.error( "Cannot delete the metadata repository {}", dir );
399 public void removeMetadataFacet( String repoId, String facetId, String name )
401 File dir = new File( getMetadataDirectory( repoId, facetId ), name );
402 if ( !FileUtils.deleteQuietly( dir ) )
404 log.error( "Cannot delete the metadata repository {}", dir );
408 public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
410 // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
411 // of this information (eg. in Lucene, as before)
413 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
414 for ( String ns : getRootNamespaces( repoId ) )
416 getArtifactsByDateRange( artifacts, repoId, ns, startTime, endTime );
418 Collections.sort( artifacts, new ArtifactComparator() );
422 private void getArtifactsByDateRange( List<ArtifactMetadata> artifacts, String repoId, String ns, Date startTime,
425 for ( String namespace : getNamespaces( repoId, ns ) )
427 getArtifactsByDateRange( artifacts, repoId, ns + "." + namespace, startTime, endTime );
430 for ( String project : getProjects( repoId, ns ) )
432 for ( String version : getProjectVersions( repoId, ns, project ) )
434 for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
436 if ( startTime == null || startTime.before( artifact.getWhenGathered() ) )
438 if ( endTime == null || endTime.after( artifact.getWhenGathered() ) )
440 artifacts.add( artifact );
448 public Collection<ArtifactMetadata> getArtifacts( String repoId, String namespace, String projectId,
449 String projectVersion )
451 Map<String, ArtifactMetadata> artifacts = new HashMap<String, ArtifactMetadata>();
453 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
455 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
457 for ( Map.Entry entry : properties.entrySet() )
459 String name = (String) entry.getKey();
460 StringTokenizer tok = new StringTokenizer( name, ":" );
461 if ( tok.hasMoreTokens() && "artifact".equals( tok.nextToken() ) )
463 String field = tok.nextToken();
464 String id = tok.nextToken();
466 ArtifactMetadata artifact = artifacts.get( id );
467 if ( artifact == null )
469 artifact = new ArtifactMetadata();
470 artifact.setRepositoryId( repoId );
471 artifact.setNamespace( namespace );
472 artifact.setProject( projectId );
473 artifact.setProjectVersion( projectVersion );
474 artifact.setVersion( projectVersion );
475 artifact.setId( id );
476 artifacts.put( id, artifact );
479 String value = (String) entry.getValue();
480 if ( "updated".equals( field ) )
482 artifact.setFileLastModified( Long.parseLong( value ) );
484 else if ( "size".equals( field ) )
486 artifact.setSize( Long.valueOf( value ) );
488 else if ( "whenGathered".equals( field ) )
490 artifact.setWhenGathered( new Date( Long.parseLong( value ) ) );
492 else if ( "version".equals( field ) )
494 artifact.setVersion( value );
496 else if ( "md5".equals( field ) )
498 artifact.setMd5( value );
500 else if ( "sha1".equals( field ) )
502 artifact.setSha1( value );
504 else if ( "facetIds".equals( field ) )
506 if ( value.length() > 0 )
508 String propertyPrefix = "artifact:facet:" + id + ":";
509 for ( String facetId : value.split( "," ) )
511 MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
512 if ( factory == null )
514 log.error( "Attempted to load unknown artifact metadata facet: " + facetId );
518 MetadataFacet facet = factory.createMetadataFacet();
519 String prefix = propertyPrefix + facet.getFacetId();
520 Map<String, String> map = new HashMap<String, String>();
521 for ( Object key : new ArrayList( properties.keySet() ) )
523 String property = (String) key;
524 if ( property.startsWith( prefix ) )
526 map.put( property.substring( prefix.length() + 1 ),
527 properties.getProperty( property ) );
530 facet.fromProperties( map );
531 artifact.addFacet( facet );
536 updateArtifactFacets( artifact, properties );
540 return artifacts.values();
545 // it's all instantly persisted
550 // nothing additional to close
555 log.warn( "Attempted to revert a session, but the file-based repository storage doesn't support it" );
558 public boolean canObtainAccess( Class<?> aClass )
563 public Object obtainAccess( Class<?> aClass )
565 throw new IllegalArgumentException(
566 "Access using " + aClass + " is not supported on the file metadata storage" );
569 private void updateArtifactFacets( ArtifactMetadata artifact, Properties properties )
571 String propertyPrefix = "artifact:facet:" + artifact.getId() + ":";
572 for ( MetadataFacet facet : artifact.getFacetList() )
574 for ( Map.Entry<String, String> e : facet.toProperties().entrySet() )
576 String key = propertyPrefix + facet.getFacetId() + ":" + e.getKey();
577 properties.setProperty( key, e.getValue() );
582 public Collection<String> getRepositories()
584 List<String> repositories = new ArrayList<String>();
585 for ( ManagedRepositoryConfiguration managedRepositoryConfiguration : configuration.getConfiguration().getManagedRepositories() )
587 repositories.add( managedRepositoryConfiguration.getId() );
592 public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
594 // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
595 // of this information (eg. in Lucene, as before)
596 // alternatively, we could build a referential tree in the content repository, however it would need some levels
597 // of depth to avoid being too broad to be useful (eg. /repository/checksums/a/ab/abcdef1234567)
599 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
600 for ( String ns : getRootNamespaces( repositoryId ) )
602 getArtifactsByChecksum( artifacts, repositoryId, ns, checksum );
607 public void removeNamespace( String repositoryId, String project )
608 throws MetadataRepositoryException
612 File namespaceDirectory = new File( getDirectory( repositoryId ), project );
613 FileUtils.deleteDirectory( namespaceDirectory );
614 //Properties properties = new Properties();
615 //properties.setProperty( "namespace", namespace );
616 //writeProperties( properties, namespaceDirectory, NAMESPACE_METADATA_KEY );
619 catch ( IOException e )
621 throw new MetadataRepositoryException( e.getMessage(), e );
625 public void removeArtifact( ArtifactMetadata artifactMetadata, String baseVersion )
626 throws MetadataRepositoryException
629 File directory = new File( getDirectory( artifactMetadata.getRepositoryId() ),
630 artifactMetadata.getNamespace() + "/" + artifactMetadata.getProject() + "/"
633 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
635 String id = artifactMetadata.getId();
637 properties.remove( "artifact:updated:" + id );
638 properties.remove( "artifact:whenGathered:" + id );
639 properties.remove( "artifact:size:" + id );
640 properties.remove( "artifact:md5:" + id );
641 properties.remove( "artifact:sha1:" + id );
642 properties.remove( "artifact:version:" + id );
643 properties.remove( "artifact:facetIds:" + id );
645 String prefix = "artifact:facet:" + id + ":";
646 for ( Object key : new ArrayList<Object>( properties.keySet() ) )
648 String property = (String) key;
649 if ( property.startsWith( prefix ) )
651 properties.remove( property );
657 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
659 catch ( IOException e )
662 log.error( e.getMessage(), e );
667 public void removeArtifact( String repoId, String namespace, String project, String version, String id )
670 File directory = new File( getDirectory( repoId ), namespace + "/" + project + "/" + version );
672 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
674 properties.remove( "artifact:updated:" + id );
675 properties.remove( "artifact:whenGathered:" + id );
676 properties.remove( "artifact:size:" + id );
677 properties.remove( "artifact:md5:" + id );
678 properties.remove( "artifact:sha1:" + id );
679 properties.remove( "artifact:version:" + id );
680 properties.remove( "artifact:facetIds:" + id );
682 String prefix = "artifact:facet:" + id + ":";
683 for ( Object key : new ArrayList<Object>( properties.keySet() ) )
685 String property = (String) key;
686 if ( property.startsWith( prefix ) )
688 properties.remove( property );
695 FileUtils.deleteDirectory( directory );
697 //writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
699 catch ( IOException e )
702 log.error( e.getMessage(), e );
707 * FIXME implements this !!!!
709 * @param repositoryId
712 * @param projectVersion
713 * @param metadataFacet will remove artifacts which have this {@link MetadataFacet} using equals
714 * @throws MetadataRepositoryException
716 public void removeArtifact( String repositoryId, String namespace, String project, String projectVersion,
717 MetadataFacet metadataFacet )
718 throws MetadataRepositoryException
720 throw new UnsupportedOperationException( "not implemented" );
723 public void removeRepository( String repoId )
725 File dir = getDirectory( repoId );
726 if ( !FileUtils.deleteQuietly( dir ) )
728 log.error( "Cannot delete repository {}", dir );
732 private void getArtifactsByChecksum( List<ArtifactMetadata> artifacts, String repositoryId, String ns,
735 for ( String namespace : getNamespaces( repositoryId, ns ) )
737 getArtifactsByChecksum( artifacts, repositoryId, ns + "." + namespace, checksum );
740 for ( String project : getProjects( repositoryId, ns ) )
742 for ( String version : getProjectVersions( repositoryId, ns, project ) )
744 for ( ArtifactMetadata artifact : getArtifacts( repositoryId, ns, project, version ) )
746 if ( checksum.equals( artifact.getMd5() ) || checksum.equals( artifact.getSha1() ) )
748 artifacts.add( artifact );
755 private File getMetadataDirectory( String repoId, String facetId )
757 return new File( getBaseDirectory( repoId ), "facets/" + facetId );
760 private String join( Collection<String> ids )
762 if ( ids != null && !ids.isEmpty() )
764 StringBuilder s = new StringBuilder();
765 for ( String id : ids )
770 return s.substring( 0, s.length() - 1 );
775 private void setProperty( Properties properties, String name, String value )
779 properties.setProperty( name, value );
783 public void updateArtifact( String repoId, String namespace, String projectId, String projectVersion,
784 ArtifactMetadata artifact )
786 ProjectVersionMetadata metadata = new ProjectVersionMetadata();
787 metadata.setId( projectVersion );
788 updateProjectVersion( repoId, namespace, projectId, metadata );
790 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
792 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
794 clearMetadataFacetProperties( artifact.getFacetList(), properties, "artifact:facet:" + artifact.getId() + ":" );
796 String id = artifact.getId();
797 properties.setProperty( "artifact:updated:" + id, Long.toString( artifact.getFileLastModified().getTime() ) );
798 properties.setProperty( "artifact:whenGathered:" + id, Long.toString( artifact.getWhenGathered().getTime() ) );
799 properties.setProperty( "artifact:size:" + id, Long.toString( artifact.getSize() ) );
800 if ( artifact.getMd5() != null )
802 properties.setProperty( "artifact:md5:" + id, artifact.getMd5() );
804 if ( artifact.getSha1() != null )
806 properties.setProperty( "artifact:sha1:" + id, artifact.getSha1() );
808 properties.setProperty( "artifact:version:" + id, artifact.getVersion() );
810 Set<String> facetIds = new LinkedHashSet<String>( artifact.getFacetIds() );
811 String property = "artifact:facetIds:" + id;
812 facetIds.addAll( Arrays.asList( properties.getProperty( property, "" ).split( "," ) ) );
813 properties.setProperty( property, join( facetIds ) );
815 updateArtifactFacets( artifact, properties );
819 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
821 catch ( IOException e )
824 log.error( e.getMessage(), e );
828 private Properties readOrCreateProperties( File directory, String propertiesKey )
832 return readProperties( directory, propertiesKey );
834 catch ( FileNotFoundException e )
836 // ignore and return new properties
838 catch ( IOException e )
841 log.error( e.getMessage(), e );
843 return new Properties();
846 private Properties readProperties( File directory, String propertiesKey )
849 Properties properties = new Properties();
850 FileInputStream in = null;
853 in = new FileInputStream( new File( directory, propertiesKey + ".properties" ) );
854 properties.load( in );
858 IOUtils.closeQuietly( in );
863 public ProjectMetadata getProject( String repoId, String namespace, String projectId )
865 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
867 Properties properties = readOrCreateProperties( directory, PROJECT_METADATA_KEY );
869 ProjectMetadata project = null;
871 String id = properties.getProperty( "id" );
874 project = new ProjectMetadata();
875 project.setNamespace( properties.getProperty( "namespace" ) );
882 public ProjectVersionMetadata getProjectVersion( String repoId, String namespace, String projectId,
883 String projectVersion )
885 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
887 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
888 String id = properties.getProperty( "id" );
889 ProjectVersionMetadata versionMetadata = null;
892 versionMetadata = new ProjectVersionMetadata();
893 versionMetadata.setId( id );
894 versionMetadata.setName( properties.getProperty( "name" ) );
895 versionMetadata.setDescription( properties.getProperty( "description" ) );
896 versionMetadata.setUrl( properties.getProperty( "url" ) );
897 versionMetadata.setIncomplete( Boolean.valueOf( properties.getProperty( "incomplete", "false" ) ) );
899 String scmConnection = properties.getProperty( "scm.connection" );
900 String scmDeveloperConnection = properties.getProperty( "scm.developerConnection" );
901 String scmUrl = properties.getProperty( "scm.url" );
902 if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
905 scm.setConnection( scmConnection );
906 scm.setDeveloperConnection( scmDeveloperConnection );
907 scm.setUrl( scmUrl );
908 versionMetadata.setScm( scm );
911 String ciSystem = properties.getProperty( "ci.system" );
912 String ciUrl = properties.getProperty( "ci.url" );
913 if ( ciSystem != null || ciUrl != null )
915 CiManagement ci = new CiManagement();
916 ci.setSystem( ciSystem );
918 versionMetadata.setCiManagement( ci );
921 String issueSystem = properties.getProperty( "issue.system" );
922 String issueUrl = properties.getProperty( "issue.url" );
923 if ( issueSystem != null || issueUrl != null )
925 IssueManagement issueManagement = new IssueManagement();
926 issueManagement.setSystem( issueSystem );
927 issueManagement.setUrl( issueUrl );
928 versionMetadata.setIssueManagement( issueManagement );
931 String orgName = properties.getProperty( "org.name" );
932 String orgUrl = properties.getProperty( "org.url" );
933 if ( orgName != null || orgUrl != null )
935 Organization org = new Organization();
936 org.setName( orgName );
937 org.setUrl( orgUrl );
938 versionMetadata.setOrganization( org );
941 boolean done = false;
945 String licenseName = properties.getProperty( "license." + i + ".name" );
946 String licenseUrl = properties.getProperty( "license." + i + ".url" );
947 if ( licenseName != null || licenseUrl != null )
949 License license = new License();
950 license.setName( licenseName );
951 license.setUrl( licenseUrl );
952 versionMetadata.addLicense( license );
965 String mailingListName = properties.getProperty( "mailingList." + i + ".name" );
966 if ( mailingListName != null )
968 MailingList mailingList = new MailingList();
969 mailingList.setName( mailingListName );
970 mailingList.setMainArchiveUrl( properties.getProperty( "mailingList." + i + ".archive" ) );
971 String p = properties.getProperty( "mailingList." + i + ".otherArchives" );
972 if ( p != null && p.length() > 0 )
974 mailingList.setOtherArchives( Arrays.asList( p.split( "," ) ) );
978 mailingList.setOtherArchives( Collections.<String>emptyList() );
980 mailingList.setPostAddress( properties.getProperty( "mailingList." + i + ".post" ) );
981 mailingList.setSubscribeAddress( properties.getProperty( "mailingList." + i + ".subscribe" ) );
982 mailingList.setUnsubscribeAddress( properties.getProperty( "mailingList." + i + ".unsubscribe" ) );
983 versionMetadata.addMailingList( mailingList );
996 String dependencyArtifactId = properties.getProperty( "dependency." + i + ".artifactId" );
997 if ( dependencyArtifactId != null )
999 Dependency dependency = new Dependency();
1000 dependency.setArtifactId( dependencyArtifactId );
1001 dependency.setGroupId( properties.getProperty( "dependency." + i + ".groupId" ) );
1002 dependency.setClassifier( properties.getProperty( "dependency." + i + ".classifier" ) );
1003 dependency.setOptional(
1004 Boolean.valueOf( properties.getProperty( "dependency." + i + ".optional" ) ) );
1005 dependency.setScope( properties.getProperty( "dependency." + i + ".scope" ) );
1006 dependency.setSystemPath( properties.getProperty( "dependency." + i + ".systemPath" ) );
1007 dependency.setType( properties.getProperty( "dependency." + i + ".type" ) );
1008 dependency.setVersion( properties.getProperty( "dependency." + i + ".version" ) );
1009 dependency.setOptional(
1010 Boolean.valueOf( properties.getProperty( "dependency." + i + ".optional" ) ) );
1011 versionMetadata.addDependency( dependency );
1020 String facetIds = properties.getProperty( "facetIds", "" );
1021 if ( facetIds.length() > 0 )
1023 for ( String facetId : facetIds.split( "," ) )
1025 MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
1026 if ( factory == null )
1028 log.error( "Attempted to load unknown project version metadata facet: {}", facetId );
1032 MetadataFacet facet = factory.createMetadataFacet();
1033 Map<String, String> map = new HashMap<String, String>();
1034 for ( Object key : new ArrayList( properties.keySet() ) )
1036 String property = (String) key;
1037 if ( property.startsWith( facet.getFacetId() ) )
1039 map.put( property.substring( facet.getFacetId().length() + 1 ),
1040 properties.getProperty( property ) );
1043 facet.fromProperties( map );
1044 versionMetadata.addFacet( facet );
1049 updateProjectVersionFacets( versionMetadata, properties );
1051 return versionMetadata;
1054 public Collection<String> getArtifactVersions( String repoId, String namespace, String projectId,
1055 String projectVersion )
1057 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1059 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1061 Set<String> versions = new HashSet<String>();
1062 for ( Map.Entry entry : properties.entrySet() )
1064 String name = (String) entry.getKey();
1065 if ( name.startsWith( "artifact:version:" ) )
1067 versions.add( (String) entry.getValue() );
1073 public Collection<ProjectVersionReference> getProjectReferences( String repoId, String namespace, String projectId,
1074 String projectVersion )
1076 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1078 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1079 int numberOfRefs = Integer.parseInt( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
1081 List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
1082 for ( int i = 0; i < numberOfRefs; i++ )
1084 ProjectVersionReference reference = new ProjectVersionReference();
1085 reference.setProjectId( properties.getProperty( "ref:reference." + i + ".projectId" ) );
1086 reference.setNamespace( properties.getProperty( "ref:reference." + i + ".namespace" ) );
1087 reference.setProjectVersion( properties.getProperty( "ref:reference." + i + ".projectVersion" ) );
1088 reference.setReferenceType( ProjectVersionReference.ReferenceType.valueOf(
1089 properties.getProperty( "ref:reference." + i + ".referenceType" ) ) );
1090 references.add( reference );
1095 public Collection<String> getRootNamespaces( String repoId )
1097 return getNamespaces( repoId, null );
1100 public Collection<String> getNamespaces( String repoId, String baseNamespace )
1102 List<String> allNamespaces = new ArrayList<String>();
1103 File directory = getDirectory( repoId );
1104 File[] files = directory.listFiles();
1105 if ( files != null )
1107 for ( File namespace : files )
1109 if ( new File( namespace, NAMESPACE_METADATA_KEY + ".properties" ).exists() )
1111 allNamespaces.add( namespace.getName() );
1116 Set<String> namespaces = new LinkedHashSet<String>();
1117 int fromIndex = baseNamespace != null ? baseNamespace.length() + 1 : 0;
1118 for ( String namespace : allNamespaces )
1120 if ( baseNamespace == null || namespace.startsWith( baseNamespace + "." ) )
1122 int i = namespace.indexOf( '.', fromIndex );
1125 namespaces.add( namespace.substring( fromIndex, i ) );
1129 namespaces.add( namespace.substring( fromIndex ) );
1133 return new ArrayList<String>( namespaces );
1136 public Collection<String> getProjects( String repoId, String namespace )
1138 List<String> projects = new ArrayList<String>();
1139 File directory = new File( getDirectory( repoId ), namespace );
1140 File[] files = directory.listFiles();
1141 if ( files != null )
1143 for ( File project : files )
1145 if ( new File( project, PROJECT_METADATA_KEY + ".properties" ).exists() )
1147 projects.add( project.getName() );
1154 public Collection<String> getProjectVersions( String repoId, String namespace, String projectId )
1156 List<String> projectVersions = new ArrayList<String>();
1157 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
1158 File[] files = directory.listFiles();
1159 if ( files != null )
1161 for ( File projectVersion : files )
1163 if ( new File( projectVersion, PROJECT_VERSION_METADATA_KEY + ".properties" ).exists() )
1165 projectVersions.add( projectVersion.getName() );
1169 return projectVersions;
1172 public void removeProject( String repositoryId, String namespace, String projectId )
1173 throws MetadataRepositoryException
1175 File directory = new File( getDirectory( repositoryId ), namespace + "/" + projectId );
1178 if ( directory.exists() )
1180 FileUtils.deleteDirectory( directory );
1183 catch ( IOException e )
1185 throw new MetadataRepositoryException( e.getMessage(), e );
1189 public void removeProjectVersion( String repoId, String namespace, String projectId, String projectVersion )
1190 throws MetadataRepositoryException
1192 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1193 if ( directory.exists() )
1197 FileUtils.deleteDirectory( directory );
1199 catch ( IOException e )
1201 throw new MetadataRepositoryException( e.getMessage(), e );
1206 private void writeProperties( Properties properties, File directory, String propertiesKey )
1210 FileOutputStream os = new FileOutputStream( new File( directory, propertiesKey + ".properties" ) );
1213 properties.store( os, null );
1217 IOUtils.closeQuietly( os );
1221 private static class ArtifactComparator
1222 implements Comparator<ArtifactMetadata>
1224 public int compare( ArtifactMetadata artifact1, ArtifactMetadata artifact2 )
1226 if ( artifact1.getWhenGathered() == artifact2.getWhenGathered() )
1230 if ( artifact1.getWhenGathered() == null )
1234 if ( artifact2.getWhenGathered() == null )
1238 return artifact1.getWhenGathered().compareTo( artifact2.getWhenGathered() );
1242 public List<ArtifactMetadata> getArtifacts( String repoId )
1244 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
1245 for ( String ns : getRootNamespaces( repoId ) )
1247 getArtifacts( artifacts, repoId, ns );
1252 private void getArtifacts( List<ArtifactMetadata> artifacts, String repoId, String ns )
1254 for ( String namespace : getNamespaces( repoId, ns ) )
1256 getArtifacts( artifacts, repoId, ns + "." + namespace );
1259 for ( String project : getProjects( repoId, ns ) )
1261 for ( String version : getProjectVersions( repoId, ns, project ) )
1263 for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
1265 artifacts.add( artifact );