]> source.dussan.org Git - archiva.git/blob
00cef08285cc67b47efdf7de8e77e16d32f3fce3
[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 com.google.common.collect.ImmutableMap;
23 import org.apache.archiva.metadata.model.ArtifactMetadata;
24 import org.apache.archiva.metadata.model.CiManagement;
25 import org.apache.archiva.metadata.model.Dependency;
26 import org.apache.archiva.metadata.model.FacetedMetadata;
27 import org.apache.archiva.metadata.model.IssueManagement;
28 import org.apache.archiva.metadata.model.License;
29 import org.apache.archiva.metadata.model.MailingList;
30 import org.apache.archiva.metadata.model.MetadataFacet;
31 import org.apache.archiva.metadata.model.MetadataFacetFactory;
32 import org.apache.archiva.metadata.model.Organization;
33 import org.apache.archiva.metadata.model.ProjectMetadata;
34 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
35 import org.apache.archiva.metadata.model.ProjectVersionReference;
36 import org.apache.archiva.metadata.model.Scm;
37 import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
38 import org.apache.archiva.metadata.repository.MetadataRepository;
39 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
40 import org.apache.archiva.metadata.repository.MetadataResolutionException;
41 import org.apache.archiva.metadata.repository.RepositorySession;
42 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
43 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsProvider;
44 import org.apache.commons.lang.StringUtils;
45 import org.apache.jackrabbit.JcrConstants;
46 import org.apache.jackrabbit.commons.JcrUtils;
47 import org.apache.jackrabbit.commons.cnd.CndImporter;
48 import org.apache.jackrabbit.commons.cnd.ParseException;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 import javax.jcr.NamespaceRegistry;
53 import javax.jcr.Node;
54 import javax.jcr.PathNotFoundException;
55 import javax.jcr.Property;
56 import javax.jcr.Repository;
57 import javax.jcr.RepositoryException;
58 import javax.jcr.Session;
59 import javax.jcr.SimpleCredentials;
60 import javax.jcr.ValueFactory;
61 import javax.jcr.Workspace;
62 import javax.jcr.nodetype.NodeTypeManager;
63 import javax.jcr.nodetype.NodeTypeTemplate;
64 import javax.jcr.query.Query;
65 import javax.jcr.query.QueryManager;
66 import javax.jcr.query.QueryResult;
67 import javax.jcr.query.Row;
68 import javax.jcr.query.RowIterator;
69 import java.io.IOException;
70 import java.io.InputStreamReader;
71 import java.io.Reader;
72 import java.util.ArrayList;
73 import java.util.Arrays;
74 import java.util.Calendar;
75 import java.util.Collection;
76 import java.util.Collections;
77 import java.util.Date;
78 import java.util.HashMap;
79 import java.util.Iterator;
80 import java.util.LinkedHashSet;
81 import java.util.List;
82 import java.util.Map;
83 import java.util.Map.Entry;
84 import java.util.Set;
85
86 import static javax.jcr.Property.JCR_LAST_MODIFIED;
87 import static org.apache.archiva.metadata.repository.jcr.JcrConstants.DEPENDENCY_NODE_TYPE;
88 import static org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_VERSION_PROPERTIES;
89
90 /**
91  * TODO below: revise storage format for project version metadata
92  * TODO revise reference storage
93  */
94 public class JcrMetadataRepository
95     implements MetadataRepository, RepositoryStatisticsProvider
96 {
97
98
99     private static final String QUERY_ARTIFACT_1 = "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE + "] AS artifact WHERE ISDESCENDANTNODE(artifact,'/";
100
101     static final String QUERY_ARTIFACTS_BY_PROJECT_VERSION_1 = "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE
102         + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) INNER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE
103         + "] AS facet ON ISCHILDNODE(facet, projectVersion) WHERE ([facet].[";
104     static final String QUERY_ARTIFACTS_BY_PROJECT_VERSION_2= "] = $value)";
105
106     static final String QUERY_ARTIFACTS_BY_METADATA_1 = "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE + "] AS artifact INNER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE
107         + "] AS facet ON ISCHILDNODE(facet, artifact) WHERE ([facet].[";
108     static final String QUERY_ARTIFACTS_BY_METADATA_2 = "] = $value)";
109
110     static final String QUERY_ARTIFACTS_BY_PROPERTY_1 = "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE
111            + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) WHERE ([projectVersion].[";
112     static final String QUERY_ARTIFACTS_BY_PROPERTY_2 = "] = $value)";
113
114
115     private static final String QUERY_ARTIFACT_2 = "')";
116
117     private final Map<String, MetadataFacetFactory> metadataFacetFactories;
118
119     private Logger log = LoggerFactory.getLogger( JcrMetadataRepository.class );
120
121     private Repository repository;
122
123     public JcrMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories, Repository repository )
124         throws RepositoryException
125     {
126         this.metadataFacetFactories = metadataFacetFactories;
127         this.repository = repository;
128     }
129
130
131     public static void initializeNodeTypes( Session session )
132         throws RepositoryException
133     {
134
135         // TODO: consider using namespaces for facets instead of the current approach:
136         // (if used, check if actually called by normal injection)
137 //        for ( String facetId : metadataFacetFactories.keySet() )
138 //        {
139 //            session.getWorkspace().getNamespaceRegistry().registerNamespace( facetId, facetId );
140 //        }
141         Workspace workspace = session.getWorkspace();
142         NamespaceRegistry registry = workspace.getNamespaceRegistry();
143
144         if ( !Arrays.asList( registry.getPrefixes() ).contains( "archiva" ) )
145         {
146             registry.registerNamespace( "archiva", "http://archiva.apache.org/jcr/" );
147         }
148
149         NodeTypeManager nodeTypeManager = workspace.getNodeTypeManager();
150         try(
151             Reader cndReader = new InputStreamReader(
152                 Thread.currentThread( ).getContextClassLoader( ).getResourceAsStream( "org/apache/archiva/metadata/repository/jcr/jcr-schema.cnd" ) ))
153         {
154             CndImporter.registerNodeTypes( cndReader, session );
155         }
156         catch ( ParseException e )
157         {
158             e.printStackTrace( );
159         }
160         catch ( IOException e )
161         {
162             e.printStackTrace( );
163         }
164
165
166 //        registerMixinNodeType( nodeTypeManager, REPOSITORY_NODE_TYPE );
167 //        registerMixinNodeType( nodeTypeManager, NAMESPACE_NODE_TYPE );
168 //        registerMixinNodeType( nodeTypeManager, PROJECT_NODE_TYPE );
169 //        registerMixinNodeType( nodeTypeManager, PROJECT_VERSION_NODE_TYPE );
170 //        registerMixinNodeType( nodeTypeManager, ARTIFACT_NODE_TYPE );
171 //        registerMixinNodeType( nodeTypeManager, FACET_NODE_TYPE );
172 //        registerMixinNodeType( nodeTypeManager, DEPENDENCY_NODE_TYPE );
173
174
175     }
176
177     private static void registerMixinNodeType( NodeTypeManager nodeTypeManager, String name )
178         throws RepositoryException
179     {
180         // for now just don't re-create - but in future if we change the definition, make sure to remove first as an
181         // upgrade path
182         if ( !nodeTypeManager.hasNodeType( name ) )
183         {
184             NodeTypeTemplate nodeType = nodeTypeManager.createNodeTypeTemplate();
185             nodeType.setMixin( true );
186             nodeType.setName( name );
187             nodeType.setQueryable( true );
188             nodeTypeManager.registerNodeType( nodeType, false );
189         }
190     }
191
192     private Session getSession(RepositorySession repositorySession) throws MetadataRepositoryException {
193         if (repositorySession instanceof JcrRepositorySession ) {
194             return ( (JcrRepositorySession) repositorySession ).getJcrSession();
195         } else {
196             throw new MetadataRepositoryException( "The given session object is not a JcrSession instance: " + repositorySession.getClass( ).getName( ) );
197         }
198     }
199
200     @Override
201     public void updateProject( RepositorySession session, String repositoryId, ProjectMetadata project )
202         throws MetadataRepositoryException
203     {
204         final Session jcrSession = getSession( session );
205         updateProject( jcrSession, repositoryId, project.getNamespace(), project.getId() );
206     }
207
208     private void updateProject( Session jcrSession, String repositoryId, String namespace, String projectId )
209         throws MetadataRepositoryException
210     {
211         updateNamespace( jcrSession , repositoryId, namespace );
212
213         try
214         {
215             getOrAddProjectNode( jcrSession, repositoryId, namespace, projectId );
216         }
217         catch ( RepositoryException e )
218         {
219             throw new MetadataRepositoryException( e.getMessage(), e );
220         }
221     }
222
223     @Override
224     public void updateArtifact( RepositorySession session, String repositoryId, String namespace, String projectId, String projectVersion,
225                                 ArtifactMetadata artifactMeta )
226         throws MetadataRepositoryException
227     {
228         final Session jcrSession = getSession( session );
229         updateNamespace( session, repositoryId, namespace );
230
231         try
232         {
233             Node node =
234                 getOrAddArtifactNode( jcrSession, repositoryId, namespace, projectId, projectVersion, artifactMeta.getId() );
235
236             node.setProperty( "id", artifactMeta.getId( ) );
237             Calendar cal = Calendar.getInstance();
238             cal.setTime( artifactMeta.getFileLastModified() );
239             node.setProperty( JCR_LAST_MODIFIED, cal );
240
241             cal = Calendar.getInstance();
242             cal.setTime( artifactMeta.getWhenGathered() );
243             node.setProperty( "whenGathered", cal );
244
245             node.setProperty( "size", artifactMeta.getSize() );
246             node.setProperty( "md5", artifactMeta.getMd5() );
247             node.setProperty( "sha1", artifactMeta.getSha1() );
248
249             node.setProperty( "version", artifactMeta.getVersion() );
250
251             // iterate over available facets to update/add/remove from the artifactMetadata
252             for ( String facetId : metadataFacetFactories.keySet() )
253             {
254                 MetadataFacet metadataFacet = artifactMeta.getFacet( facetId );
255                 if ( metadataFacet == null )
256                 {
257                     continue;
258                 }
259                 if ( node.hasNode( facetId ) )
260                 {
261                     node.getNode( facetId ).remove();
262                 }
263                 if ( metadataFacet != null )
264                 {
265                     // recreate, to ensure properties are removed
266                     Node n = node.addNode( facetId);
267                     n.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE );
268
269                     for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
270                     {
271                         n.setProperty( entry.getKey(), entry.getValue() );
272                     }
273                 }
274             }
275         }
276         catch ( RepositoryException e )
277         {
278             throw new MetadataRepositoryException( e.getMessage(), e );
279         }
280     }
281
282     @Override
283     public void updateProjectVersion( RepositorySession session, String repositoryId, String namespace, String projectId,
284                                       ProjectVersionMetadata versionMetadata )
285         throws MetadataRepositoryException
286     {
287         final Session jcrSession = getSession( session );
288         updateProject( jcrSession, repositoryId, namespace, projectId );
289
290         try
291         {
292             Node versionNode =
293                 getOrAddProjectVersionNode( jcrSession, repositoryId, namespace, projectId, versionMetadata.getId() );
294             versionNode.setProperty( "id", versionMetadata.getId( ) );
295             versionNode.setProperty( "name", StringUtils.isEmpty( versionMetadata.getName() ) ? "" : versionMetadata.getName() );
296             versionNode.setProperty( "description", StringUtils.isEmpty( versionMetadata.getDescription() ) ? "" : versionMetadata.getDescription() );
297             versionNode.setProperty( "url", versionMetadata.getUrl() );
298             versionNode.setProperty( "incomplete", versionMetadata.isIncomplete() );
299
300             // FIXME: decide how to treat these in the content repo
301             if ( versionMetadata.getScm() != null )
302             {
303                 versionNode.setProperty( "scm.connection", versionMetadata.getScm().getConnection() );
304                 versionNode.setProperty( "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
305                 versionNode.setProperty( "scm.url", versionMetadata.getScm().getUrl() );
306             }
307             if ( versionMetadata.getCiManagement() != null )
308             {
309                 versionNode.setProperty( "ci.system", versionMetadata.getCiManagement().getSystem() );
310                 versionNode.setProperty( "ci.url", versionMetadata.getCiManagement().getUrl() );
311             }
312             if ( versionMetadata.getIssueManagement() != null )
313             {
314                 versionNode.setProperty( "issue.system", versionMetadata.getIssueManagement().getSystem() );
315                 versionNode.setProperty( "issue.url", versionMetadata.getIssueManagement().getUrl() );
316             }
317             if ( versionMetadata.getOrganization() != null )
318             {
319                 versionNode.setProperty( "org.name", versionMetadata.getOrganization().getName() );
320                 versionNode.setProperty( "org.url", versionMetadata.getOrganization().getUrl() );
321             }
322             int i = 0;
323             for ( License license : versionMetadata.getLicenses() )
324             {
325                 versionNode.setProperty( "license." + i + ".name", license.getName() );
326                 versionNode.setProperty( "license." + i + ".url", license.getUrl() );
327                 i++;
328             }
329             i = 0;
330             for ( MailingList mailingList : versionMetadata.getMailingLists() )
331             {
332                 versionNode.setProperty( "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
333                 versionNode.setProperty( "mailingList." + i + ".name", mailingList.getName() );
334                 versionNode.setProperty( "mailingList." + i + ".post", mailingList.getPostAddress() );
335                 versionNode.setProperty( "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
336                 versionNode.setProperty( "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
337                 versionNode.setProperty( "mailingList." + i + ".otherArchives",
338                                          join( mailingList.getOtherArchives() ) );
339                 i++;
340             }
341
342             if ( !versionMetadata.getDependencies().isEmpty() )
343             {
344                 Node dependenciesNode = JcrUtils.getOrAddNode( versionNode, "dependencies" );
345
346                 for ( Dependency dependency : versionMetadata.getDependencies() )
347                 {
348                     // Note that we deliberately don't alter the namespace path - not enough dependencies for
349                     // number of nodes at a given depth to be an issue. Similarly, we don't add subnodes for each
350                     // component of the ID as that creates extra depth and causes a great cost in space and memory
351
352                     // FIXME: change group ID to namespace
353                     // FIXME: change to artifact's ID - this is constructed by the Maven 2 format for now.
354                     //        This won't support types where the extension doesn't match the type.
355                     //        (see also Maven2RepositoryStorage#readProjectVersionMetadata construction of POM)
356                     String id =
357                         dependency.getGroupId() + ";" + dependency.getArtifactId() + "-" + dependency.getVersion();
358                     if ( dependency.getClassifier() != null )
359                     {
360                         id += "-" + dependency.getClassifier();
361                     }
362                     id += "." + dependency.getType();
363
364                     Node n = JcrUtils.getOrAddNode( dependenciesNode, id, DEPENDENCY_NODE_TYPE );
365                     n.setProperty( "id", id );
366
367                     // FIXME: remove temp code just to make it keep working
368                     n.setProperty( "groupId", dependency.getGroupId() );
369                     n.setProperty( "artifactId", dependency.getArtifactId() );
370                     n.setProperty( "version", dependency.getVersion() );
371                     n.setProperty( "type", dependency.getType() );
372                     n.setProperty( "classifier", dependency.getClassifier() );
373                     n.setProperty( "scope", dependency.getScope() );
374                     n.setProperty( "systemPath", dependency.getSystemPath() );
375                     n.setProperty( "optional", dependency.isOptional() );
376
377                     // node has no native content at this time, just facets
378                     // no need to list a type as it's implied by the path. Parents are Maven specific.
379
380                     // FIXME: add scope, systemPath, type, version, classifier & maven2 specific IDs as a facet
381                     //        (should also have been added to the Dependency)
382
383                     // TODO: add a property that is a weak reference to the originating artifact, creating it if
384                     //       necessary (without adding the archiva:artifact mixin so that it doesn't get listed as an
385                     //       artifact, which gives a different meaning to "incomplete" which is a known local project
386                     //       that doesn't have metadata yet but has artifacts). (Though we may want to give it the
387                     //       artifact mixin and another property to identify all non-local artifacts for the closure
388                     //       reports)
389                 }
390             }
391
392             for ( MetadataFacet facet : versionMetadata.getFacetList() )
393             {
394                 // recreate, to ensure properties are removed
395                 if ( versionNode.hasNode( facet.getFacetId() ) )
396                 {
397                     versionNode.getNode( facet.getFacetId() ).remove();
398                 }
399                 Node n = versionNode.addNode( facet.getFacetId() );
400                 n.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE );
401
402                 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
403                 {
404                     n.setProperty( entry.getKey(), entry.getValue() );
405                 }
406             }
407         }
408         catch ( RepositoryException e )
409         {
410             throw new MetadataRepositoryException( e.getMessage(), e );
411         }
412     }
413
414     private void updateNamespace(Session jcrSession, String repositoryId, String namespace) throws MetadataRepositoryException
415     {
416         try
417         {
418             Node node = getOrAddNamespaceNode( jcrSession, repositoryId, namespace );
419             node.setProperty( "id", namespace );
420             node.setProperty( "namespace", namespace );
421         }
422         catch ( RepositoryException e )
423         {
424             throw new MetadataRepositoryException( e.getMessage(), e );
425         }
426     }
427
428     @Override
429     public void updateNamespace( RepositorySession session, String repositoryId, String namespace )
430         throws MetadataRepositoryException
431     {
432         updateNamespace( getSession(session), repositoryId, namespace );
433     }
434
435     @Override
436     public void removeProject( RepositorySession session, String repositoryId, String namespace, String projectId )
437         throws MetadataRepositoryException
438     {
439         final Session jcrSession = getSession( session );
440         try
441         {
442             Node root = jcrSession.getRootNode();
443             String namespacePath = getNamespacePath( repositoryId, namespace );
444
445             if ( root.hasNode( namespacePath ) )
446             {
447                 Iterator<Node> nodeIterator = JcrUtils.getChildNodes( root.getNode( namespacePath ) ).iterator();
448                 while ( nodeIterator.hasNext() )
449                 {
450                     Node node = nodeIterator.next();
451                     if ( node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_NODE_TYPE ) && projectId.equals( node.getName() ) )
452                     {
453                         node.remove();
454                     }
455                 }
456
457             }
458         }
459         catch ( RepositoryException e )
460         {
461             throw new MetadataRepositoryException( e.getMessage(), e );
462         }
463
464     }
465
466
467     @Override
468     public boolean hasMetadataFacet( RepositorySession session, String repositoryId, String facetId )
469         throws MetadataRepositoryException
470     {
471         final Session jcrSession = getSession( session );
472         try
473         {
474             Node node = jcrSession.getRootNode().getNode( getFacetPath( repositoryId, facetId ) );
475             return node.getNodes().hasNext();
476         }
477         catch ( PathNotFoundException e )
478         {
479             // ignored - the facet doesn't exist, so return false
480             return false;
481         }
482         catch ( RepositoryException e )
483         {
484             throw new MetadataRepositoryException( e.getMessage(), e );
485         }
486     }
487
488     @Override
489     public List<String> getMetadataFacets( RepositorySession session, String repositoryId, String facetId )
490         throws MetadataRepositoryException
491     {
492         final Session jcrSession = getSession( session );
493         List<String> facets = new ArrayList<>();
494
495         try
496         {
497             // no need to construct node-by-node here, as we'll find in the next instance, the facet names have / and
498             // are paths themselves
499             Node node = jcrSession.getRootNode().getNode( getFacetPath( repositoryId, facetId ) );
500
501             // TODO: this is a bit awkward. Might be better to review the purpose of this function - why is the list of
502             //   paths helpful?
503             recurse( facets, "", node );
504         }
505         catch ( PathNotFoundException e )
506         {
507             // ignored - the facet doesn't exist, so return the empty list
508         }
509         catch ( RepositoryException e )
510         {
511             throw new MetadataRepositoryException( e.getMessage(), e );
512         }
513         return facets;
514     }
515
516     private void recurse( List<String> facets, String prefix, Node node )
517         throws RepositoryException
518     {
519         for ( Node n : JcrUtils.getChildNodes( node ) )
520         {
521             String name = prefix + "/" + n.getName();
522             if ( n.hasNodes() )
523             {
524                 recurse( facets, name, n );
525             }
526             else
527             {
528                 // strip leading / first
529                 facets.add( name.substring( 1 ) );
530             }
531         }
532     }
533
534     @Override
535     public MetadataFacet getMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
536         throws MetadataRepositoryException
537     {
538         final Session jcrSession = getSession( session );
539         MetadataFacet metadataFacet = null;
540         try
541         {
542             Node root = jcrSession.getRootNode();
543             Node node = root.getNode( getFacetPath( repositoryId, facetId, name ) );
544
545             if ( metadataFacetFactories == null )
546             {
547                 return metadataFacet;
548             }
549
550             MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
551             if ( metadataFacetFactory != null )
552             {
553                 metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
554                 Map<String, String> map = new HashMap<>();
555                 for ( Property property : JcrUtils.getProperties( node ) )
556                 {
557                     String p = property.getName();
558                     if ( !p.startsWith( "jcr:" ) )
559                     {
560                         map.put( p, property.getString() );
561                     }
562                 }
563                 metadataFacet.fromProperties( map );
564             }
565         }
566         catch ( PathNotFoundException e )
567         {
568             // ignored - the facet doesn't exist, so return null
569         }
570         catch ( RepositoryException e )
571         {
572             throw new MetadataRepositoryException( e.getMessage(), e );
573         }
574         return metadataFacet;
575     }
576
577     @Override
578     public void addMetadataFacet( RepositorySession session, String repositoryId, MetadataFacet metadataFacet )
579         throws MetadataRepositoryException
580     {
581         final Session jcrSession = getSession( session );
582         try
583         {
584             Node repo = getOrAddRepositoryNode( jcrSession, repositoryId );
585             Node facets = JcrUtils.getOrAddNode( repo, "facets" );
586
587             String id = metadataFacet.getFacetId();
588             Node facetNode = JcrUtils.getOrAddNode( facets, id );
589
590             Node node = getOrAddNodeByPath( facetNode, metadataFacet.getName() );
591
592             for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
593             {
594                 node.setProperty( entry.getKey(), entry.getValue() );
595             }
596         }
597         catch ( RepositoryException e )
598         {
599             throw new MetadataRepositoryException( e.getMessage(), e );
600         }
601     }
602
603     @Override
604     public void removeNamespace( RepositorySession session, String repositoryId, String projectId )
605         throws MetadataRepositoryException
606     {
607         final Session jcrSession = getSession( session );
608         try
609         {
610             Node root = jcrSession.getRootNode();
611             String path = getNamespacePath( repositoryId, projectId );
612             if ( root.hasNode( path ) )
613             {
614                 Node node = root.getNode( path );
615                 if ( node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.NAMESPACE_NODE_TYPE ) )
616                 {
617                     node.remove();
618                 }
619             }
620         }
621         catch ( RepositoryException e )
622         {
623             throw new MetadataRepositoryException( e.getMessage(), e );
624         }
625     }
626
627     @Override
628     public void removeMetadataFacets( RepositorySession session, String repositoryId, String facetId )
629         throws MetadataRepositoryException
630     {
631         final Session jcrSession = getSession( session );
632         try
633         {
634             Node root = jcrSession.getRootNode();
635             String path = getFacetPath( repositoryId, facetId );
636             if ( root.hasNode( path ) )
637             {
638                 root.getNode( path ).remove();
639             }
640         }
641         catch ( RepositoryException e )
642         {
643             throw new MetadataRepositoryException( e.getMessage(), e );
644         }
645     }
646
647     @Override
648     public void removeMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
649         throws MetadataRepositoryException
650     {
651         final Session jcrSession = getSession( session );
652         try
653         {
654             Node root = jcrSession.getRootNode();
655             String path = getFacetPath( repositoryId, facetId, name );
656             if ( root.hasNode( path ) )
657             {
658                 Node node = root.getNode( path );
659                 do
660                 {
661                     // also remove empty container nodes
662                     Node parent = node.getParent();
663                     node.remove();
664                     node = parent;
665                 }
666                 while ( !node.hasNodes() );
667             }
668         }
669         catch ( RepositoryException e )
670         {
671             throw new MetadataRepositoryException( e.getMessage(), e );
672         }
673     }
674
675     @Override
676     public List<ArtifactMetadata> getArtifactsByDateRange( RepositorySession session, String repoId, Date startTime, Date endTime )
677         throws MetadataRepositoryException
678     {
679         final Session jcrSession = getSession( session );
680
681         List<ArtifactMetadata> artifacts;
682
683         String q = getArtifactQuery( repoId );
684
685         if ( startTime != null )
686         {
687             q += " AND [whenGathered] >= $start";
688         }
689         if ( endTime != null )
690         {
691             q += " AND [whenGathered] <= $end";
692         }
693
694         try
695         {
696             Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
697             ValueFactory valueFactory = jcrSession.getValueFactory();
698             if ( startTime != null )
699             {
700                 query.bindValue( "start", valueFactory.createValue( createCalendar( startTime ) ) );
701             }
702             if ( endTime != null )
703             {
704                 query.bindValue( "end", valueFactory.createValue( createCalendar( endTime ) ) );
705             }
706             QueryResult result = query.execute();
707
708             artifacts = new ArrayList<>();
709             for ( Node n : JcrUtils.getNodes( result ) )
710             {
711                 artifacts.add( getArtifactFromNode( repoId, n ) );
712             }
713         }
714         catch ( RepositoryException e )
715         {
716             throw new MetadataRepositoryException( e.getMessage(), e );
717         }
718         return artifacts;
719     }
720
721
722     @Override
723     public List<ArtifactMetadata> getArtifactsByChecksum( RepositorySession session, String repositoryId, String checksum )
724         throws MetadataRepositoryException
725     {
726         final Session jcrSession = getSession( session );
727         List<ArtifactMetadata> artifacts;
728
729         String q = getArtifactQuery( repositoryId ) + " AND ([sha1] = $checksum OR [md5] = $checksum)";
730
731         try
732         {
733             Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
734             ValueFactory valueFactory = jcrSession.getValueFactory();
735             query.bindValue( "checksum", valueFactory.createValue( checksum ) );
736             QueryResult result = query.execute();
737
738             artifacts = new ArrayList<>();
739             for ( Node n : JcrUtils.getNodes( result ) )
740             {
741                 artifacts.add( getArtifactFromNode( repositoryId, n ) );
742             }
743         }
744         catch ( RepositoryException e )
745         {
746             throw new MetadataRepositoryException( e.getMessage(), e );
747         }
748         return artifacts;
749     }
750
751     public List<ArtifactMetadata> runJcrQuery( Session jcrSession, String repositoryId, String q, Map<String, String> bindingParam)
752         throws MetadataRepositoryException
753     {
754         return runJcrQuery( jcrSession, repositoryId, q, bindingParam, true );
755     }
756
757     public List<ArtifactMetadata> runJcrQuery( final Session jcrSession, final String repositoryId, final String qParam,
758                                                final Map<String, String> bindingParam, final boolean checkPath )
759         throws MetadataRepositoryException
760     {
761
762         String q = qParam;
763         List<ArtifactMetadata> artifacts;
764         if ( repositoryId != null && checkPath )
765         {
766             q += " AND ISDESCENDANTNODE(artifact,'/" + getRepositoryContentPath( repositoryId ) + "')";
767         }
768
769         log.info( "Running JCR Query: {}", q );
770
771         try
772         {
773             QueryResult result = runNativeJcrQuery( jcrSession, q, bindingParam );
774             artifacts = new ArrayList<>();
775             RowIterator rows = result.getRows();
776             while ( rows.hasNext() )
777             {
778                 Row row = rows.nextRow();
779                 Node node = row.getNode( "artifact" );
780                 artifacts.add( getArtifactFromNode( repositoryId, node ) );
781             }
782         }
783         catch ( RepositoryException e )
784         {
785             throw new MetadataRepositoryException( e.getMessage(), e );
786         }
787         log.info( "Artifacts found {}", artifacts.size() );
788         for ( ArtifactMetadata meta : artifacts )
789         {
790             log.info( "Artifact: " + meta.getVersion() + " " + meta.getFacetList() );
791         }
792         return artifacts;
793     }
794
795     public QueryResult runNativeJcrQuery( final Session jcrSession, final String q, final Map<String, String> bindingParam)
796         throws MetadataRepositoryException
797     {
798         Map<String, String> bindings;
799         if (bindingParam==null) {
800             bindings = new HashMap<>( );
801         } else {
802             bindings = bindingParam;
803         }
804
805         try
806         {
807             Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
808             ValueFactory valueFactory = jcrSession.getValueFactory();
809             for ( Entry<String, String> entry : bindings.entrySet() )
810             {
811                 query.bindValue( entry.getKey(), valueFactory.createValue( entry.getValue() ) );
812             }
813             long start = System.currentTimeMillis( );
814             QueryResult result = query.execute();
815             long end = System.currentTimeMillis( );
816             log.info( "JCR Query ran in {} milliseconds: {}", end - start, q );
817             return result;
818         }
819         catch ( RepositoryException e )
820         {
821             throw new MetadataRepositoryException( e.getMessage(), e );
822         }
823     }
824
825     @Override
826     public List<ArtifactMetadata> getArtifactsByProjectVersionMetadata( RepositorySession session, String key, String value, String repositoryId )
827         throws MetadataRepositoryException
828     {
829         final Session jcrSession = getSession( session );
830         final String q = new StringBuilder( QUERY_ARTIFACTS_BY_PROJECT_VERSION_1 ).append( key ).append( QUERY_ARTIFACTS_BY_PROJECT_VERSION_2 ).toString();
831         return runJcrQuery( jcrSession, repositoryId, q, ImmutableMap.of( "value", value ) );
832     }
833
834
835     @Override
836     public List<ArtifactMetadata> getArtifactsByMetadata( RepositorySession session, String key, String value, String repositoryId )
837         throws MetadataRepositoryException
838     {
839         final Session jcrSession = getSession( session );
840         final String q = new StringBuilder( QUERY_ARTIFACTS_BY_METADATA_1 ).append( key ).append( QUERY_ARTIFACTS_BY_METADATA_2 ).toString( );
841         return runJcrQuery( jcrSession, repositoryId, q, ImmutableMap.of( "value", value ) );
842     }
843
844
845     @Override
846     public List<ArtifactMetadata> getArtifactsByProperty( RepositorySession session, String key, String value, String repositoryId )
847         throws MetadataRepositoryException
848     {
849         final Session jcrSession = getSession( session );
850         final String q = new StringBuilder( QUERY_ARTIFACTS_BY_PROPERTY_1 ).append( key ).append( QUERY_ARTIFACTS_BY_PROPERTY_2 ).toString();
851         return runJcrQuery( jcrSession, repositoryId, q, ImmutableMap.of( "value", value ) );
852     }
853
854
855     @Override
856     public void removeRepository( RepositorySession session, String repositoryId )
857         throws MetadataRepositoryException
858     {
859         final Session jcrSession = getSession( session );
860         try
861         {
862             Node root = jcrSession.getRootNode();
863             String path = getRepositoryPath( repositoryId );
864             if ( root.hasNode( path ) )
865             {
866                 root.getNode( path ).remove();
867             }
868         }
869         catch ( RepositoryException e )
870         {
871             throw new MetadataRepositoryException( e.getMessage(), e );
872         }
873     }
874
875     @Override
876     public List<ArtifactMetadata> getArtifacts( RepositorySession session, String repositoryId )
877         throws MetadataRepositoryException
878     {
879         final Session jcrSession = getSession( session );
880         List<ArtifactMetadata> artifacts;
881
882         String q = getArtifactQuery( repositoryId );
883
884         try
885         {
886             Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
887             QueryResult result = query.execute();
888
889             artifacts = new ArrayList<>();
890             for ( Node n : JcrUtils.getNodes( result ) )
891             {
892                 if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ) )
893                 {
894                     artifacts.add( getArtifactFromNode( repositoryId, n ) );
895                 }
896             }
897         }
898         catch ( RepositoryException e )
899         {
900             throw new MetadataRepositoryException( e.getMessage(), e );
901         }
902         return artifacts;
903     }
904
905     private static String getArtifactQuery( String repositoryId )
906     {
907         return new StringBuilder(QUERY_ARTIFACT_1).append(getRepositoryContentPath( repositoryId )).append(QUERY_ARTIFACT_2).toString();
908     }
909
910     @Override
911     public ProjectMetadata getProject( RepositorySession session, String repositoryId, String namespace, String projectId )
912         throws MetadataResolutionException
913     {
914         final Session jcrSession;
915         try
916         {
917             jcrSession = getSession( session );
918         }
919         catch ( MetadataRepositoryException e )
920         {
921             throw new MetadataResolutionException( e.getMessage() );
922         }
923         ProjectMetadata metadata = null;
924
925         try
926         {
927             Node root = jcrSession.getRootNode();
928
929             // basically just checking it exists
930             String path = getProjectPath( repositoryId, namespace, projectId );
931             if ( root.hasNode( path ) )
932             {
933                 metadata = new ProjectMetadata();
934                 metadata.setId( projectId );
935                 metadata.setNamespace( namespace );
936             }
937         }
938         catch ( RepositoryException e )
939         {
940             throw new MetadataResolutionException( e.getMessage(), e );
941         }
942
943         return metadata;
944     }
945
946     @Override
947     public ProjectVersionMetadata getProjectVersion( RepositorySession session, String repositoryId, String namespace, String projectId,
948                                                      String projectVersion )
949         throws MetadataResolutionException
950     {
951         final Session jcrSession;
952         try
953         {
954             jcrSession = getSession( session );
955         }
956         catch ( MetadataRepositoryException e )
957         {
958             throw new MetadataResolutionException( e.getMessage() );
959         }
960         ProjectVersionMetadata versionMetadata;
961
962         try
963         {
964             Node root = jcrSession.getRootNode();
965
966             String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
967             if ( !root.hasNode( path ) )
968             {
969                 return null;
970             }
971
972             Node node = root.getNode( path );
973
974             versionMetadata = new ProjectVersionMetadata();
975             versionMetadata.setId( projectVersion );
976             versionMetadata.setName( getPropertyString( node, "name" ) );
977             versionMetadata.setDescription( getPropertyString( node, "description" ) );
978             versionMetadata.setUrl( getPropertyString( node, "url" ) );
979             versionMetadata.setIncomplete(
980                 node.hasProperty( "incomplete" ) && node.getProperty( "incomplete" ).getBoolean() );
981
982             // FIXME: decide how to treat these in the content repo
983             String scmConnection = getPropertyString( node, "scm.connection" );
984             String scmDeveloperConnection = getPropertyString( node, "scm.developerConnection" );
985             String scmUrl = getPropertyString( node, "scm.url" );
986             if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
987             {
988                 Scm scm = new Scm();
989                 scm.setConnection( scmConnection );
990                 scm.setDeveloperConnection( scmDeveloperConnection );
991                 scm.setUrl( scmUrl );
992                 versionMetadata.setScm( scm );
993             }
994
995             String ciSystem = getPropertyString( node, "ci.system" );
996             String ciUrl = getPropertyString( node, "ci.url" );
997             if ( ciSystem != null || ciUrl != null )
998             {
999                 CiManagement ci = new CiManagement();
1000                 ci.setSystem( ciSystem );
1001                 ci.setUrl( ciUrl );
1002                 versionMetadata.setCiManagement( ci );
1003             }
1004
1005             String issueSystem = getPropertyString( node, "issue.system" );
1006             String issueUrl = getPropertyString( node, "issue.url" );
1007             if ( issueSystem != null || issueUrl != null )
1008             {
1009                 IssueManagement issueManagement = new IssueManagement();
1010                 issueManagement.setSystem( issueSystem );
1011                 issueManagement.setUrl( issueUrl );
1012                 versionMetadata.setIssueManagement( issueManagement );
1013             }
1014
1015             String orgName = getPropertyString( node, "org.name" );
1016             String orgUrl = getPropertyString( node, "org.url" );
1017             if ( orgName != null || orgUrl != null )
1018             {
1019                 Organization org = new Organization();
1020                 org.setName( orgName );
1021                 org.setUrl( orgUrl );
1022                 versionMetadata.setOrganization( org );
1023             }
1024
1025             boolean done = false;
1026             int i = 0;
1027             while ( !done )
1028             {
1029                 String licenseName = getPropertyString( node, "license." + i + ".name" );
1030                 String licenseUrl = getPropertyString( node, "license." + i + ".url" );
1031                 if ( licenseName != null || licenseUrl != null )
1032                 {
1033                     License license = new License();
1034                     license.setName( licenseName );
1035                     license.setUrl( licenseUrl );
1036                     versionMetadata.addLicense( license );
1037                 }
1038                 else
1039                 {
1040                     done = true;
1041                 }
1042                 i++;
1043             }
1044
1045             done = false;
1046             i = 0;
1047             while ( !done )
1048             {
1049                 String mailingListName = getPropertyString( node, "mailingList." + i + ".name" );
1050                 if ( mailingListName != null )
1051                 {
1052                     MailingList mailingList = new MailingList();
1053                     mailingList.setName( mailingListName );
1054                     mailingList.setMainArchiveUrl( getPropertyString( node, "mailingList." + i + ".archive" ) );
1055                     String n = "mailingList." + i + ".otherArchives";
1056                     if ( node.hasProperty( n ) )
1057                     {
1058                         mailingList.setOtherArchives( Arrays.asList( getPropertyString( node, n ).split( "," ) ) );
1059                     }
1060                     else
1061                     {
1062                         mailingList.setOtherArchives( Collections.<String>emptyList() );
1063                     }
1064                     mailingList.setPostAddress( getPropertyString( node, "mailingList." + i + ".post" ) );
1065                     mailingList.setSubscribeAddress( getPropertyString( node, "mailingList." + i + ".subscribe" ) );
1066                     mailingList.setUnsubscribeAddress( getPropertyString( node, "mailingList." + i + ".unsubscribe" ) );
1067                     versionMetadata.addMailingList( mailingList );
1068                 }
1069                 else
1070                 {
1071                     done = true;
1072                 }
1073                 i++;
1074             }
1075
1076             if ( node.hasNode( "dependencies" ) )
1077             {
1078                 Node dependenciesNode = node.getNode( "dependencies" );
1079                 for ( Node n : JcrUtils.getChildNodes( dependenciesNode ) )
1080                 {
1081                     if ( n.isNodeType( DEPENDENCY_NODE_TYPE ) )
1082                     {
1083                         Dependency dependency = new Dependency();
1084                         // FIXME: correct these properties
1085                         dependency.setArtifactId( getPropertyString( n, "artifactId" ) );
1086                         dependency.setGroupId( getPropertyString( n, "groupId" ) );
1087                         dependency.setClassifier( getPropertyString( n, "classifier" ) );
1088                         dependency.setOptional( Boolean.valueOf( getPropertyString( n, "optional" ) ) );
1089                         dependency.setScope( getPropertyString( n, "scope" ) );
1090                         dependency.setSystemPath( getPropertyString( n, "systemPath" ) );
1091                         dependency.setType( getPropertyString( n, "type" ) );
1092                         dependency.setVersion( getPropertyString( n, "version" ) );
1093                         versionMetadata.addDependency( dependency );
1094                     }
1095                 }
1096             }
1097
1098             retrieveFacetProperties( versionMetadata, node );
1099         }
1100         catch ( RepositoryException e )
1101         {
1102             throw new MetadataResolutionException( e.getMessage(), e );
1103         }
1104
1105         return versionMetadata;
1106     }
1107
1108     private void retrieveFacetProperties( FacetedMetadata metadata, Node node ) throws RepositoryException
1109     {
1110         for ( Node n : JcrUtils.getChildNodes( node ) )
1111         {
1112             if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE ) )
1113             {
1114                 String name = n.getName();
1115                 MetadataFacetFactory factory = metadataFacetFactories.get( name );
1116                 if ( factory == null )
1117                 {
1118                     log.error( "Attempted to load unknown project version metadata facet: {}", name );
1119                 }
1120                 else
1121                 {
1122                     MetadataFacet facet = factory.createMetadataFacet();
1123                     Map<String, String> map = new HashMap<>();
1124                     for ( Property property : JcrUtils.getProperties( n ) )
1125                     {
1126                         String p = property.getName();
1127                         if ( !p.startsWith( "jcr:" ) )
1128                         {
1129                             map.put( p, property.getString() );
1130                         }
1131                     }
1132                     facet.fromProperties( map );
1133                     metadata.addFacet( facet );
1134                 }
1135             }
1136         }
1137     }
1138
1139     @Override
1140     public Collection<String> getArtifactVersions( RepositorySession session, String repositoryId, String namespace, String projectId,
1141                                                    String projectVersion )
1142         throws MetadataResolutionException
1143     {
1144         final Session jcrSession;
1145         try
1146         {
1147             jcrSession = getSession( session );
1148         }
1149         catch ( MetadataRepositoryException e )
1150         {
1151             throw new MetadataResolutionException( e.getMessage() );
1152         }
1153         Set<String> versions = new LinkedHashSet<String>();
1154
1155         try
1156         {
1157             Node root = jcrSession.getRootNode();
1158
1159             Node node = root.getNode( getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) );
1160
1161             for ( Node n : JcrUtils.getChildNodes( node ) )
1162             {
1163                 versions.add( n.getProperty( "version" ).getString() );
1164             }
1165         }
1166         catch ( PathNotFoundException e )
1167         {
1168             // ignore repo not found for now
1169         }
1170         catch ( RepositoryException e )
1171         {
1172             throw new MetadataResolutionException( e.getMessage(), e );
1173         }
1174
1175         return versions;
1176     }
1177
1178     @Override
1179     public Collection<ProjectVersionReference> getProjectReferences( RepositorySession session, String repositoryId, String namespace,
1180                                                                      String projectId, String projectVersion )
1181         throws MetadataResolutionException
1182     {
1183         final Session jcrSession;
1184         try
1185         {
1186             jcrSession = getSession( session );
1187         }
1188         catch ( MetadataRepositoryException e )
1189         {
1190             throw new MetadataResolutionException( e.getMessage() );
1191         }
1192
1193         List<ProjectVersionReference> references = new ArrayList<>();
1194
1195         // TODO: bind variables instead
1196         String q = "SELECT * FROM [archiva:dependency] WHERE ISDESCENDANTNODE([/repositories/" + repositoryId
1197             + "/content]) AND [groupId]='" + namespace + "' AND [artifactId]='" + projectId + "'";
1198         if ( projectVersion != null )
1199         {
1200             q += " AND [version]='" + projectVersion + "'";
1201         }
1202         try
1203         {
1204             Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
1205             QueryResult result = query.execute();
1206
1207             for ( Node n : JcrUtils.getNodes( result ) )
1208             {
1209                 n = n.getParent(); // dependencies grouping element
1210
1211                 n = n.getParent(); // project version
1212                 String usedByProjectVersion = n.getName();
1213
1214                 n = n.getParent(); // project
1215                 String usedByProject = n.getName();
1216
1217                 n = n.getParent(); // namespace
1218                 String usedByNamespace = n.getProperty( "namespace" ).getString();
1219
1220                 ProjectVersionReference ref = new ProjectVersionReference();
1221                 ref.setNamespace( usedByNamespace );
1222                 ref.setProjectId( usedByProject );
1223                 ref.setProjectVersion( usedByProjectVersion );
1224                 ref.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
1225                 references.add( ref );
1226             }
1227         }
1228         catch ( RepositoryException e )
1229         {
1230             throw new MetadataResolutionException( e.getMessage(), e );
1231         }
1232
1233         return references;
1234     }
1235
1236     @Override
1237     public Collection<String> getRootNamespaces( RepositorySession session, String repositoryId )
1238         throws MetadataResolutionException
1239     {
1240         return getNamespaces(session , repositoryId, null );
1241     }
1242
1243     @Override
1244     public Collection<String> getNamespaces( RepositorySession session, String repositoryId, String baseNamespace )
1245         throws MetadataResolutionException
1246     {
1247         String path = baseNamespace != null
1248             ? getNamespacePath( repositoryId, baseNamespace )
1249             : getRepositoryContentPath( repositoryId );
1250
1251         try
1252         {
1253             return getNodeNames( getSession(session), path, org.apache.archiva.metadata.repository.jcr.JcrConstants.NAMESPACE_NODE_TYPE );
1254         }
1255         catch ( MetadataRepositoryException e )
1256         {
1257             throw new MetadataResolutionException( e.getMessage( ) );
1258         }
1259     }
1260
1261     @Override
1262     public Collection<String> getProjects( RepositorySession session, String repositoryId, String namespace )
1263         throws MetadataResolutionException
1264     {
1265         try
1266         {
1267             return getNodeNames( getSession(session), getNamespacePath( repositoryId, namespace ), org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_NODE_TYPE );
1268         }
1269         catch ( MetadataRepositoryException e )
1270         {
1271             throw new MetadataResolutionException( e.getMessage( ) );
1272         }
1273     }
1274
1275     @Override
1276     public Collection<String> getProjectVersions( RepositorySession session, String repositoryId, String namespace, String projectId )
1277         throws MetadataResolutionException
1278     {
1279         try
1280         {
1281             return getNodeNames( getSession(session), getProjectPath( repositoryId, namespace, projectId ), org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE );
1282         }
1283         catch ( MetadataRepositoryException e )
1284         {
1285             throw new MetadataResolutionException( e.getMessage( ) );
1286         }
1287     }
1288
1289     @Override
1290     public void removeArtifact( RepositorySession session, ArtifactMetadata artifactMetadata, String baseVersion )
1291         throws MetadataRepositoryException
1292     {
1293         final Session jcrSession = getSession( session );
1294         String repositoryId = artifactMetadata.getRepositoryId();
1295
1296         try
1297         {
1298             Node root = jcrSession.getRootNode();
1299             String path =
1300                 getProjectVersionPath( repositoryId, artifactMetadata.getNamespace(), artifactMetadata.getProject(),
1301                                        baseVersion );
1302
1303             if ( root.hasNode( path ) )
1304             {
1305                 Node node = root.getNode( path );
1306
1307                 for ( Node n : JcrUtils.getChildNodes( node ) )
1308                 {
1309                     if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ) )
1310                     {
1311                         if ( n.hasProperty( "version" ) )
1312                         {
1313                             String version = n.getProperty( "version" ).getString();
1314                             if ( StringUtils.equals( version, artifactMetadata.getVersion() ) )
1315                             {
1316                                 n.remove();
1317                             }
1318                         }
1319
1320                     }
1321                 }
1322             }
1323         }
1324         catch ( RepositoryException e )
1325         {
1326             throw new MetadataRepositoryException( e.getMessage(), e );
1327         }
1328
1329
1330     }
1331
1332
1333     @Override
1334     public void removeProjectVersion( RepositorySession session, String repoId, String namespace, String projectId, String projectVersion )
1335         throws MetadataRepositoryException
1336     {
1337         final Session jcrSession = getSession( session );
1338         try
1339         {
1340
1341             String path = getProjectPath( repoId, namespace, projectId );
1342             Node root = jcrSession.getRootNode();
1343
1344             Node nodeAtPath = root.getNode( path );
1345
1346             for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1347             {
1348                 if ( node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE ) && StringUtils.equals( projectVersion,
1349                                                                                          node.getName() ) )
1350                 {
1351                     node.remove();
1352                 }
1353             }
1354         }
1355         catch ( RepositoryException e )
1356         {
1357             throw new MetadataRepositoryException( e.getMessage(), e );
1358         }
1359     }
1360
1361     @Override
1362     public void removeArtifact( RepositorySession session, String repositoryId, String namespace, String projectId, String projectVersion,
1363                                 String id )
1364         throws MetadataRepositoryException
1365     {
1366         final Session jcrSession = getSession( session );
1367         try
1368         {
1369             Node root = jcrSession.getRootNode();
1370             String path = getArtifactPath( repositoryId, namespace, projectId, projectVersion, id );
1371             if ( root.hasNode( path ) )
1372             {
1373                 root.getNode( path ).remove();
1374             }
1375
1376             // remove version
1377
1378             path = getProjectPath( repositoryId, namespace, projectId );
1379
1380             Node nodeAtPath = root.getNode( path );
1381
1382             for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1383             {
1384                 if ( node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE ) //
1385                     && StringUtils.equals( node.getName(), projectVersion ) )
1386                 {
1387                     node.remove();
1388                 }
1389             }
1390         }
1391         catch ( RepositoryException e )
1392         {
1393             throw new MetadataRepositoryException( e.getMessage(), e );
1394         }
1395     }
1396
1397     @Override
1398     public void removeArtifact( RepositorySession session, String repositoryId, String namespace, String project, String projectVersion,
1399                                 MetadataFacet metadataFacet )
1400         throws MetadataRepositoryException
1401     {
1402         final Session jcrSession = getSession( session );
1403         try
1404         {
1405             Node root = jcrSession.getRootNode();
1406             String path = getProjectVersionPath( repositoryId, namespace, project, projectVersion );
1407
1408             if ( root.hasNode( path ) )
1409             {
1410                 Node node = root.getNode( path );
1411
1412                 for ( Node n : JcrUtils.getChildNodes( node ) )
1413                 {
1414                     if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ) )
1415                     {
1416                         ArtifactMetadata artifactMetadata = getArtifactFromNode( repositoryId, n );
1417                         log.debug( "artifactMetadata: {}", artifactMetadata );
1418                         MetadataFacet metadataFacetToRemove = artifactMetadata.getFacet( metadataFacet.getFacetId() );
1419                         if ( metadataFacetToRemove != null && metadataFacet.equals( metadataFacetToRemove ) )
1420                         {
1421                             n.remove();
1422                         }
1423                     }
1424                 }
1425             }
1426         }
1427         catch ( RepositoryException e )
1428         {
1429             throw new MetadataRepositoryException( e.getMessage(), e );
1430         }
1431     }
1432
1433     @Override
1434     public Collection<ArtifactMetadata> getArtifacts( RepositorySession session, String repositoryId, String namespace, String projectId,
1435                                                       String projectVersion )
1436         throws MetadataResolutionException
1437     {
1438         final Session jcrSession;
1439         try
1440         {
1441             jcrSession = getSession( session );
1442         }
1443         catch ( MetadataRepositoryException e )
1444         {
1445             throw new MetadataResolutionException( e.getMessage( ) );
1446         }
1447         List<ArtifactMetadata> artifacts = new ArrayList<>();
1448
1449         try
1450         {
1451             Node root = jcrSession.getRootNode();
1452             String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
1453
1454             if ( root.hasNode( path ) )
1455             {
1456                 Node node = root.getNode( path );
1457
1458                 for ( Node n : JcrUtils.getChildNodes( node ) )
1459                 {
1460                     if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ) )
1461                     {
1462                         artifacts.add( getArtifactFromNode( repositoryId, n ) );
1463                     }
1464                 }
1465             }
1466         }
1467         catch ( RepositoryException e )
1468         {
1469             throw new MetadataResolutionException( e.getMessage(), e );
1470         }
1471
1472         return artifacts;
1473     }
1474
1475
1476     @Override
1477     public boolean canObtainAccess( Class<?> aClass )
1478     {
1479         return aClass == Session.class;
1480     }
1481
1482     @SuppressWarnings( "unchecked" )
1483     @Override
1484     public <T> T obtainAccess( RepositorySession session, Class<T> aClass )
1485         throws MetadataRepositoryException
1486     {
1487         if ( aClass == Session.class )
1488         {
1489             return (T) getSession( session );
1490         }
1491         throw new IllegalArgumentException(
1492             "Access using " + aClass + " is not supported on the JCR metadata storage" );
1493     }
1494
1495     @Override
1496     public void close()
1497         throws MetadataRepositoryException
1498     {
1499     }
1500
1501
1502     /**
1503      * Exact is ignored as we can't do exact search in any property, we need a key
1504      */
1505     @Override
1506     public List<ArtifactMetadata> searchArtifacts( RepositorySession session, String repositoryId, String text, boolean exact )
1507         throws MetadataRepositoryException
1508     {
1509         return searchArtifacts( session, repositoryId, null, text, exact );
1510     }
1511
1512     @Override
1513     public List<ArtifactMetadata> searchArtifacts( RepositorySession session, String repositoryId, String key, String text, boolean exact )
1514         throws MetadataRepositoryException
1515     {
1516         final Session jcrSession = getSession( session );
1517         String theKey = key == null ? "*" : "[" + key + "]";
1518         String projectVersionCondition =
1519             exact ? "(projectVersion." + theKey + " = $value)" : "contains([projectVersion]." + theKey + ", $value)";
1520         String facetCondition = exact ? "(facet." + theKey + " = $value)" : "contains([facet]." + theKey + ", $value)";
1521         String descendantCondition = repositoryId == null ?
1522             " AND [projectVersion].[jcr:path] LIKE '/repositories/%/content/%'" :
1523             " AND ISDESCENDANTNODE(projectVersion,'/" + getRepositoryContentPath( repositoryId ) + "')";
1524         List<ArtifactMetadata> result = new ArrayList<>( );
1525         if (key==null || (key!=null && Arrays.binarySearch( PROJECT_VERSION_VERSION_PROPERTIES, key )>=0))
1526         {
1527             // We search only for project version properties if the key is a valid property name
1528             String q1 =
1529                 "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE
1530                     + "] AS projectVersion LEFT OUTER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE
1531                     + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) WHERE " + projectVersionCondition + descendantCondition;
1532              result.addAll(runJcrQuery( jcrSession, repositoryId, q1, ImmutableMap.of( "value", text ), false ));
1533         }
1534         String q2 =
1535             "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE
1536                 + "] AS projectVersion LEFT OUTER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE
1537                 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) LEFT OUTER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE
1538                 + "] AS facet ON ISCHILDNODE(facet, projectVersion) WHERE " + facetCondition + descendantCondition;
1539         result.addAll( runJcrQuery( jcrSession, repositoryId, q2, ImmutableMap.of( "value", text ), false ) );
1540         return result;
1541     }
1542
1543     private ArtifactMetadata getArtifactFromNode( String repositoryId, Node artifactNode )
1544         throws RepositoryException
1545     {
1546         String id = artifactNode.getName();
1547
1548         ArtifactMetadata artifact = new ArtifactMetadata();
1549         artifact.setId( id );
1550         artifact.setRepositoryId( repositoryId == null ? artifactNode.getAncestor( 2 ).getName() : repositoryId );
1551
1552         Node projectVersionNode = artifactNode.getParent();
1553         Node projectNode = projectVersionNode.getParent();
1554         Node namespaceNode = projectNode.getParent();
1555
1556         artifact.setNamespace( namespaceNode.getProperty( "namespace" ).getString() );
1557         artifact.setProject( projectNode.getName() );
1558         artifact.setProjectVersion( projectVersionNode.getName() );
1559         artifact.setVersion( artifactNode.hasProperty( "version" )
1560                                  ? artifactNode.getProperty( "version" ).getString()
1561                                  : projectVersionNode.getName() );
1562
1563         if ( artifactNode.hasProperty( JCR_LAST_MODIFIED ) )
1564         {
1565             artifact.setFileLastModified( artifactNode.getProperty( JCR_LAST_MODIFIED ).getDate().getTimeInMillis() );
1566         }
1567
1568         if ( artifactNode.hasProperty( "whenGathered" ) )
1569         {
1570             artifact.setWhenGathered( artifactNode.getProperty( "whenGathered" ).getDate().getTime() );
1571         }
1572
1573         if ( artifactNode.hasProperty( "size" ) )
1574         {
1575             artifact.setSize( artifactNode.getProperty( "size" ).getLong() );
1576         }
1577
1578         if ( artifactNode.hasProperty( "md5" ) )
1579         {
1580             artifact.setMd5( artifactNode.getProperty( "md5" ).getString() );
1581         }
1582
1583         if ( artifactNode.hasProperty( "sha1" ) )
1584         {
1585             artifact.setSha1( artifactNode.getProperty( "sha1" ).getString() );
1586         }
1587
1588         retrieveFacetProperties( artifact, artifactNode );
1589         return artifact;
1590     }
1591
1592     private static String getPropertyString( Node node, String name )
1593         throws RepositoryException
1594     {
1595         return node.hasProperty( name ) ? node.getProperty( name ).getString() : null;
1596     }
1597
1598     private Collection<String> getNodeNames( Session jcrSession, String path, String nodeType )
1599         throws MetadataResolutionException
1600     {
1601
1602         List<String> names = new ArrayList<>();
1603
1604         try
1605         {
1606             Node root = jcrSession.getRootNode();
1607
1608             Node nodeAtPath = root.getNode( path );
1609
1610             for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1611             {
1612                 if ( node.isNodeType( nodeType ) )
1613                 {
1614                     names.add( node.getName() );
1615                 }
1616             }
1617         }
1618         catch ( PathNotFoundException e )
1619         {
1620             // ignore repo not found for now
1621         }
1622         catch ( RepositoryException e )
1623         {
1624             throw new MetadataResolutionException( e.getMessage(), e );
1625         }
1626
1627         return names;
1628     }
1629
1630     private static String getRepositoryPath( String repositoryId )
1631     {
1632         return "repositories/" + repositoryId;
1633     }
1634
1635     private static String getRepositoryContentPath( String repositoryId )
1636     {
1637         return getRepositoryPath( repositoryId ) + "/content";
1638     }
1639
1640     private static String getFacetPath( String repositoryId, String facetId )
1641     {
1642         return getRepositoryPath( repositoryId ) + "/facets/" + facetId;
1643     }
1644
1645     private static String getNamespacePath( String repositoryId, String namespace )
1646     {
1647         return getRepositoryContentPath( repositoryId ) + "/" + namespace.replace( '.', '/' );
1648     }
1649
1650     private static String getProjectPath( String repositoryId, String namespace, String projectId )
1651     {
1652         return getNamespacePath( repositoryId, namespace ) + "/" + projectId;
1653     }
1654
1655     private static String getProjectVersionPath( String repositoryId, String namespace, String projectId,
1656                                                  String projectVersion )
1657     {
1658         return getProjectPath( repositoryId, namespace, projectId ) + "/" + projectVersion;
1659     }
1660
1661     private static String getArtifactPath( String repositoryId, String namespace, String projectId,
1662                                            String projectVersion, String id )
1663     {
1664         return getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) + "/" + id;
1665     }
1666
1667     private Node getOrAddNodeByPath( Node baseNode, String name )
1668         throws RepositoryException
1669     {
1670         return getOrAddNodeByPath( baseNode, name, null );
1671     }
1672
1673     private Node getOrAddNodeByPath( Node baseNode, String name, String nodeType )
1674         throws RepositoryException
1675     {
1676         log.debug( "getOrAddNodeByPath " + baseNode + " " + name + " " + nodeType );
1677         Node node = baseNode;
1678         for ( String n : name.split( "/" ) )
1679         {
1680             node = JcrUtils.getOrAddNode( node, n );
1681             if ( nodeType != null && !node.isNodeType( nodeType ))
1682             {
1683                 node.addMixin( nodeType );
1684             }
1685             if (!node.hasProperty( "id" )) {
1686                 node.setProperty( "id", n );
1687             }
1688         }
1689         return node;
1690     }
1691
1692     private static String getFacetPath( String repositoryId, String facetId, String name )
1693     {
1694         return getFacetPath( repositoryId, facetId ) + "/" + name;
1695     }
1696
1697     private Node getOrAddRepositoryNode( Session jcrSession, String repositoryId )
1698         throws RepositoryException
1699     {
1700         log.debug( "getOrAddRepositoryNode " + repositoryId );
1701         Node root = jcrSession.getRootNode();
1702         Node node = JcrUtils.getOrAddNode( root, "repositories" );
1703         log.debug( "Repositories " + node );
1704         node = JcrUtils.getOrAddNode( node, repositoryId, JcrConstants.NT_UNSTRUCTURED );
1705         if (!node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.REPOSITORY_NODE_TYPE )) {
1706             node.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.REPOSITORY_NODE_TYPE );
1707         }
1708         if (!node.hasProperty( "id" )) {
1709             node.setProperty( "id", repositoryId );
1710         }
1711         return node;
1712     }
1713
1714     private Node getOrAddRepositoryContentNode( Session jcrSession, String repositoryId )
1715         throws RepositoryException
1716     {
1717         Node node = getOrAddRepositoryNode( jcrSession, repositoryId );
1718         return JcrUtils.getOrAddNode( node, "content" );
1719     }
1720
1721     private Node getOrAddNamespaceNode( Session jcrSession, String repositoryId, String namespace )
1722         throws RepositoryException
1723     {
1724         Node repo = getOrAddRepositoryContentNode( jcrSession, repositoryId );
1725         return getOrAddNodeByPath( repo, namespace.replace( '.', '/' ), org.apache.archiva.metadata.repository.jcr.JcrConstants.NAMESPACE_NODE_TYPE );
1726     }
1727
1728     private Node getOrAddProjectNode( Session jcrSession, String repositoryId, String namespace, String projectId )
1729         throws RepositoryException
1730     {
1731         Node namespaceNode = getOrAddNamespaceNode( jcrSession, repositoryId, namespace );
1732         Node node = JcrUtils.getOrAddNode( namespaceNode, projectId );
1733         if (!node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_NODE_TYPE ))
1734         {
1735             node.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_NODE_TYPE );
1736         }
1737         if (!node.hasProperty( "id" ))
1738         {
1739             node.setProperty( "id", projectId );
1740         }
1741         return node;
1742     }
1743
1744     private Node getOrAddProjectVersionNode( Session jcrSession, String repositoryId, String namespace, String projectId,
1745                                              String projectVersion )
1746         throws RepositoryException
1747     {
1748         Node projectNode = getOrAddProjectNode( jcrSession, repositoryId, namespace, projectId );
1749         log.debug( "Project node {}", projectNode );
1750         Node projectVersionNode = JcrUtils.getOrAddNode( projectNode, projectVersion, JcrConstants.NT_UNSTRUCTURED);
1751         if (!projectVersionNode.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE ))
1752         {
1753             projectVersionNode.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE );
1754         }
1755         if (!projectVersionNode.hasProperty( "id" ))
1756         {
1757             projectVersionNode.setProperty( "id", projectVersion );
1758         }
1759
1760         log.debug( "Project version node {}", projectVersionNode );
1761         return projectVersionNode;
1762     }
1763
1764     private Node getOrAddArtifactNode( Session jcrSession, String repositoryId, String namespace, String projectId, String projectVersion,
1765                                        String id )
1766         throws RepositoryException
1767     {
1768         Node versionNode = getOrAddProjectVersionNode( jcrSession, repositoryId, namespace, projectId, projectVersion );
1769         Node node = JcrUtils.getOrAddNode( versionNode, id);
1770         if (!node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ))
1771         {
1772             node.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE );
1773         }
1774         if (!node.hasProperty( "id" )) {
1775             node.setProperty( "id", id );
1776         }
1777         return node;
1778     }
1779
1780     private static Calendar createCalendar( Date time )
1781     {
1782         Calendar cal = Calendar.getInstance();
1783         cal.setTime( time );
1784         return cal;
1785     }
1786
1787     private String join( Collection<String> ids )
1788     {
1789         if ( ids != null && !ids.isEmpty() )
1790         {
1791             StringBuilder s = new StringBuilder();
1792             for ( String id : ids )
1793             {
1794                 s.append( id );
1795                 s.append( "," );
1796             }
1797             return s.substring( 0, s.length() - 1 );
1798         }
1799         return null;
1800     }
1801
1802
1803     @Override
1804     public void populateStatistics( RepositorySession repositorySession, MetadataRepository repository, String repositoryId,
1805                                     RepositoryStatistics repositoryStatistics )
1806         throws MetadataRepositoryException
1807     {
1808         if ( !( repository instanceof JcrMetadataRepository ) )
1809         {
1810             throw new MetadataRepositoryException(
1811                 "The statistics population is only possible for JcrMetdataRepository implementations" );
1812         }
1813         Session session = getSession( repositorySession );
1814         // TODO: these may be best as running totals, maintained by observations on the properties in JCR
1815
1816         try
1817         {
1818             QueryManager queryManager = session.getWorkspace().getQueryManager();
1819
1820             // TODO: Check, if this is still the case - Switched to Jackrabbit OAK with archiva 3.0
1821             // Former statement: JCR-SQL2 query will not complete on a large repo in Jackrabbit 2.2.0 - see JCR-2835
1822             //    Using the JCR-SQL2 variants gives
1823             //      "org.apache.lucene.search.BooleanQuery$TooManyClauses: maxClauseCount is set to 1024"
1824 //            String whereClause = "WHERE ISDESCENDANTNODE([/repositories/" + repositoryId + "/content])";
1825 //            Query query = queryManager.createQuery( "SELECT size FROM [archiva:artifact] " + whereClause,
1826 //                                                    Query.JCR_SQL2 );
1827             String whereClause = "WHERE ISDESCENDANTNODE([/repositories/" + repositoryId + "/content])";
1828             Query query = queryManager.createQuery( "SELECT size FROM [archiva:artifact] " + whereClause, Query.JCR_SQL2 );
1829
1830             QueryResult queryResult = query.execute();
1831
1832             Map<String, Integer> totalByType = new HashMap<>();
1833             long totalSize = 0, totalArtifacts = 0;
1834             for ( Row row : JcrUtils.getRows( queryResult ) )
1835             {
1836                 Node n = row.getNode();
1837                 totalSize += row.getValue( "size" ).getLong();
1838
1839                 String type;
1840                 if ( n.hasNode( MavenArtifactFacet.FACET_ID ) )
1841                 {
1842                     Node facetNode = n.getNode( MavenArtifactFacet.FACET_ID );
1843                     type = facetNode.getProperty( "type" ).getString();
1844                 }
1845                 else
1846                 {
1847                     type = "Other";
1848                 }
1849                 Integer prev = totalByType.get( type );
1850                 totalByType.put( type, prev != null ? prev + 1 : 1 );
1851
1852                 totalArtifacts++;
1853             }
1854
1855             repositoryStatistics.setTotalArtifactCount( totalArtifacts );
1856             repositoryStatistics.setTotalArtifactFileSize( totalSize );
1857             for ( Map.Entry<String, Integer> entry : totalByType.entrySet() )
1858             {
1859                 log.info( "Setting count for type: {} = {}", entry.getKey(), entry.getValue() );
1860                 repositoryStatistics.setTotalCountForType( entry.getKey(), entry.getValue() );
1861             }
1862
1863             // The query ordering is a trick to ensure that the size is correct, otherwise due to lazy init it will be -1
1864 //            query = queryManager.createQuery( "SELECT * FROM [archiva:project] " + whereClause, Query.JCR_SQL2 );
1865             query = queryManager.createQuery( "SELECT * FROM [archiva:project] " + whereClause + " ORDER BY [jcr:score]",
1866                                               Query.JCR_SQL2 );
1867             repositoryStatistics.setTotalProjectCount( query.execute().getRows().getSize() );
1868
1869 //            query = queryManager.createQuery(
1870 //                "SELECT * FROM [archiva:namespace] " + whereClause + " AND namespace IS NOT NULL", Query.JCR_SQL2 );
1871             query = queryManager.createQuery(
1872                 "SELECT * FROM [archiva:namespace] " + whereClause + " AND namespace IS NOT NULL ORDER BY [jcr:score]",
1873                 Query.JCR_SQL2 );
1874             repositoryStatistics.setTotalGroupCount( query.execute().getRows().getSize() );
1875         }
1876         catch ( RepositoryException e )
1877         {
1878             throw new MetadataRepositoryException( e.getMessage(), e );
1879         }
1880     }
1881
1882
1883     public Session login() throws RepositoryException
1884     {
1885         return repository.login(new SimpleCredentials( "admin", "admin".toCharArray() ) );
1886     }
1887 }