1 package org.apache.archiva.metadata.repository.jcr;
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.metadata.model.ArtifactMetadata;
23 import org.apache.archiva.metadata.model.CiManagement;
24 import org.apache.archiva.metadata.model.Dependency;
25 import org.apache.archiva.metadata.model.IssueManagement;
26 import org.apache.archiva.metadata.model.License;
27 import org.apache.archiva.metadata.model.MailingList;
28 import org.apache.archiva.metadata.model.MetadataFacet;
29 import org.apache.archiva.metadata.model.MetadataFacetFactory;
30 import org.apache.archiva.metadata.model.Organization;
31 import org.apache.archiva.metadata.model.ProjectMetadata;
32 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
33 import org.apache.archiva.metadata.model.ProjectVersionReference;
34 import org.apache.archiva.metadata.model.Scm;
35 import org.apache.archiva.metadata.repository.MetadataRepository;
36 import org.apache.archiva.metadata.repository.MetadataResolutionException;
37 import org.apache.jackrabbit.core.TransientRepository;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.Calendar;
45 import java.util.Collection;
46 import java.util.Collections;
47 import java.util.Comparator;
48 import java.util.Date;
49 import java.util.HashMap;
50 import java.util.LinkedHashSet;
51 import java.util.List;
54 import javax.jcr.LoginException;
55 import javax.jcr.Node;
56 import javax.jcr.NodeIterator;
57 import javax.jcr.PathNotFoundException;
58 import javax.jcr.Property;
59 import javax.jcr.PropertyIterator;
60 import javax.jcr.Repository;
61 import javax.jcr.RepositoryException;
62 import javax.jcr.Session;
63 import javax.jcr.SimpleCredentials;
66 * @plexus.component role="org.apache.archiva.metadata.repository.MetadataRepository"
67 * @todo path construction should be centralised
68 * @todo review all methods for alternate implementations (use of queries)
69 * @todo below: exception handling
70 * @todo below: revise storage format for project version metadata
72 public class JcrMetadataRepository
73 implements MetadataRepository
76 * @plexus.requirement role="org.apache.archiva.metadata.model.MetadataFacetFactory"
78 private Map<String, MetadataFacetFactory> metadataFacetFactories;
80 private static final Logger log = LoggerFactory.getLogger( JcrMetadataRepository.class );
82 private static Repository repository;
84 private Session session;
86 public JcrMetadataRepository()
88 // TODO: need to close this at the end - do we need to add it in the API?
92 // TODO: push this in from the test, and make it possible from the webapp
93 if ( repository == null )
95 repository = new TransientRepository( new File( "src/test/repository.xml" ), new File( "target/jcr" ) );
97 // TODO: shouldn't do this in constructor since it's a singleton
98 session = repository.login( new SimpleCredentials( "username", "password".toCharArray() ) );
100 catch ( LoginException e )
103 throw new RuntimeException( e );
105 catch ( RepositoryException e )
108 throw new RuntimeException( e );
112 public void updateProject( String repositoryId, ProjectMetadata project )
114 String namespace = project.getNamespace();
115 String projectId = project.getId();
116 updateProject( repositoryId, namespace, projectId );
119 private void updateProject( String repositoryId, String namespace, String projectId )
121 updateNamespace( repositoryId, namespace );
125 Node namespaceNode = getOrCreateNamespaceNode( repositoryId, namespace );
126 getOrCreateNode( namespaceNode, projectId );
128 catch ( RepositoryException e )
131 throw new RuntimeException( e );
135 public void updateArtifact( String repositoryId, String namespace, String projectId, String projectVersion,
136 ArtifactMetadata artifactMeta )
140 Node node = getOrCreateArtifactNode( repositoryId, namespace, projectId, projectVersion,
141 artifactMeta.getId() );
143 Calendar cal = Calendar.getInstance();
144 cal.setTime( artifactMeta.getFileLastModified() );
145 node.setProperty( "updated", cal );
147 cal = Calendar.getInstance();
148 cal.setTime( artifactMeta.getWhenGathered() );
149 node.setProperty( "whenGathered", cal );
151 node.setProperty( "size", artifactMeta.getSize() );
152 node.setProperty( "md5", artifactMeta.getMd5() );
153 node.setProperty( "sha1", artifactMeta.getSha1() );
155 node.setProperty( "version", artifactMeta.getVersion() );
157 // TODO: namespaced properties instead?
158 Node facetNode = getOrCreateNode( node, "facets" );
159 for ( MetadataFacet facet : artifactMeta.getFacetList() )
161 // TODO: need to clear it?
162 Node n = getOrCreateNode( facetNode, facet.getFacetId() );
164 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
166 n.setProperty( entry.getKey(), entry.getValue() );
170 catch ( RepositoryException e )
173 throw new RuntimeException( e );
177 private Node getOrCreateArtifactNode( String repositoryId, String namespace, String projectId,
178 String projectVersion, String id )
179 throws RepositoryException
181 Node versionNode = getOrCreateProjectVersionNode( repositoryId, namespace, projectId, projectVersion );
182 return getOrCreateNode( versionNode, id );
185 public void updateProjectVersion( String repositoryId, String namespace, String projectId,
186 ProjectVersionMetadata versionMetadata )
188 updateProject( repositoryId, namespace, projectId );
192 Node versionNode = getOrCreateProjectVersionNode( repositoryId, namespace, projectId,
193 versionMetadata.getId() );
195 versionNode.setProperty( "name", versionMetadata.getName() );
196 versionNode.setProperty( "description", versionMetadata.getDescription() );
197 versionNode.setProperty( "url", versionMetadata.getUrl() );
198 versionNode.setProperty( "incomplete", versionMetadata.isIncomplete() );
200 // TODO: decide how to treat these in the content repo
201 if ( versionMetadata.getScm() != null )
203 versionNode.setProperty( "scm.connection", versionMetadata.getScm().getConnection() );
204 versionNode.setProperty( "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
205 versionNode.setProperty( "scm.url", versionMetadata.getScm().getUrl() );
207 if ( versionMetadata.getCiManagement() != null )
209 versionNode.setProperty( "ci.system", versionMetadata.getCiManagement().getSystem() );
210 versionNode.setProperty( "ci.url", versionMetadata.getCiManagement().getUrl() );
212 if ( versionMetadata.getIssueManagement() != null )
214 versionNode.setProperty( "issue.system", versionMetadata.getIssueManagement().getSystem() );
215 versionNode.setProperty( "issue.url", versionMetadata.getIssueManagement().getUrl() );
217 if ( versionMetadata.getOrganization() != null )
219 versionNode.setProperty( "org.name", versionMetadata.getOrganization().getName() );
220 versionNode.setProperty( "org.url", versionMetadata.getOrganization().getUrl() );
223 for ( License license : versionMetadata.getLicenses() )
225 versionNode.setProperty( "license." + i + ".name", license.getName() );
226 versionNode.setProperty( "license." + i + ".url", license.getUrl() );
230 for ( MailingList mailingList : versionMetadata.getMailingLists() )
232 versionNode.setProperty( "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
233 versionNode.setProperty( "mailingList." + i + ".name", mailingList.getName() );
234 versionNode.setProperty( "mailingList." + i + ".post", mailingList.getPostAddress() );
235 versionNode.setProperty( "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
236 versionNode.setProperty( "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
237 versionNode.setProperty( "mailingList." + i + ".otherArchives", join(
238 mailingList.getOtherArchives() ) );
242 for ( Dependency dependency : versionMetadata.getDependencies() )
244 versionNode.setProperty( "dependency." + i + ".classifier", dependency.getClassifier() );
245 versionNode.setProperty( "dependency." + i + ".scope", dependency.getScope() );
246 versionNode.setProperty( "dependency." + i + ".systemPath", dependency.getSystemPath() );
247 versionNode.setProperty( "dependency." + i + ".artifactId", dependency.getArtifactId() );
248 versionNode.setProperty( "dependency." + i + ".groupId", dependency.getGroupId() );
249 versionNode.setProperty( "dependency." + i + ".version", dependency.getVersion() );
250 versionNode.setProperty( "dependency." + i + ".type", dependency.getType() );
254 // TODO: namespaced properties instead?
255 Node facetNode = getOrCreateNode( versionNode, "facets" );
256 for ( MetadataFacet facet : versionMetadata.getFacetList() )
258 // TODO: shouldn't need to recreate, just update
259 if ( facetNode.hasNode( facet.getFacetId() ) )
261 facetNode.getNode( facet.getFacetId() ).remove();
263 Node n = facetNode.addNode( facet.getFacetId() );
265 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
267 n.setProperty( entry.getKey(), entry.getValue() );
271 catch ( RepositoryException e )
274 throw new RuntimeException( e );
278 private Node getOrCreateProjectVersionNode( String repositoryId, String namespace, String projectId,
279 String projectVersion )
280 throws RepositoryException
282 Node namespaceNode = getOrCreateNamespaceNode( repositoryId, namespace );
283 Node projectNode = getOrCreateNode( namespaceNode, projectId );
284 return getOrCreateNode( projectNode, projectVersion );
287 private Node getOrCreateNode( Node baseNode, String name )
288 throws RepositoryException
290 return baseNode.hasNode( name ) ? baseNode.getNode( name ) : baseNode.addNode( name );
293 private Node getOrCreateNamespaceNode( String repositoryId, String namespace )
294 throws RepositoryException
296 Node repo = getOrCreateRepositoryContentNode( repositoryId );
297 return getOrCreateNode( repo, namespace );
300 private Node getOrCreateRepositoryContentNode( String repositoryId )
301 throws RepositoryException
303 Node node = getOrCreateRepositoryNode( repositoryId );
304 return getOrCreateNode( node, "content" );
307 private Node getOrCreateRepositoryNode( String repositoryId )
308 throws RepositoryException
310 Node root = session.getRootNode();
311 Node node = getOrCreateNode( root, "repositories" );
312 node = getOrCreateNode( node, repositoryId );
316 public void updateProjectReference( String repositoryId, String namespace, String projectId, String projectVersion,
317 ProjectVersionReference reference )
319 // TODO: try weak reference?
320 // TODO: is this tree the right way up? It differs from the content model
323 Node node = getOrCreateRepositoryContentNode( repositoryId );
324 node = getOrCreateNode( node, namespace );
325 node = getOrCreateNode( node, projectId );
326 node = getOrCreateNode( node, projectVersion );
327 node = getOrCreateNode( node, "references" );
328 node = getOrCreateNode( node, reference.getNamespace() );
329 node = getOrCreateNode( node, reference.getProjectId() );
330 node = getOrCreateNode( node, reference.getProjectVersion() );
331 node.setProperty( "type", reference.getReferenceType().toString() );
333 catch ( RepositoryException e )
336 throw new RuntimeException( e );
340 public void updateNamespace( String repositoryId, String namespace )
344 Node node = getOrCreateNamespaceNode( repositoryId, namespace );
345 node.setProperty( "namespace", namespace );
347 catch ( RepositoryException e )
350 throw new RuntimeException( e );
354 public List<String> getMetadataFacets( String repositoryId, String facetId )
356 List<String> facets = new ArrayList<String>();
360 Node root = session.getRootNode();
361 Node node = root.getNode( "repositories/" + repositoryId + "/facets/" + facetId );
363 // TODO: could we simply query all nodes with no children?
364 recurse( facets, "", node );
366 catch ( PathNotFoundException e )
368 // TODO: handle this case differently?
371 catch ( RepositoryException e )
374 throw new RuntimeException( e );
379 private void recurse( List<String> facets, String prefix, Node node )
380 throws RepositoryException
382 NodeIterator iterator = node.getNodes();
383 while ( iterator.hasNext() )
385 Node n = iterator.nextNode();
386 String name = prefix + "/" + n.getName();
389 recurse( facets, name, n );
393 // strip leading / first
394 facets.add( name.substring( 1 ) );
400 public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
402 MetadataFacet metadataFacet = null;
405 Node root = session.getRootNode();
406 Node node = root.getNode( "repositories/" + repositoryId + "/facets/" + facetId + "/" + name );
408 MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
409 if ( metadataFacetFactory != null )
411 metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
412 Map<String, String> map = new HashMap<String, String>();
413 PropertyIterator iterator = node.getProperties();
414 while ( iterator.hasNext() )
416 Property property = iterator.nextProperty();
417 String p = property.getName();
418 if ( !p.startsWith( "jcr:" ) )
420 map.put( p, property.getString() );
423 metadataFacet.fromProperties( map );
426 catch ( PathNotFoundException e )
428 // TODO: handle this case differently?
431 catch ( RepositoryException e )
434 throw new RuntimeException( e );
436 return metadataFacet;
439 public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
443 Node repo = getOrCreateRepositoryNode( repositoryId );
444 Node facets = getOrCreateNode( repo, "facets" );
446 String id = metadataFacet.getFacetId();
447 Node facetNode = getOrCreateNode( facets, id );
449 Node node = getOrCreatePath( facetNode, metadataFacet.getName() );
451 for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
453 node.setProperty( entry.getKey(), entry.getValue() );
456 catch ( RepositoryException e )
459 throw new RuntimeException( e );
463 private Node getOrCreatePath( Node baseNode, String name )
464 throws RepositoryException
466 Node node = baseNode;
467 for ( String n : name.split( "/" ) )
469 node = getOrCreateNode( node, n );
474 public void removeMetadataFacets( String repositoryId, String facetId )
478 Node root = session.getRootNode();
479 String path = "repositories/" + repositoryId + "/facets/" + facetId;
480 // TODO: exception if missing?
481 if ( root.hasNode( path ) )
483 root.getNode( path ).remove();
486 catch ( RepositoryException e )
489 throw new RuntimeException( e );
493 public void removeMetadataFacet( String repositoryId, String facetId, String name )
497 Node root = session.getRootNode();
498 String path = "repositories/" + repositoryId + "/facets/" + facetId + "/" + name;
499 // TODO: exception if missing?
500 if ( root.hasNode( path ) )
502 Node node = root.getNode( path );
505 Node parent = node.getParent();
509 while ( !node.hasNodes() );
512 catch ( RepositoryException e )
515 throw new RuntimeException( e );
519 public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
521 // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
522 // of this information (eg. in Lucene, as before)
524 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
525 for ( String ns : getRootNamespaces( repoId ) )
527 getArtifactsByDateRange( artifacts, repoId, ns, startTime, endTime );
529 Collections.sort( artifacts, new ArtifactComparator() );
533 private void getArtifactsByDateRange( List<ArtifactMetadata> artifacts, String repoId, String ns, Date startTime,
536 for ( String namespace : getNamespaces( repoId, ns ) )
538 getArtifactsByDateRange( artifacts, repoId, ns + "." + namespace, startTime, endTime );
541 for ( String project : getProjects( repoId, ns ) )
543 for ( String version : getProjectVersions( repoId, ns, project ) )
545 for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
547 if ( startTime == null || startTime.before( artifact.getWhenGathered() ) )
549 if ( endTime == null || endTime.after( artifact.getWhenGathered() ) )
551 artifacts.add( artifact );
559 public Collection<String> getRepositories()
561 List<String> repositories;
565 Node root = session.getRootNode();
566 if ( root.hasNode( "repositories" ) )
568 Node node = root.getNode( "repositories" );
570 repositories = new ArrayList<String>();
571 NodeIterator i = node.getNodes();
572 while ( i.hasNext() )
574 Node n = i.nextNode();
575 repositories.add( n.getName() );
580 repositories = Collections.emptyList();
583 catch ( RepositoryException e )
586 throw new RuntimeException( e );
591 public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
593 // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
594 // of this information (eg. in Lucene, as before)
595 // alternatively, we could build a referential tree in the content repository, however it would need some levels
596 // of depth to avoid being too broad to be useful (eg. /repository/checksums/a/ab/abcdef1234567)
598 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
599 for ( String ns : getRootNamespaces( repositoryId ) )
601 getArtifactsByChecksum( artifacts, repositoryId, ns, checksum );
606 private void getArtifactsByChecksum( List<ArtifactMetadata> artifacts, String repositoryId, String ns,
609 for ( String namespace : getNamespaces( repositoryId, ns ) )
611 getArtifactsByChecksum( artifacts, repositoryId, ns + "." + namespace, checksum );
614 for ( String project : getProjects( repositoryId, ns ) )
616 for ( String version : getProjectVersions( repositoryId, ns, project ) )
618 for ( ArtifactMetadata artifact : getArtifacts( repositoryId, ns, project, version ) )
620 if ( checksum.equals( artifact.getMd5() ) || checksum.equals( artifact.getSha1() ) )
622 artifacts.add( artifact );
629 public void deleteArtifact( String repositoryId, String namespace, String projectId, String projectVersion,
634 Node root = session.getRootNode();
636 "repositories/" + repositoryId + "/content/" + namespace + "/" + projectId + "/" + projectVersion +
638 // TODO: exception if missing?
639 if ( root.hasNode( path ) )
641 root.getNode( path ).remove();
644 catch ( RepositoryException e )
647 throw new RuntimeException( e );
651 public void deleteRepository( String repositoryId )
655 Node root = session.getRootNode();
656 String path = "repositories/" + repositoryId;
657 // TODO: exception if missing?
658 if ( root.hasNode( path ) )
660 root.getNode( path ).remove();
663 catch ( RepositoryException e )
666 throw new RuntimeException( e );
670 public List<ArtifactMetadata> getArtifacts( String repositoryId )
672 // TODO: query faster?
673 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
674 for ( String ns : getRootNamespaces( repositoryId ) )
676 getArtifacts( artifacts, repositoryId, ns );
681 private void getArtifacts( List<ArtifactMetadata> artifacts, String repoId, String ns )
683 for ( String namespace : getNamespaces( repoId, ns ) )
685 getArtifacts( artifacts, repoId, ns + "." + namespace );
688 for ( String project : getProjects( repoId, ns ) )
690 for ( String version : getProjectVersions( repoId, ns, project ) )
692 for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
694 artifacts.add( artifact );
700 public ProjectMetadata getProject( String repositoryId, String namespace, String projectId )
702 ProjectMetadata metadata = null;
706 Node root = session.getRootNode();
708 // basically just checking it exists
709 String path = "repositories/" + repositoryId + "/content/" + namespace + "/" + projectId;
710 if ( root.hasNode( path ) )
712 metadata = new ProjectMetadata();
713 metadata.setId( projectId );
714 metadata.setNamespace( namespace );
717 catch ( RepositoryException e )
720 throw new RuntimeException( e );
726 public ProjectVersionMetadata getProjectVersion( String repositoryId, String namespace, String projectId,
727 String projectVersion )
728 throws MetadataResolutionException
730 ProjectVersionMetadata versionMetadata;
734 Node root = session.getRootNode();
737 "repositories/" + repositoryId + "/content/" + namespace + "/" + projectId + "/" + projectVersion;
738 if ( !root.hasNode( path ) )
743 Node node = root.getNode( path );
745 versionMetadata = new ProjectVersionMetadata();
746 versionMetadata.setId( projectVersion );
747 versionMetadata.setName( getPropertyString( node, "name" ) );
748 versionMetadata.setDescription( getPropertyString( node, "description" ) );
749 versionMetadata.setUrl( getPropertyString( node, "url" ) );
750 versionMetadata.setIncomplete( node.hasProperty( "incomplete" ) && node.getProperty(
751 "incomplete" ).getBoolean() );
753 // TODO: decide how to treat these in the content repo
754 String scmConnection = getPropertyString( node, "scm.connection" );
755 String scmDeveloperConnection = getPropertyString( node, "scm.developerConnection" );
756 String scmUrl = getPropertyString( node, "scm.url" );
757 if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
760 scm.setConnection( scmConnection );
761 scm.setDeveloperConnection( scmDeveloperConnection );
762 scm.setUrl( scmUrl );
763 versionMetadata.setScm( scm );
766 String ciSystem = getPropertyString( node, "ci.system" );
767 String ciUrl = getPropertyString( node, "ci.url" );
768 if ( ciSystem != null || ciUrl != null )
770 CiManagement ci = new CiManagement();
771 ci.setSystem( ciSystem );
773 versionMetadata.setCiManagement( ci );
776 String issueSystem = getPropertyString( node, "issue.system" );
777 String issueUrl = getPropertyString( node, "issue.url" );
778 if ( issueSystem != null || issueUrl != null )
780 IssueManagement issueManagement = new IssueManagement();
781 issueManagement.setSystem( issueSystem );
782 issueManagement.setUrl( issueUrl );
783 versionMetadata.setIssueManagement( issueManagement );
786 String orgName = getPropertyString( node, "org.name" );
787 String orgUrl = getPropertyString( node, "org.url" );
788 if ( orgName != null || orgUrl != null )
790 Organization org = new Organization();
791 org.setName( orgName );
792 org.setUrl( orgUrl );
793 versionMetadata.setOrganization( org );
796 boolean done = false;
800 String licenseName = getPropertyString( node, "license." + i + ".name" );
801 String licenseUrl = getPropertyString( node, "license." + i + ".url" );
802 if ( licenseName != null || licenseUrl != null )
804 License license = new License();
805 license.setName( licenseName );
806 license.setUrl( licenseUrl );
807 versionMetadata.addLicense( license );
820 String mailingListName = getPropertyString( node, "mailingList." + i + ".name" );
821 if ( mailingListName != null )
823 MailingList mailingList = new MailingList();
824 mailingList.setName( mailingListName );
825 mailingList.setMainArchiveUrl( getPropertyString( node, "mailingList." + i + ".archive" ) );
826 String n = "mailingList." + i + ".otherArchives";
827 if ( node.hasProperty( n ) )
829 mailingList.setOtherArchives( Arrays.asList( getPropertyString( node, n ).split( "," ) ) );
833 mailingList.setOtherArchives( Collections.<String>emptyList() );
835 mailingList.setPostAddress( getPropertyString( node, "mailingList." + i + ".post" ) );
836 mailingList.setSubscribeAddress( getPropertyString( node, "mailingList." + i + ".subscribe" ) );
837 mailingList.setUnsubscribeAddress( getPropertyString( node, "mailingList." + i + ".unsubscribe" ) );
838 versionMetadata.addMailingList( mailingList );
851 String dependencyArtifactId = getPropertyString( node, "dependency." + i + ".artifactId" );
852 if ( dependencyArtifactId != null )
854 Dependency dependency = new Dependency();
855 dependency.setArtifactId( dependencyArtifactId );
856 dependency.setGroupId( getPropertyString( node, "dependency." + i + ".groupId" ) );
857 dependency.setClassifier( getPropertyString( node, "dependency." + i + ".classifier" ) );
858 dependency.setOptional( Boolean.valueOf( getPropertyString( node,
859 "dependency." + i + ".optional" ) ) );
860 dependency.setScope( getPropertyString( node, "dependency." + i + ".scope" ) );
861 dependency.setSystemPath( getPropertyString( node, "dependency." + i + ".systemPath" ) );
862 dependency.setType( getPropertyString( node, "dependency." + i + ".type" ) );
863 dependency.setVersion( getPropertyString( node, "dependency." + i + ".version" ) );
864 versionMetadata.addDependency( dependency );
873 if ( node.hasNode( "facets" ) )
875 NodeIterator j = node.getNode( "facets" ).getNodes();
877 while ( j.hasNext() )
879 Node facetNode = j.nextNode();
881 MetadataFacetFactory factory = metadataFacetFactories.get( facetNode.getName() );
882 if ( factory == null )
884 log.error( "Attempted to load unknown project version metadata facet: " + facetNode.getName() );
888 MetadataFacet facet = factory.createMetadataFacet();
889 Map<String, String> map = new HashMap<String, String>();
890 PropertyIterator iterator = facetNode.getProperties();
891 while ( iterator.hasNext() )
893 Property property = iterator.nextProperty();
894 String p = property.getName();
895 if ( !p.startsWith( "jcr:" ) )
897 map.put( p, property.getString() );
900 facet.fromProperties( map );
901 versionMetadata.addFacet( facet );
906 catch ( RepositoryException e )
909 throw new RuntimeException( e );
912 return versionMetadata;
915 private static String getPropertyString( Node node, String name )
916 throws RepositoryException
918 return node.hasProperty( name ) ? node.getProperty( name ).getString() : null;
921 public Collection<String> getArtifactVersions( String repositoryId, String namespace, String projectId,
922 String projectVersion )
924 Set<String> versions = new LinkedHashSet<String>();
928 Node root = session.getRootNode();
930 Node node = root.getNode(
931 "repositories/" + repositoryId + "/content/" + namespace + "/" + projectId + "/" + projectVersion );
933 NodeIterator iterator = node.getNodes();
934 while ( iterator.hasNext() )
936 Node n = iterator.nextNode();
938 versions.add( n.getProperty( "version" ).getString() );
941 catch ( PathNotFoundException e )
943 // ignore repo not found for now
944 // TODO: throw specific exception if repo doesn't exist
946 catch ( RepositoryException e )
949 throw new RuntimeException( e );
955 public Collection<ProjectVersionReference> getProjectReferences( String repositoryId, String namespace,
956 String projectId, String projectVersion )
958 List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
962 Node root = session.getRootNode();
965 "repositories/" + repositoryId + "/content/" + namespace + "/" + projectId + "/" + projectVersion +
967 if ( root.hasNode( path ) )
969 Node node = root.getNode( path );
971 // TODO: use query by reference type
972 NodeIterator i = node.getNodes();
973 while ( i.hasNext() )
975 Node ns = i.nextNode();
977 NodeIterator j = ns.getNodes();
979 while ( j.hasNext() )
981 Node project = j.nextNode();
983 NodeIterator k = project.getNodes();
985 while ( k.hasNext() )
987 Node version = k.nextNode();
989 ProjectVersionReference ref = new ProjectVersionReference();
990 ref.setNamespace( ns.getName() );
991 ref.setProjectId( project.getName() );
992 ref.setProjectVersion( version.getName() );
993 String type = version.getProperty( "type" ).getString();
994 ref.setReferenceType( ProjectVersionReference.ReferenceType.valueOf( type ) );
995 references.add( ref );
1001 catch ( RepositoryException e )
1004 throw new RuntimeException( e );
1010 public Collection<String> getRootNamespaces( String repositoryId )
1012 return getNamespaces( repositoryId, null );
1015 private Collection<String> getNodeNames( String path )
1017 List<String> names = new ArrayList<String>();
1021 Node root = session.getRootNode();
1023 Node repository = root.getNode( path );
1025 NodeIterator nodes = repository.getNodes();
1026 while ( nodes.hasNext() )
1028 Node node = nodes.nextNode();
1029 names.add( node.getName() );
1032 catch ( PathNotFoundException e )
1034 // ignore repo not found for now
1035 // TODO: throw specific exception if repo doesn't exist
1037 catch ( RepositoryException e )
1040 throw new RuntimeException( e );
1046 public Collection<String> getNamespaces( String repositoryId, String baseNamespace )
1048 // TODO: could be simpler with pathed namespaces, rely on namespace property
1049 Collection<String> allNamespaces = getNodeNames( "repositories/" + repositoryId + "/content" );
1051 Set<String> namespaces = new LinkedHashSet<String>();
1052 int fromIndex = baseNamespace != null ? baseNamespace.length() + 1 : 0;
1053 for ( String namespace : allNamespaces )
1055 if ( baseNamespace == null || namespace.startsWith( baseNamespace + "." ) )
1057 int i = namespace.indexOf( '.', fromIndex );
1060 namespaces.add( namespace.substring( fromIndex, i ) );
1064 namespaces.add( namespace.substring( fromIndex ) );
1068 return new ArrayList<String>( namespaces );
1071 public Collection<String> getProjects( String repositoryId, String namespace )
1073 // TODO: could be simpler with pathed namespaces, rely on namespace property
1074 return getNodeNames( "repositories/" + repositoryId + "/content/" + namespace );
1077 public Collection<String> getProjectVersions( String repositoryId, String namespace, String projectId )
1079 // TODO: could be simpler with pathed namespaces, rely on namespace property
1080 return getNodeNames( "repositories/" + repositoryId + "/content/" + namespace + "/" + projectId );
1083 public Collection<ArtifactMetadata> getArtifacts( String repositoryId, String namespace, String projectId,
1084 String projectVersion )
1086 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
1090 Node root = session.getRootNode();
1092 "repositories/" + repositoryId + "/content/" + namespace + "/" + projectId + "/" + projectVersion;
1094 if ( root.hasNode( path ) )
1096 Node node = root.getNode( path );
1098 NodeIterator iterator = node.getNodes();
1099 while ( iterator.hasNext() )
1101 Node artifactNode = iterator.nextNode();
1103 String id = artifactNode.getName();
1105 ArtifactMetadata artifact = new ArtifactMetadata();
1106 artifact.setId( id );
1107 artifact.setRepositoryId( repositoryId );
1108 artifact.setNamespace( namespace );
1109 artifact.setProject( projectId );
1110 artifact.setProjectVersion( projectVersion );
1111 artifact.setVersion( artifactNode.hasProperty( "version" ) ? artifactNode.getProperty(
1112 "version" ).getString() : projectVersion );
1114 if ( artifactNode.hasProperty( "updated" ) )
1116 artifact.setFileLastModified( artifactNode.getProperty(
1117 "updated" ).getDate().getTimeInMillis() );
1120 if ( artifactNode.hasProperty( "whenGathered" ) )
1122 artifact.setWhenGathered( artifactNode.getProperty( "whenGathered" ).getDate().getTime() );
1125 if ( artifactNode.hasProperty( "size" ) )
1127 artifact.setSize( artifactNode.getProperty( "size" ).getLong() );
1130 if ( artifactNode.hasProperty( "md5" ) )
1132 artifact.setMd5( artifactNode.getProperty( "md5" ).getString() );
1135 if ( artifactNode.hasProperty( "sha1" ) )
1137 artifact.setSha1( artifactNode.getProperty( "sha1" ).getString() );
1140 if ( artifactNode.hasNode( "facets" ) )
1142 NodeIterator j = artifactNode.getNode( "facets" ).getNodes();
1144 while ( j.hasNext() )
1146 Node facetNode = j.nextNode();
1148 MetadataFacetFactory factory = metadataFacetFactories.get( facetNode.getName() );
1149 if ( factory == null )
1151 log.error( "Attempted to load unknown project version metadata facet: " + facetNode.getName() );
1155 MetadataFacet facet = factory.createMetadataFacet();
1156 Map<String, String> map = new HashMap<String, String>();
1157 PropertyIterator i = facetNode.getProperties();
1158 while ( i.hasNext() )
1160 Property p = i.nextProperty();
1161 String property = p.getName();
1162 map.put( property, p.getString() );
1164 facet.fromProperties( map );
1165 artifact.addFacet( facet );
1169 artifacts.add( artifact );
1173 catch ( RepositoryException e )
1176 throw new RuntimeException( e );
1186 // TODO: this shouldn't be here! Repository may need a context
1189 catch ( RepositoryException e )
1192 throw new RuntimeException( e );
1197 public void setMetadataFacetFactories( Map<String, MetadataFacetFactory> metadataFacetFactories )
1199 this.metadataFacetFactories = metadataFacetFactories;
1201 // TODO: check if actually called by normal injection
1203 // for ( String facetId : metadataFacetFactories.keySet() )
1205 // // TODO: second arg should be a better URL for the namespace
1206 // session.getWorkspace().getNamespaceRegistry().registerNamespace( facetId, facetId );
1210 private static class ArtifactComparator
1211 implements Comparator<ArtifactMetadata>
1213 public int compare( ArtifactMetadata artifact1, ArtifactMetadata artifact2 )
1215 if ( artifact1.getWhenGathered() == artifact2.getWhenGathered() )
1219 if ( artifact1.getWhenGathered() == null )
1223 if ( artifact2.getWhenGathered() == null )
1227 return artifact1.getWhenGathered().compareTo( artifact2.getWhenGathered() );
1231 private String join( Collection<String> ids )
1233 if ( ids != null && !ids.isEmpty() )
1235 StringBuilder s = new StringBuilder();
1236 for ( String id : ids )
1241 return s.substring( 0, s.length() - 1 );