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.MetadataRepositoryException;
37 import org.apache.archiva.metadata.repository.MetadataResolutionException;
38 import org.apache.jackrabbit.commons.JcrUtils;
39 import org.slf4j.Logger;
40 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.Date;
48 import java.util.HashMap;
49 import java.util.LinkedHashSet;
50 import java.util.List;
53 import javax.jcr.LoginException;
54 import javax.jcr.Node;
55 import javax.jcr.NodeIterator;
56 import javax.jcr.PathNotFoundException;
57 import javax.jcr.Property;
58 import javax.jcr.Repository;
59 import javax.jcr.RepositoryException;
60 import javax.jcr.Session;
61 import javax.jcr.SimpleCredentials;
62 import javax.jcr.ValueFactory;
63 import javax.jcr.Workspace;
64 import javax.jcr.nodetype.NodeTypeManager;
65 import javax.jcr.nodetype.NodeTypeTemplate;
66 import javax.jcr.query.Query;
67 import javax.jcr.query.QueryResult;
70 * @plexus.component role="org.apache.archiva.metadata.repository.MetadataRepository"
71 * @todo below: revise storage format for project version metadata
72 * @todo revise reference storage
74 public class JcrMetadataRepository
75 implements MetadataRepository
77 private static final String JCR_LAST_MODIFIED = "jcr:lastModified";
79 private static final String ARTIFACT_NODE_TYPE = "archiva:artifact";
81 private static final String FACET_NODE_TYPE = "archiva:facet";
83 private static final String QUERY_ARTIFACTS = "SELECT * FROM [" + ARTIFACT_NODE_TYPE + "]";
86 * @plexus.requirement role="org.apache.archiva.metadata.model.MetadataFacetFactory"
88 private Map<String, MetadataFacetFactory> metadataFacetFactories;
90 private static final Logger log = LoggerFactory.getLogger( JcrMetadataRepository.class );
95 private Repository repository;
97 private Session session;
99 public JcrMetadataRepository()
105 // TODO: need to close this at the end - do we need to add it in the API?
109 // TODO: shouldn't do this in constructor since it's a singleton
110 session = repository.login( new SimpleCredentials( "username", "password".toCharArray() ) );
112 Workspace workspace = session.getWorkspace();
113 workspace.getNamespaceRegistry().registerNamespace( "archiva", "http://archiva.apache.org/jcr/" );
115 NodeTypeManager nodeTypeManager = workspace.getNodeTypeManager();
116 registerMixinNodeType( nodeTypeManager, ARTIFACT_NODE_TYPE );
117 registerMixinNodeType( nodeTypeManager, FACET_NODE_TYPE );
119 catch ( LoginException e )
122 throw new RuntimeException( e );
124 catch ( RepositoryException e )
127 throw new RuntimeException( e );
131 private static void registerMixinNodeType( NodeTypeManager nodeTypeManager, String name )
132 throws RepositoryException
134 NodeTypeTemplate nodeType = nodeTypeManager.createNodeTypeTemplate();
135 nodeType.setMixin( true );
136 nodeType.setName( name );
137 nodeTypeManager.registerNodeType( nodeType, false );
140 public void updateProject( String repositoryId, ProjectMetadata project )
141 throws MetadataRepositoryException
143 updateProject( repositoryId, project.getNamespace(), project.getId() );
146 private void updateProject( String repositoryId, String namespace, String projectId )
147 throws MetadataRepositoryException
149 updateNamespace( repositoryId, namespace );
153 getOrAddProjectNode( repositoryId, namespace, projectId );
155 catch ( RepositoryException e )
157 throw new MetadataRepositoryException( e.getMessage(), e );
161 public void updateArtifact( String repositoryId, String namespace, String projectId, String projectVersion,
162 ArtifactMetadata artifactMeta )
163 throws MetadataRepositoryException
165 updateNamespace( repositoryId, namespace );
169 Node node = getOrAddArtifactNode( repositoryId, namespace, projectId, projectVersion,
170 artifactMeta.getId() );
172 Calendar cal = Calendar.getInstance();
173 cal.setTime( artifactMeta.getFileLastModified() );
174 node.setProperty( JCR_LAST_MODIFIED, cal );
176 cal = Calendar.getInstance();
177 cal.setTime( artifactMeta.getWhenGathered() );
178 node.setProperty( "whenGathered", cal );
180 node.setProperty( "size", artifactMeta.getSize() );
181 node.setProperty( "md5", artifactMeta.getMd5() );
182 node.setProperty( "sha1", artifactMeta.getSha1() );
184 node.setProperty( "version", artifactMeta.getVersion() );
186 for ( MetadataFacet facet : artifactMeta.getFacetList() )
188 if ( node.hasNode( facet.getFacetId() ) )
190 node.getNode( facet.getFacetId() ).remove();
193 // recreate, to ensure properties are removed
194 Node n = node.addNode( facet.getFacetId() );
195 n.addMixin( FACET_NODE_TYPE );
197 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
199 n.setProperty( entry.getKey(), entry.getValue() );
202 // TODO: need some context around this so it can be done only when needed
205 catch ( RepositoryException e )
207 throw new MetadataRepositoryException( e.getMessage(), e );
211 public void updateProjectVersion( String repositoryId, String namespace, String projectId,
212 ProjectVersionMetadata versionMetadata )
213 throws MetadataRepositoryException
215 updateProject( repositoryId, namespace, projectId );
219 Node versionNode = getOrAddProjectVersionNode( repositoryId, namespace, projectId,
220 versionMetadata.getId() );
222 versionNode.setProperty( "name", versionMetadata.getName() );
223 versionNode.setProperty( "description", versionMetadata.getDescription() );
224 versionNode.setProperty( "url", versionMetadata.getUrl() );
225 versionNode.setProperty( "incomplete", versionMetadata.isIncomplete() );
227 // TODO: decide how to treat these in the content repo
228 if ( versionMetadata.getScm() != null )
230 versionNode.setProperty( "scm.connection", versionMetadata.getScm().getConnection() );
231 versionNode.setProperty( "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
232 versionNode.setProperty( "scm.url", versionMetadata.getScm().getUrl() );
234 if ( versionMetadata.getCiManagement() != null )
236 versionNode.setProperty( "ci.system", versionMetadata.getCiManagement().getSystem() );
237 versionNode.setProperty( "ci.url", versionMetadata.getCiManagement().getUrl() );
239 if ( versionMetadata.getIssueManagement() != null )
241 versionNode.setProperty( "issue.system", versionMetadata.getIssueManagement().getSystem() );
242 versionNode.setProperty( "issue.url", versionMetadata.getIssueManagement().getUrl() );
244 if ( versionMetadata.getOrganization() != null )
246 versionNode.setProperty( "org.name", versionMetadata.getOrganization().getName() );
247 versionNode.setProperty( "org.url", versionMetadata.getOrganization().getUrl() );
250 for ( License license : versionMetadata.getLicenses() )
252 versionNode.setProperty( "license." + i + ".name", license.getName() );
253 versionNode.setProperty( "license." + i + ".url", license.getUrl() );
257 for ( MailingList mailingList : versionMetadata.getMailingLists() )
259 versionNode.setProperty( "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
260 versionNode.setProperty( "mailingList." + i + ".name", mailingList.getName() );
261 versionNode.setProperty( "mailingList." + i + ".post", mailingList.getPostAddress() );
262 versionNode.setProperty( "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
263 versionNode.setProperty( "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
264 versionNode.setProperty( "mailingList." + i + ".otherArchives", join(
265 mailingList.getOtherArchives() ) );
269 for ( Dependency dependency : versionMetadata.getDependencies() )
271 versionNode.setProperty( "dependency." + i + ".classifier", dependency.getClassifier() );
272 versionNode.setProperty( "dependency." + i + ".scope", dependency.getScope() );
273 versionNode.setProperty( "dependency." + i + ".systemPath", dependency.getSystemPath() );
274 versionNode.setProperty( "dependency." + i + ".artifactId", dependency.getArtifactId() );
275 versionNode.setProperty( "dependency." + i + ".groupId", dependency.getGroupId() );
276 versionNode.setProperty( "dependency." + i + ".version", dependency.getVersion() );
277 versionNode.setProperty( "dependency." + i + ".type", dependency.getType() );
281 for ( MetadataFacet facet : versionMetadata.getFacetList() )
283 // recreate, to ensure properties are removed
284 if ( versionNode.hasNode( facet.getFacetId() ) )
286 versionNode.getNode( facet.getFacetId() ).remove();
288 Node n = versionNode.addNode( facet.getFacetId() );
289 n.addMixin( FACET_NODE_TYPE );
291 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
293 n.setProperty( entry.getKey(), entry.getValue() );
297 catch ( RepositoryException e )
299 throw new MetadataRepositoryException( e.getMessage(), e );
303 public void updateProjectReference( String repositoryId, String namespace, String projectId, String projectVersion,
304 ProjectVersionReference reference )
305 throws MetadataRepositoryException
307 // not using weak references, since they still need to exist upfront to be referred to
310 Node node = getOrAddRepositoryContentNode( repositoryId );
311 node = JcrUtils.getOrAddNode( node, namespace );
312 node = JcrUtils.getOrAddNode( node, projectId );
313 node = JcrUtils.getOrAddNode( node, projectVersion );
314 node = JcrUtils.getOrAddNode( node, "references" );
315 node = JcrUtils.getOrAddNode( node, reference.getNamespace() );
316 node = JcrUtils.getOrAddNode( node, reference.getProjectId() );
317 node = JcrUtils.getOrAddNode( node, reference.getProjectVersion() );
318 node.setProperty( "type", reference.getReferenceType().toString() );
320 catch ( RepositoryException e )
322 throw new MetadataRepositoryException( e.getMessage(), e );
326 public void updateNamespace( String repositoryId, String namespace )
327 throws MetadataRepositoryException
331 Node node = getOrAddNamespaceNode( repositoryId, namespace );
332 node.setProperty( "namespace", namespace );
334 catch ( RepositoryException e )
336 throw new MetadataRepositoryException( e.getMessage(), e );
340 public List<String> getMetadataFacets( String repositoryId, String facetId )
341 throws MetadataRepositoryException
343 List<String> facets = new ArrayList<String>();
347 // no need to construct node-by-node here, as we'll find in the next instance, the facet names have / and
348 // are paths themselves
349 Node node = session.getRootNode().getNode( getFacetPath( repositoryId, facetId ) );
351 // TODO: this is a bit awkward. Might be better to review the purpose of this function - why is the list of
353 recurse( facets, "", node );
355 catch ( PathNotFoundException e )
357 // ignored - the facet doesn't exist, so return the empty list
359 catch ( RepositoryException e )
361 throw new MetadataRepositoryException( e.getMessage(), e );
366 private void recurse( List<String> facets, String prefix, Node node )
367 throws RepositoryException
369 for ( Node n : JcrUtils.getChildNodes( node ) )
371 String name = prefix + "/" + n.getName();
374 recurse( facets, name, n );
378 // strip leading / first
379 facets.add( name.substring( 1 ) );
384 public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
385 throws MetadataRepositoryException
387 MetadataFacet metadataFacet = null;
390 Node root = session.getRootNode();
391 Node node = root.getNode( getFacetPath( repositoryId, facetId, name ) );
393 MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
394 if ( metadataFacetFactory != null )
396 metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
397 Map<String, String> map = new HashMap<String, String>();
398 for ( Property property : JcrUtils.getProperties( node ) )
400 String p = property.getName();
401 if ( !p.startsWith( "jcr:" ) )
403 map.put( p, property.getString() );
406 metadataFacet.fromProperties( map );
409 catch ( PathNotFoundException e )
411 // ignored - the facet doesn't exist, so return null
413 catch ( RepositoryException e )
415 throw new MetadataRepositoryException( e.getMessage(), e );
417 return metadataFacet;
420 public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
421 throws MetadataRepositoryException
425 Node repo = getOrAddRepositoryNode( repositoryId );
426 Node facets = JcrUtils.getOrAddNode( repo, "facets" );
428 String id = metadataFacet.getFacetId();
429 Node facetNode = JcrUtils.getOrAddNode( facets, id );
431 Node node = getOrAddNodeByPath( facetNode, metadataFacet.getName() );
433 for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
435 node.setProperty( entry.getKey(), entry.getValue() );
438 catch ( RepositoryException e )
440 throw new MetadataRepositoryException( e.getMessage(), e );
444 public void removeMetadataFacets( String repositoryId, String facetId )
445 throws MetadataRepositoryException
449 Node root = session.getRootNode();
450 String path = getFacetPath( repositoryId, facetId );
451 if ( root.hasNode( path ) )
453 root.getNode( path ).remove();
456 catch ( RepositoryException e )
458 throw new MetadataRepositoryException( e.getMessage(), e );
462 public void removeMetadataFacet( String repositoryId, String facetId, String name )
463 throws MetadataRepositoryException
467 Node root = session.getRootNode();
468 String path = getFacetPath( repositoryId, facetId, name );
469 if ( root.hasNode( path ) )
471 Node node = root.getNode( path );
474 // also remove empty container nodes
475 Node parent = node.getParent();
479 while ( !node.hasNodes() );
482 catch ( RepositoryException e )
484 throw new MetadataRepositoryException( e.getMessage(), e );
488 public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
489 throws MetadataRepositoryException
491 List<ArtifactMetadata> artifacts;
493 String q = QUERY_ARTIFACTS;
495 String clause = " WHERE";
496 if ( startTime != null )
498 q += clause + " [whenGathered] >= $start";
501 if ( endTime != null )
503 q += clause + " [whenGathered] <= $end";
508 Query query = session.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
509 ValueFactory valueFactory = session.getValueFactory();
510 if ( startTime != null )
512 query.bindValue( "start", valueFactory.createValue( createCalendar( startTime ) ) );
514 if ( endTime != null )
516 query.bindValue( "end", valueFactory.createValue( createCalendar( endTime ) ) );
518 QueryResult result = query.execute();
520 artifacts = new ArrayList<ArtifactMetadata>();
521 for ( Node n : JcrUtils.getNodes( result ) )
523 artifacts.add( getArtifactFromNode( repoId, n ) );
526 catch ( RepositoryException e )
528 throw new MetadataRepositoryException( e.getMessage(), e );
533 public Collection<String> getRepositories()
534 throws MetadataRepositoryException
536 List<String> repositories;
540 Node root = session.getRootNode();
541 if ( root.hasNode( "repositories" ) )
543 Node node = root.getNode( "repositories" );
545 repositories = new ArrayList<String>();
546 NodeIterator i = node.getNodes();
547 while ( i.hasNext() )
549 Node n = i.nextNode();
550 repositories.add( n.getName() );
555 repositories = Collections.emptyList();
558 catch ( RepositoryException e )
560 throw new MetadataRepositoryException( e.getMessage(), e );
565 public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
566 throws MetadataRepositoryException
568 List<ArtifactMetadata> artifacts;
570 String q = QUERY_ARTIFACTS + " WHERE [sha1] = $checksum OR [md5] = $checksum";
574 Query query = session.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
575 ValueFactory valueFactory = session.getValueFactory();
576 query.bindValue( "checksum", valueFactory.createValue( checksum ) );
577 QueryResult result = query.execute();
579 artifacts = new ArrayList<ArtifactMetadata>();
580 for ( Node n : JcrUtils.getNodes( result ) )
582 artifacts.add( getArtifactFromNode( repositoryId, n ) );
585 catch ( RepositoryException e )
587 throw new MetadataRepositoryException( e.getMessage(), e );
592 public void removeArtifact( String repositoryId, String namespace, String projectId, String projectVersion,
594 throws MetadataRepositoryException
598 Node root = session.getRootNode();
599 String path = getArtifactPath( repositoryId, namespace, projectId, projectVersion, id );
600 if ( root.hasNode( path ) )
602 root.getNode( path ).remove();
605 catch ( RepositoryException e )
607 throw new MetadataRepositoryException( e.getMessage(), e );
611 public void removeRepository( String repositoryId )
612 throws MetadataRepositoryException
616 Node root = session.getRootNode();
617 String path = getRepositoryPath( repositoryId );
618 if ( root.hasNode( path ) )
620 root.getNode( path ).remove();
623 catch ( RepositoryException e )
625 throw new MetadataRepositoryException( e.getMessage(), e );
629 public List<ArtifactMetadata> getArtifacts( String repositoryId )
630 throws MetadataRepositoryException
632 List<ArtifactMetadata> artifacts;
634 String q = QUERY_ARTIFACTS;
638 Query query = session.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
639 QueryResult result = query.execute();
641 artifacts = new ArrayList<ArtifactMetadata>();
642 for ( Node n : JcrUtils.getNodes( result ) )
644 artifacts.add( getArtifactFromNode( repositoryId, n ) );
647 catch ( RepositoryException e )
649 throw new MetadataRepositoryException( e.getMessage(), e );
654 public ProjectMetadata getProject( String repositoryId, String namespace, String projectId )
655 throws MetadataResolutionException
657 ProjectMetadata metadata = null;
661 Node root = session.getRootNode();
663 // basically just checking it exists
664 String path = getProjectPath( repositoryId, namespace, projectId );
665 if ( root.hasNode( path ) )
667 metadata = new ProjectMetadata();
668 metadata.setId( projectId );
669 metadata.setNamespace( namespace );
672 catch ( RepositoryException e )
674 throw new MetadataResolutionException( e.getMessage(), e );
680 public ProjectVersionMetadata getProjectVersion( String repositoryId, String namespace, String projectId,
681 String projectVersion )
682 throws MetadataResolutionException
684 ProjectVersionMetadata versionMetadata;
688 Node root = session.getRootNode();
690 String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
691 if ( !root.hasNode( path ) )
696 Node node = root.getNode( path );
698 versionMetadata = new ProjectVersionMetadata();
699 versionMetadata.setId( projectVersion );
700 versionMetadata.setName( getPropertyString( node, "name" ) );
701 versionMetadata.setDescription( getPropertyString( node, "description" ) );
702 versionMetadata.setUrl( getPropertyString( node, "url" ) );
703 versionMetadata.setIncomplete( node.hasProperty( "incomplete" ) && node.getProperty(
704 "incomplete" ).getBoolean() );
706 // TODO: decide how to treat these in the content repo
707 String scmConnection = getPropertyString( node, "scm.connection" );
708 String scmDeveloperConnection = getPropertyString( node, "scm.developerConnection" );
709 String scmUrl = getPropertyString( node, "scm.url" );
710 if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
713 scm.setConnection( scmConnection );
714 scm.setDeveloperConnection( scmDeveloperConnection );
715 scm.setUrl( scmUrl );
716 versionMetadata.setScm( scm );
719 String ciSystem = getPropertyString( node, "ci.system" );
720 String ciUrl = getPropertyString( node, "ci.url" );
721 if ( ciSystem != null || ciUrl != null )
723 CiManagement ci = new CiManagement();
724 ci.setSystem( ciSystem );
726 versionMetadata.setCiManagement( ci );
729 String issueSystem = getPropertyString( node, "issue.system" );
730 String issueUrl = getPropertyString( node, "issue.url" );
731 if ( issueSystem != null || issueUrl != null )
733 IssueManagement issueManagement = new IssueManagement();
734 issueManagement.setSystem( issueSystem );
735 issueManagement.setUrl( issueUrl );
736 versionMetadata.setIssueManagement( issueManagement );
739 String orgName = getPropertyString( node, "org.name" );
740 String orgUrl = getPropertyString( node, "org.url" );
741 if ( orgName != null || orgUrl != null )
743 Organization org = new Organization();
744 org.setName( orgName );
745 org.setUrl( orgUrl );
746 versionMetadata.setOrganization( org );
749 boolean done = false;
753 String licenseName = getPropertyString( node, "license." + i + ".name" );
754 String licenseUrl = getPropertyString( node, "license." + i + ".url" );
755 if ( licenseName != null || licenseUrl != null )
757 License license = new License();
758 license.setName( licenseName );
759 license.setUrl( licenseUrl );
760 versionMetadata.addLicense( license );
773 String mailingListName = getPropertyString( node, "mailingList." + i + ".name" );
774 if ( mailingListName != null )
776 MailingList mailingList = new MailingList();
777 mailingList.setName( mailingListName );
778 mailingList.setMainArchiveUrl( getPropertyString( node, "mailingList." + i + ".archive" ) );
779 String n = "mailingList." + i + ".otherArchives";
780 if ( node.hasProperty( n ) )
782 mailingList.setOtherArchives( Arrays.asList( getPropertyString( node, n ).split( "," ) ) );
786 mailingList.setOtherArchives( Collections.<String>emptyList() );
788 mailingList.setPostAddress( getPropertyString( node, "mailingList." + i + ".post" ) );
789 mailingList.setSubscribeAddress( getPropertyString( node, "mailingList." + i + ".subscribe" ) );
790 mailingList.setUnsubscribeAddress( getPropertyString( node, "mailingList." + i + ".unsubscribe" ) );
791 versionMetadata.addMailingList( mailingList );
804 String dependencyArtifactId = getPropertyString( node, "dependency." + i + ".artifactId" );
805 if ( dependencyArtifactId != null )
807 Dependency dependency = new Dependency();
808 dependency.setArtifactId( dependencyArtifactId );
809 dependency.setGroupId( getPropertyString( node, "dependency." + i + ".groupId" ) );
810 dependency.setClassifier( getPropertyString( node, "dependency." + i + ".classifier" ) );
811 dependency.setOptional( Boolean.valueOf( getPropertyString( node,
812 "dependency." + i + ".optional" ) ) );
813 dependency.setScope( getPropertyString( node, "dependency." + i + ".scope" ) );
814 dependency.setSystemPath( getPropertyString( node, "dependency." + i + ".systemPath" ) );
815 dependency.setType( getPropertyString( node, "dependency." + i + ".type" ) );
816 dependency.setVersion( getPropertyString( node, "dependency." + i + ".version" ) );
817 versionMetadata.addDependency( dependency );
826 for ( Node n : JcrUtils.getChildNodes( node ) )
828 if ( n.isNodeType( FACET_NODE_TYPE ) )
830 String name = n.getName();
831 MetadataFacetFactory factory = metadataFacetFactories.get( name );
832 if ( factory == null )
834 log.error( "Attempted to load unknown project version metadata facet: " + name );
838 MetadataFacet facet = factory.createMetadataFacet();
839 Map<String, String> map = new HashMap<String, String>();
840 for ( Property property : JcrUtils.getProperties( n ) )
842 String p = property.getName();
843 if ( !p.startsWith( "jcr:" ) )
845 map.put( p, property.getString() );
848 facet.fromProperties( map );
849 versionMetadata.addFacet( facet );
854 catch ( RepositoryException e )
856 throw new MetadataResolutionException( e.getMessage(), e );
859 return versionMetadata;
862 public Collection<String> getArtifactVersions( String repositoryId, String namespace, String projectId,
863 String projectVersion )
864 throws MetadataResolutionException
866 Set<String> versions = new LinkedHashSet<String>();
870 Node root = session.getRootNode();
872 Node node = root.getNode( getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) );
874 for ( Node n : JcrUtils.getChildNodes( node ) )
876 versions.add( n.getProperty( "version" ).getString() );
879 catch ( PathNotFoundException e )
881 // ignore repo not found for now
883 catch ( RepositoryException e )
885 throw new MetadataResolutionException( e.getMessage(), e );
891 public Collection<ProjectVersionReference> getProjectReferences( String repositoryId, String namespace,
892 String projectId, String projectVersion )
893 throws MetadataResolutionException
895 List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
899 Node root = session.getRootNode();
901 String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) + "/references";
902 if ( root.hasNode( path ) )
904 Node node = root.getNode( path );
906 NodeIterator i = node.getNodes();
907 while ( i.hasNext() )
909 Node ns = i.nextNode();
911 NodeIterator j = ns.getNodes();
913 while ( j.hasNext() )
915 Node project = j.nextNode();
917 NodeIterator k = project.getNodes();
919 while ( k.hasNext() )
921 Node version = k.nextNode();
923 ProjectVersionReference ref = new ProjectVersionReference();
924 ref.setNamespace( ns.getName() );
925 ref.setProjectId( project.getName() );
926 ref.setProjectVersion( version.getName() );
927 String type = version.getProperty( "type" ).getString();
928 ref.setReferenceType( ProjectVersionReference.ReferenceType.valueOf( type ) );
929 references.add( ref );
935 catch ( RepositoryException e )
937 throw new MetadataResolutionException( e.getMessage(), e );
943 public Collection<String> getRootNamespaces( String repositoryId )
944 throws MetadataResolutionException
946 return getNamespaces( repositoryId, null );
949 public Collection<String> getNamespaces( String repositoryId, String baseNamespace )
950 throws MetadataResolutionException
952 String path = baseNamespace != null
953 ? getNamespacePath( repositoryId, baseNamespace )
954 : getRepositoryContentPath( repositoryId );
956 return getNodeNames( path );
959 public Collection<String> getProjects( String repositoryId, String namespace )
960 throws MetadataResolutionException
962 return getNodeNames( getNamespacePath( repositoryId, namespace ) );
965 public Collection<String> getProjectVersions( String repositoryId, String namespace, String projectId )
966 throws MetadataResolutionException
968 return getNodeNames( getProjectPath( repositoryId, namespace, projectId ) );
971 public Collection<ArtifactMetadata> getArtifacts( String repositoryId, String namespace, String projectId,
972 String projectVersion )
973 throws MetadataResolutionException
975 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
979 Node root = session.getRootNode();
980 String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
982 if ( root.hasNode( path ) )
984 Node node = root.getNode( path );
986 for ( Node n : JcrUtils.getChildNodes( node ) )
988 artifacts.add( getArtifactFromNode( repositoryId, n ) );
992 catch ( RepositoryException e )
994 throw new MetadataResolutionException( e.getMessage(), e );
1004 // TODO: this shouldn't be here! Repository may need a context
1007 catch ( RepositoryException e )
1010 throw new RuntimeException( e );
1015 public void setMetadataFacetFactories( Map<String, MetadataFacetFactory> metadataFacetFactories )
1017 this.metadataFacetFactories = metadataFacetFactories;
1019 // TODO: check if actually called by normal injection
1021 // TODO: consider using namespaces for facets instead of the current approach:
1022 // for ( String facetId : metadataFacetFactories.keySet() )
1024 // session.getWorkspace().getNamespaceRegistry().registerNamespace( facetId, facetId );
1028 private ArtifactMetadata getArtifactFromNode( String repositoryId, Node artifactNode )
1029 throws RepositoryException
1031 String id = artifactNode.getName();
1033 ArtifactMetadata artifact = new ArtifactMetadata();
1034 artifact.setId( id );
1035 artifact.setRepositoryId( repositoryId );
1037 Node projectVersionNode = artifactNode.getParent();
1038 Node projectNode = projectVersionNode.getParent();
1039 Node namespaceNode = projectNode.getParent();
1041 artifact.setNamespace( namespaceNode.getProperty( "namespace" ).getString() );
1042 artifact.setProject( projectNode.getName() );
1043 artifact.setProjectVersion( projectVersionNode.getName() );
1044 artifact.setVersion( artifactNode.hasProperty( "version" )
1045 ? artifactNode.getProperty( "version" ).getString()
1046 : projectVersionNode.getName() );
1048 if ( artifactNode.hasProperty( JCR_LAST_MODIFIED ) )
1050 artifact.setFileLastModified( artifactNode.getProperty( JCR_LAST_MODIFIED ).getDate().getTimeInMillis() );
1053 if ( artifactNode.hasProperty( "whenGathered" ) )
1055 artifact.setWhenGathered( artifactNode.getProperty( "whenGathered" ).getDate().getTime() );
1058 if ( artifactNode.hasProperty( "size" ) )
1060 artifact.setSize( artifactNode.getProperty( "size" ).getLong() );
1063 if ( artifactNode.hasProperty( "md5" ) )
1065 artifact.setMd5( artifactNode.getProperty( "md5" ).getString() );
1068 if ( artifactNode.hasProperty( "sha1" ) )
1070 artifact.setSha1( artifactNode.getProperty( "sha1" ).getString() );
1073 for ( Node n : JcrUtils.getChildNodes( artifactNode ) )
1075 if ( n.isNodeType( FACET_NODE_TYPE ) )
1077 String name = n.getName();
1078 MetadataFacetFactory factory = metadataFacetFactories.get( name );
1079 if ( factory == null )
1081 log.error( "Attempted to load unknown project version metadata facet: " + name );
1085 MetadataFacet facet = factory.createMetadataFacet();
1086 Map<String, String> map = new HashMap<String, String>();
1087 for ( Property p : JcrUtils.getProperties( n ) )
1089 String property = p.getName();
1090 if ( !property.startsWith( "jcr:" ) )
1092 map.put( property, p.getString() );
1095 facet.fromProperties( map );
1096 artifact.addFacet( facet );
1103 private static String getPropertyString( Node node, String name )
1104 throws RepositoryException
1106 return node.hasProperty( name ) ? node.getProperty( name ).getString() : null;
1109 private Collection<String> getNodeNames( String path )
1110 throws MetadataResolutionException
1112 List<String> names = new ArrayList<String>();
1116 Node root = session.getRootNode();
1118 Node repository = root.getNode( path );
1120 NodeIterator nodes = repository.getNodes();
1121 while ( nodes.hasNext() )
1123 Node node = nodes.nextNode();
1124 names.add( node.getName() );
1127 catch ( PathNotFoundException e )
1129 // ignore repo not found for now
1131 catch ( RepositoryException e )
1133 throw new MetadataResolutionException( e.getMessage(), e );
1139 private static String getRepositoryPath( String repositoryId )
1141 return "repositories/" + repositoryId;
1144 private static String getRepositoryContentPath( String repositoryId )
1146 return getRepositoryPath( repositoryId ) + "/content/";
1149 private static String getFacetPath( String repositoryId, String facetId )
1151 return getRepositoryPath( repositoryId ) + "/facets/" + facetId;
1154 private static String getNamespacePath( String repositoryId, String namespace )
1156 return getRepositoryContentPath( repositoryId ) + namespace.replace( '.', '/' );
1159 private static String getProjectPath( String repositoryId, String namespace, String projectId )
1161 return getNamespacePath( repositoryId, namespace ) + "/" + projectId;
1164 private static String getProjectVersionPath( String repositoryId, String namespace, String projectId,
1165 String projectVersion )
1167 return getProjectPath( repositoryId, namespace, projectId ) + "/" + projectVersion;
1170 private static String getArtifactPath( String repositoryId, String namespace, String projectId,
1171 String projectVersion, String id )
1173 return getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) + "/" + id;
1176 private Node getOrAddNodeByPath( Node baseNode, String name )
1177 throws RepositoryException
1179 Node node = baseNode;
1180 for ( String n : name.split( "/" ) )
1182 node = JcrUtils.getOrAddNode( node, n );
1187 private static String getFacetPath( String repositoryId, String facetId, String name )
1189 return getFacetPath( repositoryId, facetId ) + "/" + name;
1192 private Node getOrAddRepositoryNode( String repositoryId )
1193 throws RepositoryException
1195 Node root = session.getRootNode();
1196 Node node = JcrUtils.getOrAddNode( root, "repositories" );
1197 node = JcrUtils.getOrAddNode( node, repositoryId );
1201 private Node getOrAddRepositoryContentNode( String repositoryId )
1202 throws RepositoryException
1204 Node node = getOrAddRepositoryNode( repositoryId );
1205 return JcrUtils.getOrAddNode( node, "content" );
1208 private Node getOrAddNamespaceNode( String repositoryId, String namespace )
1209 throws RepositoryException
1211 Node repo = getOrAddRepositoryContentNode( repositoryId );
1212 return getOrAddNodeByPath( repo, namespace.replace( '.', '/' ) );
1215 private Node getOrAddProjectNode( String repositoryId, String namespace, String projectId )
1216 throws RepositoryException
1218 Node namespaceNode = getOrAddNamespaceNode( repositoryId, namespace );
1219 return JcrUtils.getOrAddNode( namespaceNode, projectId );
1222 private Node getOrAddProjectVersionNode( String repositoryId, String namespace, String projectId,
1223 String projectVersion )
1224 throws RepositoryException
1226 Node projectNode = getOrAddProjectNode( repositoryId, namespace, projectId );
1227 return JcrUtils.getOrAddNode( projectNode, projectVersion );
1230 private Node getOrAddArtifactNode( String repositoryId, String namespace, String projectId, String projectVersion,
1232 throws RepositoryException
1234 Node versionNode = getOrAddProjectVersionNode( repositoryId, namespace, projectId, projectVersion );
1235 Node node = JcrUtils.getOrAddNode( versionNode, id );
1236 node.addMixin( ARTIFACT_NODE_TYPE );
1240 private static Calendar createCalendar( Date time )
1242 Calendar cal = Calendar.getInstance();
1243 cal.setTime( time );
1247 private String join( Collection<String> ids )
1249 if ( ids != null && !ids.isEmpty() )
1251 StringBuilder s = new StringBuilder();
1252 for ( String id : ids )
1257 return s.substring( 0, s.length() - 1 );
1262 public Session getJcrSession()