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.NamespaceRegistry;
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 * @todo below: revise storage format for project version metadata
71 * @todo revise reference storage
73 public class JcrMetadataRepository
74 implements MetadataRepository
76 private static final String JCR_LAST_MODIFIED = "jcr:lastModified";
78 static final String NAMESPACE_NODE_TYPE = "archiva:namespace";
80 static final String PROJECT_NODE_TYPE = "archiva:project";
82 static final String PROJECT_VERSION_NODE_TYPE = "archiva:projectVersion";
84 static final String ARTIFACT_NODE_TYPE = "archiva:artifact";
86 static final String FACET_NODE_TYPE = "archiva:facet";
88 private static final String DEPENDENCY_NODE_TYPE = "archiva:dependency";
90 private final Map<String, MetadataFacetFactory> metadataFacetFactories;
92 private static final Logger log = LoggerFactory.getLogger( JcrMetadataRepository.class );
94 private Repository repository;
96 private Session session;
98 public JcrMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories, Repository repository )
99 throws RepositoryException
101 this.metadataFacetFactories = metadataFacetFactories;
102 this.repository = repository;
104 session = repository.login( new SimpleCredentials( "admin", "admin".toCharArray() ) );
107 static void initialize( Session session )
108 throws RepositoryException
110 // TODO: consider using namespaces for facets instead of the current approach:
111 // (if used, check if actually called by normal injection)
112 // for ( String facetId : metadataFacetFactories.keySet() )
114 // session.getWorkspace().getNamespaceRegistry().registerNamespace( facetId, facetId );
117 Workspace workspace = session.getWorkspace();
118 NamespaceRegistry registry = workspace.getNamespaceRegistry();
120 if ( !Arrays.asList( registry.getPrefixes() ).contains( "archiva" ) )
122 registry.registerNamespace( "archiva", "http://archiva.apache.org/jcr/" );
125 NodeTypeManager nodeTypeManager = workspace.getNodeTypeManager();
126 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.NAMESPACE_NODE_TYPE );
127 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.PROJECT_NODE_TYPE );
128 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.PROJECT_VERSION_NODE_TYPE );
129 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.ARTIFACT_NODE_TYPE );
130 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.FACET_NODE_TYPE );
131 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.DEPENDENCY_NODE_TYPE );
134 private static void registerMixinNodeType( NodeTypeManager nodeTypeManager, String name )
135 throws RepositoryException
137 NodeTypeTemplate nodeType = nodeTypeManager.createNodeTypeTemplate();
138 nodeType.setMixin( true );
139 nodeType.setName( name );
141 // for now just don't re-create - but in future if we change the definition, make sure to remove first as an
143 if ( !nodeTypeManager.hasNodeType( name ) )
145 nodeTypeManager.registerNodeType( nodeType, false );
149 public void updateProject( String repositoryId, ProjectMetadata project )
150 throws MetadataRepositoryException
152 updateProject( repositoryId, project.getNamespace(), project.getId() );
155 private void updateProject( String repositoryId, String namespace, String projectId )
156 throws MetadataRepositoryException
158 updateNamespace( repositoryId, namespace );
162 getOrAddProjectNode( repositoryId, namespace, projectId );
164 catch ( RepositoryException e )
166 throw new MetadataRepositoryException( e.getMessage(), e );
170 public void updateArtifact( String repositoryId, String namespace, String projectId, String projectVersion,
171 ArtifactMetadata artifactMeta )
172 throws MetadataRepositoryException
174 updateNamespace( repositoryId, namespace );
178 Node node = getOrAddArtifactNode( repositoryId, namespace, projectId, projectVersion,
179 artifactMeta.getId() );
181 Calendar cal = Calendar.getInstance();
182 cal.setTime( artifactMeta.getFileLastModified() );
183 node.setProperty( JCR_LAST_MODIFIED, cal );
185 cal = Calendar.getInstance();
186 cal.setTime( artifactMeta.getWhenGathered() );
187 node.setProperty( "whenGathered", cal );
189 node.setProperty( "size", artifactMeta.getSize() );
190 node.setProperty( "md5", artifactMeta.getMd5() );
191 node.setProperty( "sha1", artifactMeta.getSha1() );
193 node.setProperty( "version", artifactMeta.getVersion() );
195 for ( MetadataFacet facet : artifactMeta.getFacetList() )
197 if ( node.hasNode( facet.getFacetId() ) )
199 node.getNode( facet.getFacetId() ).remove();
202 // recreate, to ensure properties are removed
203 Node n = node.addNode( facet.getFacetId() );
204 n.addMixin( FACET_NODE_TYPE );
206 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
208 n.setProperty( entry.getKey(), entry.getValue() );
212 catch ( RepositoryException e )
214 throw new MetadataRepositoryException( e.getMessage(), e );
218 public void updateProjectVersion( String repositoryId, String namespace, String projectId,
219 ProjectVersionMetadata versionMetadata )
220 throws MetadataRepositoryException
222 updateProject( repositoryId, namespace, projectId );
226 Node versionNode = getOrAddProjectVersionNode( repositoryId, namespace, projectId,
227 versionMetadata.getId() );
229 versionNode.setProperty( "name", versionMetadata.getName() );
230 versionNode.setProperty( "description", versionMetadata.getDescription() );
231 versionNode.setProperty( "url", versionMetadata.getUrl() );
232 versionNode.setProperty( "incomplete", versionMetadata.isIncomplete() );
234 // FIXME: decide how to treat these in the content repo
235 if ( versionMetadata.getScm() != null )
237 versionNode.setProperty( "scm.connection", versionMetadata.getScm().getConnection() );
238 versionNode.setProperty( "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
239 versionNode.setProperty( "scm.url", versionMetadata.getScm().getUrl() );
241 if ( versionMetadata.getCiManagement() != null )
243 versionNode.setProperty( "ci.system", versionMetadata.getCiManagement().getSystem() );
244 versionNode.setProperty( "ci.url", versionMetadata.getCiManagement().getUrl() );
246 if ( versionMetadata.getIssueManagement() != null )
248 versionNode.setProperty( "issue.system", versionMetadata.getIssueManagement().getSystem() );
249 versionNode.setProperty( "issue.url", versionMetadata.getIssueManagement().getUrl() );
251 if ( versionMetadata.getOrganization() != null )
253 versionNode.setProperty( "org.name", versionMetadata.getOrganization().getName() );
254 versionNode.setProperty( "org.url", versionMetadata.getOrganization().getUrl() );
257 for ( License license : versionMetadata.getLicenses() )
259 versionNode.setProperty( "license." + i + ".name", license.getName() );
260 versionNode.setProperty( "license." + i + ".url", license.getUrl() );
264 for ( MailingList mailingList : versionMetadata.getMailingLists() )
266 versionNode.setProperty( "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
267 versionNode.setProperty( "mailingList." + i + ".name", mailingList.getName() );
268 versionNode.setProperty( "mailingList." + i + ".post", mailingList.getPostAddress() );
269 versionNode.setProperty( "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
270 versionNode.setProperty( "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
271 versionNode.setProperty( "mailingList." + i + ".otherArchives", join(
272 mailingList.getOtherArchives() ) );
276 if ( !versionMetadata.getDependencies().isEmpty() )
278 Node dependenciesNode = JcrUtils.getOrAddNode( versionNode, "dependencies" );
280 for ( Dependency dependency : versionMetadata.getDependencies() )
282 // Note that we deliberately don't alter the namespace path - not enough dependencies for
283 // number of nodes at a given depth to be an issue. Similarly, we don't add subnodes for each
284 // component of the ID as that creates extra depth and causes a great cost in space and memory
286 // FIXME: change group ID to namespace
287 // FIXME: change to artifact's ID - this is constructed by the Maven 2 format for now.
288 // This won't support types where the extension doesn't match the type.
289 // (see also Maven2RepositoryStorage#readProjectVersionMetadata construction of POM)
291 dependency.getGroupId() + ";" + dependency.getArtifactId() + "-" + dependency.getVersion();
292 if ( dependency.getClassifier() != null )
294 id += "-" + dependency.getClassifier();
296 id += "." + dependency.getType();
298 Node n = JcrUtils.getOrAddNode( dependenciesNode, id );
299 n.addMixin( DEPENDENCY_NODE_TYPE );
301 // FIXME: remove temp code just to make it keep working
302 n.setProperty( "groupId", dependency.getGroupId() );
303 n.setProperty( "artifactId", dependency.getArtifactId() );
304 n.setProperty( "version", dependency.getVersion() );
305 n.setProperty( "type", dependency.getType() );
306 n.setProperty( "classifier", dependency.getClassifier() );
307 n.setProperty( "scope", dependency.getScope() );
308 n.setProperty( "systemPath", dependency.getSystemPath() );
309 n.setProperty( "optional", dependency.isOptional() );
311 // node has no native content at this time, just facets
312 // no need to list a type as it's implied by the path. Parents are Maven specific.
314 // FIXME: add scope, systemPath, type, version, classifier & maven2 specific IDs as a facet
315 // (should also have been added to the Dependency)
317 // TODO: add a property that is a weak reference to the originating artifact, creating it if
318 // necessary (without adding the archiva:artifact mixin so that it doesn't get listed as an
319 // artifact, which gives a different meaning to "incomplete" which is a known local project
320 // that doesn't have metadata yet but has artifacts). (Though we may want to give it the
321 // artifact mixin and another property to identify all non-local artifacts for the closure
326 for ( MetadataFacet facet : versionMetadata.getFacetList() )
328 // recreate, to ensure properties are removed
329 if ( versionNode.hasNode( facet.getFacetId() ) )
331 versionNode.getNode( facet.getFacetId() ).remove();
333 Node n = versionNode.addNode( facet.getFacetId() );
334 n.addMixin( FACET_NODE_TYPE );
336 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
338 n.setProperty( entry.getKey(), entry.getValue() );
342 catch ( RepositoryException e )
344 throw new MetadataRepositoryException( e.getMessage(), e );
348 // FIXME: remove this and projectversionreference
349 public void updateProjectReference( String repositoryId, String namespace, String projectId, String projectVersion,
350 ProjectVersionReference reference )
351 throws MetadataRepositoryException
353 // not using weak references, since they still need to exist upfront to be referred to
356 Node node = getOrAddRepositoryContentNode( repositoryId );
357 node = JcrUtils.getOrAddNode( node, namespace );
358 node = JcrUtils.getOrAddNode( node, projectId );
359 node = JcrUtils.getOrAddNode( node, projectVersion );
360 node = JcrUtils.getOrAddNode( node, "references" );
361 node = JcrUtils.getOrAddNode( node, reference.getNamespace() );
362 node = JcrUtils.getOrAddNode( node, reference.getProjectId() );
363 node = JcrUtils.getOrAddNode( node, reference.getProjectVersion() );
364 node.setProperty( "type", reference.getReferenceType().toString() );
366 catch ( RepositoryException e )
368 throw new MetadataRepositoryException( e.getMessage(), e );
372 public void updateNamespace( String repositoryId, String namespace )
373 throws MetadataRepositoryException
377 Node node = getOrAddNamespaceNode( repositoryId, namespace );
378 node.setProperty( "namespace", namespace );
380 catch ( RepositoryException e )
382 throw new MetadataRepositoryException( e.getMessage(), e );
386 public List<String> getMetadataFacets( String repositoryId, String facetId )
387 throws MetadataRepositoryException
389 List<String> facets = new ArrayList<String>();
393 // no need to construct node-by-node here, as we'll find in the next instance, the facet names have / and
394 // are paths themselves
395 Node node = session.getRootNode().getNode( getFacetPath( repositoryId, facetId ) );
397 // TODO: this is a bit awkward. Might be better to review the purpose of this function - why is the list of
399 recurse( facets, "", node );
401 catch ( PathNotFoundException e )
403 // ignored - the facet doesn't exist, so return the empty list
405 catch ( RepositoryException e )
407 throw new MetadataRepositoryException( e.getMessage(), e );
412 private void recurse( List<String> facets, String prefix, Node node )
413 throws RepositoryException
415 for ( Node n : JcrUtils.getChildNodes( node ) )
417 String name = prefix + "/" + n.getName();
420 recurse( facets, name, n );
424 // strip leading / first
425 facets.add( name.substring( 1 ) );
430 public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
431 throws MetadataRepositoryException
433 MetadataFacet metadataFacet = null;
436 Node root = session.getRootNode();
437 Node node = root.getNode( getFacetPath( repositoryId, facetId, name ) );
439 MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
440 if ( metadataFacetFactory != null )
442 metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
443 Map<String, String> map = new HashMap<String, String>();
444 for ( Property property : JcrUtils.getProperties( node ) )
446 String p = property.getName();
447 if ( !p.startsWith( "jcr:" ) )
449 map.put( p, property.getString() );
452 metadataFacet.fromProperties( map );
455 catch ( PathNotFoundException e )
457 // ignored - the facet doesn't exist, so return null
459 catch ( RepositoryException e )
461 throw new MetadataRepositoryException( e.getMessage(), e );
463 return metadataFacet;
466 public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
467 throws MetadataRepositoryException
471 Node repo = getOrAddRepositoryNode( repositoryId );
472 Node facets = JcrUtils.getOrAddNode( repo, "facets" );
474 String id = metadataFacet.getFacetId();
475 Node facetNode = JcrUtils.getOrAddNode( facets, id );
477 Node node = getOrAddNodeByPath( facetNode, metadataFacet.getName() );
479 for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
481 node.setProperty( entry.getKey(), entry.getValue() );
484 catch ( RepositoryException e )
486 throw new MetadataRepositoryException( e.getMessage(), e );
490 public void removeMetadataFacets( String repositoryId, String facetId )
491 throws MetadataRepositoryException
495 Node root = session.getRootNode();
496 String path = getFacetPath( repositoryId, facetId );
497 if ( root.hasNode( path ) )
499 root.getNode( path ).remove();
502 catch ( RepositoryException e )
504 throw new MetadataRepositoryException( e.getMessage(), e );
508 public void removeMetadataFacet( String repositoryId, String facetId, String name )
509 throws MetadataRepositoryException
513 Node root = session.getRootNode();
514 String path = getFacetPath( repositoryId, facetId, name );
515 if ( root.hasNode( path ) )
517 Node node = root.getNode( path );
520 // also remove empty container nodes
521 Node parent = node.getParent();
525 while ( !node.hasNodes() );
528 catch ( RepositoryException e )
530 throw new MetadataRepositoryException( e.getMessage(), e );
534 public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
535 throws MetadataRepositoryException
537 List<ArtifactMetadata> artifacts;
539 String q = getArtifactQuery( repoId );
541 if ( startTime != null )
543 q += " AND [whenGathered] >= $start";
545 if ( endTime != null )
547 q += " AND [whenGathered] <= $end";
552 Query query = session.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
553 ValueFactory valueFactory = session.getValueFactory();
554 if ( startTime != null )
556 query.bindValue( "start", valueFactory.createValue( createCalendar( startTime ) ) );
558 if ( endTime != null )
560 query.bindValue( "end", valueFactory.createValue( createCalendar( endTime ) ) );
562 QueryResult result = query.execute();
564 artifacts = new ArrayList<ArtifactMetadata>();
565 for ( Node n : JcrUtils.getNodes( result ) )
567 artifacts.add( getArtifactFromNode( repoId, n ) );
570 catch ( RepositoryException e )
572 throw new MetadataRepositoryException( e.getMessage(), e );
577 public Collection<String> getRepositories()
578 throws MetadataRepositoryException
580 List<String> repositories;
584 Node root = session.getRootNode();
585 if ( root.hasNode( "repositories" ) )
587 Node node = root.getNode( "repositories" );
589 repositories = new ArrayList<String>();
590 NodeIterator i = node.getNodes();
591 while ( i.hasNext() )
593 Node n = i.nextNode();
594 repositories.add( n.getName() );
599 repositories = Collections.emptyList();
602 catch ( RepositoryException e )
604 throw new MetadataRepositoryException( e.getMessage(), e );
609 public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
610 throws MetadataRepositoryException
612 List<ArtifactMetadata> artifacts;
614 String q = getArtifactQuery( repositoryId ) + " AND ([sha1] = $checksum OR [md5] = $checksum)";
618 Query query = session.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
619 ValueFactory valueFactory = session.getValueFactory();
620 query.bindValue( "checksum", valueFactory.createValue( checksum ) );
621 QueryResult result = query.execute();
623 artifacts = new ArrayList<ArtifactMetadata>();
624 for ( Node n : JcrUtils.getNodes( result ) )
626 artifacts.add( getArtifactFromNode( repositoryId, n ) );
629 catch ( RepositoryException e )
631 throw new MetadataRepositoryException( e.getMessage(), e );
636 public void removeArtifact( String repositoryId, String namespace, String projectId, String projectVersion,
638 throws MetadataRepositoryException
642 Node root = session.getRootNode();
643 String path = getArtifactPath( repositoryId, namespace, projectId, projectVersion, id );
644 if ( root.hasNode( path ) )
646 root.getNode( path ).remove();
649 catch ( RepositoryException e )
651 throw new MetadataRepositoryException( e.getMessage(), e );
655 public void removeRepository( String repositoryId )
656 throws MetadataRepositoryException
660 Node root = session.getRootNode();
661 String path = getRepositoryPath( repositoryId );
662 if ( root.hasNode( path ) )
664 root.getNode( path ).remove();
667 catch ( RepositoryException e )
669 throw new MetadataRepositoryException( e.getMessage(), e );
673 public List<ArtifactMetadata> getArtifacts( String repositoryId )
674 throws MetadataRepositoryException
676 List<ArtifactMetadata> artifacts;
678 String q = getArtifactQuery( repositoryId );
682 Query query = session.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
683 QueryResult result = query.execute();
685 artifacts = new ArrayList<ArtifactMetadata>();
686 for ( Node n : JcrUtils.getNodes( result ) )
688 if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
690 artifacts.add( getArtifactFromNode( repositoryId, n ) );
694 catch ( RepositoryException e )
696 throw new MetadataRepositoryException( e.getMessage(), e );
701 private static String getArtifactQuery( String repositoryId )
703 return "SELECT * FROM [" + ARTIFACT_NODE_TYPE + "] AS artifact WHERE ISDESCENDANTNODE(artifact,'/" +
704 getRepositoryContentPath( repositoryId ) + "')";
707 public ProjectMetadata getProject( String repositoryId, String namespace, String projectId )
708 throws MetadataResolutionException
710 ProjectMetadata metadata = null;
714 Node root = session.getRootNode();
716 // basically just checking it exists
717 String path = getProjectPath( repositoryId, namespace, projectId );
718 if ( root.hasNode( path ) )
720 metadata = new ProjectMetadata();
721 metadata.setId( projectId );
722 metadata.setNamespace( namespace );
725 catch ( RepositoryException e )
727 throw new MetadataResolutionException( e.getMessage(), e );
733 public ProjectVersionMetadata getProjectVersion( String repositoryId, String namespace, String projectId,
734 String projectVersion )
735 throws MetadataResolutionException
737 ProjectVersionMetadata versionMetadata;
741 Node root = session.getRootNode();
743 String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
744 if ( !root.hasNode( path ) )
749 Node node = root.getNode( path );
751 versionMetadata = new ProjectVersionMetadata();
752 versionMetadata.setId( projectVersion );
753 versionMetadata.setName( getPropertyString( node, "name" ) );
754 versionMetadata.setDescription( getPropertyString( node, "description" ) );
755 versionMetadata.setUrl( getPropertyString( node, "url" ) );
756 versionMetadata.setIncomplete( node.hasProperty( "incomplete" ) && node.getProperty(
757 "incomplete" ).getBoolean() );
759 // FIXME: decide how to treat these in the content repo
760 String scmConnection = getPropertyString( node, "scm.connection" );
761 String scmDeveloperConnection = getPropertyString( node, "scm.developerConnection" );
762 String scmUrl = getPropertyString( node, "scm.url" );
763 if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
766 scm.setConnection( scmConnection );
767 scm.setDeveloperConnection( scmDeveloperConnection );
768 scm.setUrl( scmUrl );
769 versionMetadata.setScm( scm );
772 String ciSystem = getPropertyString( node, "ci.system" );
773 String ciUrl = getPropertyString( node, "ci.url" );
774 if ( ciSystem != null || ciUrl != null )
776 CiManagement ci = new CiManagement();
777 ci.setSystem( ciSystem );
779 versionMetadata.setCiManagement( ci );
782 String issueSystem = getPropertyString( node, "issue.system" );
783 String issueUrl = getPropertyString( node, "issue.url" );
784 if ( issueSystem != null || issueUrl != null )
786 IssueManagement issueManagement = new IssueManagement();
787 issueManagement.setSystem( issueSystem );
788 issueManagement.setUrl( issueUrl );
789 versionMetadata.setIssueManagement( issueManagement );
792 String orgName = getPropertyString( node, "org.name" );
793 String orgUrl = getPropertyString( node, "org.url" );
794 if ( orgName != null || orgUrl != null )
796 Organization org = new Organization();
797 org.setName( orgName );
798 org.setUrl( orgUrl );
799 versionMetadata.setOrganization( org );
802 boolean done = false;
806 String licenseName = getPropertyString( node, "license." + i + ".name" );
807 String licenseUrl = getPropertyString( node, "license." + i + ".url" );
808 if ( licenseName != null || licenseUrl != null )
810 License license = new License();
811 license.setName( licenseName );
812 license.setUrl( licenseUrl );
813 versionMetadata.addLicense( license );
826 String mailingListName = getPropertyString( node, "mailingList." + i + ".name" );
827 if ( mailingListName != null )
829 MailingList mailingList = new MailingList();
830 mailingList.setName( mailingListName );
831 mailingList.setMainArchiveUrl( getPropertyString( node, "mailingList." + i + ".archive" ) );
832 String n = "mailingList." + i + ".otherArchives";
833 if ( node.hasProperty( n ) )
835 mailingList.setOtherArchives( Arrays.asList( getPropertyString( node, n ).split( "," ) ) );
839 mailingList.setOtherArchives( Collections.<String>emptyList() );
841 mailingList.setPostAddress( getPropertyString( node, "mailingList." + i + ".post" ) );
842 mailingList.setSubscribeAddress( getPropertyString( node, "mailingList." + i + ".subscribe" ) );
843 mailingList.setUnsubscribeAddress( getPropertyString( node, "mailingList." + i + ".unsubscribe" ) );
844 versionMetadata.addMailingList( mailingList );
853 if ( node.hasNode( "dependencies" ) )
855 Node dependenciesNode = node.getNode( "dependencies" );
856 for ( Node n : JcrUtils.getChildNodes( dependenciesNode ) )
858 if ( n.isNodeType( DEPENDENCY_NODE_TYPE ) )
860 Dependency dependency = new Dependency();
861 // FIXME: correct these properties
862 dependency.setArtifactId( getPropertyString( n, "artifactId" ) );
863 dependency.setGroupId( getPropertyString( n, "groupId" ) );
864 dependency.setClassifier( getPropertyString( n, "classifier" ) );
865 dependency.setOptional( Boolean.valueOf( getPropertyString( n, "optional" ) ) );
866 dependency.setScope( getPropertyString( n, "scope" ) );
867 dependency.setSystemPath( getPropertyString( n, "systemPath" ) );
868 dependency.setType( getPropertyString( n, "type" ) );
869 dependency.setVersion( getPropertyString( n, "version" ) );
870 versionMetadata.addDependency( dependency );
875 for ( Node n : JcrUtils.getChildNodes( node ) )
877 if ( n.isNodeType( FACET_NODE_TYPE ) )
879 String name = n.getName();
880 MetadataFacetFactory factory = metadataFacetFactories.get( name );
881 if ( factory == null )
883 log.error( "Attempted to load unknown project version metadata facet: " + name );
887 MetadataFacet facet = factory.createMetadataFacet();
888 Map<String, String> map = new HashMap<String, String>();
889 for ( Property property : JcrUtils.getProperties( n ) )
891 String p = property.getName();
892 if ( !p.startsWith( "jcr:" ) )
894 map.put( p, property.getString() );
897 facet.fromProperties( map );
898 versionMetadata.addFacet( facet );
903 catch ( RepositoryException e )
905 throw new MetadataResolutionException( e.getMessage(), e );
908 return versionMetadata;
911 public Collection<String> getArtifactVersions( String repositoryId, String namespace, String projectId,
912 String projectVersion )
913 throws MetadataResolutionException
915 Set<String> versions = new LinkedHashSet<String>();
919 Node root = session.getRootNode();
921 Node node = root.getNode( getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) );
923 for ( Node n : JcrUtils.getChildNodes( node ) )
925 versions.add( n.getProperty( "version" ).getString() );
928 catch ( PathNotFoundException e )
930 // ignore repo not found for now
932 catch ( RepositoryException e )
934 throw new MetadataResolutionException( e.getMessage(), e );
940 public Collection<ProjectVersionReference> getProjectReferences( String repositoryId, String namespace,
941 String projectId, String projectVersion )
942 throws MetadataResolutionException
944 List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
946 // TODO: bind variables instead
947 String q = "SELECT * FROM [archiva:dependency] WHERE ISDESCENDANTNODE([/repositories/" + repositoryId +
948 "/content]) AND [groupId]='" + namespace + "' AND [artifactId]='" + projectId + "'";
949 if ( projectVersion != null )
951 q += " AND [version]='" + projectVersion + "'";
955 Query query = session.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
956 QueryResult result = query.execute();
958 for ( Node n : JcrUtils.getNodes( result ) )
960 n = n.getParent(); // dependencies grouping element
962 n = n.getParent(); // project version
963 String usedByProjectVersion = n.getName();
965 n = n.getParent(); // project
966 String usedByProject = n.getName();
968 n = n.getParent(); // namespace
969 String usedByNamespace = n.getProperty( "namespace" ).getString();
971 ProjectVersionReference ref = new ProjectVersionReference();
972 ref.setNamespace( usedByNamespace );
973 ref.setProjectId( usedByProject );
974 ref.setProjectVersion( usedByProjectVersion );
975 ref.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
976 references.add( ref );
979 catch ( RepositoryException e )
981 throw new MetadataResolutionException( e.getMessage(), e );
987 public Collection<String> getRootNamespaces( String repositoryId )
988 throws MetadataResolutionException
990 return getNamespaces( repositoryId, null );
993 public Collection<String> getNamespaces( String repositoryId, String baseNamespace )
994 throws MetadataResolutionException
996 String path = baseNamespace != null
997 ? getNamespacePath( repositoryId, baseNamespace )
998 : getRepositoryContentPath( repositoryId );
1000 return getNodeNames( path, NAMESPACE_NODE_TYPE );
1003 public Collection<String> getProjects( String repositoryId, String namespace )
1004 throws MetadataResolutionException
1006 return getNodeNames( getNamespacePath( repositoryId, namespace ), PROJECT_NODE_TYPE );
1009 public Collection<String> getProjectVersions( String repositoryId, String namespace, String projectId )
1010 throws MetadataResolutionException
1012 return getNodeNames( getProjectPath( repositoryId, namespace, projectId ), PROJECT_VERSION_NODE_TYPE );
1015 public Collection<ArtifactMetadata> getArtifacts( String repositoryId, String namespace, String projectId,
1016 String projectVersion )
1017 throws MetadataResolutionException
1019 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
1023 Node root = session.getRootNode();
1024 String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
1026 if ( root.hasNode( path ) )
1028 Node node = root.getNode( path );
1030 for ( Node n : JcrUtils.getChildNodes( node ) )
1032 if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
1034 artifacts.add( getArtifactFromNode( repositoryId, n ) );
1039 catch ( RepositoryException e )
1041 throw new MetadataResolutionException( e.getMessage(), e );
1048 throws MetadataRepositoryException
1054 catch ( RepositoryException e )
1056 throw new MetadataRepositoryException( e.getMessage(), e );
1060 public void revert()
1061 throws MetadataRepositoryException
1065 session.refresh( false );
1067 catch ( RepositoryException e )
1069 throw new MetadataRepositoryException( e.getMessage(), e );
1073 public boolean canObtainAccess( Class<?> aClass )
1075 return aClass == Session.class;
1078 public Object obtainAccess( Class<?> aClass )
1080 if ( aClass == Session.class )
1084 throw new IllegalArgumentException(
1085 "Access using " + aClass + " is not supported on the JCR metadata storage" );
1093 private ArtifactMetadata getArtifactFromNode( String repositoryId, Node artifactNode )
1094 throws RepositoryException
1096 String id = artifactNode.getName();
1098 ArtifactMetadata artifact = new ArtifactMetadata();
1099 artifact.setId( id );
1100 artifact.setRepositoryId( repositoryId );
1102 Node projectVersionNode = artifactNode.getParent();
1103 Node projectNode = projectVersionNode.getParent();
1104 Node namespaceNode = projectNode.getParent();
1106 artifact.setNamespace( namespaceNode.getProperty( "namespace" ).getString() );
1107 artifact.setProject( projectNode.getName() );
1108 artifact.setProjectVersion( projectVersionNode.getName() );
1109 artifact.setVersion( artifactNode.hasProperty( "version" )
1110 ? artifactNode.getProperty( "version" ).getString()
1111 : projectVersionNode.getName() );
1113 if ( artifactNode.hasProperty( JCR_LAST_MODIFIED ) )
1115 artifact.setFileLastModified( artifactNode.getProperty( JCR_LAST_MODIFIED ).getDate().getTimeInMillis() );
1118 if ( artifactNode.hasProperty( "whenGathered" ) )
1120 artifact.setWhenGathered( artifactNode.getProperty( "whenGathered" ).getDate().getTime() );
1123 if ( artifactNode.hasProperty( "size" ) )
1125 artifact.setSize( artifactNode.getProperty( "size" ).getLong() );
1128 if ( artifactNode.hasProperty( "md5" ) )
1130 artifact.setMd5( artifactNode.getProperty( "md5" ).getString() );
1133 if ( artifactNode.hasProperty( "sha1" ) )
1135 artifact.setSha1( artifactNode.getProperty( "sha1" ).getString() );
1138 for ( Node n : JcrUtils.getChildNodes( artifactNode ) )
1140 if ( n.isNodeType( FACET_NODE_TYPE ) )
1142 String name = n.getName();
1143 MetadataFacetFactory factory = metadataFacetFactories.get( name );
1144 if ( factory == null )
1146 log.error( "Attempted to load unknown project version metadata facet: " + name );
1150 MetadataFacet facet = factory.createMetadataFacet();
1151 Map<String, String> map = new HashMap<String, String>();
1152 for ( Property p : JcrUtils.getProperties( n ) )
1154 String property = p.getName();
1155 if ( !property.startsWith( "jcr:" ) )
1157 map.put( property, p.getString() );
1160 facet.fromProperties( map );
1161 artifact.addFacet( facet );
1168 private static String getPropertyString( Node node, String name )
1169 throws RepositoryException
1171 return node.hasProperty( name ) ? node.getProperty( name ).getString() : null;
1174 private Collection<String> getNodeNames( String path, String nodeType )
1175 throws MetadataResolutionException
1177 List<String> names = new ArrayList<String>();
1181 Node root = session.getRootNode();
1183 Node nodeAtPath = root.getNode( path );
1185 for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1187 if ( node.isNodeType( nodeType ) )
1189 names.add( node.getName() );
1193 catch ( PathNotFoundException e )
1195 // ignore repo not found for now
1197 catch ( RepositoryException e )
1199 throw new MetadataResolutionException( e.getMessage(), e );
1205 private static String getRepositoryPath( String repositoryId )
1207 return "repositories/" + repositoryId;
1210 private static String getRepositoryContentPath( String repositoryId )
1212 return getRepositoryPath( repositoryId ) + "/content/";
1215 private static String getFacetPath( String repositoryId, String facetId )
1217 return getRepositoryPath( repositoryId ) + "/facets/" + facetId;
1220 private static String getNamespacePath( String repositoryId, String namespace )
1222 return getRepositoryContentPath( repositoryId ) + namespace.replace( '.', '/' );
1225 private static String getProjectPath( String repositoryId, String namespace, String projectId )
1227 return getNamespacePath( repositoryId, namespace ) + "/" + projectId;
1230 private static String getProjectVersionPath( String repositoryId, String namespace, String projectId,
1231 String projectVersion )
1233 return getProjectPath( repositoryId, namespace, projectId ) + "/" + projectVersion;
1236 private static String getArtifactPath( String repositoryId, String namespace, String projectId,
1237 String projectVersion, String id )
1239 return getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) + "/" + id;
1242 private Node getOrAddNodeByPath( Node baseNode, String name )
1243 throws RepositoryException
1245 return getOrAddNodeByPath( baseNode, name, null );
1248 private Node getOrAddNodeByPath( Node baseNode, String name, String nodeType )
1249 throws RepositoryException
1251 Node node = baseNode;
1252 for ( String n : name.split( "/" ) )
1254 node = JcrUtils.getOrAddNode( node, n );
1255 if ( nodeType != null )
1257 node.addMixin( nodeType );
1263 private static String getFacetPath( String repositoryId, String facetId, String name )
1265 return getFacetPath( repositoryId, facetId ) + "/" + name;
1268 private Node getOrAddRepositoryNode( String repositoryId )
1269 throws RepositoryException
1271 Node root = session.getRootNode();
1272 Node node = JcrUtils.getOrAddNode( root, "repositories" );
1273 node = JcrUtils.getOrAddNode( node, repositoryId );
1277 private Node getOrAddRepositoryContentNode( String repositoryId )
1278 throws RepositoryException
1280 Node node = getOrAddRepositoryNode( repositoryId );
1281 return JcrUtils.getOrAddNode( node, "content" );
1284 private Node getOrAddNamespaceNode( String repositoryId, String namespace )
1285 throws RepositoryException
1287 Node repo = getOrAddRepositoryContentNode( repositoryId );
1288 return getOrAddNodeByPath( repo, namespace.replace( '.', '/' ), NAMESPACE_NODE_TYPE );
1291 private Node getOrAddProjectNode( String repositoryId, String namespace, String projectId )
1292 throws RepositoryException
1294 Node namespaceNode = getOrAddNamespaceNode( repositoryId, namespace );
1295 Node node = JcrUtils.getOrAddNode( namespaceNode, projectId );
1296 node.addMixin( PROJECT_NODE_TYPE );
1300 private Node getOrAddProjectVersionNode( String repositoryId, String namespace, String projectId,
1301 String projectVersion )
1302 throws RepositoryException
1304 Node projectNode = getOrAddProjectNode( repositoryId, namespace, projectId );
1305 Node node = JcrUtils.getOrAddNode( projectNode, projectVersion );
1306 node.addMixin( PROJECT_VERSION_NODE_TYPE );
1310 private Node getOrAddArtifactNode( String repositoryId, String namespace, String projectId, String projectVersion,
1312 throws RepositoryException
1314 Node versionNode = getOrAddProjectVersionNode( repositoryId, namespace, projectId, projectVersion );
1315 Node node = JcrUtils.getOrAddNode( versionNode, id );
1316 node.addMixin( ARTIFACT_NODE_TYPE );
1320 private static Calendar createCalendar( Date time )
1322 Calendar cal = Calendar.getInstance();
1323 cal.setTime( time );
1327 private String join( Collection<String> ids )
1329 if ( ids != null && !ids.isEmpty() )
1331 StringBuilder s = new StringBuilder();
1332 for ( String id : ids )
1337 return s.substring( 0, s.length() - 1 );
1342 public Session getJcrSession()