1 package org.apache.archiva.metadata.repository.jcr;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
22 import org.apache.archiva.metadata.model.ArtifactMetadata;
23 import org.apache.archiva.metadata.model.CiManagement;
24 import org.apache.archiva.metadata.model.Dependency;
25 import org.apache.archiva.metadata.model.IssueManagement;
26 import org.apache.archiva.metadata.model.License;
27 import org.apache.archiva.metadata.model.MailingList;
28 import org.apache.archiva.metadata.model.MetadataFacet;
29 import org.apache.archiva.metadata.model.MetadataFacetFactory;
30 import org.apache.archiva.metadata.model.Organization;
31 import org.apache.archiva.metadata.model.ProjectMetadata;
32 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
33 import org.apache.archiva.metadata.model.ProjectVersionReference;
34 import org.apache.archiva.metadata.model.Scm;
35 import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
36 import org.apache.archiva.metadata.repository.MetadataRepository;
37 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
38 import org.apache.archiva.metadata.repository.MetadataResolutionException;
39 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
40 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsProvider;
41 import org.apache.commons.lang.StringUtils;
42 import org.apache.jackrabbit.commons.JcrUtils;
43 import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
44 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
48 import com.google.common.collect.ImmutableMap;
50 import javax.jcr.InvalidItemStateException;
51 import javax.jcr.NamespaceRegistry;
52 import javax.jcr.Node;
53 import javax.jcr.NodeIterator;
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;
70 import java.util.ArrayList;
71 import java.util.Arrays;
72 import java.util.Calendar;
73 import java.util.Collection;
74 import java.util.Collections;
75 import java.util.Date;
76 import java.util.HashMap;
77 import java.util.Iterator;
78 import java.util.LinkedHashSet;
79 import java.util.List;
81 import java.util.Map.Entry;
85 * TODO below: revise storage format for project version metadata
86 * TODO revise reference storage
88 public class JcrMetadataRepository
89 implements MetadataRepository,RepositoryStatisticsProvider
92 private static final String JCR_LAST_MODIFIED = "jcr:lastModified";
94 static final String NAMESPACE_NODE_TYPE = "archiva:namespace";
96 static final String PROJECT_NODE_TYPE = "archiva:project";
98 static final String PROJECT_VERSION_NODE_TYPE = "archiva:projectVersion";
100 static final String ARTIFACT_NODE_TYPE = "archiva:artifact";
102 static final String FACET_NODE_TYPE = "archiva:facet";
104 private static final String DEPENDENCY_NODE_TYPE = "archiva:dependency";
106 private final Map<String, MetadataFacetFactory> metadataFacetFactories;
108 private Logger log = LoggerFactory.getLogger( JcrMetadataRepository.class );
110 private Repository repository;
112 private Session jcrSession;
114 public JcrMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories, Repository repository )
115 throws RepositoryException
117 this.metadataFacetFactories = metadataFacetFactories;
118 this.repository = repository;
122 public static void initialize( Session session )
123 throws RepositoryException
126 // TODO: consider using namespaces for facets instead of the current approach:
127 // (if used, check if actually called by normal injection)
128 // for ( String facetId : metadataFacetFactories.keySet() )
130 // session.getWorkspace().getNamespaceRegistry().registerNamespace( facetId, facetId );
132 Workspace workspace = session.getWorkspace();
133 NamespaceRegistry registry = workspace.getNamespaceRegistry();
135 if ( !Arrays.asList( registry.getPrefixes() ).contains( "archiva" ) )
137 registry.registerNamespace( "archiva", "http://archiva.apache.org/jcr/" );
140 NodeTypeManager nodeTypeManager = workspace.getNodeTypeManager();
141 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.NAMESPACE_NODE_TYPE );
142 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.PROJECT_NODE_TYPE );
143 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.PROJECT_VERSION_NODE_TYPE );
144 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.ARTIFACT_NODE_TYPE );
145 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.FACET_NODE_TYPE );
146 registerMixinNodeType( nodeTypeManager, JcrMetadataRepository.DEPENDENCY_NODE_TYPE );
152 private static void registerMixinNodeType( NodeTypeManager nodeTypeManager, String name )
153 throws RepositoryException
155 NodeTypeTemplate nodeType = nodeTypeManager.createNodeTypeTemplate();
156 nodeType.setMixin( true );
157 nodeType.setName( name );
159 // for now just don't re-create - but in future if we change the definition, make sure to remove first as an
161 if ( !nodeTypeManager.hasNodeType( name ) )
163 nodeTypeManager.registerNodeType( nodeType, false );
170 public void updateProject( String repositoryId, ProjectMetadata project )
171 throws MetadataRepositoryException
173 updateProject( repositoryId, project.getNamespace(), project.getId() );
176 private void updateProject( String repositoryId, String namespace, String projectId )
177 throws MetadataRepositoryException
179 updateNamespace( repositoryId, namespace );
183 getOrAddProjectNode( repositoryId, namespace, projectId );
185 catch ( RepositoryException e )
187 throw new MetadataRepositoryException( e.getMessage(), e );
192 public void updateArtifact( String repositoryId, String namespace, String projectId, String projectVersion,
193 ArtifactMetadata artifactMeta )
194 throws MetadataRepositoryException
196 updateNamespace( repositoryId, namespace );
201 getOrAddArtifactNode( repositoryId, namespace, projectId, projectVersion, artifactMeta.getId() );
203 Calendar cal = Calendar.getInstance();
204 cal.setTime( artifactMeta.getFileLastModified() );
205 node.setProperty( JCR_LAST_MODIFIED, cal );
207 cal = Calendar.getInstance();
208 cal.setTime( artifactMeta.getWhenGathered() );
209 node.setProperty( "whenGathered", cal );
211 node.setProperty( "size", artifactMeta.getSize() );
212 node.setProperty( "md5", artifactMeta.getMd5() );
213 node.setProperty( "sha1", artifactMeta.getSha1() );
215 node.setProperty( "version", artifactMeta.getVersion() );
217 // iterate over available facets to update/add/remove from the artifactMetadata
218 for ( String facetId : metadataFacetFactories.keySet() )
220 MetadataFacet metadataFacet = artifactMeta.getFacet( facetId );
221 if ( metadataFacet == null )
225 if ( node.hasNode( facetId ) )
227 node.getNode( facetId ).remove();
229 if ( metadataFacet != null )
231 // recreate, to ensure properties are removed
232 Node n = node.addNode( facetId );
233 n.addMixin( FACET_NODE_TYPE );
235 for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
237 n.setProperty( entry.getKey(), entry.getValue() );
242 catch ( RepositoryException e )
244 throw new MetadataRepositoryException( e.getMessage(), e );
249 public void updateProjectVersion( String repositoryId, String namespace, String projectId,
250 ProjectVersionMetadata versionMetadata )
251 throws MetadataRepositoryException
253 updateProject( repositoryId, namespace, projectId );
258 getOrAddProjectVersionNode( repositoryId, namespace, projectId, versionMetadata.getId() );
260 versionNode.setProperty( "name", versionMetadata.getName() );
261 versionNode.setProperty( "description", versionMetadata.getDescription() );
262 versionNode.setProperty( "url", versionMetadata.getUrl() );
263 versionNode.setProperty( "incomplete", versionMetadata.isIncomplete() );
265 // FIXME: decide how to treat these in the content repo
266 if ( versionMetadata.getScm() != null )
268 versionNode.setProperty( "scm.connection", versionMetadata.getScm().getConnection() );
269 versionNode.setProperty( "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
270 versionNode.setProperty( "scm.url", versionMetadata.getScm().getUrl() );
272 if ( versionMetadata.getCiManagement() != null )
274 versionNode.setProperty( "ci.system", versionMetadata.getCiManagement().getSystem() );
275 versionNode.setProperty( "ci.url", versionMetadata.getCiManagement().getUrl() );
277 if ( versionMetadata.getIssueManagement() != null )
279 versionNode.setProperty( "issue.system", versionMetadata.getIssueManagement().getSystem() );
280 versionNode.setProperty( "issue.url", versionMetadata.getIssueManagement().getUrl() );
282 if ( versionMetadata.getOrganization() != null )
284 versionNode.setProperty( "org.name", versionMetadata.getOrganization().getName() );
285 versionNode.setProperty( "org.url", versionMetadata.getOrganization().getUrl() );
288 for ( License license : versionMetadata.getLicenses() )
290 versionNode.setProperty( "license." + i + ".name", license.getName() );
291 versionNode.setProperty( "license." + i + ".url", license.getUrl() );
295 for ( MailingList mailingList : versionMetadata.getMailingLists() )
297 versionNode.setProperty( "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
298 versionNode.setProperty( "mailingList." + i + ".name", mailingList.getName() );
299 versionNode.setProperty( "mailingList." + i + ".post", mailingList.getPostAddress() );
300 versionNode.setProperty( "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
301 versionNode.setProperty( "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
302 versionNode.setProperty( "mailingList." + i + ".otherArchives",
303 join( mailingList.getOtherArchives() ) );
307 if ( !versionMetadata.getDependencies().isEmpty() )
309 Node dependenciesNode = JcrUtils.getOrAddNode( versionNode, "dependencies" );
311 for ( Dependency dependency : versionMetadata.getDependencies() )
313 // Note that we deliberately don't alter the namespace path - not enough dependencies for
314 // number of nodes at a given depth to be an issue. Similarly, we don't add subnodes for each
315 // component of the ID as that creates extra depth and causes a great cost in space and memory
317 // FIXME: change group ID to namespace
318 // FIXME: change to artifact's ID - this is constructed by the Maven 2 format for now.
319 // This won't support types where the extension doesn't match the type.
320 // (see also Maven2RepositoryStorage#readProjectVersionMetadata construction of POM)
322 dependency.getGroupId() + ";" + dependency.getArtifactId() + "-" + dependency.getVersion();
323 if ( dependency.getClassifier() != null )
325 id += "-" + dependency.getClassifier();
327 id += "." + dependency.getType();
329 Node n = JcrUtils.getOrAddNode( dependenciesNode, id );
330 n.addMixin( DEPENDENCY_NODE_TYPE );
332 // FIXME: remove temp code just to make it keep working
333 n.setProperty( "groupId", dependency.getGroupId() );
334 n.setProperty( "artifactId", dependency.getArtifactId() );
335 n.setProperty( "version", dependency.getVersion() );
336 n.setProperty( "type", dependency.getType() );
337 n.setProperty( "classifier", dependency.getClassifier() );
338 n.setProperty( "scope", dependency.getScope() );
339 n.setProperty( "systemPath", dependency.getSystemPath() );
340 n.setProperty( "optional", dependency.isOptional() );
342 // node has no native content at this time, just facets
343 // no need to list a type as it's implied by the path. Parents are Maven specific.
345 // FIXME: add scope, systemPath, type, version, classifier & maven2 specific IDs as a facet
346 // (should also have been added to the Dependency)
348 // TODO: add a property that is a weak reference to the originating artifact, creating it if
349 // necessary (without adding the archiva:artifact mixin so that it doesn't get listed as an
350 // artifact, which gives a different meaning to "incomplete" which is a known local project
351 // that doesn't have metadata yet but has artifacts). (Though we may want to give it the
352 // artifact mixin and another property to identify all non-local artifacts for the closure
357 for ( MetadataFacet facet : versionMetadata.getFacetList() )
359 // recreate, to ensure properties are removed
360 if ( versionNode.hasNode( facet.getFacetId() ) )
362 versionNode.getNode( facet.getFacetId() ).remove();
364 Node n = versionNode.addNode( facet.getFacetId() );
365 n.addMixin( FACET_NODE_TYPE );
367 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
369 n.setProperty( entry.getKey(), entry.getValue() );
373 catch ( RepositoryException e )
375 throw new MetadataRepositoryException( e.getMessage(), e );
380 public void updateNamespace( String repositoryId, String namespace )
381 throws MetadataRepositoryException
385 Node node = getOrAddNamespaceNode( repositoryId, namespace );
386 node.setProperty( "namespace", namespace );
388 catch ( RepositoryException e )
390 throw new MetadataRepositoryException( e.getMessage(), e );
395 public void removeProject( String repositoryId, String namespace, String projectId )
396 throws MetadataRepositoryException
400 Node root = getJcrSession().getRootNode();
401 String namespacePath = getNamespacePath( repositoryId, namespace );
403 if ( root.hasNode( namespacePath ) )
405 Iterator<Node> nodeIterator = JcrUtils.getChildNodes( root.getNode( namespacePath ) ).iterator();
406 while ( nodeIterator.hasNext() )
408 Node node = nodeIterator.next();
409 if ( node.isNodeType( PROJECT_NODE_TYPE ) && projectId.equals( node.getName() ) )
417 catch ( RepositoryException e )
419 throw new MetadataRepositoryException( e.getMessage(), e );
426 public boolean hasMetadataFacet( String repositoryId, String facetId )
427 throws MetadataRepositoryException
431 Node node = getJcrSession().getRootNode().getNode( getFacetPath( repositoryId, facetId ) );
432 return node.getNodes().hasNext();
434 catch ( PathNotFoundException e )
436 // ignored - the facet doesn't exist, so return false
439 catch ( RepositoryException e )
441 throw new MetadataRepositoryException( e.getMessage(), e );
446 public List<String> getMetadataFacets( String repositoryId, String facetId )
447 throws MetadataRepositoryException
449 List<String> facets = new ArrayList<>();
453 // no need to construct node-by-node here, as we'll find in the next instance, the facet names have / and
454 // are paths themselves
455 Node node = getJcrSession().getRootNode().getNode( getFacetPath( repositoryId, facetId ) );
457 // TODO: this is a bit awkward. Might be better to review the purpose of this function - why is the list of
459 recurse( facets, "", node );
461 catch ( PathNotFoundException e )
463 // ignored - the facet doesn't exist, so return the empty list
465 catch ( RepositoryException e )
467 throw new MetadataRepositoryException( e.getMessage(), e );
472 private void recurse( List<String> facets, String prefix, Node node )
473 throws RepositoryException
475 for ( Node n : JcrUtils.getChildNodes( node ) )
477 String name = prefix + "/" + n.getName();
480 recurse( facets, name, n );
484 // strip leading / first
485 facets.add( name.substring( 1 ) );
491 public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
492 throws MetadataRepositoryException
494 MetadataFacet metadataFacet = null;
497 Node root = getJcrSession().getRootNode();
498 Node node = root.getNode( getFacetPath( repositoryId, facetId, name ) );
500 if ( metadataFacetFactories == null )
502 return metadataFacet;
505 MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
506 if ( metadataFacetFactory != null )
508 metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
509 Map<String, String> map = new HashMap<>();
510 for ( Property property : JcrUtils.getProperties( node ) )
512 String p = property.getName();
513 if ( !p.startsWith( "jcr:" ) )
515 map.put( p, property.getString() );
518 metadataFacet.fromProperties( map );
521 catch ( PathNotFoundException e )
523 // ignored - the facet doesn't exist, so return null
525 catch ( RepositoryException e )
527 throw new MetadataRepositoryException( e.getMessage(), e );
529 return metadataFacet;
533 public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
534 throws MetadataRepositoryException
538 Node repo = getOrAddRepositoryNode( repositoryId );
539 Node facets = JcrUtils.getOrAddNode( repo, "facets" );
541 String id = metadataFacet.getFacetId();
542 Node facetNode = JcrUtils.getOrAddNode( facets, id );
544 Node node = getOrAddNodeByPath( facetNode, metadataFacet.getName() );
546 for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
548 node.setProperty( entry.getKey(), entry.getValue() );
551 catch ( RepositoryException e )
553 throw new MetadataRepositoryException( e.getMessage(), e );
558 public void removeNamespace( String repositoryId, String projectId )
559 throws MetadataRepositoryException
563 Node root = getJcrSession().getRootNode();
564 String path = getNamespacePath( repositoryId, projectId );
565 if ( root.hasNode( path ) )
567 Node node = root.getNode( path );
568 if ( node.isNodeType( NAMESPACE_NODE_TYPE ) )
574 catch ( RepositoryException e )
576 throw new MetadataRepositoryException( e.getMessage(), e );
581 public void removeMetadataFacets( String repositoryId, String facetId )
582 throws MetadataRepositoryException
586 Node root = getJcrSession().getRootNode();
587 String path = getFacetPath( repositoryId, facetId );
588 if ( root.hasNode( path ) )
590 root.getNode( path ).remove();
593 catch ( RepositoryException e )
595 throw new MetadataRepositoryException( e.getMessage(), e );
600 public void removeMetadataFacet( String repositoryId, String facetId, String name )
601 throws MetadataRepositoryException
605 Node root = getJcrSession().getRootNode();
606 String path = getFacetPath( repositoryId, facetId, name );
607 if ( root.hasNode( path ) )
609 Node node = root.getNode( path );
612 // also remove empty container nodes
613 Node parent = node.getParent();
617 while ( !node.hasNodes() );
620 catch ( RepositoryException e )
622 throw new MetadataRepositoryException( e.getMessage(), e );
627 public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
628 throws MetadataRepositoryException
630 List<ArtifactMetadata> artifacts;
632 String q = getArtifactQuery( repoId );
634 if ( startTime != null )
636 q += " AND [whenGathered] >= $start";
638 if ( endTime != null )
640 q += " AND [whenGathered] <= $end";
645 Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
646 ValueFactory valueFactory = getJcrSession().getValueFactory();
647 if ( startTime != null )
649 query.bindValue( "start", valueFactory.createValue( createCalendar( startTime ) ) );
651 if ( endTime != null )
653 query.bindValue( "end", valueFactory.createValue( createCalendar( endTime ) ) );
655 QueryResult result = query.execute();
657 artifacts = new ArrayList<>();
658 for ( Node n : JcrUtils.getNodes( result ) )
660 artifacts.add( getArtifactFromNode( repoId, n ) );
663 catch ( RepositoryException e )
665 throw new MetadataRepositoryException( e.getMessage(), e );
671 public Collection<String> getRepositories()
672 throws MetadataRepositoryException
674 List<String> repositories;
678 Node root = getJcrSession().getRootNode();
679 if ( root.hasNode( "repositories" ) )
681 Node node = root.getNode( "repositories" );
683 repositories = new ArrayList<>();
684 NodeIterator i = node.getNodes();
685 while ( i.hasNext() )
687 Node n = i.nextNode();
688 repositories.add( n.getName() );
693 repositories = Collections.emptyList();
696 catch ( RepositoryException e )
698 throw new MetadataRepositoryException( e.getMessage(), e );
704 public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
705 throws MetadataRepositoryException
707 List<ArtifactMetadata> artifacts;
709 String q = getArtifactQuery( repositoryId ) + " AND ([sha1] = $checksum OR [md5] = $checksum)";
713 Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
714 ValueFactory valueFactory = getJcrSession().getValueFactory();
715 query.bindValue( "checksum", valueFactory.createValue( checksum ) );
716 QueryResult result = query.execute();
718 artifacts = new ArrayList<>();
719 for ( Node n : JcrUtils.getNodes( result ) )
721 artifacts.add( getArtifactFromNode( repositoryId, n ) );
724 catch ( RepositoryException e )
726 throw new MetadataRepositoryException( e.getMessage(), e );
731 private List<ArtifactMetadata> runJcrQuery( String repositoryId, String q, Map<String, String> bindings )
732 throws MetadataRepositoryException
734 List<ArtifactMetadata> artifacts;
735 if ( repositoryId != null )
737 q += " AND ISDESCENDANTNODE(artifact,'/" + getRepositoryContentPath( repositoryId ) + "')";
740 log.info( "Running JCR Query: {}", q );
744 Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
745 ValueFactory valueFactory = getJcrSession().getValueFactory();
746 for ( Entry<String, String> entry : bindings.entrySet() )
748 query.bindValue( entry.getKey(), valueFactory.createValue( entry.getValue() ) );
750 long start = Calendar.getInstance().getTimeInMillis();
751 QueryResult result = query.execute();
752 long end = Calendar.getInstance().getTimeInMillis();
753 log.info( "JCR Query ran in {} milliseconds: {}", end - start , q );
755 artifacts = new ArrayList<>();
756 RowIterator rows = result.getRows();
757 while ( rows.hasNext() )
759 Row row = rows.nextRow();
760 Node node = row.getNode( "artifact" );
761 artifacts.add( getArtifactFromNode( repositoryId, node ) );
764 catch ( RepositoryException e )
766 throw new MetadataRepositoryException( e.getMessage(), e );
768 log.info("Artifacts found {}", artifacts.size());
769 for (ArtifactMetadata meta : artifacts) {
770 log.info("Artifact: "+meta.getVersion()+" "+meta.getFacetList());
776 public List<ArtifactMetadata> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
777 throws MetadataRepositoryException
780 "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + ARTIFACT_NODE_TYPE
781 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) INNER JOIN [" + FACET_NODE_TYPE
782 + "] AS facet ON ISCHILDNODE(facet, projectVersion) WHERE ([facet].[" + key + "] = $value)";
784 return runJcrQuery( repositoryId, q, ImmutableMap.of( "value", value ) );
789 public List<ArtifactMetadata> getArtifactsByMetadata( String key, String value, String repositoryId )
790 throws MetadataRepositoryException
793 "SELECT * FROM [" + ARTIFACT_NODE_TYPE + "] AS artifact INNER JOIN [" + FACET_NODE_TYPE
794 + "] AS facet ON ISCHILDNODE(facet, artifact) WHERE ([facet].[" + key + "] = $value)";
796 return runJcrQuery( repositoryId, q, ImmutableMap.of( "value", value ) );
801 public List<ArtifactMetadata> getArtifactsByProperty( String key, String value, String repositoryId )
802 throws MetadataRepositoryException
805 "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + ARTIFACT_NODE_TYPE
806 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) WHERE ([projectVersion].[" + key
809 return runJcrQuery( repositoryId, q, ImmutableMap.of( "value", value ) );
814 public void removeRepository( String repositoryId )
815 throws MetadataRepositoryException
819 Node root = getJcrSession().getRootNode();
820 String path = getRepositoryPath( repositoryId );
821 if ( root.hasNode( path ) )
823 root.getNode( path ).remove();
826 catch ( RepositoryException e )
828 throw new MetadataRepositoryException( e.getMessage(), e );
833 public List<ArtifactMetadata> getArtifacts( String repositoryId )
834 throws MetadataRepositoryException
836 List<ArtifactMetadata> artifacts;
838 String q = getArtifactQuery( repositoryId );
842 Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
843 QueryResult result = query.execute();
845 artifacts = new ArrayList<>();
846 for ( Node n : JcrUtils.getNodes( result ) )
848 if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
850 artifacts.add( getArtifactFromNode( repositoryId, n ) );
854 catch ( RepositoryException e )
856 throw new MetadataRepositoryException( e.getMessage(), e );
861 private static String getArtifactQuery( String repositoryId )
863 return "SELECT * FROM [" + ARTIFACT_NODE_TYPE + "] AS artifact WHERE ISDESCENDANTNODE(artifact,'/" +
864 getRepositoryContentPath( repositoryId ) + "')";
868 public ProjectMetadata getProject( String repositoryId, String namespace, String projectId )
869 throws MetadataResolutionException
871 ProjectMetadata metadata = null;
875 Node root = getJcrSession().getRootNode();
877 // basically just checking it exists
878 String path = getProjectPath( repositoryId, namespace, projectId );
879 if ( root.hasNode( path ) )
881 metadata = new ProjectMetadata();
882 metadata.setId( projectId );
883 metadata.setNamespace( namespace );
886 catch ( RepositoryException e )
888 throw new MetadataResolutionException( e.getMessage(), e );
895 public ProjectVersionMetadata getProjectVersion( String repositoryId, String namespace, String projectId,
896 String projectVersion )
897 throws MetadataResolutionException
899 ProjectVersionMetadata versionMetadata;
903 Node root = getJcrSession().getRootNode();
905 String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
906 if ( !root.hasNode( path ) )
911 Node node = root.getNode( path );
913 versionMetadata = new ProjectVersionMetadata();
914 versionMetadata.setId( projectVersion );
915 versionMetadata.setName( getPropertyString( node, "name" ) );
916 versionMetadata.setDescription( getPropertyString( node, "description" ) );
917 versionMetadata.setUrl( getPropertyString( node, "url" ) );
918 versionMetadata.setIncomplete(
919 node.hasProperty( "incomplete" ) && node.getProperty( "incomplete" ).getBoolean() );
921 // FIXME: decide how to treat these in the content repo
922 String scmConnection = getPropertyString( node, "scm.connection" );
923 String scmDeveloperConnection = getPropertyString( node, "scm.developerConnection" );
924 String scmUrl = getPropertyString( node, "scm.url" );
925 if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
928 scm.setConnection( scmConnection );
929 scm.setDeveloperConnection( scmDeveloperConnection );
930 scm.setUrl( scmUrl );
931 versionMetadata.setScm( scm );
934 String ciSystem = getPropertyString( node, "ci.system" );
935 String ciUrl = getPropertyString( node, "ci.url" );
936 if ( ciSystem != null || ciUrl != null )
938 CiManagement ci = new CiManagement();
939 ci.setSystem( ciSystem );
941 versionMetadata.setCiManagement( ci );
944 String issueSystem = getPropertyString( node, "issue.system" );
945 String issueUrl = getPropertyString( node, "issue.url" );
946 if ( issueSystem != null || issueUrl != null )
948 IssueManagement issueManagement = new IssueManagement();
949 issueManagement.setSystem( issueSystem );
950 issueManagement.setUrl( issueUrl );
951 versionMetadata.setIssueManagement( issueManagement );
954 String orgName = getPropertyString( node, "org.name" );
955 String orgUrl = getPropertyString( node, "org.url" );
956 if ( orgName != null || orgUrl != null )
958 Organization org = new Organization();
959 org.setName( orgName );
960 org.setUrl( orgUrl );
961 versionMetadata.setOrganization( org );
964 boolean done = false;
968 String licenseName = getPropertyString( node, "license." + i + ".name" );
969 String licenseUrl = getPropertyString( node, "license." + i + ".url" );
970 if ( licenseName != null || licenseUrl != null )
972 License license = new License();
973 license.setName( licenseName );
974 license.setUrl( licenseUrl );
975 versionMetadata.addLicense( license );
988 String mailingListName = getPropertyString( node, "mailingList." + i + ".name" );
989 if ( mailingListName != null )
991 MailingList mailingList = new MailingList();
992 mailingList.setName( mailingListName );
993 mailingList.setMainArchiveUrl( getPropertyString( node, "mailingList." + i + ".archive" ) );
994 String n = "mailingList." + i + ".otherArchives";
995 if ( node.hasProperty( n ) )
997 mailingList.setOtherArchives( Arrays.asList( getPropertyString( node, n ).split( "," ) ) );
1001 mailingList.setOtherArchives( Collections.<String>emptyList() );
1003 mailingList.setPostAddress( getPropertyString( node, "mailingList." + i + ".post" ) );
1004 mailingList.setSubscribeAddress( getPropertyString( node, "mailingList." + i + ".subscribe" ) );
1005 mailingList.setUnsubscribeAddress( getPropertyString( node, "mailingList." + i + ".unsubscribe" ) );
1006 versionMetadata.addMailingList( mailingList );
1015 if ( node.hasNode( "dependencies" ) )
1017 Node dependenciesNode = node.getNode( "dependencies" );
1018 for ( Node n : JcrUtils.getChildNodes( dependenciesNode ) )
1020 if ( n.isNodeType( DEPENDENCY_NODE_TYPE ) )
1022 Dependency dependency = new Dependency();
1023 // FIXME: correct these properties
1024 dependency.setArtifactId( getPropertyString( n, "artifactId" ) );
1025 dependency.setGroupId( getPropertyString( n, "groupId" ) );
1026 dependency.setClassifier( getPropertyString( n, "classifier" ) );
1027 dependency.setOptional( Boolean.valueOf( getPropertyString( n, "optional" ) ) );
1028 dependency.setScope( getPropertyString( n, "scope" ) );
1029 dependency.setSystemPath( getPropertyString( n, "systemPath" ) );
1030 dependency.setType( getPropertyString( n, "type" ) );
1031 dependency.setVersion( getPropertyString( n, "version" ) );
1032 versionMetadata.addDependency( dependency );
1037 for ( Node n : JcrUtils.getChildNodes( node ) )
1039 if ( n.isNodeType( FACET_NODE_TYPE ) )
1041 String name = n.getName();
1042 MetadataFacetFactory factory = metadataFacetFactories.get( name );
1043 if ( factory == null )
1045 log.error( "Attempted to load unknown project version metadata facet: {}", name );
1049 MetadataFacet facet = factory.createMetadataFacet();
1050 Map<String, String> map = new HashMap<>();
1051 for ( Property property : JcrUtils.getProperties( n ) )
1053 String p = property.getName();
1054 if ( !p.startsWith( "jcr:" ) )
1056 map.put( p, property.getString() );
1059 facet.fromProperties( map );
1060 versionMetadata.addFacet( facet );
1065 catch ( RepositoryException e )
1067 throw new MetadataResolutionException( e.getMessage(), e );
1070 return versionMetadata;
1074 public Collection<String> getArtifactVersions( String repositoryId, String namespace, String projectId,
1075 String projectVersion )
1076 throws MetadataResolutionException
1078 Set<String> versions = new LinkedHashSet<String>();
1082 Node root = getJcrSession().getRootNode();
1084 Node node = root.getNode( getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) );
1086 for ( Node n : JcrUtils.getChildNodes( node ) )
1088 versions.add( n.getProperty( "version" ).getString() );
1091 catch ( PathNotFoundException e )
1093 // ignore repo not found for now
1095 catch ( RepositoryException e )
1097 throw new MetadataResolutionException( e.getMessage(), e );
1104 public Collection<ProjectVersionReference> getProjectReferences( String repositoryId, String namespace,
1105 String projectId, String projectVersion )
1106 throws MetadataResolutionException
1109 List<ProjectVersionReference> references = new ArrayList<>();
1111 // TODO: bind variables instead
1112 String q = "SELECT * FROM [archiva:dependency] WHERE ISDESCENDANTNODE([/repositories/" + repositoryId +
1113 "/content]) AND [groupId]='" + namespace + "' AND [artifactId]='" + projectId + "'";
1114 if ( projectVersion != null )
1116 q += " AND [version]='" + projectVersion + "'";
1120 Query query = getJcrSession().getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
1121 QueryResult result = query.execute();
1123 for ( Node n : JcrUtils.getNodes( result ) )
1125 n = n.getParent(); // dependencies grouping element
1127 n = n.getParent(); // project version
1128 String usedByProjectVersion = n.getName();
1130 n = n.getParent(); // project
1131 String usedByProject = n.getName();
1133 n = n.getParent(); // namespace
1134 String usedByNamespace = n.getProperty( "namespace" ).getString();
1136 ProjectVersionReference ref = new ProjectVersionReference();
1137 ref.setNamespace( usedByNamespace );
1138 ref.setProjectId( usedByProject );
1139 ref.setProjectVersion( usedByProjectVersion );
1140 ref.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
1141 references.add( ref );
1144 catch ( RepositoryException e )
1146 throw new MetadataResolutionException( e.getMessage(), e );
1153 public Collection<String> getRootNamespaces( String repositoryId )
1154 throws MetadataResolutionException
1156 return getNamespaces( repositoryId, null );
1160 public Collection<String> getNamespaces( String repositoryId, String baseNamespace )
1161 throws MetadataResolutionException
1163 String path = baseNamespace != null
1164 ? getNamespacePath( repositoryId, baseNamespace )
1165 : getRepositoryContentPath( repositoryId );
1167 return getNodeNames( path, NAMESPACE_NODE_TYPE );
1171 public Collection<String> getProjects( String repositoryId, String namespace )
1172 throws MetadataResolutionException
1174 return getNodeNames( getNamespacePath( repositoryId, namespace ), PROJECT_NODE_TYPE );
1178 public Collection<String> getProjectVersions( String repositoryId, String namespace, String projectId )
1179 throws MetadataResolutionException
1181 return getNodeNames( getProjectPath( repositoryId, namespace, projectId ), PROJECT_VERSION_NODE_TYPE );
1185 public void removeArtifact( ArtifactMetadata artifactMetadata, String baseVersion )
1186 throws MetadataRepositoryException
1189 String repositoryId = artifactMetadata.getRepositoryId();
1193 Node root = getJcrSession().getRootNode();
1195 getProjectVersionPath( repositoryId, artifactMetadata.getNamespace(), artifactMetadata.getProject(),
1198 if ( root.hasNode( path ) )
1200 Node node = root.getNode( path );
1202 for ( Node n : JcrUtils.getChildNodes( node ) )
1204 if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
1206 if ( n.hasProperty( "version" ) )
1208 String version = n.getProperty( "version" ).getString();
1209 if ( StringUtils.equals( version, artifactMetadata.getVersion() ) )
1219 catch ( RepositoryException e )
1221 throw new MetadataRepositoryException( e.getMessage(), e );
1229 public void removeProjectVersion( String repoId, String namespace, String projectId, String projectVersion )
1230 throws MetadataRepositoryException
1235 String path = getProjectPath( repoId, namespace, projectId );
1236 Node root = getJcrSession().getRootNode();
1238 Node nodeAtPath = root.getNode( path );
1240 for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1242 if ( node.isNodeType( PROJECT_VERSION_NODE_TYPE ) && StringUtils.equals( projectVersion,
1249 catch ( RepositoryException e )
1251 throw new MetadataRepositoryException( e.getMessage(), e );
1256 public void removeArtifact( String repositoryId, String namespace, String projectId, String projectVersion,
1258 throws MetadataRepositoryException
1262 Node root = getJcrSession().getRootNode();
1263 String path = getArtifactPath( repositoryId, namespace, projectId, projectVersion, id );
1264 if ( root.hasNode( path ) )
1266 root.getNode( path ).remove();
1271 path = getProjectPath( repositoryId, namespace, projectId );
1273 Node nodeAtPath = root.getNode( path );
1275 for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1277 if ( node.isNodeType( PROJECT_VERSION_NODE_TYPE ) //
1278 && StringUtils.equals( node.getName(), projectVersion ) )
1284 catch ( RepositoryException e )
1286 throw new MetadataRepositoryException( e.getMessage(), e );
1291 public void removeArtifact( String repositoryId, String namespace, String project, String projectVersion,
1292 MetadataFacet metadataFacet )
1293 throws MetadataRepositoryException
1297 Node root = getJcrSession().getRootNode();
1298 String path = getProjectVersionPath( repositoryId, namespace, project, projectVersion );
1300 if ( root.hasNode( path ) )
1302 Node node = root.getNode( path );
1304 for ( Node n : JcrUtils.getChildNodes( node ) )
1306 if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
1308 ArtifactMetadata artifactMetadata = getArtifactFromNode( repositoryId, n );
1309 log.debug( "artifactMetadata: {}", artifactMetadata );
1310 MetadataFacet metadataFacetToRemove = artifactMetadata.getFacet( metadataFacet.getFacetId() );
1311 if ( metadataFacetToRemove != null && metadataFacet.equals( metadataFacetToRemove ) )
1319 catch ( RepositoryException e )
1321 throw new MetadataRepositoryException( e.getMessage(), e );
1326 public Collection<ArtifactMetadata> getArtifacts( String repositoryId, String namespace, String projectId,
1327 String projectVersion )
1328 throws MetadataResolutionException
1330 List<ArtifactMetadata> artifacts = new ArrayList<>();
1334 Node root = getJcrSession().getRootNode();
1335 String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
1337 if ( root.hasNode( path ) )
1339 Node node = root.getNode( path );
1341 for ( Node n : JcrUtils.getChildNodes( node ) )
1343 if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
1345 artifacts.add( getArtifactFromNode( repositoryId, n ) );
1350 catch ( RepositoryException e )
1352 throw new MetadataResolutionException( e.getMessage(), e );
1363 getJcrSession().save();
1364 } catch ( InvalidItemStateException e ) {
1365 // olamy this might happen when deleting a repo while is under scanning
1366 log.warn( "skip InvalidItemStateException:{}", e.getMessage(), e );
1368 catch ( RepositoryException e )
1370 throw new RuntimeException( e.getMessage(), e );
1375 public void revert()
1379 getJcrSession().refresh( false );
1381 catch ( RepositoryException e )
1383 throw new RuntimeException( e.getMessage(), e );
1388 public boolean canObtainAccess( Class<?> aClass )
1390 return aClass == Session.class;
1394 public <T>T obtainAccess( Class<T> aClass )
1395 throws MetadataRepositoryException
1397 if ( aClass == Session.class )
1401 return (T) getJcrSession();
1403 catch ( RepositoryException e )
1405 log.error( e.getMessage(), e );
1406 throw new MetadataRepositoryException( e.getMessage(), e );
1409 throw new IllegalArgumentException(
1410 "Access using " + aClass + " is not supported on the JCR metadata storage" );
1415 throws MetadataRepositoryException
1417 if ( jcrSession != null && jcrSession.isLive() )
1419 jcrSession.logout();
1425 * Exact is ignored as we can't do exact search in any property, we need a key
1428 public List<ArtifactMetadata> searchArtifacts( String text, String repositoryId, boolean exact )
1429 throws MetadataRepositoryException
1431 return searchArtifacts( null, text, repositoryId, exact );
1435 public List<ArtifactMetadata> searchArtifacts( String key, String text, String repositoryId, boolean e )
1436 throws MetadataRepositoryException
1438 String theKey = key == null ? "*" : "[" + key + "]";
1439 String projectVersionCondition =
1440 e ? "(projectVersion." + theKey + " = $value)" : "contains([projectVersion]." + theKey + ", $value)";
1441 String facetCondition = e ? "(facet." + theKey + " = $value)" : "contains([facet]." + theKey + ", $value)";
1443 "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE + "] AS projectVersion LEFT OUTER JOIN ["
1444 + ARTIFACT_NODE_TYPE + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) LEFT OUTER JOIN ["
1445 + FACET_NODE_TYPE + "] AS facet ON ISCHILDNODE(facet, projectVersion) WHERE ("
1446 + projectVersionCondition + " OR " + facetCondition + ")";
1447 return runJcrQuery( repositoryId, q, ImmutableMap.of( "value", text ) );
1450 private ArtifactMetadata getArtifactFromNode( String repositoryId, Node artifactNode )
1451 throws RepositoryException
1453 String id = artifactNode.getName();
1455 ArtifactMetadata artifact = new ArtifactMetadata();
1456 artifact.setId( id );
1457 artifact.setRepositoryId( repositoryId == null ? artifactNode.getAncestor(2).getName() : repositoryId );
1459 Node projectVersionNode = artifactNode.getParent();
1460 Node projectNode = projectVersionNode.getParent();
1461 Node namespaceNode = projectNode.getParent();
1463 artifact.setNamespace( namespaceNode.getProperty( "namespace" ).getString() );
1464 artifact.setProject( projectNode.getName() );
1465 artifact.setProjectVersion( projectVersionNode.getName() );
1466 artifact.setVersion( artifactNode.hasProperty( "version" )
1467 ? artifactNode.getProperty( "version" ).getString()
1468 : projectVersionNode.getName() );
1470 if ( artifactNode.hasProperty( JCR_LAST_MODIFIED ) )
1472 artifact.setFileLastModified( artifactNode.getProperty( JCR_LAST_MODIFIED ).getDate().getTimeInMillis() );
1475 if ( artifactNode.hasProperty( "whenGathered" ) )
1477 artifact.setWhenGathered( artifactNode.getProperty( "whenGathered" ).getDate().getTime() );
1480 if ( artifactNode.hasProperty( "size" ) )
1482 artifact.setSize( artifactNode.getProperty( "size" ).getLong() );
1485 if ( artifactNode.hasProperty( "md5" ) )
1487 artifact.setMd5( artifactNode.getProperty( "md5" ).getString() );
1490 if ( artifactNode.hasProperty( "sha1" ) )
1492 artifact.setSha1( artifactNode.getProperty( "sha1" ).getString() );
1495 for ( Node n : JcrUtils.getChildNodes( artifactNode ) )
1497 if ( n.isNodeType( FACET_NODE_TYPE ) )
1499 String name = n.getName();
1500 MetadataFacetFactory factory = metadataFacetFactories.get( name );
1501 if ( factory == null )
1503 log.error( "Attempted to load unknown project version metadata facet: {}", name );
1507 MetadataFacet facet = factory.createMetadataFacet();
1508 Map<String, String> map = new HashMap<>();
1509 for ( Property p : JcrUtils.getProperties( n ) )
1511 String property = p.getName();
1512 if ( !property.startsWith( "jcr:" ) )
1514 map.put( property, p.getString() );
1517 facet.fromProperties( map );
1518 artifact.addFacet( facet );
1525 private static String getPropertyString( Node node, String name )
1526 throws RepositoryException
1528 return node.hasProperty( name ) ? node.getProperty( name ).getString() : null;
1531 private Collection<String> getNodeNames( String path, String nodeType )
1532 throws MetadataResolutionException
1534 List<String> names = new ArrayList<>();
1538 Node root = getJcrSession().getRootNode();
1540 Node nodeAtPath = root.getNode( path );
1542 for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1544 if ( node.isNodeType( nodeType ) )
1546 names.add( node.getName() );
1550 catch ( PathNotFoundException e )
1552 // ignore repo not found for now
1554 catch ( RepositoryException e )
1556 throw new MetadataResolutionException( e.getMessage(), e );
1562 private static String getRepositoryPath( String repositoryId )
1564 return "repositories/" + repositoryId;
1567 private static String getRepositoryContentPath( String repositoryId )
1569 return getRepositoryPath( repositoryId ) + "/content";
1572 private static String getFacetPath( String repositoryId, String facetId )
1574 return getRepositoryPath( repositoryId ) + "/facets/" + facetId;
1577 private static String getNamespacePath( String repositoryId, String namespace )
1579 return getRepositoryContentPath( repositoryId ) + "/" + namespace.replace( '.', '/' );
1582 private static String getProjectPath( String repositoryId, String namespace, String projectId )
1584 return getNamespacePath( repositoryId, namespace ) + "/" + projectId;
1587 private static String getProjectVersionPath( String repositoryId, String namespace, String projectId,
1588 String projectVersion )
1590 return getProjectPath( repositoryId, namespace, projectId ) + "/" + projectVersion;
1593 private static String getArtifactPath( String repositoryId, String namespace, String projectId,
1594 String projectVersion, String id )
1596 return getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) + "/" + id;
1599 private Node getOrAddNodeByPath( Node baseNode, String name )
1600 throws RepositoryException
1602 return getOrAddNodeByPath( baseNode, name, null );
1605 private Node getOrAddNodeByPath( Node baseNode, String name, String nodeType )
1606 throws RepositoryException
1608 log.debug("getOrAddNodeByPath"+baseNode+" "+name+" "+nodeType);
1609 Node node = baseNode;
1610 for ( String n : name.split( "/" ) )
1612 node = JcrUtils.getOrAddNode( node, n );
1613 if ( nodeType != null )
1615 node.addMixin( nodeType );
1621 private static String getFacetPath( String repositoryId, String facetId, String name )
1623 return getFacetPath( repositoryId, facetId ) + "/" + name;
1626 private Node getOrAddRepositoryNode( String repositoryId )
1627 throws RepositoryException
1629 log.debug("getOrAddRepositoryNode "+repositoryId);
1630 Node root = getJcrSession().getRootNode();
1631 Node node = JcrUtils.getOrAddNode( root, "repositories" );
1632 log.debug("Repositories "+node);
1633 node = JcrUtils.getOrAddNode( node, repositoryId );
1637 private Node getOrAddRepositoryContentNode( String repositoryId )
1638 throws RepositoryException
1640 Node node = getOrAddRepositoryNode( repositoryId );
1641 return JcrUtils.getOrAddNode( node, "content" );
1644 private Node getOrAddNamespaceNode( String repositoryId, String namespace )
1645 throws RepositoryException
1647 Node repo = getOrAddRepositoryContentNode( repositoryId );
1648 return getOrAddNodeByPath( repo, namespace.replace( '.', '/' ), NAMESPACE_NODE_TYPE );
1651 private Node getOrAddProjectNode( String repositoryId, String namespace, String projectId )
1652 throws RepositoryException
1654 Node namespaceNode = getOrAddNamespaceNode( repositoryId, namespace );
1655 Node node = JcrUtils.getOrAddNode( namespaceNode, projectId );
1656 node.addMixin( PROJECT_NODE_TYPE );
1660 private Node getOrAddProjectVersionNode( String repositoryId, String namespace, String projectId,
1661 String projectVersion )
1662 throws RepositoryException
1664 Node projectNode = getOrAddProjectNode( repositoryId, namespace, projectId );
1665 Node node = JcrUtils.getOrAddNode( projectNode, projectVersion );
1666 node.addMixin( PROJECT_VERSION_NODE_TYPE );
1670 private Node getOrAddArtifactNode( String repositoryId, String namespace, String projectId, String projectVersion,
1672 throws RepositoryException
1674 Node versionNode = getOrAddProjectVersionNode( repositoryId, namespace, projectId, projectVersion );
1675 Node node = JcrUtils.getOrAddNode( versionNode, id );
1676 node.addMixin( ARTIFACT_NODE_TYPE );
1680 private static Calendar createCalendar( Date time )
1682 Calendar cal = Calendar.getInstance();
1683 cal.setTime( time );
1687 private String join( Collection<String> ids )
1689 if ( ids != null && !ids.isEmpty() )
1691 StringBuilder s = new StringBuilder();
1692 for ( String id : ids )
1697 return s.substring( 0, s.length() - 1 );
1702 public Session getJcrSession()
1703 throws RepositoryException
1705 if ( this.jcrSession == null || !this.jcrSession.isLive() )
1707 jcrSession = repository.login( new SimpleCredentials( "admin", "admin".toCharArray() ) );
1709 return this.jcrSession;
1713 public void populateStatistics( MetadataRepository repository, String repositoryId,
1714 RepositoryStatistics repositoryStatistics )
1715 throws MetadataRepositoryException
1717 if (!(repository instanceof JcrMetadataRepository)) {
1718 throw new MetadataRepositoryException( "The statistics population is only possible for JcrMetdataRepository implementations" );
1720 Session session = (Session) repository.obtainAccess( Session.class );
1721 // TODO: these may be best as running totals, maintained by observations on the properties in JCR
1725 QueryManager queryManager = session.getWorkspace().getQueryManager();
1727 // TODO: JCR-SQL2 query will not complete on a large repo in Jackrabbit 2.2.0 - see JCR-2835
1728 // Using the JCR-SQL2 variants gives
1729 // "org.apache.lucene.search.BooleanQuery$TooManyClauses: maxClauseCount is set to 1024"
1730 // String whereClause = "WHERE ISDESCENDANTNODE([/repositories/" + repositoryId + "/content])";
1731 // Query query = queryManager.createQuery( "SELECT size FROM [archiva:artifact] " + whereClause,
1732 // Query.JCR_SQL2 );
1733 String whereClause = "WHERE jcr:path LIKE '/repositories/" + repositoryId + "/content/%'";
1734 Query query = queryManager.createQuery( "SELECT size FROM archiva:artifact " + whereClause, Query.SQL );
1736 QueryResult queryResult = query.execute();
1738 Map<String, Integer> totalByType = new HashMap<>();
1739 long totalSize = 0, totalArtifacts = 0;
1740 for ( Row row : JcrUtils.getRows( queryResult ) )
1742 Node n = row.getNode();
1743 totalSize += row.getValue( "size" ).getLong();
1746 if ( n.hasNode( MavenArtifactFacet.FACET_ID ) )
1748 Node facetNode = n.getNode( MavenArtifactFacet.FACET_ID );
1749 type = facetNode.getProperty( "type" ).getString();
1755 Integer prev = totalByType.get( type );
1756 totalByType.put( type, prev != null ? prev + 1 : 1 );
1761 repositoryStatistics.setTotalArtifactCount( totalArtifacts );
1762 repositoryStatistics.setTotalArtifactFileSize( totalSize );
1763 for ( Map.Entry<String, Integer> entry : totalByType.entrySet() )
1765 System.out.println("Setting count for type: "+entry.getKey()+" = "+entry.getValue());
1766 repositoryStatistics.setTotalCountForType( entry.getKey(), entry.getValue() );
1769 // The query ordering is a trick to ensure that the size is correct, otherwise due to lazy init it will be -1
1770 // query = queryManager.createQuery( "SELECT * FROM [archiva:project] " + whereClause, Query.JCR_SQL2 );
1771 query = queryManager.createQuery( "SELECT * FROM archiva:project " + whereClause + " ORDER BY jcr:score",
1773 repositoryStatistics.setTotalProjectCount( query.execute().getRows().getSize() );
1775 // query = queryManager.createQuery(
1776 // "SELECT * FROM [archiva:namespace] " + whereClause + " AND namespace IS NOT NULL", Query.JCR_SQL2 );
1777 query = queryManager.createQuery(
1778 "SELECT * FROM archiva:namespace " + whereClause + " AND namespace IS NOT NULL ORDER BY jcr:score",
1780 repositoryStatistics.setTotalGroupCount( query.execute().getRows().getSize() );
1782 catch ( RepositoryException e )
1784 throw new MetadataRepositoryException( e.getMessage(), e );