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.archiva.metadata.repository.MetadataResolutionException;
40 import org.apache.commons.io.FileUtils;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 import java.io.FileNotFoundException;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.io.OutputStream;
49 import java.nio.file.Files;
50 import java.nio.file.NoSuchFileException;
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.Collection;
54 import java.util.Collections;
55 import java.util.Comparator;
56 import java.util.Date;
57 import java.util.HashMap;
58 import java.util.HashSet;
59 import java.util.LinkedHashSet;
60 import java.util.List;
62 import java.util.Properties;
64 import java.util.StringTokenizer;
66 public class FileMetadataRepository
67 implements MetadataRepository
69 private final Map<String, MetadataFacetFactory> metadataFacetFactories;
71 private final ArchivaConfiguration configuration;
73 private Logger log = LoggerFactory.getLogger( FileMetadataRepository.class );
75 private static final String PROJECT_METADATA_KEY = "project-metadata";
77 private static final String PROJECT_VERSION_METADATA_KEY = "version-metadata";
79 private static final String NAMESPACE_METADATA_KEY = "namespace-metadata";
81 private static final String METADATA_KEY = "metadata";
83 public FileMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories,
84 ArchivaConfiguration configuration )
86 this.metadataFacetFactories = metadataFacetFactories;
87 this.configuration = configuration;
90 private File getBaseDirectory( String repoId )
93 // TODO: should be configurable, like the index
94 ManagedRepositoryConfiguration managedRepositoryConfiguration =
95 configuration.getConfiguration().getManagedRepositoriesAsMap().get( repoId );
96 if ( managedRepositoryConfiguration == null )
98 return Files.createTempDirectory( repoId ).toFile();
100 String basedir = managedRepositoryConfiguration.getLocation();
101 return new File( basedir, ".archiva" );
104 private File getDirectory( String repoId )
107 return new File( getBaseDirectory( repoId ), "content" );
111 public void updateProject( String repoId, ProjectMetadata project )
113 updateProject( repoId, project.getNamespace(), project.getId() );
116 private void updateProject( String repoId, String namespace, String id )
118 // TODO: this is a more braindead implementation than we would normally expect, for prototyping purposes
119 updateNamespace( repoId, namespace );
123 File namespaceDirectory = new File( getDirectory( repoId ), namespace );
124 Properties properties = new Properties();
125 properties.setProperty( "namespace", namespace );
126 properties.setProperty( "id", id );
127 writeProperties( properties, new File( namespaceDirectory, id ), PROJECT_METADATA_KEY );
129 catch ( IOException e )
132 log.error( e.getMessage(), e );
137 public void updateProjectVersion( String repoId, String namespace, String projectId,
138 ProjectVersionMetadata versionMetadata )
143 updateProject( repoId, namespace, projectId );
146 new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + versionMetadata.getId() );
148 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
149 // remove properties that are not references or artifacts
150 for ( Object key : new ArrayList( properties.keySet() ) )
152 String name = (String) key;
153 if ( !name.contains( ":" ) && !name.equals( "facetIds" ) )
155 properties.remove( name );
158 // clear the facet contents so old properties are no longer written
159 clearMetadataFacetProperties( versionMetadata.getFacetList(), properties, "" );
161 properties.setProperty( "id", versionMetadata.getId() );
162 setProperty( properties, "name", versionMetadata.getName() );
163 setProperty( properties, "description", versionMetadata.getDescription() );
164 setProperty( properties, "url", versionMetadata.getUrl() );
165 setProperty( properties, "incomplete", String.valueOf( versionMetadata.isIncomplete() ) );
166 if ( versionMetadata.getScm() != null )
168 setProperty( properties, "scm.connection", versionMetadata.getScm().getConnection() );
169 setProperty( properties, "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
170 setProperty( properties, "scm.url", versionMetadata.getScm().getUrl() );
172 if ( versionMetadata.getCiManagement() != null )
174 setProperty( properties, "ci.system", versionMetadata.getCiManagement().getSystem() );
175 setProperty( properties, "ci.url", versionMetadata.getCiManagement().getUrl() );
177 if ( versionMetadata.getIssueManagement() != null )
179 setProperty( properties, "issue.system", versionMetadata.getIssueManagement().getSystem() );
180 setProperty( properties, "issue.url", versionMetadata.getIssueManagement().getUrl() );
182 if ( versionMetadata.getOrganization() != null )
184 setProperty( properties, "org.name", versionMetadata.getOrganization().getName() );
185 setProperty( properties, "org.url", versionMetadata.getOrganization().getUrl() );
188 for ( License license : versionMetadata.getLicenses() )
190 setProperty( properties, "license." + i + ".name", license.getName() );
191 setProperty( properties, "license." + i + ".url", license.getUrl() );
195 for ( MailingList mailingList : versionMetadata.getMailingLists() )
197 setProperty( properties, "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
198 setProperty( properties, "mailingList." + i + ".name", mailingList.getName() );
199 setProperty( properties, "mailingList." + i + ".post", mailingList.getPostAddress() );
200 setProperty( properties, "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
201 setProperty( properties, "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
202 setProperty( properties, "mailingList." + i + ".otherArchives",
203 join( mailingList.getOtherArchives() ) );
207 ProjectVersionReference reference = new ProjectVersionReference();
208 reference.setNamespace( namespace );
209 reference.setProjectId( projectId );
210 reference.setProjectVersion( versionMetadata.getId() );
211 reference.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
212 for ( Dependency dependency : versionMetadata.getDependencies() )
214 setProperty( properties, "dependency." + i + ".classifier", dependency.getClassifier() );
215 setProperty( properties, "dependency." + i + ".scope", dependency.getScope() );
216 setProperty( properties, "dependency." + i + ".systemPath", dependency.getSystemPath() );
217 setProperty( properties, "dependency." + i + ".artifactId", dependency.getArtifactId() );
218 setProperty( properties, "dependency." + i + ".groupId", dependency.getGroupId() );
219 setProperty( properties, "dependency." + i + ".version", dependency.getVersion() );
220 setProperty( properties, "dependency." + i + ".type", dependency.getType() );
221 setProperty( properties, "dependency." + i + ".optional", String.valueOf( dependency.isOptional() ) );
223 updateProjectReference( repoId, dependency.getGroupId(), dependency.getArtifactId(),
224 dependency.getVersion(), reference );
228 Set<String> facetIds = new LinkedHashSet<String>( versionMetadata.getFacetIds() );
229 facetIds.addAll( Arrays.asList( properties.getProperty( "facetIds", "" ).split( "," ) ) );
230 properties.setProperty( "facetIds", join( facetIds ) );
232 updateProjectVersionFacets( versionMetadata, properties );
234 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
236 catch ( IOException e )
239 log.error( e.getMessage(), e );
243 private void updateProjectVersionFacets( ProjectVersionMetadata versionMetadata, Properties properties )
245 for ( MetadataFacet facet : versionMetadata.getFacetList() )
247 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
249 properties.setProperty( facet.getFacetId() + ":" + entry.getKey(), entry.getValue() );
254 private static void clearMetadataFacetProperties( Collection<MetadataFacet> facetList, Properties properties,
257 List<Object> propsToRemove = new ArrayList<>();
258 for ( MetadataFacet facet : facetList )
260 for ( Object key : new ArrayList( properties.keySet() ) )
262 String keyString = (String) key;
263 if ( keyString.startsWith( prefix + facet.getFacetId() + ":" ) )
265 propsToRemove.add( key );
270 for ( Object key : propsToRemove )
272 properties.remove( key );
276 private void updateProjectReference( String repoId, String namespace, String projectId, String projectVersion,
277 ProjectVersionReference reference )
281 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
283 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
284 int i = Integer.parseInt( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
285 setProperty( properties, "ref:lastReferenceNum", Integer.toString( i ) );
286 setProperty( properties, "ref:reference." + i + ".namespace", reference.getNamespace() );
287 setProperty( properties, "ref:reference." + i + ".projectId", reference.getProjectId() );
288 setProperty( properties, "ref:reference." + i + ".projectVersion", reference.getProjectVersion() );
289 setProperty( properties, "ref:reference." + i + ".referenceType", reference.getReferenceType().toString() );
291 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
293 catch ( IOException e )
296 log.error( e.getMessage(), e );
301 public void updateNamespace( String repoId, String namespace )
305 File namespaceDirectory = new File( getDirectory( repoId ), namespace );
306 Properties properties = new Properties();
307 properties.setProperty( "namespace", namespace );
308 writeProperties( properties, namespaceDirectory, NAMESPACE_METADATA_KEY );
311 catch ( IOException e )
314 log.error( e.getMessage(), e );
319 public List<String> getMetadataFacets( String repoId, String facetId )
320 throws MetadataRepositoryException
324 File directory = getMetadataDirectory( repoId, facetId );
325 List<String> facets = new ArrayList<>();
326 recurse( facets, "", directory );
329 catch ( IOException e )
331 throw new MetadataRepositoryException( e.getMessage(), e );
336 public boolean hasMetadataFacet( String repositoryId, String facetId )
337 throws MetadataRepositoryException
339 // TODO could be improved a bit
340 return !getMetadataFacets( repositoryId, facetId ).isEmpty();
343 private void recurse( List<String> facets, String prefix, File directory )
345 File[] list = directory.listFiles();
348 for ( File dir : list )
350 if ( dir.isDirectory() )
352 recurse( facets, prefix + "/" + dir.getName(), dir );
354 else if ( dir.getName().equals( METADATA_KEY + ".properties" ) )
356 facets.add( prefix.substring( 1 ) );
363 public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
365 Properties properties;
369 readProperties( new File( getMetadataDirectory( repositoryId, facetId ), name ), METADATA_KEY );
371 catch ( FileNotFoundException e )
375 catch ( IOException e )
378 log.error( e.getMessage(), e );
381 MetadataFacet metadataFacet = null;
382 MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
383 if ( metadataFacetFactory != null )
385 metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
386 Map<String, String> map = new HashMap<>();
387 for ( Object key : new ArrayList( properties.keySet() ) )
389 String property = (String) key;
390 map.put( property, properties.getProperty( property ) );
392 metadataFacet.fromProperties( map );
394 return metadataFacet;
398 public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
400 Properties properties = new Properties();
401 properties.putAll( metadataFacet.toProperties() );
406 new File( getMetadataDirectory( repositoryId, metadataFacet.getFacetId() ), metadataFacet.getName() );
407 writeProperties( properties, directory, METADATA_KEY );
409 catch ( IOException e )
412 log.error( e.getMessage(), e );
417 public void removeMetadataFacets( String repositoryId, String facetId )
418 throws MetadataRepositoryException
422 File dir = getMetadataDirectory( repositoryId, facetId );
423 FileUtils.deleteDirectory( dir );
425 catch ( IOException e )
427 throw new MetadataRepositoryException( e.getMessage(), e );
432 public void removeMetadataFacet( String repoId, String facetId, String name )
433 throws MetadataRepositoryException
437 File dir = new File( getMetadataDirectory( repoId, facetId ), name );
438 FileUtils.deleteDirectory( dir );
440 catch ( IOException e )
442 throw new MetadataRepositoryException( e.getMessage(), e );
447 public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
448 throws MetadataRepositoryException
452 // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
453 // of this information (eg. in Lucene, as before)
455 List<ArtifactMetadata> artifacts = new ArrayList<>();
456 for ( String ns : getRootNamespaces( repoId ) )
458 getArtifactsByDateRange( artifacts, repoId, ns, startTime, endTime );
460 Collections.sort( artifacts, new ArtifactComparator() );
463 catch ( MetadataResolutionException e )
465 throw new MetadataRepositoryException( e.getMessage(), e );
469 private void getArtifactsByDateRange( List<ArtifactMetadata> artifacts, String repoId, String ns, Date startTime,
471 throws MetadataRepositoryException
475 for ( String namespace : getNamespaces( repoId, ns ) )
477 getArtifactsByDateRange( artifacts, repoId, ns + "." + namespace, startTime, endTime );
480 for ( String project : getProjects( repoId, ns ) )
482 for ( String version : getProjectVersions( repoId, ns, project ) )
484 for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
486 if ( startTime == null || startTime.before( artifact.getWhenGathered() ) )
488 if ( endTime == null || endTime.after( artifact.getWhenGathered() ) )
490 artifacts.add( artifact );
497 catch ( MetadataResolutionException e )
499 throw new MetadataRepositoryException( e.getMessage(), e );
504 public Collection<ArtifactMetadata> getArtifacts( String repoId, String namespace, String projectId,
505 String projectVersion )
506 throws MetadataResolutionException
510 Map<String, ArtifactMetadata> artifacts = new HashMap<>();
512 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
514 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
516 for ( Map.Entry entry : properties.entrySet() )
518 String name = (String) entry.getKey();
519 StringTokenizer tok = new StringTokenizer( name, ":" );
520 if ( tok.hasMoreTokens() && "artifact".equals( tok.nextToken() ) )
522 String field = tok.nextToken();
523 String id = tok.nextToken();
525 ArtifactMetadata artifact = artifacts.get( id );
526 if ( artifact == null )
528 artifact = new ArtifactMetadata();
529 artifact.setRepositoryId( repoId );
530 artifact.setNamespace( namespace );
531 artifact.setProject( projectId );
532 artifact.setProjectVersion( projectVersion );
533 artifact.setVersion( projectVersion );
534 artifact.setId( id );
535 artifacts.put( id, artifact );
538 String value = (String) entry.getValue();
539 if ( "updated".equals( field ) )
541 artifact.setFileLastModified( Long.parseLong( value ) );
543 else if ( "size".equals( field ) )
545 artifact.setSize( Long.valueOf( value ) );
547 else if ( "whenGathered".equals( field ) )
549 artifact.setWhenGathered( new Date( Long.parseLong( value ) ) );
551 else if ( "version".equals( field ) )
553 artifact.setVersion( value );
555 else if ( "md5".equals( field ) )
557 artifact.setMd5( value );
559 else if ( "sha1".equals( field ) )
561 artifact.setSha1( value );
563 else if ( "facetIds".equals( field ) )
565 if ( value.length() > 0 )
567 String propertyPrefix = "artifact:facet:" + id + ":";
568 for ( String facetId : value.split( "," ) )
570 MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
571 if ( factory == null )
573 log.error( "Attempted to load unknown artifact metadata facet: " + facetId );
577 MetadataFacet facet = factory.createMetadataFacet();
578 String prefix = propertyPrefix + facet.getFacetId();
579 Map<String, String> map = new HashMap<>();
580 for ( Object key : new ArrayList( properties.keySet() ) )
582 String property = (String) key;
583 if ( property.startsWith( prefix ) )
585 map.put( property.substring( prefix.length() + 1 ),
586 properties.getProperty( property ) );
589 facet.fromProperties( map );
590 artifact.addFacet( facet );
595 updateArtifactFacets( artifact, properties );
599 return artifacts.values();
601 catch ( IOException e )
603 throw new MetadataResolutionException( e.getMessage(), e );
610 // it's all instantly persisted
616 // nothing additional to close
622 log.warn( "Attempted to revert a session, but the file-based repository storage doesn't support it" );
626 public boolean canObtainAccess( Class<?> aClass )
632 public <T> T obtainAccess( Class<T> aClass )
634 throw new IllegalArgumentException(
635 "Access using " + aClass + " is not supported on the file metadata storage" );
638 private void updateArtifactFacets( ArtifactMetadata artifact, Properties properties )
640 String propertyPrefix = "artifact:facet:" + artifact.getId() + ":";
641 for ( MetadataFacet facet : artifact.getFacetList() )
643 for ( Map.Entry<String, String> e : facet.toProperties().entrySet() )
645 String key = propertyPrefix + facet.getFacetId() + ":" + e.getKey();
646 properties.setProperty( key, e.getValue() );
652 public Collection<String> getRepositories()
654 List<String> repositories = new ArrayList<>();
655 for ( ManagedRepositoryConfiguration managedRepositoryConfiguration : configuration.getConfiguration().getManagedRepositories() )
657 repositories.add( managedRepositoryConfiguration.getId() );
663 public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
664 throws MetadataRepositoryException
668 // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
669 // of this information (eg. in Lucene, as before)
670 // alternatively, we could build a referential tree in the content repository, however it would need some levels
671 // of depth to avoid being too broad to be useful (eg. /repository/checksums/a/ab/abcdef1234567)
673 List<ArtifactMetadata> artifacts = new ArrayList<>();
674 for ( String ns : getRootNamespaces( repositoryId ) )
676 getArtifactsByChecksum( artifacts, repositoryId, ns, checksum );
680 catch ( MetadataResolutionException e )
682 throw new MetadataRepositoryException( e.getMessage(), e );
687 public void removeNamespace( String repositoryId, String project )
688 throws MetadataRepositoryException
692 File namespaceDirectory = new File( getDirectory( repositoryId ), project );
693 FileUtils.deleteDirectory( namespaceDirectory );
694 //Properties properties = new Properties();
695 //properties.setProperty( "namespace", namespace );
696 //writeProperties( properties, namespaceDirectory, NAMESPACE_METADATA_KEY );
699 catch ( IOException e )
701 throw new MetadataRepositoryException( e.getMessage(), e );
706 public void removeArtifact( ArtifactMetadata artifactMetadata, String baseVersion )
707 throws MetadataRepositoryException
712 File directory = new File( getDirectory( artifactMetadata.getRepositoryId() ),
713 artifactMetadata.getNamespace() + "/" + artifactMetadata.getProject() + "/"
716 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
718 String id = artifactMetadata.getId();
720 properties.remove( "artifact:updated:" + id );
721 properties.remove( "artifact:whenGathered:" + id );
722 properties.remove( "artifact:size:" + id );
723 properties.remove( "artifact:md5:" + id );
724 properties.remove( "artifact:sha1:" + id );
725 properties.remove( "artifact:version:" + id );
726 properties.remove( "artifact:facetIds:" + id );
728 String prefix = "artifact:facet:" + id + ":";
729 for ( Object key : new ArrayList( properties.keySet() ) )
731 String property = (String) key;
732 if ( property.startsWith( prefix ) )
734 properties.remove( property );
738 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
740 catch ( IOException e )
742 throw new MetadataRepositoryException( e.getMessage(), e );
748 public void removeArtifact( String repoId, String namespace, String project, String version, String id )
749 throws MetadataRepositoryException
753 File directory = new File( getDirectory( repoId ), namespace + "/" + project + "/" + version );
755 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
757 properties.remove( "artifact:updated:" + id );
758 properties.remove( "artifact:whenGathered:" + id );
759 properties.remove( "artifact:size:" + id );
760 properties.remove( "artifact:md5:" + id );
761 properties.remove( "artifact:sha1:" + id );
762 properties.remove( "artifact:version:" + id );
763 properties.remove( "artifact:facetIds:" + id );
765 String prefix = "artifact:facet:" + id + ":";
766 for ( Object key : new ArrayList( properties.keySet() ) )
768 String property = (String) key;
769 if ( property.startsWith( prefix ) )
771 properties.remove( property );
775 FileUtils.deleteDirectory( directory );
776 //writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
778 catch ( IOException e )
780 throw new MetadataRepositoryException( e.getMessage(), e );
785 * FIXME implements this !!!!
787 * @param repositoryId
790 * @param projectVersion
791 * @param metadataFacet will remove artifacts which have this {@link MetadataFacet} using equals
792 * @throws MetadataRepositoryException
795 public void removeArtifact( String repositoryId, String namespace, String project, String projectVersion,
796 MetadataFacet metadataFacet )
797 throws MetadataRepositoryException
799 throw new UnsupportedOperationException( "not implemented" );
803 public void removeRepository( String repoId )
804 throws MetadataRepositoryException
808 File dir = getDirectory( repoId );
809 FileUtils.deleteDirectory( dir );
811 catch ( IOException e )
813 throw new MetadataRepositoryException( e.getMessage(), e );
817 private void getArtifactsByChecksum( List<ArtifactMetadata> artifacts, String repositoryId, String ns,
819 throws MetadataRepositoryException
823 for ( String namespace : getNamespaces( repositoryId, ns ) )
825 getArtifactsByChecksum( artifacts, repositoryId, ns + "." + namespace, checksum );
828 for ( String project : getProjects( repositoryId, ns ) )
830 for ( String version : getProjectVersions( repositoryId, ns, project ) )
832 for ( ArtifactMetadata artifact : getArtifacts( repositoryId, ns, project, version ) )
834 if ( checksum.equals( artifact.getMd5() ) || checksum.equals( artifact.getSha1() ) )
836 artifacts.add( artifact );
842 catch ( MetadataResolutionException e )
844 throw new MetadataRepositoryException( e.getMessage(), e );
849 public List<ArtifactMetadata> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
850 throws MetadataRepositoryException
852 throw new UnsupportedOperationException( "not yet implemented in File backend" );
856 public List<ArtifactMetadata> getArtifactsByMetadata( String key, String value, String repositoryId )
857 throws MetadataRepositoryException
859 throw new UnsupportedOperationException( "not yet implemented in File backend" );
863 public List<ArtifactMetadata> getArtifactsByProperty( String key, String value, String repositoryId )
864 throws MetadataRepositoryException
866 throw new UnsupportedOperationException( "getArtifactsByProperty not yet implemented in File backend" );
869 private File getMetadataDirectory( String repoId, String facetId )
872 return new File( getBaseDirectory( repoId ), "facets/" + facetId );
875 private String join( Collection<String> ids )
877 if ( ids != null && !ids.isEmpty() )
879 StringBuilder s = new StringBuilder();
880 for ( String id : ids )
885 return s.substring( 0, s.length() - 1 );
890 private void setProperty( Properties properties, String name, String value )
894 properties.setProperty( name, value );
899 public void updateArtifact( String repoId, String namespace, String projectId, String projectVersion,
900 ArtifactMetadata artifact )
904 ProjectVersionMetadata metadata = new ProjectVersionMetadata();
905 metadata.setId( projectVersion );
906 updateProjectVersion( repoId, namespace, projectId, metadata );
908 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
910 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
912 clearMetadataFacetProperties( artifact.getFacetList(), properties,
913 "artifact:facet:" + artifact.getId() + ":" );
915 String id = artifact.getId();
916 properties.setProperty( "artifact:updated:" + id,
917 Long.toString( artifact.getFileLastModified().getTime() ) );
918 properties.setProperty( "artifact:whenGathered:" + id,
919 Long.toString( artifact.getWhenGathered().getTime() ) );
920 properties.setProperty( "artifact:size:" + id, Long.toString( artifact.getSize() ) );
921 if ( artifact.getMd5() != null )
923 properties.setProperty( "artifact:md5:" + id, artifact.getMd5() );
925 if ( artifact.getSha1() != null )
927 properties.setProperty( "artifact:sha1:" + id, artifact.getSha1() );
929 properties.setProperty( "artifact:version:" + id, artifact.getVersion() );
931 Set<String> facetIds = new LinkedHashSet<String>( artifact.getFacetIds() );
932 String property = "artifact:facetIds:" + id;
933 facetIds.addAll( Arrays.asList( properties.getProperty( property, "" ).split( "," ) ) );
934 properties.setProperty( property, join( facetIds ) );
936 updateArtifactFacets( artifact, properties );
938 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
940 catch ( IOException e )
943 log.error( e.getMessage(), e );
947 private Properties readOrCreateProperties( File directory, String propertiesKey )
951 return readProperties( directory, propertiesKey );
953 catch ( FileNotFoundException | NoSuchFileException e )
955 // ignore and return new properties
957 catch ( IOException e )
960 log.error( e.getMessage(), e );
962 return new Properties();
965 private Properties readProperties( File directory, String propertiesKey )
968 Properties properties = new Properties();
969 try (InputStream in = Files.newInputStream( new File( directory, propertiesKey + ".properties" ).toPath() ))
972 properties.load( in );
978 public ProjectMetadata getProject( String repoId, String namespace, String projectId )
979 throws MetadataResolutionException
983 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
985 Properties properties = readOrCreateProperties( directory, PROJECT_METADATA_KEY );
987 ProjectMetadata project = null;
989 String id = properties.getProperty( "id" );
992 project = new ProjectMetadata();
993 project.setNamespace( properties.getProperty( "namespace" ) );
999 catch ( IOException e )
1001 throw new MetadataResolutionException( e.getMessage(), e );
1006 public ProjectVersionMetadata getProjectVersion( String repoId, String namespace, String projectId,
1007 String projectVersion )
1008 throws MetadataResolutionException
1012 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1014 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1015 String id = properties.getProperty( "id" );
1016 ProjectVersionMetadata versionMetadata = null;
1019 versionMetadata = new ProjectVersionMetadata();
1020 versionMetadata.setId( id );
1021 versionMetadata.setName( properties.getProperty( "name" ) );
1022 versionMetadata.setDescription( properties.getProperty( "description" ) );
1023 versionMetadata.setUrl( properties.getProperty( "url" ) );
1024 versionMetadata.setIncomplete( Boolean.valueOf( properties.getProperty( "incomplete", "false" ) ) );
1026 String scmConnection = properties.getProperty( "scm.connection" );
1027 String scmDeveloperConnection = properties.getProperty( "scm.developerConnection" );
1028 String scmUrl = properties.getProperty( "scm.url" );
1029 if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
1031 Scm scm = new Scm();
1032 scm.setConnection( scmConnection );
1033 scm.setDeveloperConnection( scmDeveloperConnection );
1034 scm.setUrl( scmUrl );
1035 versionMetadata.setScm( scm );
1038 String ciSystem = properties.getProperty( "ci.system" );
1039 String ciUrl = properties.getProperty( "ci.url" );
1040 if ( ciSystem != null || ciUrl != null )
1042 CiManagement ci = new CiManagement();
1043 ci.setSystem( ciSystem );
1045 versionMetadata.setCiManagement( ci );
1048 String issueSystem = properties.getProperty( "issue.system" );
1049 String issueUrl = properties.getProperty( "issue.url" );
1050 if ( issueSystem != null || issueUrl != null )
1052 IssueManagement issueManagement = new IssueManagement();
1053 issueManagement.setSystem( issueSystem );
1054 issueManagement.setUrl( issueUrl );
1055 versionMetadata.setIssueManagement( issueManagement );
1058 String orgName = properties.getProperty( "org.name" );
1059 String orgUrl = properties.getProperty( "org.url" );
1060 if ( orgName != null || orgUrl != null )
1062 Organization org = new Organization();
1063 org.setName( orgName );
1064 org.setUrl( orgUrl );
1065 versionMetadata.setOrganization( org );
1068 boolean done = false;
1072 String licenseName = properties.getProperty( "license." + i + ".name" );
1073 String licenseUrl = properties.getProperty( "license." + i + ".url" );
1074 if ( licenseName != null || licenseUrl != null )
1076 License license = new License();
1077 license.setName( licenseName );
1078 license.setUrl( licenseUrl );
1079 versionMetadata.addLicense( license );
1092 String mailingListName = properties.getProperty( "mailingList." + i + ".name" );
1093 if ( mailingListName != null )
1095 MailingList mailingList = new MailingList();
1096 mailingList.setName( mailingListName );
1097 mailingList.setMainArchiveUrl( properties.getProperty( "mailingList." + i + ".archive" ) );
1098 String p = properties.getProperty( "mailingList." + i + ".otherArchives" );
1099 if ( p != null && p.length() > 0 )
1101 mailingList.setOtherArchives( Arrays.asList( p.split( "," ) ) );
1105 mailingList.setOtherArchives( Collections.<String>emptyList() );
1107 mailingList.setPostAddress( properties.getProperty( "mailingList." + i + ".post" ) );
1108 mailingList.setSubscribeAddress( properties.getProperty( "mailingList." + i + ".subscribe" ) );
1109 mailingList.setUnsubscribeAddress(
1110 properties.getProperty( "mailingList." + i + ".unsubscribe" ) );
1111 versionMetadata.addMailingList( mailingList );
1124 String dependencyArtifactId = properties.getProperty( "dependency." + i + ".artifactId" );
1125 if ( dependencyArtifactId != null )
1127 Dependency dependency = new Dependency();
1128 dependency.setArtifactId( dependencyArtifactId );
1129 dependency.setGroupId( properties.getProperty( "dependency." + i + ".groupId" ) );
1130 dependency.setClassifier( properties.getProperty( "dependency." + i + ".classifier" ) );
1131 dependency.setOptional(
1132 Boolean.valueOf( properties.getProperty( "dependency." + i + ".optional" ) ) );
1133 dependency.setScope( properties.getProperty( "dependency." + i + ".scope" ) );
1134 dependency.setSystemPath( properties.getProperty( "dependency." + i + ".systemPath" ) );
1135 dependency.setType( properties.getProperty( "dependency." + i + ".type" ) );
1136 dependency.setVersion( properties.getProperty( "dependency." + i + ".version" ) );
1137 dependency.setOptional(
1138 Boolean.valueOf( properties.getProperty( "dependency." + i + ".optional" ) ) );
1139 versionMetadata.addDependency( dependency );
1148 String facetIds = properties.getProperty( "facetIds", "" );
1149 if ( facetIds.length() > 0 )
1151 for ( String facetId : facetIds.split( "," ) )
1153 MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
1154 if ( factory == null )
1156 log.error( "Attempted to load unknown project version metadata facet: {}", facetId );
1160 MetadataFacet facet = factory.createMetadataFacet();
1161 Map<String, String> map = new HashMap<>();
1162 for ( Object key : new ArrayList( properties.keySet() ) )
1164 String property = (String) key;
1165 if ( property.startsWith( facet.getFacetId() ) )
1167 map.put( property.substring( facet.getFacetId().length() + 1 ),
1168 properties.getProperty( property ) );
1171 facet.fromProperties( map );
1172 versionMetadata.addFacet( facet );
1177 updateProjectVersionFacets( versionMetadata, properties );
1179 return versionMetadata;
1181 catch ( IOException e )
1183 throw new MetadataResolutionException( e.getMessage(), e );
1188 public Collection<String> getArtifactVersions( String repoId, String namespace, String projectId,
1189 String projectVersion )
1190 throws MetadataResolutionException
1194 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1196 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1198 Set<String> versions = new HashSet<String>();
1199 for ( Map.Entry entry : properties.entrySet() )
1201 String name = (String) entry.getKey();
1202 if ( name.startsWith( "artifact:version:" ) )
1204 versions.add( (String) entry.getValue() );
1209 catch ( IOException e )
1211 throw new MetadataResolutionException( e.getMessage(), e );
1216 public Collection<ProjectVersionReference> getProjectReferences( String repoId, String namespace, String projectId,
1217 String projectVersion )
1218 throws MetadataResolutionException
1222 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1224 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1225 int numberOfRefs = Integer.parseInt( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
1227 List<ProjectVersionReference> references = new ArrayList<>();
1228 for ( int i = 0; i < numberOfRefs; i++ )
1230 ProjectVersionReference reference = new ProjectVersionReference();
1231 reference.setProjectId( properties.getProperty( "ref:reference." + i + ".projectId" ) );
1232 reference.setNamespace( properties.getProperty( "ref:reference." + i + ".namespace" ) );
1233 reference.setProjectVersion( properties.getProperty( "ref:reference." + i + ".projectVersion" ) );
1234 reference.setReferenceType( ProjectVersionReference.ReferenceType.valueOf(
1235 properties.getProperty( "ref:reference." + i + ".referenceType" ) ) );
1236 references.add( reference );
1240 catch ( IOException e )
1242 throw new MetadataResolutionException( e.getMessage(), e );
1247 public Collection<String> getRootNamespaces( String repoId )
1248 throws MetadataResolutionException
1250 return getNamespaces( repoId, null );
1254 public Collection<String> getNamespaces( String repoId, String baseNamespace )
1255 throws MetadataResolutionException
1259 List<String> allNamespaces = new ArrayList<>();
1260 File directory = getDirectory( repoId );
1261 File[] files = directory.listFiles();
1262 if ( files != null )
1264 for ( File namespace : files )
1266 if ( new File( namespace, NAMESPACE_METADATA_KEY + ".properties" ).exists() )
1268 allNamespaces.add( namespace.getName() );
1273 Set<String> namespaces = new LinkedHashSet<>();
1274 int fromIndex = baseNamespace != null ? baseNamespace.length() + 1 : 0;
1275 for ( String namespace : allNamespaces )
1277 if ( baseNamespace == null || namespace.startsWith( baseNamespace + "." ) )
1279 int i = namespace.indexOf( '.', fromIndex );
1282 namespaces.add( namespace.substring( fromIndex, i ) );
1286 namespaces.add( namespace.substring( fromIndex ) );
1290 return new ArrayList<>( namespaces );
1292 catch ( IOException e )
1294 throw new MetadataResolutionException( e.getMessage(), e );
1299 public Collection<String> getProjects( String repoId, String namespace )
1300 throws MetadataResolutionException
1304 List<String> projects = new ArrayList<>();
1305 File directory = new File( getDirectory( repoId ), namespace );
1306 File[] files = directory.listFiles();
1307 if ( files != null )
1309 for ( File project : files )
1311 if ( new File( project, PROJECT_METADATA_KEY + ".properties" ).exists() )
1313 projects.add( project.getName() );
1319 catch ( IOException e )
1321 throw new MetadataResolutionException( e.getMessage(), e );
1326 public Collection<String> getProjectVersions( String repoId, String namespace, String projectId )
1327 throws MetadataResolutionException
1331 List<String> projectVersions = new ArrayList<>();
1332 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
1333 File[] files = directory.listFiles();
1334 if ( files != null )
1336 for ( File projectVersion : files )
1338 if ( new File( projectVersion, PROJECT_VERSION_METADATA_KEY + ".properties" ).exists() )
1340 projectVersions.add( projectVersion.getName() );
1344 return projectVersions;
1346 catch ( IOException e )
1348 throw new MetadataResolutionException( e.getMessage(), e );
1353 public void removeProject( String repositoryId, String namespace, String projectId )
1354 throws MetadataRepositoryException
1358 File directory = new File( getDirectory( repositoryId ), namespace + "/" + projectId );
1359 FileUtils.deleteDirectory( directory );
1361 catch ( IOException e )
1363 throw new MetadataRepositoryException( e.getMessage(), e );
1368 public void removeProjectVersion( String repoId, String namespace, String projectId, String projectVersion )
1369 throws MetadataRepositoryException
1373 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1374 FileUtils.deleteDirectory( directory );
1376 catch ( IOException e )
1378 throw new MetadataRepositoryException( e.getMessage(), e );
1383 private void writeProperties( Properties properties, File directory, String propertiesKey )
1387 try (OutputStream os = Files.newOutputStream( new File( directory, propertiesKey + ".properties" ).toPath() ))
1389 properties.store( os, null );
1393 private static class ArtifactComparator
1394 implements Comparator<ArtifactMetadata>
1397 public int compare( ArtifactMetadata artifact1, ArtifactMetadata artifact2 )
1399 if ( artifact1.getWhenGathered() == artifact2.getWhenGathered() )
1403 if ( artifact1.getWhenGathered() == null )
1407 if ( artifact2.getWhenGathered() == null )
1411 return artifact1.getWhenGathered().compareTo( artifact2.getWhenGathered() );
1416 public List<ArtifactMetadata> getArtifacts( String repoId )
1417 throws MetadataRepositoryException
1421 List<ArtifactMetadata> artifacts = new ArrayList<>();
1422 for ( String ns : getRootNamespaces( repoId ) )
1424 getArtifacts( artifacts, repoId, ns );
1428 catch ( MetadataResolutionException e )
1430 throw new MetadataRepositoryException( e.getMessage(), e );
1434 private void getArtifacts( List<ArtifactMetadata> artifacts, String repoId, String ns )
1435 throws MetadataResolutionException
1437 for ( String namespace : getNamespaces( repoId, ns ) )
1439 getArtifacts( artifacts, repoId, ns + "." + namespace );
1442 for ( String project : getProjects( repoId, ns ) )
1444 for ( String version : getProjectVersions( repoId, ns, project ) )
1446 for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
1448 artifacts.add( artifact );
1455 public List<ArtifactMetadata> searchArtifacts( String text, String repositoryId, boolean exact )
1456 throws MetadataRepositoryException
1458 throw new UnsupportedOperationException( "searchArtifacts not yet implemented in File backend" );
1462 public List<ArtifactMetadata> searchArtifacts( String key, String text, String repositoryId, boolean exact )
1463 throws MetadataRepositoryException
1465 throw new UnsupportedOperationException( "searchArtifacts not yet implemented in File backend" );