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