]> source.dussan.org Git - archiva.git/blob
3b5a9e2bdbf67966f3cf181d9f62c2a5a67d8160
[archiva.git] /
1 package org.apache.archiva.metadata.repository.jcr;
2
3 /*
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
11  *
12  *   http://www.apache.org/licenses/LICENSE-2.0
13  *
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
19  * under the License.
20  */
21
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.commons.lang.StringUtils;
39 import org.apache.jackrabbit.commons.JcrUtils;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 import javax.jcr.NamespaceRegistry;
44 import javax.jcr.Node;
45 import javax.jcr.NodeIterator;
46 import javax.jcr.PathNotFoundException;
47 import javax.jcr.Property;
48 import javax.jcr.Repository;
49 import javax.jcr.RepositoryException;
50 import javax.jcr.Session;
51 import javax.jcr.SimpleCredentials;
52 import javax.jcr.ValueFactory;
53 import javax.jcr.Workspace;
54 import javax.jcr.nodetype.NodeTypeManager;
55 import javax.jcr.nodetype.NodeTypeTemplate;
56 import javax.jcr.query.Query;
57 import javax.jcr.query.QueryResult;
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.Calendar;
61 import java.util.Collection;
62 import java.util.Collections;
63 import java.util.Date;
64 import java.util.HashMap;
65 import java.util.LinkedHashSet;
66 import java.util.List;
67 import java.util.Map;
68 import java.util.Set;
69
70 /**
71  * @todo below: revise storage format for project version metadata
72  * @todo revise reference storage
73  */
74 public class JcrMetadataRepository
75     implements MetadataRepository
76 {
77     private static final String JCR_LAST_MODIFIED = "jcr:lastModified";
78
79     static final String NAMESPACE_NODE_TYPE = "archiva:namespace";
80
81     static final String PROJECT_NODE_TYPE = "archiva:project";
82
83     static final String PROJECT_VERSION_NODE_TYPE = "archiva:projectVersion";
84
85     static final String ARTIFACT_NODE_TYPE = "archiva:artifact";
86
87     static final String FACET_NODE_TYPE = "archiva:facet";
88
89     private static final String DEPENDENCY_NODE_TYPE = "archiva:dependency";
90
91     private final Map<String, MetadataFacetFactory> metadataFacetFactories;
92
93     private Logger log = LoggerFactory.getLogger( JcrMetadataRepository.class );
94
95     private Repository repository;
96
97     private Session jcrSession;
98
99     public JcrMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories, Repository repository )
100         throws RepositoryException
101     {
102         this.metadataFacetFactories = metadataFacetFactories;
103         this.repository = repository;
104
105         //session = repository.login( new SimpleCredentials( "admin", "admin".toCharArray() ) );
106     }
107
108
109     static void initialize( Session session )
110         throws RepositoryException
111     {
112         // TODO: consider using namespaces for facets instead of the current approach:
113         // (if used, check if actually called by normal injection)
114 //        for ( String facetId : metadataFacetFactories.keySet() )
115 //        {
116 //            session.getWorkspace().getNamespaceRegistry().registerNamespace( facetId, facetId );
117 //        }
118
119         Workspace workspace = session.getWorkspace();
120         NamespaceRegistry registry = workspace.getNamespaceRegistry();
121
122         if ( !Arrays.asList( registry.getPrefixes() ).contains( "archiva" ) )
123         {
124             registry.registerNamespace( "archiva", "http://archiva.apache.org/jcr/" );
125         }
126
127         NodeTypeManager nodeTypeManager = workspace.getNodeTypeManager();
128         registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.NAMESPACE_NODE_TYPE );
129         registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.PROJECT_NODE_TYPE );
130         registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.PROJECT_VERSION_NODE_TYPE );
131         registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.ARTIFACT_NODE_TYPE );
132         registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.FACET_NODE_TYPE );
133         registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.DEPENDENCY_NODE_TYPE );
134     }
135
136     private static void registerMixinNodeType( NodeTypeManager nodeTypeManager, String name )
137         throws RepositoryException
138     {
139         NodeTypeTemplate nodeType = nodeTypeManager.createNodeTypeTemplate();
140         nodeType.setMixin( true );
141         nodeType.setName( name );
142
143         // for now just don't re-create - but in future if we change the definition, make sure to remove first as an
144         // upgrade path
145         if ( !nodeTypeManager.hasNodeType( name ) )
146         {
147             nodeTypeManager.registerNodeType( nodeType, false );
148         }
149     }
150
151     public void updateProject( String repositoryId, ProjectMetadata project )
152         throws MetadataRepositoryException
153     {
154         updateProject( repositoryId, project.getNamespace(), project.getId() );
155     }
156
157     private void updateProject( String repositoryId, String namespace, String projectId )
158         throws MetadataRepositoryException
159     {
160         updateNamespace( repositoryId, namespace );
161
162         try
163         {
164             getOrAddProjectNode( repositoryId, namespace, projectId );
165         }
166         catch ( RepositoryException e )
167         {
168             throw new MetadataRepositoryException( e.getMessage(), e );
169         }
170     }
171
172     public void updateArtifact( String repositoryId, String namespace, String projectId, String projectVersion,
173                                 ArtifactMetadata artifactMeta )
174         throws MetadataRepositoryException
175     {
176         updateNamespace( repositoryId, namespace );
177
178         try
179         {
180             Node node =
181                 getOrAddArtifactNode( repositoryId, namespace, projectId, projectVersion, artifactMeta.getId() );
182
183             Calendar cal = Calendar.getInstance();
184             cal.setTime( artifactMeta.getFileLastModified() );
185             node.setProperty( JCR_LAST_MODIFIED, cal );
186
187             cal = Calendar.getInstance();
188             cal.setTime( artifactMeta.getWhenGathered() );
189             node.setProperty( "whenGathered", cal );
190
191             node.setProperty( "size", artifactMeta.getSize() );
192             node.setProperty( "md5", artifactMeta.getMd5() );
193             node.setProperty( "sha1", artifactMeta.getSha1() );
194
195             node.setProperty( "version", artifactMeta.getVersion() );
196
197             // iterate over available facets to update/add/remove from the artifactMetadata
198             for ( String facetId : metadataFacetFactories.keySet() )
199             {
200                 MetadataFacet metadataFacet = artifactMeta.getFacet( facetId );
201                 if ( metadataFacet == null )
202                 {
203                     continue;
204                 }
205                 if ( node.hasNode( facetId ) )
206                 {
207                     node.getNode( facetId ).remove();
208                 }
209                 if ( metadataFacet != null )
210                 {
211                     // recreate, to ensure properties are removed
212                     Node n = node.addNode( facetId );
213                     n.addMixin( FACET_NODE_TYPE );
214
215                     for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
216                     {
217                         n.setProperty( entry.getKey(), entry.getValue() );
218                     }
219                 }
220             }
221             /*
222             for ( MetadataFacet facet : artifactMeta.getFacetList() )
223             {
224                 if ( node.hasNode( facet.getFacetId() ) )
225                 {
226                     node.getNode( facet.getFacetId() ).remove();
227                 }
228
229                 // recreate, to ensure properties are removed
230                 Node n = node.addNode( facet.getFacetId() );
231                 n.addMixin( FACET_NODE_TYPE );
232
233                 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
234                 {
235                     n.setProperty( entry.getKey(), entry.getValue() );
236                 }
237             }
238             */
239         }
240         catch ( RepositoryException e )
241         {
242             throw new MetadataRepositoryException( e.getMessage(), e );
243         }
244     }
245
246     public void updateProjectVersion( String repositoryId, String namespace, String projectId,
247                                       ProjectVersionMetadata versionMetadata )
248         throws MetadataRepositoryException
249     {
250         updateProject( repositoryId, namespace, projectId );
251
252         try
253         {
254             Node versionNode =
255                 getOrAddProjectVersionNode( repositoryId, namespace, projectId, versionMetadata.getId() );
256
257             versionNode.setProperty( "name", versionMetadata.getName() );
258             versionNode.setProperty( "description", versionMetadata.getDescription() );
259             versionNode.setProperty( "url", versionMetadata.getUrl() );
260             versionNode.setProperty( "incomplete", versionMetadata.isIncomplete() );
261
262             // FIXME: decide how to treat these in the content repo
263             if ( versionMetadata.getScm() != null )
264             {
265                 versionNode.setProperty( "scm.connection", versionMetadata.getScm().getConnection() );
266                 versionNode.setProperty( "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
267                 versionNode.setProperty( "scm.url", versionMetadata.getScm().getUrl() );
268             }
269             if ( versionMetadata.getCiManagement() != null )
270             {
271                 versionNode.setProperty( "ci.system", versionMetadata.getCiManagement().getSystem() );
272                 versionNode.setProperty( "ci.url", versionMetadata.getCiManagement().getUrl() );
273             }
274             if ( versionMetadata.getIssueManagement() != null )
275             {
276                 versionNode.setProperty( "issue.system", versionMetadata.getIssueManagement().getSystem() );
277                 versionNode.setProperty( "issue.url", versionMetadata.getIssueManagement().getUrl() );
278             }
279             if ( versionMetadata.getOrganization() != null )
280             {
281                 versionNode.setProperty( "org.name", versionMetadata.getOrganization().getName() );
282                 versionNode.setProperty( "org.url", versionMetadata.getOrganization().getUrl() );
283             }
284             int i = 0;
285             for ( License license : versionMetadata.getLicenses() )
286             {
287                 versionNode.setProperty( "license." + i + ".name", license.getName() );
288                 versionNode.setProperty( "license." + i + ".url", license.getUrl() );
289                 i++;
290             }
291             i = 0;
292             for ( MailingList mailingList : versionMetadata.getMailingLists() )
293             {
294                 versionNode.setProperty( "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
295                 versionNode.setProperty( "mailingList." + i + ".name", mailingList.getName() );
296                 versionNode.setProperty( "mailingList." + i + ".post", mailingList.getPostAddress() );
297                 versionNode.setProperty( "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
298                 versionNode.setProperty( "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
299                 versionNode.setProperty( "mailingList." + i + ".otherArchives",
300                                          join( mailingList.getOtherArchives() ) );
301                 i++;
302             }
303
304             if ( !versionMetadata.getDependencies().isEmpty() )
305             {
306                 Node dependenciesNode = JcrUtils.getOrAddNode( versionNode, "dependencies" );
307
308                 for ( Dependency dependency : versionMetadata.getDependencies() )
309                 {
310                     // Note that we deliberately don't alter the namespace path - not enough dependencies for
311                     // number of nodes at a given depth to be an issue. Similarly, we don't add subnodes for each
312                     // component of the ID as that creates extra depth and causes a great cost in space and memory
313
314                     // FIXME: change group ID to namespace
315                     // FIXME: change to artifact's ID - this is constructed by the Maven 2 format for now.
316                     //        This won't support types where the extension doesn't match the type.
317                     //        (see also Maven2RepositoryStorage#readProjectVersionMetadata construction of POM)
318                     String id =
319                         dependency.getGroupId() + ";" + dependency.getArtifactId() + "-" + dependency.getVersion();
320                     if ( dependency.getClassifier() != null )
321                     {
322                         id += "-" + dependency.getClassifier();
323                     }
324                     id += "." + dependency.getType();
325
326                     Node n = JcrUtils.getOrAddNode( dependenciesNode, id );
327                     n.addMixin( DEPENDENCY_NODE_TYPE );
328
329                     // FIXME: remove temp code just to make it keep working
330                     n.setProperty( "groupId", dependency.getGroupId() );
331                     n.setProperty( "artifactId", dependency.getArtifactId() );
332                     n.setProperty( "version", dependency.getVersion() );
333                     n.setProperty( "type", dependency.getType() );
334                     n.setProperty( "classifier", dependency.getClassifier() );
335                     n.setProperty( "scope", dependency.getScope() );
336                     n.setProperty( "systemPath", dependency.getSystemPath() );
337                     n.setProperty( "optional", dependency.isOptional() );
338
339                     // node has no native content at this time, just facets
340                     // no need to list a type as it's implied by the path. Parents are Maven specific.
341
342                     // FIXME: add scope, systemPath, type, version, classifier & maven2 specific IDs as a facet
343                     //        (should also have been added to the Dependency)
344
345                     // TODO: add a property that is a weak reference to the originating artifact, creating it if
346                     //       necessary (without adding the archiva:artifact mixin so that it doesn't get listed as an
347                     //       artifact, which gives a different meaning to "incomplete" which is a known local project
348                     //       that doesn't have metadata yet but has artifacts). (Though we may want to give it the
349                     //       artifact mixin and another property to identify all non-local artifacts for the closure
350                     //       reports)
351                 }
352             }
353
354             for ( MetadataFacet facet : versionMetadata.getFacetList() )
355             {
356                 // recreate, to ensure properties are removed
357                 if ( versionNode.hasNode( facet.getFacetId() ) )
358                 {
359                     versionNode.getNode( facet.getFacetId() ).remove();
360                 }
361                 Node n = versionNode.addNode( facet.getFacetId() );
362                 n.addMixin( FACET_NODE_TYPE );
363
364                 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
365                 {
366                     n.setProperty( entry.getKey(), entry.getValue() );
367                 }
368             }
369         }
370         catch ( RepositoryException e )
371         {
372             throw new MetadataRepositoryException( e.getMessage(), e );
373         }
374     }
375
376     public void updateNamespace( String repositoryId, String namespace )
377         throws MetadataRepositoryException
378     {
379         try
380         {
381             Node node = getOrAddNamespaceNode( repositoryId, namespace );
382             node.setProperty( "namespace", namespace );
383         }
384         catch ( RepositoryException e )
385         {
386             throw new MetadataRepositoryException( e.getMessage(), e );
387         }
388     }
389
390     public List<String> getMetadataFacets( String repositoryId, String facetId )
391         throws MetadataRepositoryException
392     {
393         List<String> facets = new ArrayList<String>();
394
395         try
396         {
397             // no need to construct node-by-node here, as we'll find in the next instance, the facet names have / and
398             // are paths themselves
399             Node node = getJcrSession().getRootNode().getNode( getFacetPath( repositoryId, facetId ) );
400
401             // TODO: this is a bit awkward. Might be better to review the purpose of this function - why is the list of
402             //   paths helpful?
403             recurse( facets, "", node );
404         }
405         catch ( PathNotFoundException e )
406         {
407             // ignored - the facet doesn't exist, so return the empty list
408         }
409         catch ( RepositoryException e )
410         {
411             throw new MetadataRepositoryException( e.getMessage(), e );
412         }
413         return facets;
414     }
415
416     private void recurse( List<String> facets, String prefix, Node node )
417         throws RepositoryException
418     {
419         for ( Node n : JcrUtils.getChildNodes( node ) )
420         {
421             String name = prefix + "/" + n.getName();
422             if ( n.hasNodes() )
423             {
424                 recurse( facets, name, n );
425             }
426             else
427             {
428                 // strip leading / first
429                 facets.add( name.substring( 1 ) );
430             }
431         }
432     }
433
434     public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
435         throws MetadataRepositoryException
436     {
437         MetadataFacet metadataFacet = null;
438         try
439         {
440             Node root = getJcrSession().getRootNode();
441             Node node = root.getNode( getFacetPath( repositoryId, facetId, name ) );
442
443             if ( metadataFacetFactories == null )
444             {
445                 return metadataFacet;
446             }
447
448             MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
449             if ( metadataFacetFactory != null )
450             {
451                 metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
452                 Map<String, String> map = new HashMap<String, String>();
453                 for ( Property property : JcrUtils.getProperties( node ) )
454                 {
455                     String p = property.getName();
456                     if ( !p.startsWith( "jcr:" ) )
457                     {
458                         map.put( p, property.getString() );
459                     }
460                 }
461                 metadataFacet.fromProperties( map );
462             }
463         }
464         catch ( PathNotFoundException e )
465         {
466             // ignored - the facet doesn't exist, so return null
467         }
468         catch ( RepositoryException e )
469         {
470             throw new MetadataRepositoryException( e.getMessage(), e );
471         }
472         return metadataFacet;
473     }
474
475     public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
476         throws MetadataRepositoryException
477     {
478         try
479         {
480             Node repo = getOrAddRepositoryNode( repositoryId );
481             Node facets = JcrUtils.getOrAddNode( repo, "facets" );
482
483             String id = metadataFacet.getFacetId();
484             Node facetNode = JcrUtils.getOrAddNode( facets, id );
485
486             Node node = getOrAddNodeByPath( facetNode, metadataFacet.getName() );
487
488             for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
489             {
490                 node.setProperty( entry.getKey(), entry.getValue() );
491             }
492         }
493         catch ( RepositoryException e )
494         {
495             throw new MetadataRepositoryException( e.getMessage(), e );
496         }
497     }
498
499     public void removeMetadataFacets( String repositoryId, String facetId )
500         throws MetadataRepositoryException
501     {
502         try
503         {
504             Node root = getJcrSession().getRootNode();
505             String path = getFacetPath( repositoryId, facetId );
506             if ( root.hasNode( path ) )
507             {
508                 root.getNode( path ).remove();
509             }
510         }
511         catch ( RepositoryException e )
512         {
513             throw new MetadataRepositoryException( e.getMessage(), e );
514         }
515     }
516
517     public void removeMetadataFacet( String repositoryId, String facetId, String name )
518         throws MetadataRepositoryException
519     {
520         try
521         {
522             Node root = getJcrSession().getRootNode();
523             String path = getFacetPath( repositoryId, facetId, name );
524             if ( root.hasNode( path ) )
525             {
526                 Node node = root.getNode( path );
527                 do
528                 {
529                     // also remove empty container nodes
530                     Node parent = node.getParent();
531                     node.remove();
532                     node = parent;
533                 }
534                 while ( !node.hasNodes() );
535             }
536         }
537         catch ( RepositoryException e )
538         {
539             throw new MetadataRepositoryException( e.getMessage(), e );
540         }
541     }
542
543     public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
544         throws MetadataRepositoryException
545     {
546         List<ArtifactMetadata> artifacts;
547
548         String q = getArtifactQuery( repoId );
549
550         if ( startTime != null )
551         {
552             q += " AND [whenGathered] >= $start";
553         }
554         if ( endTime != null )
555         {
556             q += " AND [whenGathered] <= $end";
557         }
558
559         try
560         {
561             Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
562             ValueFactory valueFactory = getJcrSession().getValueFactory();
563             if ( startTime != null )
564             {
565                 query.bindValue( "start", valueFactory.createValue( createCalendar( startTime ) ) );
566             }
567             if ( endTime != null )
568             {
569                 query.bindValue( "end", valueFactory.createValue( createCalendar( endTime ) ) );
570             }
571             QueryResult result = query.execute();
572
573             artifacts = new ArrayList<ArtifactMetadata>();
574             for ( Node n : JcrUtils.getNodes( result ) )
575             {
576                 artifacts.add( getArtifactFromNode( repoId, n ) );
577             }
578         }
579         catch ( RepositoryException e )
580         {
581             throw new MetadataRepositoryException( e.getMessage(), e );
582         }
583         return artifacts;
584     }
585
586     public Collection<String> getRepositories()
587         throws MetadataRepositoryException
588     {
589         List<String> repositories;
590
591         try
592         {
593             Node root = getJcrSession().getRootNode();
594             if ( root.hasNode( "repositories" ) )
595             {
596                 Node node = root.getNode( "repositories" );
597
598                 repositories = new ArrayList<String>();
599                 NodeIterator i = node.getNodes();
600                 while ( i.hasNext() )
601                 {
602                     Node n = i.nextNode();
603                     repositories.add( n.getName() );
604                 }
605             }
606             else
607             {
608                 repositories = Collections.emptyList();
609             }
610         }
611         catch ( RepositoryException e )
612         {
613             throw new MetadataRepositoryException( e.getMessage(), e );
614         }
615         return repositories;
616     }
617
618     public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
619         throws MetadataRepositoryException
620     {
621         List<ArtifactMetadata> artifacts;
622
623         String q = getArtifactQuery( repositoryId ) + " AND ([sha1] = $checksum OR [md5] = $checksum)";
624
625         try
626         {
627             Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
628             ValueFactory valueFactory = getJcrSession().getValueFactory();
629             query.bindValue( "checksum", valueFactory.createValue( checksum ) );
630             QueryResult result = query.execute();
631
632             artifacts = new ArrayList<ArtifactMetadata>();
633             for ( Node n : JcrUtils.getNodes( result ) )
634             {
635                 artifacts.add( getArtifactFromNode( repositoryId, n ) );
636             }
637         }
638         catch ( RepositoryException e )
639         {
640             throw new MetadataRepositoryException( e.getMessage(), e );
641         }
642         return artifacts;
643     }
644
645
646     public void removeRepository( String repositoryId )
647         throws MetadataRepositoryException
648     {
649         try
650         {
651             Node root = getJcrSession().getRootNode();
652             String path = getRepositoryPath( repositoryId );
653             if ( root.hasNode( path ) )
654             {
655                 root.getNode( path ).remove();
656             }
657         }
658         catch ( RepositoryException e )
659         {
660             throw new MetadataRepositoryException( e.getMessage(), e );
661         }
662     }
663
664     public List<ArtifactMetadata> getArtifacts( String repositoryId )
665         throws MetadataRepositoryException
666     {
667         List<ArtifactMetadata> artifacts;
668
669         String q = getArtifactQuery( repositoryId );
670
671         try
672         {
673             Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
674             QueryResult result = query.execute();
675
676             artifacts = new ArrayList<ArtifactMetadata>();
677             for ( Node n : JcrUtils.getNodes( result ) )
678             {
679                 if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
680                 {
681                     artifacts.add( getArtifactFromNode( repositoryId, n ) );
682                 }
683             }
684         }
685         catch ( RepositoryException e )
686         {
687             throw new MetadataRepositoryException( e.getMessage(), e );
688         }
689         return artifacts;
690     }
691
692     private static String getArtifactQuery( String repositoryId )
693     {
694         return "SELECT * FROM [" + ARTIFACT_NODE_TYPE + "] AS artifact WHERE ISDESCENDANTNODE(artifact,'/" +
695             getRepositoryContentPath( repositoryId ) + "')";
696     }
697
698     public ProjectMetadata getProject( String repositoryId, String namespace, String projectId )
699         throws MetadataResolutionException
700     {
701         ProjectMetadata metadata = null;
702
703         try
704         {
705             Node root = getJcrSession().getRootNode();
706
707             // basically just checking it exists
708             String path = getProjectPath( repositoryId, namespace, projectId );
709             if ( root.hasNode( path ) )
710             {
711                 metadata = new ProjectMetadata();
712                 metadata.setId( projectId );
713                 metadata.setNamespace( namespace );
714             }
715         }
716         catch ( RepositoryException e )
717         {
718             throw new MetadataResolutionException( e.getMessage(), e );
719         }
720
721         return metadata;
722     }
723
724     public ProjectVersionMetadata getProjectVersion( String repositoryId, String namespace, String projectId,
725                                                      String projectVersion )
726         throws MetadataResolutionException
727     {
728         ProjectVersionMetadata versionMetadata;
729
730         try
731         {
732             Node root = getJcrSession().getRootNode();
733
734             String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
735             if ( !root.hasNode( path ) )
736             {
737                 return null;
738             }
739
740             Node node = root.getNode( path );
741
742             versionMetadata = new ProjectVersionMetadata();
743             versionMetadata.setId( projectVersion );
744             versionMetadata.setName( getPropertyString( node, "name" ) );
745             versionMetadata.setDescription( getPropertyString( node, "description" ) );
746             versionMetadata.setUrl( getPropertyString( node, "url" ) );
747             versionMetadata.setIncomplete(
748                 node.hasProperty( "incomplete" ) && node.getProperty( "incomplete" ).getBoolean() );
749
750             // FIXME: decide how to treat these in the content repo
751             String scmConnection = getPropertyString( node, "scm.connection" );
752             String scmDeveloperConnection = getPropertyString( node, "scm.developerConnection" );
753             String scmUrl = getPropertyString( node, "scm.url" );
754             if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
755             {
756                 Scm scm = new Scm();
757                 scm.setConnection( scmConnection );
758                 scm.setDeveloperConnection( scmDeveloperConnection );
759                 scm.setUrl( scmUrl );
760                 versionMetadata.setScm( scm );
761             }
762
763             String ciSystem = getPropertyString( node, "ci.system" );
764             String ciUrl = getPropertyString( node, "ci.url" );
765             if ( ciSystem != null || ciUrl != null )
766             {
767                 CiManagement ci = new CiManagement();
768                 ci.setSystem( ciSystem );
769                 ci.setUrl( ciUrl );
770                 versionMetadata.setCiManagement( ci );
771             }
772
773             String issueSystem = getPropertyString( node, "issue.system" );
774             String issueUrl = getPropertyString( node, "issue.url" );
775             if ( issueSystem != null || issueUrl != null )
776             {
777                 IssueManagement issueManagement = new IssueManagement();
778                 issueManagement.setSystem( issueSystem );
779                 issueManagement.setUrl( issueUrl );
780                 versionMetadata.setIssueManagement( issueManagement );
781             }
782
783             String orgName = getPropertyString( node, "org.name" );
784             String orgUrl = getPropertyString( node, "org.url" );
785             if ( orgName != null || orgUrl != null )
786             {
787                 Organization org = new Organization();
788                 org.setName( orgName );
789                 org.setUrl( orgUrl );
790                 versionMetadata.setOrganization( org );
791             }
792
793             boolean done = false;
794             int i = 0;
795             while ( !done )
796             {
797                 String licenseName = getPropertyString( node, "license." + i + ".name" );
798                 String licenseUrl = getPropertyString( node, "license." + i + ".url" );
799                 if ( licenseName != null || licenseUrl != null )
800                 {
801                     License license = new License();
802                     license.setName( licenseName );
803                     license.setUrl( licenseUrl );
804                     versionMetadata.addLicense( license );
805                 }
806                 else
807                 {
808                     done = true;
809                 }
810                 i++;
811             }
812
813             done = false;
814             i = 0;
815             while ( !done )
816             {
817                 String mailingListName = getPropertyString( node, "mailingList." + i + ".name" );
818                 if ( mailingListName != null )
819                 {
820                     MailingList mailingList = new MailingList();
821                     mailingList.setName( mailingListName );
822                     mailingList.setMainArchiveUrl( getPropertyString( node, "mailingList." + i + ".archive" ) );
823                     String n = "mailingList." + i + ".otherArchives";
824                     if ( node.hasProperty( n ) )
825                     {
826                         mailingList.setOtherArchives( Arrays.asList( getPropertyString( node, n ).split( "," ) ) );
827                     }
828                     else
829                     {
830                         mailingList.setOtherArchives( Collections.<String>emptyList() );
831                     }
832                     mailingList.setPostAddress( getPropertyString( node, "mailingList." + i + ".post" ) );
833                     mailingList.setSubscribeAddress( getPropertyString( node, "mailingList." + i + ".subscribe" ) );
834                     mailingList.setUnsubscribeAddress( getPropertyString( node, "mailingList." + i + ".unsubscribe" ) );
835                     versionMetadata.addMailingList( mailingList );
836                 }
837                 else
838                 {
839                     done = true;
840                 }
841                 i++;
842             }
843
844             if ( node.hasNode( "dependencies" ) )
845             {
846                 Node dependenciesNode = node.getNode( "dependencies" );
847                 for ( Node n : JcrUtils.getChildNodes( dependenciesNode ) )
848                 {
849                     if ( n.isNodeType( DEPENDENCY_NODE_TYPE ) )
850                     {
851                         Dependency dependency = new Dependency();
852                         // FIXME: correct these properties
853                         dependency.setArtifactId( getPropertyString( n, "artifactId" ) );
854                         dependency.setGroupId( getPropertyString( n, "groupId" ) );
855                         dependency.setClassifier( getPropertyString( n, "classifier" ) );
856                         dependency.setOptional( Boolean.valueOf( getPropertyString( n, "optional" ) ) );
857                         dependency.setScope( getPropertyString( n, "scope" ) );
858                         dependency.setSystemPath( getPropertyString( n, "systemPath" ) );
859                         dependency.setType( getPropertyString( n, "type" ) );
860                         dependency.setVersion( getPropertyString( n, "version" ) );
861                         versionMetadata.addDependency( dependency );
862                     }
863                 }
864             }
865
866             for ( Node n : JcrUtils.getChildNodes( node ) )
867             {
868                 if ( n.isNodeType( FACET_NODE_TYPE ) )
869                 {
870                     String name = n.getName();
871                     MetadataFacetFactory factory = metadataFacetFactories.get( name );
872                     if ( factory == null )
873                     {
874                         log.error( "Attempted to load unknown project version metadata facet: {}", name );
875                     }
876                     else
877                     {
878                         MetadataFacet facet = factory.createMetadataFacet();
879                         Map<String, String> map = new HashMap<String, String>();
880                         for ( Property property : JcrUtils.getProperties( n ) )
881                         {
882                             String p = property.getName();
883                             if ( !p.startsWith( "jcr:" ) )
884                             {
885                                 map.put( p, property.getString() );
886                             }
887                         }
888                         facet.fromProperties( map );
889                         versionMetadata.addFacet( facet );
890                     }
891                 }
892             }
893         }
894         catch ( RepositoryException e )
895         {
896             throw new MetadataResolutionException( e.getMessage(), e );
897         }
898
899         return versionMetadata;
900     }
901
902     public Collection<String> getArtifactVersions( String repositoryId, String namespace, String projectId,
903                                                    String projectVersion )
904         throws MetadataResolutionException
905     {
906         Set<String> versions = new LinkedHashSet<String>();
907
908         try
909         {
910             Node root = getJcrSession().getRootNode();
911
912             Node node = root.getNode( getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) );
913
914             for ( Node n : JcrUtils.getChildNodes( node ) )
915             {
916                 versions.add( n.getProperty( "version" ).getString() );
917             }
918         }
919         catch ( PathNotFoundException e )
920         {
921             // ignore repo not found for now
922         }
923         catch ( RepositoryException e )
924         {
925             throw new MetadataResolutionException( e.getMessage(), e );
926         }
927
928         return versions;
929     }
930
931     public Collection<ProjectVersionReference> getProjectReferences( String repositoryId, String namespace,
932                                                                      String projectId, String projectVersion )
933         throws MetadataResolutionException
934     {
935         List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
936
937         // TODO: bind variables instead
938         String q = "SELECT * FROM [archiva:dependency] WHERE ISDESCENDANTNODE([/repositories/" + repositoryId +
939             "/content]) AND [groupId]='" + namespace + "' AND [artifactId]='" + projectId + "'";
940         if ( projectVersion != null )
941         {
942             q += " AND [version]='" + projectVersion + "'";
943         }
944         try
945         {
946             Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
947             QueryResult result = query.execute();
948
949             for ( Node n : JcrUtils.getNodes( result ) )
950             {
951                 n = n.getParent(); // dependencies grouping element
952
953                 n = n.getParent(); // project version
954                 String usedByProjectVersion = n.getName();
955
956                 n = n.getParent(); // project
957                 String usedByProject = n.getName();
958
959                 n = n.getParent(); // namespace
960                 String usedByNamespace = n.getProperty( "namespace" ).getString();
961
962                 ProjectVersionReference ref = new ProjectVersionReference();
963                 ref.setNamespace( usedByNamespace );
964                 ref.setProjectId( usedByProject );
965                 ref.setProjectVersion( usedByProjectVersion );
966                 ref.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
967                 references.add( ref );
968             }
969         }
970         catch ( RepositoryException e )
971         {
972             throw new MetadataResolutionException( e.getMessage(), e );
973         }
974
975         return references;
976     }
977
978     public Collection<String> getRootNamespaces( String repositoryId )
979         throws MetadataResolutionException
980     {
981         return getNamespaces( repositoryId, null );
982     }
983
984     public Collection<String> getNamespaces( String repositoryId, String baseNamespace )
985         throws MetadataResolutionException
986     {
987         String path = baseNamespace != null
988             ? getNamespacePath( repositoryId, baseNamespace )
989             : getRepositoryContentPath( repositoryId );
990
991         return getNodeNames( path, NAMESPACE_NODE_TYPE );
992     }
993
994     public Collection<String> getProjects( String repositoryId, String namespace )
995         throws MetadataResolutionException
996     {
997         return getNodeNames( getNamespacePath( repositoryId, namespace ), PROJECT_NODE_TYPE );
998     }
999
1000     public Collection<String> getProjectVersions( String repositoryId, String namespace, String projectId )
1001         throws MetadataResolutionException
1002     {
1003         return getNodeNames( getProjectPath( repositoryId, namespace, projectId ), PROJECT_VERSION_NODE_TYPE );
1004     }
1005
1006     public void removeArtifact( String repositoryId, String namespace, String projectId, String projectVersion,
1007                                 String id )
1008         throws MetadataRepositoryException
1009     {
1010         try
1011         {
1012             Node root = getJcrSession().getRootNode();
1013             String path = getArtifactPath( repositoryId, namespace, projectId, projectVersion, id );
1014             if ( root.hasNode( path ) )
1015             {
1016                 root.getNode( path ).remove();
1017             }
1018
1019             // remove version
1020
1021             path = getProjectPath( repositoryId, namespace, projectId );
1022
1023             Node nodeAtPath = root.getNode( path );
1024
1025             for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1026             {
1027                 if ( node.isNodeType( PROJECT_VERSION_NODE_TYPE ) && StringUtils.equals( node.getName(),
1028                                                                                          projectVersion ) )
1029                 {
1030                     node.remove();
1031                 }
1032             }
1033         }
1034         catch ( RepositoryException e )
1035         {
1036             throw new MetadataRepositoryException( e.getMessage(), e );
1037         }
1038     }
1039
1040     public void removeArtifact( String repositoryId, String namespace, String project, String projectVersion,
1041                                 MetadataFacet metadataFacet )
1042         throws MetadataRepositoryException
1043     {
1044         try
1045         {
1046             Node root = getJcrSession().getRootNode();
1047             String path = getProjectVersionPath( repositoryId, namespace, project, projectVersion );
1048
1049             if ( root.hasNode( path ) )
1050             {
1051                 Node node = root.getNode( path );
1052
1053                 for ( Node n : JcrUtils.getChildNodes( node ) )
1054                 {
1055                     if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
1056                     {
1057                         ArtifactMetadata artifactMetadata = getArtifactFromNode( repositoryId, n );
1058                         log.debug( "artifactMetadata: {}", artifactMetadata );
1059                         MetadataFacet metadataFacetToRemove = artifactMetadata.getFacet( metadataFacet.getFacetId() );
1060                         if ( metadataFacetToRemove != null && metadataFacet.equals( metadataFacetToRemove ) )
1061                         {
1062                             n.remove();
1063                         }
1064                     }
1065                 }
1066             }
1067         }
1068         catch ( RepositoryException e )
1069         {
1070             throw new MetadataRepositoryException( e.getMessage(), e );
1071         }
1072     }
1073
1074     public Collection<ArtifactMetadata> getArtifacts( String repositoryId, String namespace, String projectId,
1075                                                       String projectVersion )
1076         throws MetadataResolutionException
1077     {
1078         List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
1079
1080         try
1081         {
1082             Node root = getJcrSession().getRootNode();
1083             String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
1084
1085             if ( root.hasNode( path ) )
1086             {
1087                 Node node = root.getNode( path );
1088
1089                 for ( Node n : JcrUtils.getChildNodes( node ) )
1090                 {
1091                     if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
1092                     {
1093                         artifacts.add( getArtifactFromNode( repositoryId, n ) );
1094                     }
1095                 }
1096             }
1097         }
1098         catch ( RepositoryException e )
1099         {
1100             throw new MetadataResolutionException( e.getMessage(), e );
1101         }
1102
1103         return artifacts;
1104     }
1105
1106     public void save()
1107     {
1108         try
1109         {
1110             getJcrSession().save();
1111         }
1112         catch ( RepositoryException e )
1113         {
1114             throw new RuntimeException( e.getMessage(), e );
1115         }
1116     }
1117
1118     public void revert()
1119     {
1120         try
1121         {
1122             getJcrSession().refresh( false );
1123         }
1124         catch ( RepositoryException e )
1125         {
1126             throw new RuntimeException( e.getMessage(), e );
1127         }
1128     }
1129
1130     public boolean canObtainAccess( Class<?> aClass )
1131     {
1132         return aClass == Session.class;
1133     }
1134
1135     public Object obtainAccess( Class<?> aClass )
1136         throws MetadataRepositoryException
1137     {
1138         if ( aClass == Session.class )
1139         {
1140             try
1141             {
1142                 return getJcrSession();
1143             }
1144             catch ( RepositoryException e )
1145             {
1146                 log.error( e.getMessage(), e );
1147                 throw new MetadataRepositoryException( e.getMessage(), e );
1148             }
1149         }
1150         throw new IllegalArgumentException(
1151             "Access using " + aClass + " is not supported on the JCR metadata storage" );
1152     }
1153
1154     public void close()
1155         throws MetadataRepositoryException
1156     {
1157         try
1158         {
1159             if ( getJcrSession().isLive() )
1160             {
1161                 getJcrSession().logout();
1162             }
1163         }
1164         catch ( RepositoryException e )
1165         {
1166             log.error( e.getMessage(), e );
1167             throw new MetadataRepositoryException( e.getMessage(), e );
1168         }
1169     }
1170
1171     private ArtifactMetadata getArtifactFromNode( String repositoryId, Node artifactNode )
1172         throws RepositoryException
1173     {
1174         String id = artifactNode.getName();
1175
1176         ArtifactMetadata artifact = new ArtifactMetadata();
1177         artifact.setId( id );
1178         artifact.setRepositoryId( repositoryId );
1179
1180         Node projectVersionNode = artifactNode.getParent();
1181         Node projectNode = projectVersionNode.getParent();
1182         Node namespaceNode = projectNode.getParent();
1183
1184         artifact.setNamespace( namespaceNode.getProperty( "namespace" ).getString() );
1185         artifact.setProject( projectNode.getName() );
1186         artifact.setProjectVersion( projectVersionNode.getName() );
1187         artifact.setVersion( artifactNode.hasProperty( "version" )
1188                                  ? artifactNode.getProperty( "version" ).getString()
1189                                  : projectVersionNode.getName() );
1190
1191         if ( artifactNode.hasProperty( JCR_LAST_MODIFIED ) )
1192         {
1193             artifact.setFileLastModified( artifactNode.getProperty( JCR_LAST_MODIFIED ).getDate().getTimeInMillis() );
1194         }
1195
1196         if ( artifactNode.hasProperty( "whenGathered" ) )
1197         {
1198             artifact.setWhenGathered( artifactNode.getProperty( "whenGathered" ).getDate().getTime() );
1199         }
1200
1201         if ( artifactNode.hasProperty( "size" ) )
1202         {
1203             artifact.setSize( artifactNode.getProperty( "size" ).getLong() );
1204         }
1205
1206         if ( artifactNode.hasProperty( "md5" ) )
1207         {
1208             artifact.setMd5( artifactNode.getProperty( "md5" ).getString() );
1209         }
1210
1211         if ( artifactNode.hasProperty( "sha1" ) )
1212         {
1213             artifact.setSha1( artifactNode.getProperty( "sha1" ).getString() );
1214         }
1215
1216         for ( Node n : JcrUtils.getChildNodes( artifactNode ) )
1217         {
1218             if ( n.isNodeType( FACET_NODE_TYPE ) )
1219             {
1220                 String name = n.getName();
1221                 MetadataFacetFactory factory = metadataFacetFactories.get( name );
1222                 if ( factory == null )
1223                 {
1224                     log.error( "Attempted to load unknown project version metadata facet: " + name );
1225                 }
1226                 else
1227                 {
1228                     MetadataFacet facet = factory.createMetadataFacet();
1229                     Map<String, String> map = new HashMap<String, String>();
1230                     for ( Property p : JcrUtils.getProperties( n ) )
1231                     {
1232                         String property = p.getName();
1233                         if ( !property.startsWith( "jcr:" ) )
1234                         {
1235                             map.put( property, p.getString() );
1236                         }
1237                     }
1238                     facet.fromProperties( map );
1239                     artifact.addFacet( facet );
1240                 }
1241             }
1242         }
1243         return artifact;
1244     }
1245
1246     private static String getPropertyString( Node node, String name )
1247         throws RepositoryException
1248     {
1249         return node.hasProperty( name ) ? node.getProperty( name ).getString() : null;
1250     }
1251
1252     private Collection<String> getNodeNames( String path, String nodeType )
1253         throws MetadataResolutionException
1254     {
1255         List<String> names = new ArrayList<String>();
1256
1257         try
1258         {
1259             Node root = getJcrSession().getRootNode();
1260
1261             Node nodeAtPath = root.getNode( path );
1262
1263             for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1264             {
1265                 if ( node.isNodeType( nodeType ) )
1266                 {
1267                     names.add( node.getName() );
1268                 }
1269             }
1270         }
1271         catch ( PathNotFoundException e )
1272         {
1273             // ignore repo not found for now
1274         }
1275         catch ( RepositoryException e )
1276         {
1277             throw new MetadataResolutionException( e.getMessage(), e );
1278         }
1279
1280         return names;
1281     }
1282
1283     private static String getRepositoryPath( String repositoryId )
1284     {
1285         return "repositories/" + repositoryId;
1286     }
1287
1288     private static String getRepositoryContentPath( String repositoryId )
1289     {
1290         return getRepositoryPath( repositoryId ) + "/content/";
1291     }
1292
1293     private static String getFacetPath( String repositoryId, String facetId )
1294     {
1295         return getRepositoryPath( repositoryId ) + "/facets/" + facetId;
1296     }
1297
1298     private static String getNamespacePath( String repositoryId, String namespace )
1299     {
1300         return getRepositoryContentPath( repositoryId ) + namespace.replace( '.', '/' );
1301     }
1302
1303     private static String getProjectPath( String repositoryId, String namespace, String projectId )
1304     {
1305         return getNamespacePath( repositoryId, namespace ) + "/" + projectId;
1306     }
1307
1308     private static String getProjectVersionPath( String repositoryId, String namespace, String projectId,
1309                                                  String projectVersion )
1310     {
1311         return getProjectPath( repositoryId, namespace, projectId ) + "/" + projectVersion;
1312     }
1313
1314     private static String getArtifactPath( String repositoryId, String namespace, String projectId,
1315                                            String projectVersion, String id )
1316     {
1317         return getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) + "/" + id;
1318     }
1319
1320     private Node getOrAddNodeByPath( Node baseNode, String name )
1321         throws RepositoryException
1322     {
1323         return getOrAddNodeByPath( baseNode, name, null );
1324     }
1325
1326     private Node getOrAddNodeByPath( Node baseNode, String name, String nodeType )
1327         throws RepositoryException
1328     {
1329         Node node = baseNode;
1330         for ( String n : name.split( "/" ) )
1331         {
1332             node = JcrUtils.getOrAddNode( node, n );
1333             if ( nodeType != null )
1334             {
1335                 node.addMixin( nodeType );
1336             }
1337         }
1338         return node;
1339     }
1340
1341     private static String getFacetPath( String repositoryId, String facetId, String name )
1342     {
1343         return getFacetPath( repositoryId, facetId ) + "/" + name;
1344     }
1345
1346     private Node getOrAddRepositoryNode( String repositoryId )
1347         throws RepositoryException
1348     {
1349         Node root = getJcrSession().getRootNode();
1350         Node node = JcrUtils.getOrAddNode( root, "repositories" );
1351         node = JcrUtils.getOrAddNode( node, repositoryId );
1352         return node;
1353     }
1354
1355     private Node getOrAddRepositoryContentNode( String repositoryId )
1356         throws RepositoryException
1357     {
1358         Node node = getOrAddRepositoryNode( repositoryId );
1359         return JcrUtils.getOrAddNode( node, "content" );
1360     }
1361
1362     private Node getOrAddNamespaceNode( String repositoryId, String namespace )
1363         throws RepositoryException
1364     {
1365         Node repo = getOrAddRepositoryContentNode( repositoryId );
1366         return getOrAddNodeByPath( repo, namespace.replace( '.', '/' ), NAMESPACE_NODE_TYPE );
1367     }
1368
1369     private Node getOrAddProjectNode( String repositoryId, String namespace, String projectId )
1370         throws RepositoryException
1371     {
1372         Node namespaceNode = getOrAddNamespaceNode( repositoryId, namespace );
1373         Node node = JcrUtils.getOrAddNode( namespaceNode, projectId );
1374         node.addMixin( PROJECT_NODE_TYPE );
1375         return node;
1376     }
1377
1378     private Node getOrAddProjectVersionNode( String repositoryId, String namespace, String projectId,
1379                                              String projectVersion )
1380         throws RepositoryException
1381     {
1382         Node projectNode = getOrAddProjectNode( repositoryId, namespace, projectId );
1383         Node node = JcrUtils.getOrAddNode( projectNode, projectVersion );
1384         node.addMixin( PROJECT_VERSION_NODE_TYPE );
1385         return node;
1386     }
1387
1388     private Node getOrAddArtifactNode( String repositoryId, String namespace, String projectId, String projectVersion,
1389                                        String id )
1390         throws RepositoryException
1391     {
1392         Node versionNode = getOrAddProjectVersionNode( repositoryId, namespace, projectId, projectVersion );
1393         Node node = JcrUtils.getOrAddNode( versionNode, id );
1394         node.addMixin( ARTIFACT_NODE_TYPE );
1395         return node;
1396     }
1397
1398     private static Calendar createCalendar( Date time )
1399     {
1400         Calendar cal = Calendar.getInstance();
1401         cal.setTime( time );
1402         return cal;
1403     }
1404
1405     private String join( Collection<String> ids )
1406     {
1407         if ( ids != null && !ids.isEmpty() )
1408         {
1409             StringBuilder s = new StringBuilder();
1410             for ( String id : ids )
1411             {
1412                 s.append( id );
1413                 s.append( "," );
1414             }
1415             return s.substring( 0, s.length() - 1 );
1416         }
1417         return null;
1418     }
1419
1420     public Session getJcrSession()
1421         throws RepositoryException
1422     {
1423         if ( this.jcrSession == null || !this.jcrSession.isLive() )
1424         {
1425
1426             jcrSession = repository.login( new SimpleCredentials( "admin", "admin".toCharArray() ) );
1427
1428         }
1429         return this.jcrSession;
1430     }
1431 }