This project has retired. For details please refer to its
Attic page.
FileMetadataRepository xref
1 package org.apache.archiva.metadata.repository.file;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
43
44 import java.io.File;
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;
61 import java.util.Map;
62 import java.util.Properties;
63 import java.util.Set;
64 import java.util.StringTokenizer;
65
66 public class FileMetadataRepository
67 implements MetadataRepository
68 {
69 private final Map<String, MetadataFacetFactory> metadataFacetFactories;
70
71 private final ArchivaConfiguration configuration;
72
73 private Logger log = LoggerFactory.getLogger( FileMetadataRepository.class );
74
75 private static final String PROJECT_METADATA_KEY = "project-metadata";
76
77 private static final String PROJECT_VERSION_METADATA_KEY = "version-metadata";
78
79 private static final String NAMESPACE_METADATA_KEY = "namespace-metadata";
80
81 private static final String METADATA_KEY = "metadata";
82
83 public FileMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories,
84 ArchivaConfiguration configuration )
85 {
86 this.metadataFacetFactories = metadataFacetFactories;
87 this.configuration = configuration;
88 }
89
90 private File getBaseDirectory( String repoId )
91 throws IOException
92 {
93
94 ManagedRepositoryConfiguration managedRepositoryConfiguration =
95 configuration.getConfiguration().getManagedRepositoriesAsMap().get( repoId );
96 if ( managedRepositoryConfiguration == null )
97 {
98 return Files.createTempDirectory( repoId ).toFile();
99 }
100 String basedir = managedRepositoryConfiguration.getLocation();
101 return new File( basedir, ".archiva" );
102 }
103
104 private File getDirectory( String repoId )
105 throws IOException
106 {
107 return new File( getBaseDirectory( repoId ), "content" );
108 }
109
110 @Override
111 public void updateProject( String repoId, ProjectMetadata project )
112 {
113 updateProject( repoId, project.getNamespace(), project.getId() );
114 }
115
116 private void updateProject( String repoId, String namespace, String id )
117 {
118
119 updateNamespace( repoId, namespace );
120
121 try
122 {
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 );
128 }
129 catch ( IOException e )
130 {
131
132 log.error( e.getMessage(), e );
133 }
134 }
135
136 @Override
137 public void updateProjectVersion( String repoId, String namespace, String projectId,
138 ProjectVersionMetadata versionMetadata )
139 {
140
141 try
142 {
143 updateProject( repoId, namespace, projectId );
144
145 File directory =
146 new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + versionMetadata.getId() );
147
148 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
149
150 for ( Object key : new ArrayList( properties.keySet() ) )
151 {
152 String name = (String) key;
153 if ( !name.contains( ":" ) && !name.equals( "facetIds" ) )
154 {
155 properties.remove( name );
156 }
157
158
159 clearMetadataFacetProperties( versionMetadata.getFacetList(), properties, "" );
160 }
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 )
167 {
168 setProperty( properties, "scm.connection", versionMetadata.getScm().getConnection() );
169 setProperty( properties, "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
170 setProperty( properties, "scm.url", versionMetadata.getScm().getUrl() );
171 }
172 if ( versionMetadata.getCiManagement() != null )
173 {
174 setProperty( properties, "ci.system", versionMetadata.getCiManagement().getSystem() );
175 setProperty( properties, "ci.url", versionMetadata.getCiManagement().getUrl() );
176 }
177 if ( versionMetadata.getIssueManagement() != null )
178 {
179 setProperty( properties, "issue.system", versionMetadata.getIssueManagement().getSystem() );
180 setProperty( properties, "issue.url", versionMetadata.getIssueManagement().getUrl() );
181 }
182 if ( versionMetadata.getOrganization() != null )
183 {
184 setProperty( properties, "org.name", versionMetadata.getOrganization().getName() );
185 setProperty( properties, "org.url", versionMetadata.getOrganization().getUrl() );
186 }
187 int i = 0;
188 for ( License license : versionMetadata.getLicenses() )
189 {
190 setProperty( properties, "license." + i + ".name", license.getName() );
191 setProperty( properties, "license." + i + ".url", license.getUrl() );
192 i++;
193 }
194 i = 0;
195 for ( MailingList mailingList : versionMetadata.getMailingLists() )
196 {
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() ) );
204 i++;
205 }
206 i = 0;
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() )
213 {
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() ) );
222
223 updateProjectReference( repoId, dependency.getGroupId(), dependency.getArtifactId(),
224 dependency.getVersion(), reference );
225
226 i++;
227 }
228 Set<String> facetIds = new LinkedHashSet<String>( versionMetadata.getFacetIds() );
229 facetIds.addAll( Arrays.asList( properties.getProperty( "facetIds", "" ).split( "," ) ) );
230 properties.setProperty( "facetIds", join( facetIds ) );
231
232 updateProjectVersionFacets( versionMetadata, properties );
233
234 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
235 }
236 catch ( IOException e )
237 {
238
239 log.error( e.getMessage(), e );
240 }
241 }
242
243 private void updateProjectVersionFacets( ProjectVersionMetadata versionMetadata, Properties properties )
244 {
245 for ( MetadataFacet facet : versionMetadata.getFacetList() )
246 {
247 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
248 {
249 properties.setProperty( facet.getFacetId() + ":" + entry.getKey(), entry.getValue() );
250 }
251 }
252 }
253
254 private static void clearMetadataFacetProperties( Collection<MetadataFacet> facetList, Properties properties,
255 String prefix )
256 {
257 List<Object> propsToRemove = new ArrayList<>();
258 for ( MetadataFacet facet : facetList )
259 {
260 for ( Object key : new ArrayList( properties.keySet() ) )
261 {
262 String keyString = (String) key;
263 if ( keyString.startsWith( prefix + facet.getFacetId() + ":" ) )
264 {
265 propsToRemove.add( key );
266 }
267 }
268 }
269
270 for ( Object key : propsToRemove )
271 {
272 properties.remove( key );
273 }
274 }
275
276 private void updateProjectReference( String repoId, String namespace, String projectId, String projectVersion,
277 ProjectVersionReference reference )
278 {
279 try
280 {
281 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
282
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() );
290
291 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
292 }
293 catch ( IOException e )
294 {
295
296 log.error( e.getMessage(), e );
297 }
298 }
299
300 @Override
301 public void updateNamespace( String repoId, String namespace )
302 {
303 try
304 {
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 );
309
310 }
311 catch ( IOException e )
312 {
313
314 log.error( e.getMessage(), e );
315 }
316 }
317
318 @Override
319 public List<String> getMetadataFacets( String repoId, String facetId )
320 throws MetadataRepositoryException
321 {
322 try
323 {
324 File directory = getMetadataDirectory( repoId, facetId );
325 List<String> facets = new ArrayList<>();
326 recurse( facets, "", directory );
327 return facets;
328 }
329 catch ( IOException e )
330 {
331 throw new MetadataRepositoryException( e.getMessage(), e );
332 }
333 }
334
335 @Override
336 public boolean hasMetadataFacet( String repositoryId, String facetId )
337 throws MetadataRepositoryException
338 {
339
340 return !getMetadataFacets( repositoryId, facetId ).isEmpty();
341 }
342
343 private void recurse( List<String> facets, String prefix, File directory )
344 {
345 File[] list = directory.listFiles();
346 if ( list != null )
347 {
348 for ( File dir : list )
349 {
350 if ( dir.isDirectory() )
351 {
352 recurse( facets, prefix + "/" + dir.getName(), dir );
353 }
354 else if ( dir.getName().equals( METADATA_KEY + ".properties" ) )
355 {
356 facets.add( prefix.substring( 1 ) );
357 }
358 }
359 }
360 }
361
362 @Override
363 public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
364 {
365 Properties properties;
366 try
367 {
368 properties =
369 readProperties( new File( getMetadataDirectory( repositoryId, facetId ), name ), METADATA_KEY );
370 }
371 catch ( FileNotFoundException e )
372 {
373 return null;
374 }
375 catch ( IOException e )
376 {
377
378 log.error( e.getMessage(), e );
379 return null;
380 }
381 MetadataFacet metadataFacet = null;
382 MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
383 if ( metadataFacetFactory != null )
384 {
385 metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
386 Map<String, String> map = new HashMap<>();
387 for ( Object key : new ArrayList( properties.keySet() ) )
388 {
389 String property = (String) key;
390 map.put( property, properties.getProperty( property ) );
391 }
392 metadataFacet.fromProperties( map );
393 }
394 return metadataFacet;
395 }
396
397 @Override
398 public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
399 {
400 Properties properties = new Properties();
401 properties.putAll( metadataFacet.toProperties() );
402
403 try
404 {
405 File directory =
406 new File( getMetadataDirectory( repositoryId, metadataFacet.getFacetId() ), metadataFacet.getName() );
407 writeProperties( properties, directory, METADATA_KEY );
408 }
409 catch ( IOException e )
410 {
411
412 log.error( e.getMessage(), e );
413 }
414 }
415
416 @Override
417 public void removeMetadataFacets( String repositoryId, String facetId )
418 throws MetadataRepositoryException
419 {
420 try
421 {
422 File dir = getMetadataDirectory( repositoryId, facetId );
423 FileUtils.deleteDirectory( dir );
424 }
425 catch ( IOException e )
426 {
427 throw new MetadataRepositoryException( e.getMessage(), e );
428 }
429 }
430
431 @Override
432 public void removeMetadataFacet( String repoId, String facetId, String name )
433 throws MetadataRepositoryException
434 {
435 try
436 {
437 File dir = new File( getMetadataDirectory( repoId, facetId ), name );
438 FileUtils.deleteDirectory( dir );
439 }
440 catch ( IOException e )
441 {
442 throw new MetadataRepositoryException( e.getMessage(), e );
443 }
444 }
445
446 @Override
447 public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
448 throws MetadataRepositoryException
449 {
450 try
451 {
452
453
454
455 List<ArtifactMetadata> artifacts = new ArrayList<>();
456 for ( String ns : getRootNamespaces( repoId ) )
457 {
458 getArtifactsByDateRange( artifacts, repoId, ns, startTime, endTime );
459 }
460 Collections.sort( artifacts, new ArtifactComparator() );
461 return artifacts;
462 }
463 catch ( MetadataResolutionException e )
464 {
465 throw new MetadataRepositoryException( e.getMessage(), e );
466 }
467 }
468
469 private void getArtifactsByDateRange( List<ArtifactMetadata> artifacts, String repoId, String ns, Date startTime,
470 Date endTime )
471 throws MetadataRepositoryException
472 {
473 try
474 {
475 for ( String namespace : getNamespaces( repoId, ns ) )
476 {
477 getArtifactsByDateRange( artifacts, repoId, ns + "." + namespace, startTime, endTime );
478 }
479
480 for ( String project : getProjects( repoId, ns ) )
481 {
482 for ( String version : getProjectVersions( repoId, ns, project ) )
483 {
484 for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
485 {
486 if ( startTime == null || startTime.before( artifact.getWhenGathered() ) )
487 {
488 if ( endTime == null || endTime.after( artifact.getWhenGathered() ) )
489 {
490 artifacts.add( artifact );
491 }
492 }
493 }
494 }
495 }
496 }
497 catch ( MetadataResolutionException e )
498 {
499 throw new MetadataRepositoryException( e.getMessage(), e );
500 }
501 }
502
503 @Override
504 public Collection<ArtifactMetadata> getArtifacts( String repoId, String namespace, String projectId,
505 String projectVersion )
506 throws MetadataResolutionException
507 {
508 try
509 {
510 Map<String, ArtifactMetadata> artifacts = new HashMap<>();
511
512 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
513
514 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
515
516 for ( Map.Entry entry : properties.entrySet() )
517 {
518 String name = (String) entry.getKey();
519 StringTokenizer tok = new StringTokenizer( name, ":" );
520 if ( tok.hasMoreTokens() && "artifact".equals( tok.nextToken() ) )
521 {
522 String field = tok.nextToken();
523 String id = tok.nextToken();
524
525 ArtifactMetadata artifact = artifacts.get( id );
526 if ( artifact == null )
527 {
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 );
536 }
537
538 String value = (String) entry.getValue();
539 if ( "updated".equals( field ) )
540 {
541 artifact.setFileLastModified( Long.parseLong( value ) );
542 }
543 else if ( "size".equals( field ) )
544 {
545 artifact.setSize( Long.valueOf( value ) );
546 }
547 else if ( "whenGathered".equals( field ) )
548 {
549 artifact.setWhenGathered( new Date( Long.parseLong( value ) ) );
550 }
551 else if ( "version".equals( field ) )
552 {
553 artifact.setVersion( value );
554 }
555 else if ( "md5".equals( field ) )
556 {
557 artifact.setMd5( value );
558 }
559 else if ( "sha1".equals( field ) )
560 {
561 artifact.setSha1( value );
562 }
563 else if ( "facetIds".equals( field ) )
564 {
565 if ( value.length() > 0 )
566 {
567 String propertyPrefix = "artifact:facet:" + id + ":";
568 for ( String facetId : value.split( "," ) )
569 {
570 MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
571 if ( factory == null )
572 {
573 log.error( "Attempted to load unknown artifact metadata facet: " + facetId );
574 }
575 else
576 {
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() ) )
581 {
582 String property = (String) key;
583 if ( property.startsWith( prefix ) )
584 {
585 map.put( property.substring( prefix.length() + 1 ),
586 properties.getProperty( property ) );
587 }
588 }
589 facet.fromProperties( map );
590 artifact.addFacet( facet );
591 }
592 }
593 }
594
595 updateArtifactFacets( artifact, properties );
596 }
597 }
598 }
599 return artifacts.values();
600 }
601 catch ( IOException e )
602 {
603 throw new MetadataResolutionException( e.getMessage(), e );
604 }
605 }
606
607 @Override
608 public void save()
609 {
610
611 }
612
613 @Override
614 public void close()
615 {
616
617 }
618
619 @Override
620 public void revert()
621 {
622 log.warn( "Attempted to revert a session, but the file-based repository storage doesn't support it" );
623 }
624
625 @Override
626 public boolean canObtainAccess( Class<?> aClass )
627 {
628 return false;
629 }
630
631 @Override
632 public <T> T obtainAccess( Class<T> aClass )
633 {
634 throw new IllegalArgumentException(
635 "Access using " + aClass + " is not supported on the file metadata storage" );
636 }
637
638 private void updateArtifactFacets( ArtifactMetadata artifact, Properties properties )
639 {
640 String propertyPrefix = "artifact:facet:" + artifact.getId() + ":";
641 for ( MetadataFacet facet : artifact.getFacetList() )
642 {
643 for ( Map.Entry<String, String> e : facet.toProperties().entrySet() )
644 {
645 String key = propertyPrefix + facet.getFacetId() + ":" + e.getKey();
646 properties.setProperty( key, e.getValue() );
647 }
648 }
649 }
650
651 @Override
652 public Collection<String> getRepositories()
653 {
654 List<String> repositories = new ArrayList<>();
655 for ( ManagedRepositoryConfiguration managedRepositoryConfiguration : configuration.getConfiguration().getManagedRepositories() )
656 {
657 repositories.add( managedRepositoryConfiguration.getId() );
658 }
659 return repositories;
660 }
661
662 @Override
663 public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
664 throws MetadataRepositoryException
665 {
666 try
667 {
668
669
670
671
672
673 List<ArtifactMetadata> artifacts = new ArrayList<>();
674 for ( String ns : getRootNamespaces( repositoryId ) )
675 {
676 getArtifactsByChecksum( artifacts, repositoryId, ns, checksum );
677 }
678 return artifacts;
679 }
680 catch ( MetadataResolutionException e )
681 {
682 throw new MetadataRepositoryException( e.getMessage(), e );
683 }
684 }
685
686 @Override
687 public void removeNamespace( String repositoryId, String project )
688 throws MetadataRepositoryException
689 {
690 try
691 {
692 File namespaceDirectory = new File( getDirectory( repositoryId ), project );
693 FileUtils.deleteDirectory( namespaceDirectory );
694
695
696
697
698 }
699 catch ( IOException e )
700 {
701 throw new MetadataRepositoryException( e.getMessage(), e );
702 }
703 }
704
705 @Override
706 public void removeArtifact( ArtifactMetadata artifactMetadata, String baseVersion )
707 throws MetadataRepositoryException
708 {
709
710 try
711 {
712 File directory = new File( getDirectory( artifactMetadata.getRepositoryId() ),
713 artifactMetadata.getNamespace() + "/" + artifactMetadata.getProject() + "/"
714 + baseVersion );
715
716 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
717
718 String id = artifactMetadata.getId();
719
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 );
727
728 String prefix = "artifact:facet:" + id + ":";
729 for ( Object key : new ArrayList( properties.keySet() ) )
730 {
731 String property = (String) key;
732 if ( property.startsWith( prefix ) )
733 {
734 properties.remove( property );
735 }
736 }
737
738 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
739 }
740 catch ( IOException e )
741 {
742 throw new MetadataRepositoryException( e.getMessage(), e );
743 }
744
745 }
746
747 @Override
748 public void removeArtifact( String repoId, String namespace, String project, String version, String id )
749 throws MetadataRepositoryException
750 {
751 try
752 {
753 File directory = new File( getDirectory( repoId ), namespace + "/" + project + "/" + version );
754
755 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
756
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 );
764
765 String prefix = "artifact:facet:" + id + ":";
766 for ( Object key : new ArrayList( properties.keySet() ) )
767 {
768 String property = (String) key;
769 if ( property.startsWith( prefix ) )
770 {
771 properties.remove( property );
772 }
773 }
774
775 FileUtils.deleteDirectory( directory );
776
777 }
778 catch ( IOException e )
779 {
780 throw new MetadataRepositoryException( e.getMessage(), e );
781 }
782 }
783
784
785
786
787
788
789
790
791
792
793
794 @Override
795 public void removeArtifact( String repositoryId, String namespace, String project, String projectVersion,
796 MetadataFacet metadataFacet )
797 throws MetadataRepositoryException
798 {
799 throw new UnsupportedOperationException( "not implemented" );
800 }
801
802 @Override
803 public void removeRepository( String repoId )
804 throws MetadataRepositoryException
805 {
806 try
807 {
808 File dir = getDirectory( repoId );
809 FileUtils.deleteDirectory( dir );
810 }
811 catch ( IOException e )
812 {
813 throw new MetadataRepositoryException( e.getMessage(), e );
814 }
815 }
816
817 private void getArtifactsByChecksum( List<ArtifactMetadata> artifacts, String repositoryId, String ns,
818 String checksum )
819 throws MetadataRepositoryException
820 {
821 try
822 {
823 for ( String namespace : getNamespaces( repositoryId, ns ) )
824 {
825 getArtifactsByChecksum( artifacts, repositoryId, ns + "." + namespace, checksum );
826 }
827
828 for ( String project : getProjects( repositoryId, ns ) )
829 {
830 for ( String version : getProjectVersions( repositoryId, ns, project ) )
831 {
832 for ( ArtifactMetadata artifact : getArtifacts( repositoryId, ns, project, version ) )
833 {
834 if ( checksum.equals( artifact.getMd5() ) || checksum.equals( artifact.getSha1() ) )
835 {
836 artifacts.add( artifact );
837 }
838 }
839 }
840 }
841 }
842 catch ( MetadataResolutionException e )
843 {
844 throw new MetadataRepositoryException( e.getMessage(), e );
845 }
846 }
847
848 @Override
849 public List<ArtifactMetadata> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
850 throws MetadataRepositoryException
851 {
852 throw new UnsupportedOperationException( "not yet implemented in File backend" );
853 }
854
855 @Override
856 public List<ArtifactMetadata> getArtifactsByMetadata( String key, String value, String repositoryId )
857 throws MetadataRepositoryException
858 {
859 throw new UnsupportedOperationException( "not yet implemented in File backend" );
860 }
861
862 @Override
863 public List<ArtifactMetadata> getArtifactsByProperty( String key, String value, String repositoryId )
864 throws MetadataRepositoryException
865 {
866 throw new UnsupportedOperationException( "getArtifactsByProperty not yet implemented in File backend" );
867 }
868
869 private File getMetadataDirectory( String repoId, String facetId )
870 throws IOException
871 {
872 return new File( getBaseDirectory( repoId ), "facets/" + facetId );
873 }
874
875 private String join( Collection<String> ids )
876 {
877 if ( ids != null && !ids.isEmpty() )
878 {
879 StringBuilder s = new StringBuilder();
880 for ( String id : ids )
881 {
882 s.append( id );
883 s.append( "," );
884 }
885 return s.substring( 0, s.length() - 1 );
886 }
887 return "";
888 }
889
890 private void setProperty( Properties properties, String name, String value )
891 {
892 if ( value != null )
893 {
894 properties.setProperty( name, value );
895 }
896 }
897
898 @Override
899 public void updateArtifact( String repoId, String namespace, String projectId, String projectVersion,
900 ArtifactMetadata artifact )
901 {
902 try
903 {
904 ProjectVersionMetadata metadata = new ProjectVersionMetadata();
905 metadata.setId( projectVersion );
906 updateProjectVersion( repoId, namespace, projectId, metadata );
907
908 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
909
910 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
911
912 clearMetadataFacetProperties( artifact.getFacetList(), properties,
913 "artifact:facet:" + artifact.getId() + ":" );
914
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 )
922 {
923 properties.setProperty( "artifact:md5:" + id, artifact.getMd5() );
924 }
925 if ( artifact.getSha1() != null )
926 {
927 properties.setProperty( "artifact:sha1:" + id, artifact.getSha1() );
928 }
929 properties.setProperty( "artifact:version:" + id, artifact.getVersion() );
930
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 ) );
935
936 updateArtifactFacets( artifact, properties );
937
938 writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
939 }
940 catch ( IOException e )
941 {
942
943 log.error( e.getMessage(), e );
944 }
945 }
946
947 private Properties readOrCreateProperties( File directory, String propertiesKey )
948 {
949 try
950 {
951 return readProperties( directory, propertiesKey );
952 }
953 catch ( FileNotFoundException | NoSuchFileException e )
954 {
955
956 }
957 catch ( IOException e )
958 {
959
960 log.error( e.getMessage(), e );
961 }
962 return new Properties();
963 }
964
965 private Properties readProperties( File directory, String propertiesKey )
966 throws IOException
967 {
968 Properties properties = new Properties();
969 try (InputStream in = Files.newInputStream( new File( directory, propertiesKey + ".properties" ).toPath() ))
970 {
971
972 properties.load( in );
973 }
974 return properties;
975 }
976
977 @Override
978 public ProjectMetadata getProject( String repoId, String namespace, String projectId )
979 throws MetadataResolutionException
980 {
981 try
982 {
983 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
984
985 Properties properties = readOrCreateProperties( directory, PROJECT_METADATA_KEY );
986
987 ProjectMetadata project = null;
988
989 String id = properties.getProperty( "id" );
990 if ( id != null )
991 {
992 project = new ProjectMetadata();
993 project.setNamespace( properties.getProperty( "namespace" ) );
994 project.setId( id );
995 }
996
997 return project;
998 }
999 catch ( IOException e )
1000 {
1001 throw new MetadataResolutionException( e.getMessage(), e );
1002 }
1003 }
1004
1005 @Override
1006 public ProjectVersionMetadata getProjectVersion( String repoId, String namespace, String projectId,
1007 String projectVersion )
1008 throws MetadataResolutionException
1009 {
1010 try
1011 {
1012 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1013
1014 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1015 String id = properties.getProperty( "id" );
1016 ProjectVersionMetadata versionMetadata = null;
1017 if ( id != null )
1018 {
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" ) ) );
1025
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 )
1030 {
1031 Scm scm = new Scm();
1032 scm.setConnection( scmConnection );
1033 scm.setDeveloperConnection( scmDeveloperConnection );
1034 scm.setUrl( scmUrl );
1035 versionMetadata.setScm( scm );
1036 }
1037
1038 String ciSystem = properties.getProperty( "ci.system" );
1039 String ciUrl = properties.getProperty( "ci.url" );
1040 if ( ciSystem != null || ciUrl != null )
1041 {
1042 CiManagement ci = new CiManagement();
1043 ci.setSystem( ciSystem );
1044 ci.setUrl( ciUrl );
1045 versionMetadata.setCiManagement( ci );
1046 }
1047
1048 String issueSystem = properties.getProperty( "issue.system" );
1049 String issueUrl = properties.getProperty( "issue.url" );
1050 if ( issueSystem != null || issueUrl != null )
1051 {
1052 IssueManagement issueManagement = new IssueManagement();
1053 issueManagement.setSystem( issueSystem );
1054 issueManagement.setUrl( issueUrl );
1055 versionMetadata.setIssueManagement( issueManagement );
1056 }
1057
1058 String orgName = properties.getProperty( "org.name" );
1059 String orgUrl = properties.getProperty( "org.url" );
1060 if ( orgName != null || orgUrl != null )
1061 {
1062 Organization org = new Organization();
1063 org.setName( orgName );
1064 org.setUrl( orgUrl );
1065 versionMetadata.setOrganization( org );
1066 }
1067
1068 boolean done = false;
1069 int i = 0;
1070 while ( !done )
1071 {
1072 String licenseName = properties.getProperty( "license." + i + ".name" );
1073 String licenseUrl = properties.getProperty( "license." + i + ".url" );
1074 if ( licenseName != null || licenseUrl != null )
1075 {
1076 License license = new License();
1077 license.setName( licenseName );
1078 license.setUrl( licenseUrl );
1079 versionMetadata.addLicense( license );
1080 }
1081 else
1082 {
1083 done = true;
1084 }
1085 i++;
1086 }
1087
1088 done = false;
1089 i = 0;
1090 while ( !done )
1091 {
1092 String mailingListName = properties.getProperty( "mailingList." + i + ".name" );
1093 if ( mailingListName != null )
1094 {
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 )
1100 {
1101 mailingList.setOtherArchives( Arrays.asList( p.split( "," ) ) );
1102 }
1103 else
1104 {
1105 mailingList.setOtherArchives( Collections.<String>emptyList() );
1106 }
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 );
1112 }
1113 else
1114 {
1115 done = true;
1116 }
1117 i++;
1118 }
1119
1120 done = false;
1121 i = 0;
1122 while ( !done )
1123 {
1124 String dependencyArtifactId = properties.getProperty( "dependency." + i + ".artifactId" );
1125 if ( dependencyArtifactId != null )
1126 {
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 );
1140 }
1141 else
1142 {
1143 done = true;
1144 }
1145 i++;
1146 }
1147
1148 String facetIds = properties.getProperty( "facetIds", "" );
1149 if ( facetIds.length() > 0 )
1150 {
1151 for ( String facetId : facetIds.split( "," ) )
1152 {
1153 MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
1154 if ( factory == null )
1155 {
1156 log.error( "Attempted to load unknown project version metadata facet: {}", facetId );
1157 }
1158 else
1159 {
1160 MetadataFacet facet = factory.createMetadataFacet();
1161 Map<String, String> map = new HashMap<>();
1162 for ( Object key : new ArrayList( properties.keySet() ) )
1163 {
1164 String property = (String) key;
1165 if ( property.startsWith( facet.getFacetId() ) )
1166 {
1167 map.put( property.substring( facet.getFacetId().length() + 1 ),
1168 properties.getProperty( property ) );
1169 }
1170 }
1171 facet.fromProperties( map );
1172 versionMetadata.addFacet( facet );
1173 }
1174 }
1175 }
1176
1177 updateProjectVersionFacets( versionMetadata, properties );
1178 }
1179 return versionMetadata;
1180 }
1181 catch ( IOException e )
1182 {
1183 throw new MetadataResolutionException( e.getMessage(), e );
1184 }
1185 }
1186
1187 @Override
1188 public Collection<String> getArtifactVersions( String repoId, String namespace, String projectId,
1189 String projectVersion )
1190 throws MetadataResolutionException
1191 {
1192 try
1193 {
1194 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1195
1196 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1197
1198 Set<String> versions = new HashSet<String>();
1199 for ( Map.Entry entry : properties.entrySet() )
1200 {
1201 String name = (String) entry.getKey();
1202 if ( name.startsWith( "artifact:version:" ) )
1203 {
1204 versions.add( (String) entry.getValue() );
1205 }
1206 }
1207 return versions;
1208 }
1209 catch ( IOException e )
1210 {
1211 throw new MetadataResolutionException( e.getMessage(), e );
1212 }
1213 }
1214
1215 @Override
1216 public Collection<ProjectVersionReference> getProjectReferences( String repoId, String namespace, String projectId,
1217 String projectVersion )
1218 throws MetadataResolutionException
1219 {
1220 try
1221 {
1222 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1223
1224 Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1225 int numberOfRefs = Integer.parseInt( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
1226
1227 List<ProjectVersionReference> references = new ArrayList<>();
1228 for ( int i = 0; i < numberOfRefs; i++ )
1229 {
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 );
1237 }
1238 return references;
1239 }
1240 catch ( IOException e )
1241 {
1242 throw new MetadataResolutionException( e.getMessage(), e );
1243 }
1244 }
1245
1246 @Override
1247 public Collection<String> getRootNamespaces( String repoId )
1248 throws MetadataResolutionException
1249 {
1250 return getNamespaces( repoId, null );
1251 }
1252
1253 @Override
1254 public Collection<String> getNamespaces( String repoId, String baseNamespace )
1255 throws MetadataResolutionException
1256 {
1257 try
1258 {
1259 List<String> allNamespaces = new ArrayList<>();
1260 File directory = getDirectory( repoId );
1261 File[] files = directory.listFiles();
1262 if ( files != null )
1263 {
1264 for ( File namespace : files )
1265 {
1266 if ( new File( namespace, NAMESPACE_METADATA_KEY + ".properties" ).exists() )
1267 {
1268 allNamespaces.add( namespace.getName() );
1269 }
1270 }
1271 }
1272
1273 Set<String> namespaces = new LinkedHashSet<>();
1274 int fromIndex = baseNamespace != null ? baseNamespace.length() + 1 : 0;
1275 for ( String namespace : allNamespaces )
1276 {
1277 if ( baseNamespace == null || namespace.startsWith( baseNamespace + "." ) )
1278 {
1279 int i = namespace.indexOf( '.', fromIndex );
1280 if ( i >= 0 )
1281 {
1282 namespaces.add( namespace.substring( fromIndex, i ) );
1283 }
1284 else
1285 {
1286 namespaces.add( namespace.substring( fromIndex ) );
1287 }
1288 }
1289 }
1290 return new ArrayList<>( namespaces );
1291 }
1292 catch ( IOException e )
1293 {
1294 throw new MetadataResolutionException( e.getMessage(), e );
1295 }
1296 }
1297
1298 @Override
1299 public Collection<String> getProjects( String repoId, String namespace )
1300 throws MetadataResolutionException
1301 {
1302 try
1303 {
1304 List<String> projects = new ArrayList<>();
1305 File directory = new File( getDirectory( repoId ), namespace );
1306 File[] files = directory.listFiles();
1307 if ( files != null )
1308 {
1309 for ( File project : files )
1310 {
1311 if ( new File( project, PROJECT_METADATA_KEY + ".properties" ).exists() )
1312 {
1313 projects.add( project.getName() );
1314 }
1315 }
1316 }
1317 return projects;
1318 }
1319 catch ( IOException e )
1320 {
1321 throw new MetadataResolutionException( e.getMessage(), e );
1322 }
1323 }
1324
1325 @Override
1326 public Collection<String> getProjectVersions( String repoId, String namespace, String projectId )
1327 throws MetadataResolutionException
1328 {
1329 try
1330 {
1331 List<String> projectVersions = new ArrayList<>();
1332 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
1333 File[] files = directory.listFiles();
1334 if ( files != null )
1335 {
1336 for ( File projectVersion : files )
1337 {
1338 if ( new File( projectVersion, PROJECT_VERSION_METADATA_KEY + ".properties" ).exists() )
1339 {
1340 projectVersions.add( projectVersion.getName() );
1341 }
1342 }
1343 }
1344 return projectVersions;
1345 }
1346 catch ( IOException e )
1347 {
1348 throw new MetadataResolutionException( e.getMessage(), e );
1349 }
1350 }
1351
1352 @Override
1353 public void removeProject( String repositoryId, String namespace, String projectId )
1354 throws MetadataRepositoryException
1355 {
1356 try
1357 {
1358 File directory = new File( getDirectory( repositoryId ), namespace + "/" + projectId );
1359 FileUtils.deleteDirectory( directory );
1360 }
1361 catch ( IOException e )
1362 {
1363 throw new MetadataRepositoryException( e.getMessage(), e );
1364 }
1365 }
1366
1367 @Override
1368 public void removeProjectVersion( String repoId, String namespace, String projectId, String projectVersion )
1369 throws MetadataRepositoryException
1370 {
1371 try
1372 {
1373 File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1374 FileUtils.deleteDirectory( directory );
1375 }
1376 catch ( IOException e )
1377 {
1378 throw new MetadataRepositoryException( e.getMessage(), e );
1379 }
1380
1381 }
1382
1383 private void writeProperties( Properties properties, File directory, String propertiesKey )
1384 throws IOException
1385 {
1386 directory.mkdirs();
1387 try (OutputStream os = Files.newOutputStream( new File( directory, propertiesKey + ".properties" ).toPath() ))
1388 {
1389 properties.store( os, null );
1390 }
1391 }
1392
1393 private static class ArtifactComparator
1394 implements Comparator<ArtifactMetadata>
1395 {
1396 @Override
1397 public int compare( ArtifactMetadata artifact1, ArtifactMetadata artifact2 )
1398 {
1399 if ( artifact1.getWhenGathered() == artifact2.getWhenGathered() )
1400 {
1401 return 0;
1402 }
1403 if ( artifact1.getWhenGathered() == null )
1404 {
1405 return 1;
1406 }
1407 if ( artifact2.getWhenGathered() == null )
1408 {
1409 return -1;
1410 }
1411 return artifact1.getWhenGathered().compareTo( artifact2.getWhenGathered() );
1412 }
1413 }
1414
1415 @Override
1416 public List<ArtifactMetadata> getArtifacts( String repoId )
1417 throws MetadataRepositoryException
1418 {
1419 try
1420 {
1421 List<ArtifactMetadata> artifacts = new ArrayList<>();
1422 for ( String ns : getRootNamespaces( repoId ) )
1423 {
1424 getArtifacts( artifacts, repoId, ns );
1425 }
1426 return artifacts;
1427 }
1428 catch ( MetadataResolutionException e )
1429 {
1430 throw new MetadataRepositoryException( e.getMessage(), e );
1431 }
1432 }
1433
1434 private void getArtifacts( List<ArtifactMetadata> artifacts, String repoId, String ns )
1435 throws MetadataResolutionException
1436 {
1437 for ( String namespace : getNamespaces( repoId, ns ) )
1438 {
1439 getArtifacts( artifacts, repoId, ns + "." + namespace );
1440 }
1441
1442 for ( String project : getProjects( repoId, ns ) )
1443 {
1444 for ( String version : getProjectVersions( repoId, ns, project ) )
1445 {
1446 for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
1447 {
1448 artifacts.add( artifact );
1449 }
1450 }
1451 }
1452 }
1453
1454 @Override
1455 public List<ArtifactMetadata> searchArtifacts( String text, String repositoryId, boolean exact )
1456 throws MetadataRepositoryException
1457 {
1458 throw new UnsupportedOperationException( "searchArtifacts not yet implemented in File backend" );
1459 }
1460
1461 @Override
1462 public List<ArtifactMetadata> searchArtifacts( String key, String text, String repositoryId, boolean exact )
1463 throws MetadataRepositoryException
1464 {
1465 throw new UnsupportedOperationException( "searchArtifacts not yet implemented in File backend" );
1466 }
1467 }