1 package org.apache.archiva.metadata.repository.jcr;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
22 import 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.IssueManagement;
27 import org.apache.archiva.metadata.model.License;
28 import org.apache.archiva.metadata.model.MailingList;
29 import org.apache.archiva.metadata.model.MetadataFacet;
30 import org.apache.archiva.metadata.model.MetadataFacetFactory;
31 import org.apache.archiva.metadata.model.Organization;
32 import org.apache.archiva.metadata.model.ProjectMetadata;
33 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
34 import org.apache.archiva.metadata.model.ProjectVersionReference;
35 import org.apache.archiva.metadata.model.Scm;
36 import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
37 import org.apache.archiva.metadata.repository.MetadataRepository;
38 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
39 import org.apache.archiva.metadata.repository.MetadataResolutionException;
40 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
41 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsProvider;
42 import org.apache.commons.lang.StringUtils;
43 import org.apache.jackrabbit.commons.JcrUtils;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 import javax.jcr.InvalidItemStateException;
48 import javax.jcr.NamespaceRegistry;
49 import javax.jcr.Node;
50 import javax.jcr.NodeIterator;
51 import javax.jcr.PathNotFoundException;
52 import javax.jcr.Property;
53 import javax.jcr.Repository;
54 import javax.jcr.RepositoryException;
55 import javax.jcr.Session;
56 import javax.jcr.SimpleCredentials;
57 import javax.jcr.ValueFactory;
58 import javax.jcr.Workspace;
59 import javax.jcr.nodetype.NodeTypeManager;
60 import javax.jcr.nodetype.NodeTypeTemplate;
61 import javax.jcr.query.Query;
62 import javax.jcr.query.QueryManager;
63 import javax.jcr.query.QueryResult;
64 import javax.jcr.query.Row;
65 import javax.jcr.query.RowIterator;
66 import java.util.ArrayList;
67 import java.util.Arrays;
68 import java.util.Calendar;
69 import java.util.Collection;
70 import java.util.Collections;
71 import java.util.Date;
72 import java.util.HashMap;
73 import java.util.Iterator;
74 import java.util.LinkedHashSet;
75 import java.util.List;
77 import java.util.Map.Entry;
81 * TODO below: revise storage format for project version metadata
82 * TODO revise reference storage
84 public class JcrMetadataRepository
85 implements MetadataRepository, RepositoryStatisticsProvider
88 private static final String JCR_LAST_MODIFIED = "jcr:lastModified";
90 static final String NAMESPACE_NODE_TYPE = "archiva:namespace";
92 static final String PROJECT_NODE_TYPE = "archiva:project";
94 static final String PROJECT_VERSION_NODE_TYPE = "archiva:projectVersion";
96 static final String ARTIFACT_NODE_TYPE = "archiva:artifact";
98 static final String FACET_NODE_TYPE = "archiva:facet";
100 private static final String DEPENDENCY_NODE_TYPE = "archiva:dependency";
102 private final Map<String, MetadataFacetFactory> metadataFacetFactories;
104 private Logger log = LoggerFactory.getLogger( JcrMetadataRepository.class );
106 private Repository repository;
108 private Session jcrSession;
110 public JcrMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories, Repository repository )
111 throws RepositoryException
113 this.metadataFacetFactories = metadataFacetFactories;
114 this.repository = repository;
118 public static void initialize( Session session )
119 throws RepositoryException
122 // TODO: consider using namespaces for facets instead of the current approach:
123 // (if used, check if actually called by normal injection)
124 // for ( String facetId : metadataFacetFactories.keySet() )
126 // session.getWorkspace().getNamespaceRegistry().registerNamespace( facetId, facetId );
128 Workspace workspace = session.getWorkspace();
129 NamespaceRegistry registry = workspace.getNamespaceRegistry();
131 if ( !Arrays.asList( registry.getPrefixes() ).contains( "archiva" ) )
133 registry.registerNamespace( "archiva", "http://archiva.apache.org/jcr/" );
136 NodeTypeManager nodeTypeManager = workspace.getNodeTypeManager();
137 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.NAMESPACE_NODE_TYPE );
138 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.PROJECT_NODE_TYPE );
139 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.PROJECT_VERSION_NODE_TYPE );
140 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.ARTIFACT_NODE_TYPE );
141 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.FACET_NODE_TYPE );
142 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.DEPENDENCY_NODE_TYPE );
147 private static void registerMixinNodeType( NodeTypeManager nodeTypeManager, String name )
148 throws RepositoryException
150 NodeTypeTemplate nodeType = nodeTypeManager.createNodeTypeTemplate();
151 nodeType.setMixin( true );
152 nodeType.setName( name );
154 // for now just don't re-create - but in future if we change the definition, make sure to remove first as an
156 if ( !nodeTypeManager.hasNodeType( name ) )
158 nodeTypeManager.registerNodeType( nodeType, false );
164 public void updateProject( String repositoryId, ProjectMetadata project )
165 throws MetadataRepositoryException
167 updateProject( repositoryId, project.getNamespace(), project.getId() );
170 private void updateProject( String repositoryId, String namespace, String projectId )
171 throws MetadataRepositoryException
173 updateNamespace( repositoryId, namespace );
177 getOrAddProjectNode( repositoryId, namespace, projectId );
179 catch ( RepositoryException e )
181 throw new MetadataRepositoryException( e.getMessage(), e );
186 public void updateArtifact( String repositoryId, String namespace, String projectId, String projectVersion,
187 ArtifactMetadata artifactMeta )
188 throws MetadataRepositoryException
190 updateNamespace( repositoryId, namespace );
195 getOrAddArtifactNode( repositoryId, namespace, projectId, projectVersion, artifactMeta.getId() );
197 Calendar cal = Calendar.getInstance();
198 cal.setTime( artifactMeta.getFileLastModified() );
199 node.setProperty( JCR_LAST_MODIFIED, cal );
201 cal = Calendar.getInstance();
202 cal.setTime( artifactMeta.getWhenGathered() );
203 node.setProperty( "whenGathered", cal );
205 node.setProperty( "size", artifactMeta.getSize() );
206 node.setProperty( "md5", artifactMeta.getMd5() );
207 node.setProperty( "sha1", artifactMeta.getSha1() );
209 node.setProperty( "version", artifactMeta.getVersion() );
211 // iterate over available facets to update/add/remove from the artifactMetadata
212 for ( String facetId : metadataFacetFactories.keySet() )
214 MetadataFacet metadataFacet = artifactMeta.getFacet( facetId );
215 if ( metadataFacet == null )
219 if ( node.hasNode( facetId ) )
221 node.getNode( facetId ).remove();
223 if ( metadataFacet != null )
225 // recreate, to ensure properties are removed
226 Node n = node.addNode( facetId );
227 n.addMixin( FACET_NODE_TYPE );
229 for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
231 n.setProperty( entry.getKey(), entry.getValue() );
236 catch ( RepositoryException e )
238 throw new MetadataRepositoryException( e.getMessage(), e );
243 public void updateProjectVersion( String repositoryId, String namespace, String projectId,
244 ProjectVersionMetadata versionMetadata )
245 throws MetadataRepositoryException
247 updateProject( repositoryId, namespace, projectId );
252 getOrAddProjectVersionNode( repositoryId, namespace, projectId, versionMetadata.getId() );
254 versionNode.setProperty( "name", versionMetadata.getName() );
255 versionNode.setProperty( "description", versionMetadata.getDescription() );
256 versionNode.setProperty( "url", versionMetadata.getUrl() );
257 versionNode.setProperty( "incomplete", versionMetadata.isIncomplete() );
259 // FIXME: decide how to treat these in the content repo
260 if ( versionMetadata.getScm() != null )
262 versionNode.setProperty( "scm.connection", versionMetadata.getScm().getConnection() );
263 versionNode.setProperty( "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
264 versionNode.setProperty( "scm.url", versionMetadata.getScm().getUrl() );
266 if ( versionMetadata.getCiManagement() != null )
268 versionNode.setProperty( "ci.system", versionMetadata.getCiManagement().getSystem() );
269 versionNode.setProperty( "ci.url", versionMetadata.getCiManagement().getUrl() );
271 if ( versionMetadata.getIssueManagement() != null )
273 versionNode.setProperty( "issue.system", versionMetadata.getIssueManagement().getSystem() );
274 versionNode.setProperty( "issue.url", versionMetadata.getIssueManagement().getUrl() );
276 if ( versionMetadata.getOrganization() != null )
278 versionNode.setProperty( "org.name", versionMetadata.getOrganization().getName() );
279 versionNode.setProperty( "org.url", versionMetadata.getOrganization().getUrl() );
282 for ( License license : versionMetadata.getLicenses() )
284 versionNode.setProperty( "license." + i + ".name", license.getName() );
285 versionNode.setProperty( "license." + i + ".url", license.getUrl() );
289 for ( MailingList mailingList : versionMetadata.getMailingLists() )
291 versionNode.setProperty( "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
292 versionNode.setProperty( "mailingList." + i + ".name", mailingList.getName() );
293 versionNode.setProperty( "mailingList." + i + ".post", mailingList.getPostAddress() );
294 versionNode.setProperty( "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
295 versionNode.setProperty( "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
296 versionNode.setProperty( "mailingList." + i + ".otherArchives",
297 join( mailingList.getOtherArchives() ) );
301 if ( !versionMetadata.getDependencies().isEmpty() )
303 Node dependenciesNode = JcrUtils.getOrAddNode( versionNode, "dependencies" );
305 for ( Dependency dependency : versionMetadata.getDependencies() )
307 // Note that we deliberately don't alter the namespace path - not enough dependencies for
308 // number of nodes at a given depth to be an issue. Similarly, we don't add subnodes for each
309 // component of the ID as that creates extra depth and causes a great cost in space and memory
311 // FIXME: change group ID to namespace
312 // FIXME: change to artifact's ID - this is constructed by the Maven 2 format for now.
313 // This won't support types where the extension doesn't match the type.
314 // (see also Maven2RepositoryStorage#readProjectVersionMetadata construction of POM)
316 dependency.getGroupId() + ";" + dependency.getArtifactId() + "-" + dependency.getVersion();
317 if ( dependency.getClassifier() != null )
319 id += "-" + dependency.getClassifier();
321 id += "." + dependency.getType();
323 Node n = JcrUtils.getOrAddNode( dependenciesNode, id );
324 n.addMixin( DEPENDENCY_NODE_TYPE );
326 // FIXME: remove temp code just to make it keep working
327 n.setProperty( "groupId", dependency.getGroupId() );
328 n.setProperty( "artifactId", dependency.getArtifactId() );
329 n.setProperty( "version", dependency.getVersion() );
330 n.setProperty( "type", dependency.getType() );
331 n.setProperty( "classifier", dependency.getClassifier() );
332 n.setProperty( "scope", dependency.getScope() );
333 n.setProperty( "systemPath", dependency.getSystemPath() );
334 n.setProperty( "optional", dependency.isOptional() );
336 // node has no native content at this time, just facets
337 // no need to list a type as it's implied by the path. Parents are Maven specific.
339 // FIXME: add scope, systemPath, type, version, classifier & maven2 specific IDs as a facet
340 // (should also have been added to the Dependency)
342 // TODO: add a property that is a weak reference to the originating artifact, creating it if
343 // necessary (without adding the archiva:artifact mixin so that it doesn't get listed as an
344 // artifact, which gives a different meaning to "incomplete" which is a known local project
345 // that doesn't have metadata yet but has artifacts). (Though we may want to give it the
346 // artifact mixin and another property to identify all non-local artifacts for the closure
351 for ( MetadataFacet facet : versionMetadata.getFacetList() )
353 // recreate, to ensure properties are removed
354 if ( versionNode.hasNode( facet.getFacetId() ) )
356 versionNode.getNode( facet.getFacetId() ).remove();
358 Node n = versionNode.addNode( facet.getFacetId() );
359 n.addMixin( FACET_NODE_TYPE );
361 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
363 n.setProperty( entry.getKey(), entry.getValue() );
367 catch ( RepositoryException e )
369 throw new MetadataRepositoryException( e.getMessage(), e );
374 public void updateNamespace( String repositoryId, String namespace )
375 throws MetadataRepositoryException
379 Node node = getOrAddNamespaceNode( repositoryId, namespace );
380 node.setProperty( "namespace", namespace );
382 catch ( RepositoryException e )
384 throw new MetadataRepositoryException( e.getMessage(), e );
389 public void removeProject( String repositoryId, String namespace, String projectId )
390 throws MetadataRepositoryException
394 Node root = getJcrSession().getRootNode();
395 String namespacePath = getNamespacePath( repositoryId, namespace );
397 if ( root.hasNode( namespacePath ) )
399 Iterator<Node> nodeIterator = JcrUtils.getChildNodes( root.getNode( namespacePath ) ).iterator();
400 while ( nodeIterator.hasNext() )
402 Node node = nodeIterator.next();
403 if ( node.isNodeType( PROJECT_NODE_TYPE ) && projectId.equals( node.getName() ) )
411 catch ( RepositoryException e )
413 throw new MetadataRepositoryException( e.getMessage(), e );
420 public boolean hasMetadataFacet( String repositoryId, String facetId )
421 throws MetadataRepositoryException
425 Node node = getJcrSession().getRootNode().getNode( getFacetPath( repositoryId, facetId ) );
426 return node.getNodes().hasNext();
428 catch ( PathNotFoundException e )
430 // ignored - the facet doesn't exist, so return false
433 catch ( RepositoryException e )
435 throw new MetadataRepositoryException( e.getMessage(), e );
440 public List<String> getMetadataFacets( String repositoryId, String facetId )
441 throws MetadataRepositoryException
443 List<String> facets = new ArrayList<>();
447 // no need to construct node-by-node here, as we'll find in the next instance, the facet names have / and
448 // are paths themselves
449 Node node = getJcrSession().getRootNode().getNode( getFacetPath( repositoryId, facetId ) );
451 // TODO: this is a bit awkward. Might be better to review the purpose of this function - why is the list of
453 recurse( facets, "", node );
455 catch ( PathNotFoundException e )
457 // ignored - the facet doesn't exist, so return the empty list
459 catch ( RepositoryException e )
461 throw new MetadataRepositoryException( e.getMessage(), e );
466 private void recurse( List<String> facets, String prefix, Node node )
467 throws RepositoryException
469 for ( Node n : JcrUtils.getChildNodes( node ) )
471 String name = prefix + "/" + n.getName();
474 recurse( facets, name, n );
478 // strip leading / first
479 facets.add( name.substring( 1 ) );
485 public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
486 throws MetadataRepositoryException
488 MetadataFacet metadataFacet = null;
491 Node root = getJcrSession().getRootNode();
492 Node node = root.getNode( getFacetPath( repositoryId, facetId, name ) );
494 if ( metadataFacetFactories == null )
496 return metadataFacet;
499 MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
500 if ( metadataFacetFactory != null )
502 metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
503 Map<String, String> map = new HashMap<>();
504 for ( Property property : JcrUtils.getProperties( node ) )
506 String p = property.getName();
507 if ( !p.startsWith( "jcr:" ) )
509 map.put( p, property.getString() );
512 metadataFacet.fromProperties( map );
515 catch ( PathNotFoundException e )
517 // ignored - the facet doesn't exist, so return null
519 catch ( RepositoryException e )
521 throw new MetadataRepositoryException( e.getMessage(), e );
523 return metadataFacet;
527 public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
528 throws MetadataRepositoryException
532 Node repo = getOrAddRepositoryNode( repositoryId );
533 Node facets = JcrUtils.getOrAddNode( repo, "facets" );
535 String id = metadataFacet.getFacetId();
536 Node facetNode = JcrUtils.getOrAddNode( facets, id );
538 Node node = getOrAddNodeByPath( facetNode, metadataFacet.getName() );
540 for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
542 node.setProperty( entry.getKey(), entry.getValue() );
545 catch ( RepositoryException e )
547 throw new MetadataRepositoryException( e.getMessage(), e );
552 public void removeNamespace( String repositoryId, String projectId )
553 throws MetadataRepositoryException
557 Node root = getJcrSession().getRootNode();
558 String path = getNamespacePath( repositoryId, projectId );
559 if ( root.hasNode( path ) )
561 Node node = root.getNode( path );
562 if ( node.isNodeType( NAMESPACE_NODE_TYPE ) )
568 catch ( RepositoryException e )
570 throw new MetadataRepositoryException( e.getMessage(), e );
575 public void removeMetadataFacets( String repositoryId, String facetId )
576 throws MetadataRepositoryException
580 Node root = getJcrSession().getRootNode();
581 String path = getFacetPath( repositoryId, facetId );
582 if ( root.hasNode( path ) )
584 root.getNode( path ).remove();
587 catch ( RepositoryException e )
589 throw new MetadataRepositoryException( e.getMessage(), e );
594 public void removeMetadataFacet( String repositoryId, String facetId, String name )
595 throws MetadataRepositoryException
599 Node root = getJcrSession().getRootNode();
600 String path = getFacetPath( repositoryId, facetId, name );
601 if ( root.hasNode( path ) )
603 Node node = root.getNode( path );
606 // also remove empty container nodes
607 Node parent = node.getParent();
611 while ( !node.hasNodes() );
614 catch ( RepositoryException e )
616 throw new MetadataRepositoryException( e.getMessage(), e );
621 public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
622 throws MetadataRepositoryException
624 List<ArtifactMetadata> artifacts;
626 String q = getArtifactQuery( repoId );
628 if ( startTime != null )
630 q += " AND [whenGathered] >= $start";
632 if ( endTime != null )
634 q += " AND [whenGathered] <= $end";
639 Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
640 ValueFactory valueFactory = getJcrSession().getValueFactory();
641 if ( startTime != null )
643 query.bindValue( "start", valueFactory.createValue( createCalendar( startTime ) ) );
645 if ( endTime != null )
647 query.bindValue( "end", valueFactory.createValue( createCalendar( endTime ) ) );
649 QueryResult result = query.execute();
651 artifacts = new ArrayList<>();
652 for ( Node n : JcrUtils.getNodes( result ) )
654 artifacts.add( getArtifactFromNode( repoId, n ) );
657 catch ( RepositoryException e )
659 throw new MetadataRepositoryException( e.getMessage(), e );
665 public Collection<String> getRepositories()
666 throws MetadataRepositoryException
668 List<String> repositories;
672 Node root = getJcrSession().getRootNode();
673 if ( root.hasNode( "repositories" ) )
675 Node node = root.getNode( "repositories" );
677 repositories = new ArrayList<>();
678 NodeIterator i = node.getNodes();
679 while ( i.hasNext() )
681 Node n = i.nextNode();
682 repositories.add( n.getName() );
687 repositories = Collections.emptyList();
690 catch ( RepositoryException e )
692 throw new MetadataRepositoryException( e.getMessage(), e );
698 public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
699 throws MetadataRepositoryException
701 List<ArtifactMetadata> artifacts;
703 String q = getArtifactQuery( repositoryId ) + " AND ([sha1] = $checksum OR [md5] = $checksum)";
707 Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
708 ValueFactory valueFactory = getJcrSession().getValueFactory();
709 query.bindValue( "checksum", valueFactory.createValue( checksum ) );
710 QueryResult result = query.execute();
712 artifacts = new ArrayList<>();
713 for ( Node n : JcrUtils.getNodes( result ) )
715 artifacts.add( getArtifactFromNode( repositoryId, n ) );
718 catch ( RepositoryException e )
720 throw new MetadataRepositoryException( e.getMessage(), e );
725 private List<ArtifactMetadata> runJcrQuery( String repositoryId, String q, Map<String, String> bindings )
726 throws MetadataRepositoryException
728 List<ArtifactMetadata> artifacts;
729 if ( repositoryId != null )
731 q += " AND ISDESCENDANTNODE(artifact,'/" + getRepositoryContentPath( repositoryId ) + "')";
734 log.info( "Running JCR Query: {}", q );
738 Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
739 ValueFactory valueFactory = getJcrSession().getValueFactory();
740 for ( Entry<String, String> entry : bindings.entrySet() )
742 query.bindValue( entry.getKey(), valueFactory.createValue( entry.getValue() ) );
744 long start = Calendar.getInstance().getTimeInMillis();
745 QueryResult result = query.execute();
746 long end = Calendar.getInstance().getTimeInMillis();
747 log.info( "JCR Query ran in {} milliseconds: {}", end - start, q );
749 artifacts = new ArrayList<>();
750 RowIterator rows = result.getRows();
751 while ( rows.hasNext() )
753 Row row = rows.nextRow();
754 Node node = row.getNode( "artifact" );
755 artifacts.add( getArtifactFromNode( repositoryId, node ) );
758 catch ( RepositoryException e )
760 throw new MetadataRepositoryException( e.getMessage(), e );
762 log.info( "Artifacts found {}", artifacts.size() );
763 for ( ArtifactMetadata meta : artifacts )
765 log.info( "Artifact: " + meta.getVersion() + " " + meta.getFacetList() );
771 public List<ArtifactMetadata> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
772 throws MetadataRepositoryException
775 "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + ARTIFACT_NODE_TYPE
776 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) INNER JOIN [" + FACET_NODE_TYPE
777 + "] AS facet ON ISCHILDNODE(facet, projectVersion) WHERE ([facet].[" + key + "] = $value)";
779 return runJcrQuery( repositoryId, q, ImmutableMap.of( "value", value ) );
784 public List<ArtifactMetadata> getArtifactsByMetadata( String key, String value, String repositoryId )
785 throws MetadataRepositoryException
787 String q = "SELECT * FROM [" + ARTIFACT_NODE_TYPE + "] AS artifact INNER JOIN [" + FACET_NODE_TYPE
788 + "] AS facet ON ISCHILDNODE(facet, artifact) WHERE ([facet].[" + key + "] = $value)";
790 return runJcrQuery( repositoryId, q, ImmutableMap.of( "value", value ) );
795 public List<ArtifactMetadata> getArtifactsByProperty( String key, String value, String repositoryId )
796 throws MetadataRepositoryException
799 "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + ARTIFACT_NODE_TYPE
800 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) WHERE ([projectVersion].[" + key
803 return runJcrQuery( repositoryId, q, ImmutableMap.of( "value", value ) );
808 public void removeRepository( String repositoryId )
809 throws MetadataRepositoryException
813 Node root = getJcrSession().getRootNode();
814 String path = getRepositoryPath( repositoryId );
815 if ( root.hasNode( path ) )
817 root.getNode( path ).remove();
820 catch ( RepositoryException e )
822 throw new MetadataRepositoryException( e.getMessage(), e );
827 public List<ArtifactMetadata> getArtifacts( String repositoryId )
828 throws MetadataRepositoryException
830 List<ArtifactMetadata> artifacts;
832 String q = getArtifactQuery( repositoryId );
836 Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
837 QueryResult result = query.execute();
839 artifacts = new ArrayList<>();
840 for ( Node n : JcrUtils.getNodes( result ) )
842 if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
844 artifacts.add( getArtifactFromNode( repositoryId, n ) );
848 catch ( RepositoryException e )
850 throw new MetadataRepositoryException( e.getMessage(), e );
855 private static String getArtifactQuery( String repositoryId )
857 return "SELECT * FROM [" + ARTIFACT_NODE_TYPE + "] AS artifact WHERE ISDESCENDANTNODE(artifact,'/"
858 + getRepositoryContentPath( repositoryId ) + "')";
862 public ProjectMetadata getProject( String repositoryId, String namespace, String projectId )
863 throws MetadataResolutionException
865 ProjectMetadata metadata = null;
869 Node root = getJcrSession().getRootNode();
871 // basically just checking it exists
872 String path = getProjectPath( repositoryId, namespace, projectId );
873 if ( root.hasNode( path ) )
875 metadata = new ProjectMetadata();
876 metadata.setId( projectId );
877 metadata.setNamespace( namespace );
880 catch ( RepositoryException e )
882 throw new MetadataResolutionException( e.getMessage(), e );
889 public ProjectVersionMetadata getProjectVersion( String repositoryId, String namespace, String projectId,
890 String projectVersion )
891 throws MetadataResolutionException
893 ProjectVersionMetadata versionMetadata;
897 Node root = getJcrSession().getRootNode();
899 String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
900 if ( !root.hasNode( path ) )
905 Node node = root.getNode( path );
907 versionMetadata = new ProjectVersionMetadata();
908 versionMetadata.setId( projectVersion );
909 versionMetadata.setName( getPropertyString( node, "name" ) );
910 versionMetadata.setDescription( getPropertyString( node, "description" ) );
911 versionMetadata.setUrl( getPropertyString( node, "url" ) );
912 versionMetadata.setIncomplete(
913 node.hasProperty( "incomplete" ) && node.getProperty( "incomplete" ).getBoolean() );
915 // FIXME: decide how to treat these in the content repo
916 String scmConnection = getPropertyString( node, "scm.connection" );
917 String scmDeveloperConnection = getPropertyString( node, "scm.developerConnection" );
918 String scmUrl = getPropertyString( node, "scm.url" );
919 if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
922 scm.setConnection( scmConnection );
923 scm.setDeveloperConnection( scmDeveloperConnection );
924 scm.setUrl( scmUrl );
925 versionMetadata.setScm( scm );
928 String ciSystem = getPropertyString( node, "ci.system" );
929 String ciUrl = getPropertyString( node, "ci.url" );
930 if ( ciSystem != null || ciUrl != null )
932 CiManagement ci = new CiManagement();
933 ci.setSystem( ciSystem );
935 versionMetadata.setCiManagement( ci );
938 String issueSystem = getPropertyString( node, "issue.system" );
939 String issueUrl = getPropertyString( node, "issue.url" );
940 if ( issueSystem != null || issueUrl != null )
942 IssueManagement issueManagement = new IssueManagement();
943 issueManagement.setSystem( issueSystem );
944 issueManagement.setUrl( issueUrl );
945 versionMetadata.setIssueManagement( issueManagement );
948 String orgName = getPropertyString( node, "org.name" );
949 String orgUrl = getPropertyString( node, "org.url" );
950 if ( orgName != null || orgUrl != null )
952 Organization org = new Organization();
953 org.setName( orgName );
954 org.setUrl( orgUrl );
955 versionMetadata.setOrganization( org );
958 boolean done = false;
962 String licenseName = getPropertyString( node, "license." + i + ".name" );
963 String licenseUrl = getPropertyString( node, "license." + i + ".url" );
964 if ( licenseName != null || licenseUrl != null )
966 License license = new License();
967 license.setName( licenseName );
968 license.setUrl( licenseUrl );
969 versionMetadata.addLicense( license );
982 String mailingListName = getPropertyString( node, "mailingList." + i + ".name" );
983 if ( mailingListName != null )
985 MailingList mailingList = new MailingList();
986 mailingList.setName( mailingListName );
987 mailingList.setMainArchiveUrl( getPropertyString( node, "mailingList." + i + ".archive" ) );
988 String n = "mailingList." + i + ".otherArchives";
989 if ( node.hasProperty( n ) )
991 mailingList.setOtherArchives( Arrays.asList( getPropertyString( node, n ).split( "," ) ) );
995 mailingList.setOtherArchives( Collections.<String>emptyList() );
997 mailingList.setPostAddress( getPropertyString( node, "mailingList." + i + ".post" ) );
998 mailingList.setSubscribeAddress( getPropertyString( node, "mailingList." + i + ".subscribe" ) );
999 mailingList.setUnsubscribeAddress( getPropertyString( node, "mailingList." + i + ".unsubscribe" ) );
1000 versionMetadata.addMailingList( mailingList );
1009 if ( node.hasNode( "dependencies" ) )
1011 Node dependenciesNode = node.getNode( "dependencies" );
1012 for ( Node n : JcrUtils.getChildNodes( dependenciesNode ) )
1014 if ( n.isNodeType( DEPENDENCY_NODE_TYPE ) )
1016 Dependency dependency = new Dependency();
1017 // FIXME: correct these properties
1018 dependency.setArtifactId( getPropertyString( n, "artifactId" ) );
1019 dependency.setGroupId( getPropertyString( n, "groupId" ) );
1020 dependency.setClassifier( getPropertyString( n, "classifier" ) );
1021 dependency.setOptional( Boolean.valueOf( getPropertyString( n, "optional" ) ) );
1022 dependency.setScope( getPropertyString( n, "scope" ) );
1023 dependency.setSystemPath( getPropertyString( n, "systemPath" ) );
1024 dependency.setType( getPropertyString( n, "type" ) );
1025 dependency.setVersion( getPropertyString( n, "version" ) );
1026 versionMetadata.addDependency( dependency );
1031 for ( Node n : JcrUtils.getChildNodes( node ) )
1033 if ( n.isNodeType( FACET_NODE_TYPE ) )
1035 String name = n.getName();
1036 MetadataFacetFactory factory = metadataFacetFactories.get( name );
1037 if ( factory == null )
1039 log.error( "Attempted to load unknown project version metadata facet: {}", name );
1043 MetadataFacet facet = factory.createMetadataFacet();
1044 Map<String, String> map = new HashMap<>();
1045 for ( Property property : JcrUtils.getProperties( n ) )
1047 String p = property.getName();
1048 if ( !p.startsWith( "jcr:" ) )
1050 map.put( p, property.getString() );
1053 facet.fromProperties( map );
1054 versionMetadata.addFacet( facet );
1059 catch ( RepositoryException e )
1061 throw new MetadataResolutionException( e.getMessage(), e );
1064 return versionMetadata;
1068 public Collection<String> getArtifactVersions( String repositoryId, String namespace, String projectId,
1069 String projectVersion )
1070 throws MetadataResolutionException
1072 Set<String> versions = new LinkedHashSet<String>();
1076 Node root = getJcrSession().getRootNode();
1078 Node node = root.getNode( getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) );
1080 for ( Node n : JcrUtils.getChildNodes( node ) )
1082 versions.add( n.getProperty( "version" ).getString() );
1085 catch ( PathNotFoundException e )
1087 // ignore repo not found for now
1089 catch ( RepositoryException e )
1091 throw new MetadataResolutionException( e.getMessage(), e );
1098 public Collection<ProjectVersionReference> getProjectReferences( String repositoryId, String namespace,
1099 String projectId, String projectVersion )
1100 throws MetadataResolutionException
1103 List<ProjectVersionReference> references = new ArrayList<>();
1105 // TODO: bind variables instead
1106 String q = "SELECT * FROM [archiva:dependency] WHERE ISDESCENDANTNODE([/repositories/" + repositoryId
1107 + "/content]) AND [groupId]='" + namespace + "' AND [artifactId]='" + projectId + "'";
1108 if ( projectVersion != null )
1110 q += " AND [version]='" + projectVersion + "'";
1114 Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
1115 QueryResult result = query.execute();
1117 for ( Node n : JcrUtils.getNodes( result ) )
1119 n = n.getParent(); // dependencies grouping element
1121 n = n.getParent(); // project version
1122 String usedByProjectVersion = n.getName();
1124 n = n.getParent(); // project
1125 String usedByProject = n.getName();
1127 n = n.getParent(); // namespace
1128 String usedByNamespace = n.getProperty( "namespace" ).getString();
1130 ProjectVersionReference ref = new ProjectVersionReference();
1131 ref.setNamespace( usedByNamespace );
1132 ref.setProjectId( usedByProject );
1133 ref.setProjectVersion( usedByProjectVersion );
1134 ref.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
1135 references.add( ref );
1138 catch ( RepositoryException e )
1140 throw new MetadataResolutionException( e.getMessage(), e );
1147 public Collection<String> getRootNamespaces( String repositoryId )
1148 throws MetadataResolutionException
1150 return getNamespaces( repositoryId, null );
1154 public Collection<String> getNamespaces( String repositoryId, String baseNamespace )
1155 throws MetadataResolutionException
1157 String path = baseNamespace != null
1158 ? getNamespacePath( repositoryId, baseNamespace )
1159 : getRepositoryContentPath( repositoryId );
1161 return getNodeNames( path, NAMESPACE_NODE_TYPE );
1165 public Collection<String> getProjects( String repositoryId, String namespace )
1166 throws MetadataResolutionException
1168 return getNodeNames( getNamespacePath( repositoryId, namespace ), PROJECT_NODE_TYPE );
1172 public Collection<String> getProjectVersions( String repositoryId, String namespace, String projectId )
1173 throws MetadataResolutionException
1175 return getNodeNames( getProjectPath( repositoryId, namespace, projectId ), PROJECT_VERSION_NODE_TYPE );
1179 public void removeArtifact( ArtifactMetadata artifactMetadata, String baseVersion )
1180 throws MetadataRepositoryException
1183 String repositoryId = artifactMetadata.getRepositoryId();
1187 Node root = getJcrSession().getRootNode();
1189 getProjectVersionPath( repositoryId, artifactMetadata.getNamespace(), artifactMetadata.getProject(),
1192 if ( root.hasNode( path ) )
1194 Node node = root.getNode( path );
1196 for ( Node n : JcrUtils.getChildNodes( node ) )
1198 if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
1200 if ( n.hasProperty( "version" ) )
1202 String version = n.getProperty( "version" ).getString();
1203 if ( StringUtils.equals( version, artifactMetadata.getVersion() ) )
1213 catch ( RepositoryException e )
1215 throw new MetadataRepositoryException( e.getMessage(), e );
1223 public void removeProjectVersion( String repoId, String namespace, String projectId, String projectVersion )
1224 throws MetadataRepositoryException
1229 String path = getProjectPath( repoId, namespace, projectId );
1230 Node root = getJcrSession().getRootNode();
1232 Node nodeAtPath = root.getNode( path );
1234 for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1236 if ( node.isNodeType( PROJECT_VERSION_NODE_TYPE ) && StringUtils.equals( projectVersion,
1243 catch ( RepositoryException e )
1245 throw new MetadataRepositoryException( e.getMessage(), e );
1250 public void removeArtifact( String repositoryId, String namespace, String projectId, String projectVersion,
1252 throws MetadataRepositoryException
1256 Node root = getJcrSession().getRootNode();
1257 String path = getArtifactPath( repositoryId, namespace, projectId, projectVersion, id );
1258 if ( root.hasNode( path ) )
1260 root.getNode( path ).remove();
1265 path = getProjectPath( repositoryId, namespace, projectId );
1267 Node nodeAtPath = root.getNode( path );
1269 for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1271 if ( node.isNodeType( PROJECT_VERSION_NODE_TYPE ) //
1272 && StringUtils.equals( node.getName(), projectVersion ) )
1278 catch ( RepositoryException e )
1280 throw new MetadataRepositoryException( e.getMessage(), e );
1285 public void removeArtifact( String repositoryId, String namespace, String project, String projectVersion,
1286 MetadataFacet metadataFacet )
1287 throws MetadataRepositoryException
1291 Node root = getJcrSession().getRootNode();
1292 String path = getProjectVersionPath( repositoryId, namespace, project, projectVersion );
1294 if ( root.hasNode( path ) )
1296 Node node = root.getNode( path );
1298 for ( Node n : JcrUtils.getChildNodes( node ) )
1300 if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
1302 ArtifactMetadata artifactMetadata = getArtifactFromNode( repositoryId, n );
1303 log.debug( "artifactMetadata: {}", artifactMetadata );
1304 MetadataFacet metadataFacetToRemove = artifactMetadata.getFacet( metadataFacet.getFacetId() );
1305 if ( metadataFacetToRemove != null && metadataFacet.equals( metadataFacetToRemove ) )
1313 catch ( RepositoryException e )
1315 throw new MetadataRepositoryException( e.getMessage(), e );
1320 public Collection<ArtifactMetadata> getArtifacts( String repositoryId, String namespace, String projectId,
1321 String projectVersion )
1322 throws MetadataResolutionException
1324 List<ArtifactMetadata> artifacts = new ArrayList<>();
1328 Node root = getJcrSession().getRootNode();
1329 String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
1331 if ( root.hasNode( path ) )
1333 Node node = root.getNode( path );
1335 for ( Node n : JcrUtils.getChildNodes( node ) )
1337 if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
1339 artifacts.add( getArtifactFromNode( repositoryId, n ) );
1344 catch ( RepositoryException e )
1346 throw new MetadataResolutionException( e.getMessage(), e );
1357 getJcrSession().save();
1359 catch ( InvalidItemStateException e )
1361 // olamy this might happen when deleting a repo while is under scanning
1362 log.warn( "skip InvalidItemStateException:{}", e.getMessage(), e );
1364 catch ( RepositoryException e )
1366 throw new RuntimeException( e.getMessage(), e );
1371 public void revert()
1375 getJcrSession().refresh( false );
1377 catch ( RepositoryException e )
1379 throw new RuntimeException( e.getMessage(), e );
1384 public boolean canObtainAccess( Class<?> aClass )
1386 return aClass == Session.class;
1390 public <T> T obtainAccess( Class<T> aClass )
1391 throws MetadataRepositoryException
1393 if ( aClass == Session.class )
1397 return (T) getJcrSession();
1399 catch ( RepositoryException e )
1401 log.error( e.getMessage(), e );
1402 throw new MetadataRepositoryException( e.getMessage(), e );
1405 throw new IllegalArgumentException(
1406 "Access using " + aClass + " is not supported on the JCR metadata storage" );
1411 throws MetadataRepositoryException
1413 if ( jcrSession != null && jcrSession.isLive() )
1415 jcrSession.logout();
1421 * Exact is ignored as we can't do exact search in any property, we need a key
1424 public List<ArtifactMetadata> searchArtifacts( String text, String repositoryId, boolean exact )
1425 throws MetadataRepositoryException
1427 return searchArtifacts( null, text, repositoryId, exact );
1431 public List<ArtifactMetadata> searchArtifacts( String key, String text, String repositoryId, boolean e )
1432 throws MetadataRepositoryException
1434 String theKey = key == null ? "*" : "[" + key + "]";
1435 String projectVersionCondition =
1436 e ? "(projectVersion." + theKey + " = $value)" : "contains([projectVersion]." + theKey + ", $value)";
1437 String facetCondition = e ? "(facet." + theKey + " = $value)" : "contains([facet]." + theKey + ", $value)";
1439 "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE + "] AS projectVersion LEFT OUTER JOIN [" + ARTIFACT_NODE_TYPE
1440 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) LEFT OUTER JOIN [" + FACET_NODE_TYPE
1441 + "] AS facet ON ISCHILDNODE(facet, projectVersion) WHERE (" + projectVersionCondition + " OR "
1442 + facetCondition + ")";
1443 return runJcrQuery( repositoryId, q, ImmutableMap.of( "value", text ) );
1446 private ArtifactMetadata getArtifactFromNode( String repositoryId, Node artifactNode )
1447 throws RepositoryException
1449 String id = artifactNode.getName();
1451 ArtifactMetadata artifact = new ArtifactMetadata();
1452 artifact.setId( id );
1453 artifact.setRepositoryId( repositoryId == null ? artifactNode.getAncestor( 2 ).getName() : repositoryId );
1455 Node projectVersionNode = artifactNode.getParent();
1456 Node projectNode = projectVersionNode.getParent();
1457 Node namespaceNode = projectNode.getParent();
1459 artifact.setNamespace( namespaceNode.getProperty( "namespace" ).getString() );
1460 artifact.setProject( projectNode.getName() );
1461 artifact.setProjectVersion( projectVersionNode.getName() );
1462 artifact.setVersion( artifactNode.hasProperty( "version" )
1463 ? artifactNode.getProperty( "version" ).getString()
1464 : projectVersionNode.getName() );
1466 if ( artifactNode.hasProperty( JCR_LAST_MODIFIED ) )
1468 artifact.setFileLastModified( artifactNode.getProperty( JCR_LAST_MODIFIED ).getDate().getTimeInMillis() );
1471 if ( artifactNode.hasProperty( "whenGathered" ) )
1473 artifact.setWhenGathered( artifactNode.getProperty( "whenGathered" ).getDate().getTime() );
1476 if ( artifactNode.hasProperty( "size" ) )
1478 artifact.setSize( artifactNode.getProperty( "size" ).getLong() );
1481 if ( artifactNode.hasProperty( "md5" ) )
1483 artifact.setMd5( artifactNode.getProperty( "md5" ).getString() );
1486 if ( artifactNode.hasProperty( "sha1" ) )
1488 artifact.setSha1( artifactNode.getProperty( "sha1" ).getString() );
1491 for ( Node n : JcrUtils.getChildNodes( artifactNode ) )
1493 if ( n.isNodeType( FACET_NODE_TYPE ) )
1495 String name = n.getName();
1496 MetadataFacetFactory factory = metadataFacetFactories.get( name );
1497 if ( factory == null )
1499 log.error( "Attempted to load unknown project version metadata facet: {}", name );
1503 MetadataFacet facet = factory.createMetadataFacet();
1504 Map<String, String> map = new HashMap<>();
1505 for ( Property p : JcrUtils.getProperties( n ) )
1507 String property = p.getName();
1508 if ( !property.startsWith( "jcr:" ) )
1510 map.put( property, p.getString() );
1513 facet.fromProperties( map );
1514 artifact.addFacet( facet );
1521 private static String getPropertyString( Node node, String name )
1522 throws RepositoryException
1524 return node.hasProperty( name ) ? node.getProperty( name ).getString() : null;
1527 private Collection<String> getNodeNames( String path, String nodeType )
1528 throws MetadataResolutionException
1530 List<String> names = new ArrayList<>();
1534 Node root = getJcrSession().getRootNode();
1536 Node nodeAtPath = root.getNode( path );
1538 for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1540 if ( node.isNodeType( nodeType ) )
1542 names.add( node.getName() );
1546 catch ( PathNotFoundException e )
1548 // ignore repo not found for now
1550 catch ( RepositoryException e )
1552 throw new MetadataResolutionException( e.getMessage(), e );
1558 private static String getRepositoryPath( String repositoryId )
1560 return "repositories/" + repositoryId;
1563 private static String getRepositoryContentPath( String repositoryId )
1565 return getRepositoryPath( repositoryId ) + "/content";
1568 private static String getFacetPath( String repositoryId, String facetId )
1570 return getRepositoryPath( repositoryId ) + "/facets/" + facetId;
1573 private static String getNamespacePath( String repositoryId, String namespace )
1575 return getRepositoryContentPath( repositoryId ) + "/" + namespace.replace( '.', '/' );
1578 private static String getProjectPath( String repositoryId, String namespace, String projectId )
1580 return getNamespacePath( repositoryId, namespace ) + "/" + projectId;
1583 private static String getProjectVersionPath( String repositoryId, String namespace, String projectId,
1584 String projectVersion )
1586 return getProjectPath( repositoryId, namespace, projectId ) + "/" + projectVersion;
1589 private static String getArtifactPath( String repositoryId, String namespace, String projectId,
1590 String projectVersion, String id )
1592 return getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) + "/" + id;
1595 private Node getOrAddNodeByPath( Node baseNode, String name )
1596 throws RepositoryException
1598 return getOrAddNodeByPath( baseNode, name, null );
1601 private Node getOrAddNodeByPath( Node baseNode, String name, String nodeType )
1602 throws RepositoryException
1604 log.debug( "getOrAddNodeByPath" + baseNode + " " + name + " " + nodeType );
1605 Node node = baseNode;
1606 for ( String n : name.split( "/" ) )
1608 node = JcrUtils.getOrAddNode( node, n );
1609 if ( nodeType != null )
1611 node.addMixin( nodeType );
1617 private static String getFacetPath( String repositoryId, String facetId, String name )
1619 return getFacetPath( repositoryId, facetId ) + "/" + name;
1622 private Node getOrAddRepositoryNode( String repositoryId )
1623 throws RepositoryException
1625 log.debug( "getOrAddRepositoryNode " + repositoryId );
1626 Node root = getJcrSession().getRootNode();
1627 Node node = JcrUtils.getOrAddNode( root, "repositories" );
1628 log.debug( "Repositories " + node );
1629 node = JcrUtils.getOrAddNode( node, repositoryId );
1633 private Node getOrAddRepositoryContentNode( String repositoryId )
1634 throws RepositoryException
1636 Node node = getOrAddRepositoryNode( repositoryId );
1637 return JcrUtils.getOrAddNode( node, "content" );
1640 private Node getOrAddNamespaceNode( String repositoryId, String namespace )
1641 throws RepositoryException
1643 Node repo = getOrAddRepositoryContentNode( repositoryId );
1644 return getOrAddNodeByPath( repo, namespace.replace( '.', '/' ), NAMESPACE_NODE_TYPE );
1647 private Node getOrAddProjectNode( String repositoryId, String namespace, String projectId )
1648 throws RepositoryException
1650 Node namespaceNode = getOrAddNamespaceNode( repositoryId, namespace );
1651 Node node = JcrUtils.getOrAddNode( namespaceNode, projectId );
1652 node.addMixin( PROJECT_NODE_TYPE );
1656 private Node getOrAddProjectVersionNode( String repositoryId, String namespace, String projectId,
1657 String projectVersion )
1658 throws RepositoryException
1660 Node projectNode = getOrAddProjectNode( repositoryId, namespace, projectId );
1661 Node node = JcrUtils.getOrAddNode( projectNode, projectVersion );
1662 node.addMixin( PROJECT_VERSION_NODE_TYPE );
1666 private Node getOrAddArtifactNode( String repositoryId, String namespace, String projectId, String projectVersion,
1668 throws RepositoryException
1670 Node versionNode = getOrAddProjectVersionNode( repositoryId, namespace, projectId, projectVersion );
1671 Node node = JcrUtils.getOrAddNode( versionNode, id );
1672 node.addMixin( ARTIFACT_NODE_TYPE );
1676 private static Calendar createCalendar( Date time )
1678 Calendar cal = Calendar.getInstance();
1679 cal.setTime( time );
1683 private String join( Collection<String> ids )
1685 if ( ids != null && !ids.isEmpty() )
1687 StringBuilder s = new StringBuilder();
1688 for ( String id : ids )
1693 return s.substring( 0, s.length() - 1 );
1698 public Session getJcrSession()
1699 throws RepositoryException
1701 if ( this.jcrSession == null || !this.jcrSession.isLive() )
1703 jcrSession = repository.login( new SimpleCredentials( "admin", "admin".toCharArray() ) );
1705 return this.jcrSession;
1709 public void populateStatistics( MetadataRepository repository, String repositoryId,
1710 RepositoryStatistics repositoryStatistics )
1711 throws MetadataRepositoryException
1713 if ( !( repository instanceof JcrMetadataRepository ) )
1715 throw new MetadataRepositoryException(
1716 "The statistics population is only possible for JcrMetdataRepository implementations" );
1718 Session session = (Session) repository.obtainAccess( Session.class );
1719 // TODO: these may be best as running totals, maintained by observations on the properties in JCR
1723 QueryManager queryManager = session.getWorkspace().getQueryManager();
1725 // TODO: JCR-SQL2 query will not complete on a large repo in Jackrabbit 2.2.0 - see JCR-2835
1726 // Using the JCR-SQL2 variants gives
1727 // "org.apache.lucene.search.BooleanQuery$TooManyClauses: maxClauseCount is set to 1024"
1728 // String whereClause = "WHERE ISDESCENDANTNODE([/repositories/" + repositoryId + "/content])";
1729 // Query query = queryManager.createQuery( "SELECT size FROM [archiva:artifact] " + whereClause,
1730 // Query.JCR_SQL2 );
1731 String whereClause = "WHERE jcr:path LIKE '/repositories/" + repositoryId + "/content/%'";
1732 Query query = queryManager.createQuery( "SELECT size FROM archiva:artifact " + whereClause, Query.SQL );
1734 QueryResult queryResult = query.execute();
1736 Map<String, Integer> totalByType = new HashMap<>();
1737 long totalSize = 0, totalArtifacts = 0;
1738 for ( Row row : JcrUtils.getRows( queryResult ) )
1740 Node n = row.getNode();
1741 totalSize += row.getValue( "size" ).getLong();
1744 if ( n.hasNode( MavenArtifactFacet.FACET_ID ) )
1746 Node facetNode = n.getNode( MavenArtifactFacet.FACET_ID );
1747 type = facetNode.getProperty( "type" ).getString();
1753 Integer prev = totalByType.get( type );
1754 totalByType.put( type, prev != null ? prev + 1 : 1 );
1759 repositoryStatistics.setTotalArtifactCount( totalArtifacts );
1760 repositoryStatistics.setTotalArtifactFileSize( totalSize );
1761 for ( Map.Entry<String, Integer> entry : totalByType.entrySet() )
1763 log.info( "Setting count for type: {} = {}", entry.getKey(), entry.getValue() );
1764 repositoryStatistics.setTotalCountForType( entry.getKey(), entry.getValue() );
1767 // The query ordering is a trick to ensure that the size is correct, otherwise due to lazy init it will be -1
1768 // query = queryManager.createQuery( "SELECT * FROM [archiva:project] " + whereClause, Query.JCR_SQL2 );
1769 query = queryManager.createQuery( "SELECT * FROM archiva:project " + whereClause + " ORDER BY jcr:score",
1771 repositoryStatistics.setTotalProjectCount( query.execute().getRows().getSize() );
1773 // query = queryManager.createQuery(
1774 // "SELECT * FROM [archiva:namespace] " + whereClause + " AND namespace IS NOT NULL", Query.JCR_SQL2 );
1775 query = queryManager.createQuery(
1776 "SELECT * FROM archiva:namespace " + whereClause + " AND namespace IS NOT NULL ORDER BY jcr:score",
1778 repositoryStatistics.setTotalGroupCount( query.execute().getRows().getSize() );
1780 catch ( RepositoryException e )
1782 throw new MetadataRepositoryException( e.getMessage(), e );