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 if ( !Files.deleteIfExists( dir.toPath() ) )
425 log.error( "Cannot delete the metadata repository {}", dir );
428 catch ( IOException e )
430 throw new MetadataRepositoryException( e.getMessage(), e );
435 public void removeMetadataFacet( String repoId, String facetId, String name )
436 throws MetadataRepositoryException
440 File dir = new File( getMetadataDirectory( repoId, facetId ), name );
441 if ( !Files.deleteIfExists( dir.toPath() ) )
443 log.error( "Cannot delete the metadata repository {}", dir );
446 catch ( IOException e )
448 throw new MetadataRepositoryException( e.getMessage(), e );
453 public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
454 throws MetadataRepositoryException
458 // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
459 // of this information (eg. in Lucene, as before)
461 List<ArtifactMetadata> artifacts = new ArrayList<>();
462 for ( String ns : getRootNamespaces( repoId ) )
464 getArtifactsByDateRange( artifacts, repoId, ns, startTime, endTime );
466 Collections.sort( artifacts, new ArtifactComparator() );
469 catch ( MetadataResolutionException e )
471 throw new MetadataRepositoryException( e.getMessage(), e );
475 private void getArtifactsByDateRange( List<ArtifactMetadata> artifacts, String repoId, String ns, Date startTime,
477 throws MetadataRepositoryException
481 for ( String namespace : getNamespaces( repoId, ns ) )
483 getArtifactsByDateRange( artifacts, repoId, ns + "." + namespace, startTime, endTime );
486 for ( String project : getProjects( repoId, ns ) )
488 for ( String version : getProjectVersions( repoId, ns, project ) )
490 for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
492 if ( startTime == null || startTime.before( artifact.getWhenGathered() ) )
494 if ( endTime == null || endTime.after( artifact.getWhenGathered() ) )
496 artifacts.add( artifact );
503 catch ( MetadataResolutionException e )
505 throw new MetadataRepositoryException( e.getMessage(), e );
510 public Collection<ArtifactMetadata> getArtifacts( String repoId, String namespace, String projectId,
511 String projectVersion )
512 throws MetadataResolutionException
516 Map<String, ArtifactMetadata> artifacts = new HashMap<>();
518 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
520 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
522 for ( Map.Entry entry : properties.entrySet() )
524 String name = (String) entry.getKey();
525 StringTokenizer tok = new StringTokenizer( name, ":" );
526 if ( tok.hasMoreTokens() && "artifact".equals( tok.nextToken() ) )
528 String field = tok.nextToken();
529 String id = tok.nextToken();
531 ArtifactMetadata artifact = artifacts.get( id );
532 if ( artifact == null )
534 artifact = new ArtifactMetadata();
535 artifact.setRepositoryId( repoId );
536 artifact.setNamespace( namespace );
537 artifact.setProject( projectId );
538 artifact.setProjectVersion( projectVersion );
539 artifact.setVersion( projectVersion );
540 artifact.setId( id );
541 artifacts.put( id, artifact );
544 String value = (String) entry.getValue();
545 if ( "updated".equals( field ) )
547 artifact.setFileLastModified( Long.parseLong( value ) );
549 else if ( "size".equals( field ) )
551 artifact.setSize( Long.valueOf( value ) );
553 else if ( "whenGathered".equals( field ) )
555 artifact.setWhenGathered( new Date( Long.parseLong( value ) ) );
557 else if ( "version".equals( field ) )
559 artifact.setVersion( value );
561 else if ( "md5".equals( field ) )
563 artifact.setMd5( value );
565 else if ( "sha1".equals( field ) )
567 artifact.setSha1( value );
569 else if ( "facetIds".equals( field ) )
571 if ( value.length() > 0 )
573 String propertyPrefix = "artifact:facet:" + id + ":";
574 for ( String facetId : value.split( "," ) )
576 MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
577 if ( factory == null )
579 log.error( "Attempted to load unknown artifact metadata facet: " + facetId );
583 MetadataFacet facet = factory.createMetadataFacet();
584 String prefix = propertyPrefix + facet.getFacetId();
585 Map<String, String> map = new HashMap<>();
586 for ( Object key : new ArrayList( properties.keySet() ) )
588 String property = (String) key;
589 if ( property.startsWith( prefix ) )
591 map.put( property.substring( prefix.length() + 1 ),
592 properties.getProperty( property ) );
595 facet.fromProperties( map );
596 artifact.addFacet( facet );
601 updateArtifactFacets( artifact, properties );
605 return artifacts.values();
607 catch ( IOException e )
609 throw new MetadataResolutionException( e.getMessage(), e );
616 // it's all instantly persisted
622 // nothing additional to close
628 log.warn( "Attempted to revert a session, but the file-based repository storage doesn't support it" );
632 public boolean canObtainAccess( Class<?> aClass )
638 public <T> T obtainAccess( Class<T> aClass )
640 throw new IllegalArgumentException(
641 "Access using " + aClass + " is not supported on the file metadata storage" );
644 private void updateArtifactFacets( ArtifactMetadata artifact, Properties properties )
646 String propertyPrefix = "artifact:facet:" + artifact.getId() + ":";
647 for ( MetadataFacet facet : artifact.getFacetList() )
649 for ( Map.Entry<String, String> e : facet.toProperties().entrySet() )
651 String key = propertyPrefix + facet.getFacetId() + ":" + e.getKey();
652 properties.setProperty( key, e.getValue() );
658 public Collection<String> getRepositories()
660 List<String> repositories = new ArrayList<>();
661 for ( ManagedRepositoryConfiguration managedRepositoryConfiguration : configuration.getConfiguration().getManagedRepositories() )
663 repositories.add( managedRepositoryConfiguration.getId() );
669 public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
670 throws MetadataRepositoryException
674 // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
675 // of this information (eg. in Lucene, as before)
676 // alternatively, we could build a referential tree in the content repository, however it would need some levels
677 // of depth to avoid being too broad to be useful (eg. /repository/checksums/a/ab/abcdef1234567)
679 List<ArtifactMetadata> artifacts = new ArrayList<>();
680 for ( String ns : getRootNamespaces( repositoryId ) )
682 getArtifactsByChecksum( artifacts, repositoryId, ns, checksum );
686 catch ( MetadataResolutionException e )
688 throw new MetadataRepositoryException( e.getMessage(), e );
693 public void removeNamespace( String repositoryId, String project )
694 throws MetadataRepositoryException
698 File namespaceDirectory = new File( getDirectory( repositoryId ), project );
699 FileUtils.deleteDirectory( namespaceDirectory );
700 //Properties properties = new Properties();
701 //properties.setProperty( "namespace", namespace );
702 //writeProperties( properties, namespaceDirectory, NAMESPACE_METADATA_KEY );
705 catch ( IOException e )
707 throw new MetadataRepositoryException( e.getMessage(), e );
712 public void removeArtifact( ArtifactMetadata artifactMetadata, String baseVersion )
713 throws MetadataRepositoryException
718 File directory = new File( getDirectory( artifactMetadata.getRepositoryId() ),
719 artifactMetadata.getNamespace() + "/" + artifactMetadata.getProject() + "/"
722 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
724 String id = artifactMetadata.getId();
726 properties.remove( "artifact:updated:" + id );
727 properties.remove( "artifact:whenGathered:" + id );
728 properties.remove( "artifact:size:" + id );
729 properties.remove( "artifact:md5:" + id );
730 properties.remove( "artifact:sha1:" + id );
731 properties.remove( "artifact:version:" + id );
732 properties.remove( "artifact:facetIds:" + id );
734 String prefix = "artifact:facet:" + id + ":";
735 for ( Object key : new ArrayList( properties.keySet() ) )
737 String property = (String) key;
738 if ( property.startsWith( prefix ) )
740 properties.remove( property );
744 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
746 catch ( IOException e )
748 throw new MetadataRepositoryException( e.getMessage(), e );
754 public void removeArtifact( String repoId, String namespace, String project, String version, String id )
755 throws MetadataRepositoryException
759 File directory = new File( getDirectory( repoId ), namespace + "/" + project + "/" + version );
761 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
763 properties.remove( "artifact:updated:" + id );
764 properties.remove( "artifact:whenGathered:" + id );
765 properties.remove( "artifact:size:" + id );
766 properties.remove( "artifact:md5:" + id );
767 properties.remove( "artifact:sha1:" + id );
768 properties.remove( "artifact:version:" + id );
769 properties.remove( "artifact:facetIds:" + id );
771 String prefix = "artifact:facet:" + id + ":";
772 for ( Object key : new ArrayList( properties.keySet() ) )
774 String property = (String) key;
775 if ( property.startsWith( prefix ) )
777 properties.remove( property );
781 Files.deleteIfExists( directory.toPath() );
782 //writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
784 catch ( IOException e )
786 throw new MetadataRepositoryException( e.getMessage(), e );
791 * FIXME implements this !!!!
793 * @param repositoryId
796 * @param projectVersion
797 * @param metadataFacet will remove artifacts which have this {@link MetadataFacet} using equals
798 * @throws MetadataRepositoryException
801 public void removeArtifact( String repositoryId, String namespace, String project, String projectVersion,
802 MetadataFacet metadataFacet )
803 throws MetadataRepositoryException
805 throw new UnsupportedOperationException( "not implemented" );
809 public void removeRepository( String repoId )
810 throws MetadataRepositoryException
814 File dir = getDirectory( repoId );
815 if ( !Files.deleteIfExists( dir.toPath() ) )
817 log.error( "Cannot delete repository {}", dir );
820 catch ( IOException e )
822 throw new MetadataRepositoryException( e.getMessage(), e );
826 private void getArtifactsByChecksum( List<ArtifactMetadata> artifacts, String repositoryId, String ns,
828 throws MetadataRepositoryException
832 for ( String namespace : getNamespaces( repositoryId, ns ) )
834 getArtifactsByChecksum( artifacts, repositoryId, ns + "." + namespace, checksum );
837 for ( String project : getProjects( repositoryId, ns ) )
839 for ( String version : getProjectVersions( repositoryId, ns, project ) )
841 for ( ArtifactMetadata artifact : getArtifacts( repositoryId, ns, project, version ) )
843 if ( checksum.equals( artifact.getMd5() ) || checksum.equals( artifact.getSha1() ) )
845 artifacts.add( artifact );
851 catch ( MetadataResolutionException e )
853 throw new MetadataRepositoryException( e.getMessage(), e );
858 public List<ArtifactMetadata> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
859 throws MetadataRepositoryException
861 throw new UnsupportedOperationException( "not yet implemented in File backend" );
865 public List<ArtifactMetadata> getArtifactsByMetadata( String key, String value, String repositoryId )
866 throws MetadataRepositoryException
868 throw new UnsupportedOperationException( "not yet implemented in File backend" );
872 public List<ArtifactMetadata> getArtifactsByProperty( String key, String value, String repositoryId )
873 throws MetadataRepositoryException
875 throw new UnsupportedOperationException( "getArtifactsByProperty not yet implemented in File backend" );
878 private File getMetadataDirectory( String repoId, String facetId )
881 return new File( getBaseDirectory( repoId ), "facets/" + facetId );
884 private String join( Collection<String> ids )
886 if ( ids != null && !ids.isEmpty() )
888 StringBuilder s = new StringBuilder();
889 for ( String id : ids )
894 return s.substring( 0, s.length() - 1 );
899 private void setProperty( Properties properties, String name, String value )
903 properties.setProperty( name, value );
908 public void updateArtifact( String repoId, String namespace, String projectId, String projectVersion,
909 ArtifactMetadata artifact )
913 ProjectVersionMetadata metadata = new ProjectVersionMetadata();
914 metadata.setId( projectVersion );
915 updateProjectVersion( repoId, namespace, projectId, metadata );
917 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
919 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
921 clearMetadataFacetProperties( artifact.getFacetList(), properties,
922 "artifact:facet:" + artifact.getId() + ":" );
924 String id = artifact.getId();
925 properties.setProperty( "artifact:updated:" + id,
926 Long.toString( artifact.getFileLastModified().getTime() ) );
927 properties.setProperty( "artifact:whenGathered:" + id,
928 Long.toString( artifact.getWhenGathered().getTime() ) );
929 properties.setProperty( "artifact:size:" + id, Long.toString( artifact.getSize() ) );
930 if ( artifact.getMd5() != null )
932 properties.setProperty( "artifact:md5:" + id, artifact.getMd5() );
934 if ( artifact.getSha1() != null )
936 properties.setProperty( "artifact:sha1:" + id, artifact.getSha1() );
938 properties.setProperty( "artifact:version:" + id, artifact.getVersion() );
940 Set<String> facetIds = new LinkedHashSet<String>( artifact.getFacetIds() );
941 String property = "artifact:facetIds:" + id;
942 facetIds.addAll( Arrays.asList( properties.getProperty( property, "" ).split( "," ) ) );
943 properties.setProperty( property, join( facetIds ) );
945 updateArtifactFacets( artifact, properties );
947 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
949 catch ( IOException e )
952 log.error( e.getMessage(), e );
956 private Properties readOrCreateProperties( File directory, String propertiesKey )
960 return readProperties( directory, propertiesKey );
962 catch ( FileNotFoundException | NoSuchFileException e )
964 // ignore and return new properties
966 catch ( IOException e )
969 log.error( e.getMessage(), e );
971 return new Properties();
974 private Properties readProperties( File directory, String propertiesKey )
977 Properties properties = new Properties();
978 try (InputStream in = Files.newInputStream( new File( directory, propertiesKey + ".properties" ).toPath() ))
981 properties.load( in );
987 public ProjectMetadata getProject( String repoId, String namespace, String projectId )
988 throws MetadataResolutionException
992 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
994 Properties properties = readOrCreateProperties( directory, PROJECT_METADATA_KEY );
996 ProjectMetadata project = null;
998 String id = properties.getProperty( "id" );
1001 project = new ProjectMetadata();
1002 project.setNamespace( properties.getProperty( "namespace" ) );
1003 project.setId( id );
1008 catch ( IOException e )
1010 throw new MetadataResolutionException( e.getMessage(), e );
1015 public ProjectVersionMetadata getProjectVersion( String repoId, String namespace, String projectId,
1016 String projectVersion )
1017 throws MetadataResolutionException
1021 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1023 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1024 String id = properties.getProperty( "id" );
1025 ProjectVersionMetadata versionMetadata = null;
1028 versionMetadata = new ProjectVersionMetadata();
1029 versionMetadata.setId( id );
1030 versionMetadata.setName( properties.getProperty( "name" ) );
1031 versionMetadata.setDescription( properties.getProperty( "description" ) );
1032 versionMetadata.setUrl( properties.getProperty( "url" ) );
1033 versionMetadata.setIncomplete( Boolean.valueOf( properties.getProperty( "incomplete", "false" ) ) );
1035 String scmConnection = properties.getProperty( "scm.connection" );
1036 String scmDeveloperConnection = properties.getProperty( "scm.developerConnection" );
1037 String scmUrl = properties.getProperty( "scm.url" );
1038 if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
1040 Scm scm = new Scm();
1041 scm.setConnection( scmConnection );
1042 scm.setDeveloperConnection( scmDeveloperConnection );
1043 scm.setUrl( scmUrl );
1044 versionMetadata.setScm( scm );
1047 String ciSystem = properties.getProperty( "ci.system" );
1048 String ciUrl = properties.getProperty( "ci.url" );
1049 if ( ciSystem != null || ciUrl != null )
1051 CiManagement ci = new CiManagement();
1052 ci.setSystem( ciSystem );
1054 versionMetadata.setCiManagement( ci );
1057 String issueSystem = properties.getProperty( "issue.system" );
1058 String issueUrl = properties.getProperty( "issue.url" );
1059 if ( issueSystem != null || issueUrl != null )
1061 IssueManagement issueManagement = new IssueManagement();
1062 issueManagement.setSystem( issueSystem );
1063 issueManagement.setUrl( issueUrl );
1064 versionMetadata.setIssueManagement( issueManagement );
1067 String orgName = properties.getProperty( "org.name" );
1068 String orgUrl = properties.getProperty( "org.url" );
1069 if ( orgName != null || orgUrl != null )
1071 Organization org = new Organization();
1072 org.setName( orgName );
1073 org.setUrl( orgUrl );
1074 versionMetadata.setOrganization( org );
1077 boolean done = false;
1081 String licenseName = properties.getProperty( "license." + i + ".name" );
1082 String licenseUrl = properties.getProperty( "license." + i + ".url" );
1083 if ( licenseName != null || licenseUrl != null )
1085 License license = new License();
1086 license.setName( licenseName );
1087 license.setUrl( licenseUrl );
1088 versionMetadata.addLicense( license );
1101 String mailingListName = properties.getProperty( "mailingList." + i + ".name" );
1102 if ( mailingListName != null )
1104 MailingList mailingList = new MailingList();
1105 mailingList.setName( mailingListName );
1106 mailingList.setMainArchiveUrl( properties.getProperty( "mailingList." + i + ".archive" ) );
1107 String p = properties.getProperty( "mailingList." + i + ".otherArchives" );
1108 if ( p != null && p.length() > 0 )
1110 mailingList.setOtherArchives( Arrays.asList( p.split( "," ) ) );
1114 mailingList.setOtherArchives( Collections.<String>emptyList() );
1116 mailingList.setPostAddress( properties.getProperty( "mailingList." + i + ".post" ) );
1117 mailingList.setSubscribeAddress( properties.getProperty( "mailingList." + i + ".subscribe" ) );
1118 mailingList.setUnsubscribeAddress(
1119 properties.getProperty( "mailingList." + i + ".unsubscribe" ) );
1120 versionMetadata.addMailingList( mailingList );
1133 String dependencyArtifactId = properties.getProperty( "dependency." + i + ".artifactId" );
1134 if ( dependencyArtifactId != null )
1136 Dependency dependency = new Dependency();
1137 dependency.setArtifactId( dependencyArtifactId );
1138 dependency.setGroupId( properties.getProperty( "dependency." + i + ".groupId" ) );
1139 dependency.setClassifier( properties.getProperty( "dependency." + i + ".classifier" ) );
1140 dependency.setOptional(
1141 Boolean.valueOf( properties.getProperty( "dependency." + i + ".optional" ) ) );
1142 dependency.setScope( properties.getProperty( "dependency." + i + ".scope" ) );
1143 dependency.setSystemPath( properties.getProperty( "dependency." + i + ".systemPath" ) );
1144 dependency.setType( properties.getProperty( "dependency." + i + ".type" ) );
1145 dependency.setVersion( properties.getProperty( "dependency." + i + ".version" ) );
1146 dependency.setOptional(
1147 Boolean.valueOf( properties.getProperty( "dependency." + i + ".optional" ) ) );
1148 versionMetadata.addDependency( dependency );
1157 String facetIds = properties.getProperty( "facetIds", "" );
1158 if ( facetIds.length() > 0 )
1160 for ( String facetId : facetIds.split( "," ) )
1162 MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
1163 if ( factory == null )
1165 log.error( "Attempted to load unknown project version metadata facet: {}", facetId );
1169 MetadataFacet facet = factory.createMetadataFacet();
1170 Map<String, String> map = new HashMap<>();
1171 for ( Object key : new ArrayList( properties.keySet() ) )
1173 String property = (String) key;
1174 if ( property.startsWith( facet.getFacetId() ) )
1176 map.put( property.substring( facet.getFacetId().length() + 1 ),
1177 properties.getProperty( property ) );
1180 facet.fromProperties( map );
1181 versionMetadata.addFacet( facet );
1186 updateProjectVersionFacets( versionMetadata, properties );
1188 return versionMetadata;
1190 catch ( IOException e )
1192 throw new MetadataResolutionException( e.getMessage(), e );
1197 public Collection<String> getArtifactVersions( String repoId, String namespace, String projectId,
1198 String projectVersion )
1199 throws MetadataResolutionException
1203 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1205 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1207 Set<String> versions = new HashSet<String>();
1208 for ( Map.Entry entry : properties.entrySet() )
1210 String name = (String) entry.getKey();
1211 if ( name.startsWith( "artifact:version:" ) )
1213 versions.add( (String) entry.getValue() );
1218 catch ( IOException e )
1220 throw new MetadataResolutionException( e.getMessage(), e );
1225 public Collection<ProjectVersionReference> getProjectReferences( String repoId, String namespace, String projectId,
1226 String projectVersion )
1227 throws MetadataResolutionException
1231 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1233 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1234 int numberOfRefs = Integer.parseInt( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
1236 List<ProjectVersionReference> references = new ArrayList<>();
1237 for ( int i = 0; i < numberOfRefs; i++ )
1239 ProjectVersionReference reference = new ProjectVersionReference();
1240 reference.setProjectId( properties.getProperty( "ref:reference." + i + ".projectId" ) );
1241 reference.setNamespace( properties.getProperty( "ref:reference." + i + ".namespace" ) );
1242 reference.setProjectVersion( properties.getProperty( "ref:reference." + i + ".projectVersion" ) );
1243 reference.setReferenceType( ProjectVersionReference.ReferenceType.valueOf(
1244 properties.getProperty( "ref:reference." + i + ".referenceType" ) ) );
1245 references.add( reference );
1249 catch ( IOException e )
1251 throw new MetadataResolutionException( e.getMessage(), e );
1256 public Collection<String> getRootNamespaces( String repoId )
1257 throws MetadataResolutionException
1259 return getNamespaces( repoId, null );
1263 public Collection<String> getNamespaces( String repoId, String baseNamespace )
1264 throws MetadataResolutionException
1268 List<String> allNamespaces = new ArrayList<>();
1269 File directory = getDirectory( repoId );
1270 File[] files = directory.listFiles();
1271 if ( files != null )
1273 for ( File namespace : files )
1275 if ( new File( namespace, NAMESPACE_METADATA_KEY + ".properties" ).exists() )
1277 allNamespaces.add( namespace.getName() );
1282 Set<String> namespaces = new LinkedHashSet<>();
1283 int fromIndex = baseNamespace != null ? baseNamespace.length() + 1 : 0;
1284 for ( String namespace : allNamespaces )
1286 if ( baseNamespace == null || namespace.startsWith( baseNamespace + "." ) )
1288 int i = namespace.indexOf( '.', fromIndex );
1291 namespaces.add( namespace.substring( fromIndex, i ) );
1295 namespaces.add( namespace.substring( fromIndex ) );
1299 return new ArrayList<>( namespaces );
1301 catch ( IOException e )
1303 throw new MetadataResolutionException( e.getMessage(), e );
1308 public Collection<String> getProjects( String repoId, String namespace )
1309 throws MetadataResolutionException
1313 List<String> projects = new ArrayList<>();
1314 File directory = new File( getDirectory( repoId ), namespace );
1315 File[] files = directory.listFiles();
1316 if ( files != null )
1318 for ( File project : files )
1320 if ( new File( project, PROJECT_METADATA_KEY + ".properties" ).exists() )
1322 projects.add( project.getName() );
1328 catch ( IOException e )
1330 throw new MetadataResolutionException( e.getMessage(), e );
1335 public Collection<String> getProjectVersions( String repoId, String namespace, String projectId )
1336 throws MetadataResolutionException
1340 List<String> projectVersions = new ArrayList<>();
1341 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
1342 File[] files = directory.listFiles();
1343 if ( files != null )
1345 for ( File projectVersion : files )
1347 if ( new File( projectVersion, PROJECT_VERSION_METADATA_KEY + ".properties" ).exists() )
1349 projectVersions.add( projectVersion.getName() );
1353 return projectVersions;
1355 catch ( IOException e )
1357 throw new MetadataResolutionException( e.getMessage(), e );
1362 public void removeProject( String repositoryId, String namespace, String projectId )
1363 throws MetadataRepositoryException
1367 File directory = new File( getDirectory( repositoryId ), namespace + "/" + projectId );
1368 Files.deleteIfExists( directory.toPath() );
1370 catch ( IOException e )
1372 throw new MetadataRepositoryException( e.getMessage(), e );
1377 public void removeProjectVersion( String repoId, String namespace, String projectId, String projectVersion )
1378 throws MetadataRepositoryException
1382 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1383 Files.deleteIfExists( directory.toPath() );
1385 catch ( IOException e )
1387 throw new MetadataRepositoryException( e.getMessage(), e );
1392 private void writeProperties( Properties properties, File directory, String propertiesKey )
1396 try (OutputStream os = Files.newOutputStream( new File( directory, propertiesKey + ".properties" ).toPath() ))
1398 properties.store( os, null );
1402 private static class ArtifactComparator
1403 implements Comparator<ArtifactMetadata>
1406 public int compare( ArtifactMetadata artifact1, ArtifactMetadata artifact2 )
1408 if ( artifact1.getWhenGathered() == artifact2.getWhenGathered() )
1412 if ( artifact1.getWhenGathered() == null )
1416 if ( artifact2.getWhenGathered() == null )
1420 return artifact1.getWhenGathered().compareTo( artifact2.getWhenGathered() );
1425 public List<ArtifactMetadata> getArtifacts( String repoId )
1426 throws MetadataRepositoryException
1430 List<ArtifactMetadata> artifacts = new ArrayList<>();
1431 for ( String ns : getRootNamespaces( repoId ) )
1433 getArtifacts( artifacts, repoId, ns );
1437 catch ( MetadataResolutionException e )
1439 throw new MetadataRepositoryException( e.getMessage(), e );
1443 private void getArtifacts( List<ArtifactMetadata> artifacts, String repoId, String ns )
1444 throws MetadataResolutionException
1446 for ( String namespace : getNamespaces( repoId, ns ) )
1448 getArtifacts( artifacts, repoId, ns + "." + namespace );
1451 for ( String project : getProjects( repoId, ns ) )
1453 for ( String version : getProjectVersions( repoId, ns, project ) )
1455 for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
1457 artifacts.add( artifact );
1464 public List<ArtifactMetadata> searchArtifacts( String text, String repositoryId, boolean exact )
1465 throws MetadataRepositoryException
1467 throw new UnsupportedOperationException( "searchArtifacts not yet implemented in File backend" );
1471 public List<ArtifactMetadata> searchArtifacts( String key, String text, String repositoryId, boolean exact )
1472 throws MetadataRepositoryException
1474 throw new UnsupportedOperationException( "searchArtifacts not yet implemented in File backend" );