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.FacetedMetadata;
27 import org.apache.archiva.metadata.model.IssueManagement;
28 import org.apache.archiva.metadata.model.License;
29 import org.apache.archiva.metadata.model.MailingList;
30 import org.apache.archiva.metadata.model.MetadataFacet;
31 import org.apache.archiva.metadata.model.MetadataFacetFactory;
32 import org.apache.archiva.metadata.model.Organization;
33 import org.apache.archiva.metadata.model.ProjectMetadata;
34 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
35 import org.apache.archiva.metadata.model.ProjectVersionReference;
36 import org.apache.archiva.metadata.model.Scm;
37 import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
38 import org.apache.archiva.metadata.repository.MetadataRepository;
39 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
40 import org.apache.archiva.metadata.repository.MetadataResolutionException;
41 import org.apache.archiva.metadata.repository.RepositorySession;
42 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
43 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsProvider;
44 import org.apache.commons.lang.StringUtils;
45 import org.apache.jackrabbit.JcrConstants;
46 import org.apache.jackrabbit.commons.JcrUtils;
47 import org.apache.jackrabbit.commons.cnd.CndImporter;
48 import org.apache.jackrabbit.commons.cnd.ParseException;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
52 import javax.jcr.NamespaceRegistry;
53 import javax.jcr.Node;
54 import javax.jcr.PathNotFoundException;
55 import javax.jcr.Property;
56 import javax.jcr.Repository;
57 import javax.jcr.RepositoryException;
58 import javax.jcr.Session;
59 import javax.jcr.SimpleCredentials;
60 import javax.jcr.ValueFactory;
61 import javax.jcr.Workspace;
62 import javax.jcr.nodetype.NodeTypeManager;
63 import javax.jcr.nodetype.NodeTypeTemplate;
64 import javax.jcr.query.Query;
65 import javax.jcr.query.QueryManager;
66 import javax.jcr.query.QueryResult;
67 import javax.jcr.query.Row;
68 import javax.jcr.query.RowIterator;
69 import java.io.IOException;
70 import java.io.InputStreamReader;
71 import java.io.Reader;
72 import java.util.ArrayList;
73 import java.util.Arrays;
74 import java.util.Calendar;
75 import java.util.Collection;
76 import java.util.Collections;
77 import java.util.Date;
78 import java.util.HashMap;
79 import java.util.Iterator;
80 import java.util.LinkedHashSet;
81 import java.util.List;
83 import java.util.Map.Entry;
86 import static javax.jcr.Property.JCR_LAST_MODIFIED;
87 import static org.apache.archiva.metadata.repository.jcr.JcrConstants.DEPENDENCY_NODE_TYPE;
88 import static org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_VERSION_PROPERTIES;
91 * TODO below: revise storage format for project version metadata
92 * TODO revise reference storage
94 public class JcrMetadataRepository
95 implements MetadataRepository, RepositoryStatisticsProvider
99 private static final String QUERY_ARTIFACT_1 = "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE + "] AS artifact WHERE ISDESCENDANTNODE(artifact,'/";
101 static final String QUERY_ARTIFACTS_BY_PROJECT_VERSION_1 = "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE
102 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) INNER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE
103 + "] AS facet ON ISCHILDNODE(facet, projectVersion) WHERE ([facet].[";
104 static final String QUERY_ARTIFACTS_BY_PROJECT_VERSION_2= "] = $value)";
106 static final String QUERY_ARTIFACTS_BY_METADATA_1 = "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE + "] AS artifact INNER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE
107 + "] AS facet ON ISCHILDNODE(facet, artifact) WHERE ([facet].[";
108 static final String QUERY_ARTIFACTS_BY_METADATA_2 = "] = $value)";
110 static final String QUERY_ARTIFACTS_BY_PROPERTY_1 = "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE
111 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) WHERE ([projectVersion].[";
112 static final String QUERY_ARTIFACTS_BY_PROPERTY_2 = "] = $value)";
115 private static final String QUERY_ARTIFACT_2 = "')";
117 private final Map<String, MetadataFacetFactory> metadataFacetFactories;
119 private Logger log = LoggerFactory.getLogger( JcrMetadataRepository.class );
121 private Repository repository;
123 public JcrMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories, Repository repository )
124 throws RepositoryException
126 this.metadataFacetFactories = metadataFacetFactories;
127 this.repository = repository;
131 public static void initializeNodeTypes( Session session )
132 throws RepositoryException
135 // TODO: consider using namespaces for facets instead of the current approach:
136 // (if used, check if actually called by normal injection)
137 // for ( String facetId : metadataFacetFactories.keySet() )
139 // session.getWorkspace().getNamespaceRegistry().registerNamespace( facetId, facetId );
141 Workspace workspace = session.getWorkspace();
142 NamespaceRegistry registry = workspace.getNamespaceRegistry();
144 if ( !Arrays.asList( registry.getPrefixes() ).contains( "archiva" ) )
146 registry.registerNamespace( "archiva", "http://archiva.apache.org/jcr/" );
149 NodeTypeManager nodeTypeManager = workspace.getNodeTypeManager();
151 Reader cndReader = new InputStreamReader(
152 Thread.currentThread( ).getContextClassLoader( ).getResourceAsStream( "org/apache/archiva/metadata/repository/jcr/jcr-schema.cnd" ) ))
154 CndImporter.registerNodeTypes( cndReader, session );
156 catch ( ParseException e )
158 e.printStackTrace( );
160 catch ( IOException e )
162 e.printStackTrace( );
166 // registerMixinNodeType( nodeTypeManager, REPOSITORY_NODE_TYPE );
167 // registerMixinNodeType( nodeTypeManager, NAMESPACE_NODE_TYPE );
168 // registerMixinNodeType( nodeTypeManager, PROJECT_NODE_TYPE );
169 // registerMixinNodeType( nodeTypeManager, PROJECT_VERSION_NODE_TYPE );
170 // registerMixinNodeType( nodeTypeManager, ARTIFACT_NODE_TYPE );
171 // registerMixinNodeType( nodeTypeManager, FACET_NODE_TYPE );
172 // registerMixinNodeType( nodeTypeManager, DEPENDENCY_NODE_TYPE );
177 private static void registerMixinNodeType( NodeTypeManager nodeTypeManager, String name )
178 throws RepositoryException
180 // for now just don't re-create - but in future if we change the definition, make sure to remove first as an
182 if ( !nodeTypeManager.hasNodeType( name ) )
184 NodeTypeTemplate nodeType = nodeTypeManager.createNodeTypeTemplate();
185 nodeType.setMixin( true );
186 nodeType.setName( name );
187 nodeType.setQueryable( true );
188 nodeTypeManager.registerNodeType( nodeType, false );
192 private Session getSession(RepositorySession repositorySession) throws MetadataRepositoryException {
193 if (repositorySession instanceof JcrRepositorySession ) {
194 return ( (JcrRepositorySession) repositorySession ).getJcrSession();
196 throw new MetadataRepositoryException( "The given session object is not a JcrSession instance: " + repositorySession.getClass( ).getName( ) );
201 public void updateProject( RepositorySession session, String repositoryId, ProjectMetadata project )
202 throws MetadataRepositoryException
204 final Session jcrSession = getSession( session );
205 updateProject( jcrSession, repositoryId, project.getNamespace(), project.getId() );
208 private void updateProject( Session jcrSession, String repositoryId, String namespace, String projectId )
209 throws MetadataRepositoryException
211 updateNamespace( jcrSession , repositoryId, namespace );
215 getOrAddProjectNode( jcrSession, repositoryId, namespace, projectId );
217 catch ( RepositoryException e )
219 throw new MetadataRepositoryException( e.getMessage(), e );
224 public void updateArtifact( RepositorySession session, String repositoryId, String namespace, String projectId, String projectVersion,
225 ArtifactMetadata artifactMeta )
226 throws MetadataRepositoryException
228 final Session jcrSession = getSession( session );
229 updateNamespace( session, repositoryId, namespace );
234 getOrAddArtifactNode( jcrSession, repositoryId, namespace, projectId, projectVersion, artifactMeta.getId() );
236 node.setProperty( "id", artifactMeta.getId( ) );
237 Calendar cal = Calendar.getInstance();
238 cal.setTime( artifactMeta.getFileLastModified() );
239 node.setProperty( JCR_LAST_MODIFIED, cal );
241 cal = Calendar.getInstance();
242 cal.setTime( artifactMeta.getWhenGathered() );
243 node.setProperty( "whenGathered", cal );
245 node.setProperty( "size", artifactMeta.getSize() );
246 node.setProperty( "md5", artifactMeta.getMd5() );
247 node.setProperty( "sha1", artifactMeta.getSha1() );
249 node.setProperty( "version", artifactMeta.getVersion() );
251 // iterate over available facets to update/add/remove from the artifactMetadata
252 for ( String facetId : metadataFacetFactories.keySet() )
254 MetadataFacet metadataFacet = artifactMeta.getFacet( facetId );
255 if ( metadataFacet == null )
259 if ( node.hasNode( facetId ) )
261 node.getNode( facetId ).remove();
263 if ( metadataFacet != null )
265 // recreate, to ensure properties are removed
266 Node n = node.addNode( facetId);
267 n.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE );
269 for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
271 n.setProperty( entry.getKey(), entry.getValue() );
276 catch ( RepositoryException e )
278 throw new MetadataRepositoryException( e.getMessage(), e );
283 public void updateProjectVersion( RepositorySession session, String repositoryId, String namespace, String projectId,
284 ProjectVersionMetadata versionMetadata )
285 throws MetadataRepositoryException
287 final Session jcrSession = getSession( session );
288 updateProject( jcrSession, repositoryId, namespace, projectId );
293 getOrAddProjectVersionNode( jcrSession, repositoryId, namespace, projectId, versionMetadata.getId() );
294 versionNode.setProperty( "id", versionMetadata.getId( ) );
295 versionNode.setProperty( "name", StringUtils.isEmpty( versionMetadata.getName() ) ? "" : versionMetadata.getName() );
296 versionNode.setProperty( "description", StringUtils.isEmpty( versionMetadata.getDescription() ) ? "" : versionMetadata.getDescription() );
297 versionNode.setProperty( "url", versionMetadata.getUrl() );
298 versionNode.setProperty( "incomplete", versionMetadata.isIncomplete() );
300 // FIXME: decide how to treat these in the content repo
301 if ( versionMetadata.getScm() != null )
303 versionNode.setProperty( "scm.connection", versionMetadata.getScm().getConnection() );
304 versionNode.setProperty( "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
305 versionNode.setProperty( "scm.url", versionMetadata.getScm().getUrl() );
307 if ( versionMetadata.getCiManagement() != null )
309 versionNode.setProperty( "ci.system", versionMetadata.getCiManagement().getSystem() );
310 versionNode.setProperty( "ci.url", versionMetadata.getCiManagement().getUrl() );
312 if ( versionMetadata.getIssueManagement() != null )
314 versionNode.setProperty( "issue.system", versionMetadata.getIssueManagement().getSystem() );
315 versionNode.setProperty( "issue.url", versionMetadata.getIssueManagement().getUrl() );
317 if ( versionMetadata.getOrganization() != null )
319 versionNode.setProperty( "org.name", versionMetadata.getOrganization().getName() );
320 versionNode.setProperty( "org.url", versionMetadata.getOrganization().getUrl() );
323 for ( License license : versionMetadata.getLicenses() )
325 versionNode.setProperty( "license." + i + ".name", license.getName() );
326 versionNode.setProperty( "license." + i + ".url", license.getUrl() );
330 for ( MailingList mailingList : versionMetadata.getMailingLists() )
332 versionNode.setProperty( "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
333 versionNode.setProperty( "mailingList." + i + ".name", mailingList.getName() );
334 versionNode.setProperty( "mailingList." + i + ".post", mailingList.getPostAddress() );
335 versionNode.setProperty( "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
336 versionNode.setProperty( "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
337 versionNode.setProperty( "mailingList." + i + ".otherArchives",
338 join( mailingList.getOtherArchives() ) );
342 if ( !versionMetadata.getDependencies().isEmpty() )
344 Node dependenciesNode = JcrUtils.getOrAddNode( versionNode, "dependencies" );
346 for ( Dependency dependency : versionMetadata.getDependencies() )
348 // Note that we deliberately don't alter the namespace path - not enough dependencies for
349 // number of nodes at a given depth to be an issue. Similarly, we don't add subnodes for each
350 // component of the ID as that creates extra depth and causes a great cost in space and memory
352 // FIXME: change group ID to namespace
353 // FIXME: change to artifact's ID - this is constructed by the Maven 2 format for now.
354 // This won't support types where the extension doesn't match the type.
355 // (see also Maven2RepositoryStorage#readProjectVersionMetadata construction of POM)
357 dependency.getGroupId() + ";" + dependency.getArtifactId() + "-" + dependency.getVersion();
358 if ( dependency.getClassifier() != null )
360 id += "-" + dependency.getClassifier();
362 id += "." + dependency.getType();
364 Node n = JcrUtils.getOrAddNode( dependenciesNode, id, DEPENDENCY_NODE_TYPE );
365 n.setProperty( "id", id );
367 // FIXME: remove temp code just to make it keep working
368 n.setProperty( "groupId", dependency.getGroupId() );
369 n.setProperty( "artifactId", dependency.getArtifactId() );
370 n.setProperty( "version", dependency.getVersion() );
371 n.setProperty( "type", dependency.getType() );
372 n.setProperty( "classifier", dependency.getClassifier() );
373 n.setProperty( "scope", dependency.getScope() );
374 n.setProperty( "systemPath", dependency.getSystemPath() );
375 n.setProperty( "optional", dependency.isOptional() );
377 // node has no native content at this time, just facets
378 // no need to list a type as it's implied by the path. Parents are Maven specific.
380 // FIXME: add scope, systemPath, type, version, classifier & maven2 specific IDs as a facet
381 // (should also have been added to the Dependency)
383 // TODO: add a property that is a weak reference to the originating artifact, creating it if
384 // necessary (without adding the archiva:artifact mixin so that it doesn't get listed as an
385 // artifact, which gives a different meaning to "incomplete" which is a known local project
386 // that doesn't have metadata yet but has artifacts). (Though we may want to give it the
387 // artifact mixin and another property to identify all non-local artifacts for the closure
392 for ( MetadataFacet facet : versionMetadata.getFacetList() )
394 // recreate, to ensure properties are removed
395 if ( versionNode.hasNode( facet.getFacetId() ) )
397 versionNode.getNode( facet.getFacetId() ).remove();
399 Node n = versionNode.addNode( facet.getFacetId() );
400 n.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE );
402 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
404 n.setProperty( entry.getKey(), entry.getValue() );
408 catch ( RepositoryException e )
410 throw new MetadataRepositoryException( e.getMessage(), e );
414 private void updateNamespace(Session jcrSession, String repositoryId, String namespace) throws MetadataRepositoryException
418 Node node = getOrAddNamespaceNode( jcrSession, repositoryId, namespace );
419 node.setProperty( "id", namespace );
420 node.setProperty( "namespace", namespace );
422 catch ( RepositoryException e )
424 throw new MetadataRepositoryException( e.getMessage(), e );
429 public void updateNamespace( RepositorySession session, String repositoryId, String namespace )
430 throws MetadataRepositoryException
432 updateNamespace( getSession(session), repositoryId, namespace );
436 public void removeProject( RepositorySession session, String repositoryId, String namespace, String projectId )
437 throws MetadataRepositoryException
439 final Session jcrSession = getSession( session );
442 Node root = jcrSession.getRootNode();
443 String namespacePath = getNamespacePath( repositoryId, namespace );
445 if ( root.hasNode( namespacePath ) )
447 Iterator<Node> nodeIterator = JcrUtils.getChildNodes( root.getNode( namespacePath ) ).iterator();
448 while ( nodeIterator.hasNext() )
450 Node node = nodeIterator.next();
451 if ( node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_NODE_TYPE ) && projectId.equals( node.getName() ) )
459 catch ( RepositoryException e )
461 throw new MetadataRepositoryException( e.getMessage(), e );
468 public boolean hasMetadataFacet( RepositorySession session, String repositoryId, String facetId )
469 throws MetadataRepositoryException
471 final Session jcrSession = getSession( session );
474 Node node = jcrSession.getRootNode().getNode( getFacetPath( repositoryId, facetId ) );
475 return node.getNodes().hasNext();
477 catch ( PathNotFoundException e )
479 // ignored - the facet doesn't exist, so return false
482 catch ( RepositoryException e )
484 throw new MetadataRepositoryException( e.getMessage(), e );
489 public List<String> getMetadataFacets( RepositorySession session, String repositoryId, String facetId )
490 throws MetadataRepositoryException
492 final Session jcrSession = getSession( session );
493 List<String> facets = new ArrayList<>();
497 // no need to construct node-by-node here, as we'll find in the next instance, the facet names have / and
498 // are paths themselves
499 Node node = jcrSession.getRootNode().getNode( getFacetPath( repositoryId, facetId ) );
501 // TODO: this is a bit awkward. Might be better to review the purpose of this function - why is the list of
503 recurse( facets, "", node );
505 catch ( PathNotFoundException e )
507 // ignored - the facet doesn't exist, so return the empty list
509 catch ( RepositoryException e )
511 throw new MetadataRepositoryException( e.getMessage(), e );
516 private void recurse( List<String> facets, String prefix, Node node )
517 throws RepositoryException
519 for ( Node n : JcrUtils.getChildNodes( node ) )
521 String name = prefix + "/" + n.getName();
524 recurse( facets, name, n );
528 // strip leading / first
529 facets.add( name.substring( 1 ) );
535 public MetadataFacet getMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
536 throws MetadataRepositoryException
538 final Session jcrSession = getSession( session );
539 MetadataFacet metadataFacet = null;
542 Node root = jcrSession.getRootNode();
543 Node node = root.getNode( getFacetPath( repositoryId, facetId, name ) );
545 if ( metadataFacetFactories == null )
547 return metadataFacet;
550 MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
551 if ( metadataFacetFactory != null )
553 metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
554 Map<String, String> map = new HashMap<>();
555 for ( Property property : JcrUtils.getProperties( node ) )
557 String p = property.getName();
558 if ( !p.startsWith( "jcr:" ) )
560 map.put( p, property.getString() );
563 metadataFacet.fromProperties( map );
566 catch ( PathNotFoundException e )
568 // ignored - the facet doesn't exist, so return null
570 catch ( RepositoryException e )
572 throw new MetadataRepositoryException( e.getMessage(), e );
574 return metadataFacet;
578 public void addMetadataFacet( RepositorySession session, String repositoryId, MetadataFacet metadataFacet )
579 throws MetadataRepositoryException
581 final Session jcrSession = getSession( session );
584 Node repo = getOrAddRepositoryNode( jcrSession, repositoryId );
585 Node facets = JcrUtils.getOrAddNode( repo, "facets" );
587 String id = metadataFacet.getFacetId();
588 Node facetNode = JcrUtils.getOrAddNode( facets, id );
590 Node node = getOrAddNodeByPath( facetNode, metadataFacet.getName() );
592 for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
594 node.setProperty( entry.getKey(), entry.getValue() );
597 catch ( RepositoryException e )
599 throw new MetadataRepositoryException( e.getMessage(), e );
604 public void removeNamespace( RepositorySession session, String repositoryId, String projectId )
605 throws MetadataRepositoryException
607 final Session jcrSession = getSession( session );
610 Node root = jcrSession.getRootNode();
611 String path = getNamespacePath( repositoryId, projectId );
612 if ( root.hasNode( path ) )
614 Node node = root.getNode( path );
615 if ( node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.NAMESPACE_NODE_TYPE ) )
621 catch ( RepositoryException e )
623 throw new MetadataRepositoryException( e.getMessage(), e );
628 public void removeMetadataFacets( RepositorySession session, String repositoryId, String facetId )
629 throws MetadataRepositoryException
631 final Session jcrSession = getSession( session );
634 Node root = jcrSession.getRootNode();
635 String path = getFacetPath( repositoryId, facetId );
636 if ( root.hasNode( path ) )
638 root.getNode( path ).remove();
641 catch ( RepositoryException e )
643 throw new MetadataRepositoryException( e.getMessage(), e );
648 public void removeMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
649 throws MetadataRepositoryException
651 final Session jcrSession = getSession( session );
654 Node root = jcrSession.getRootNode();
655 String path = getFacetPath( repositoryId, facetId, name );
656 if ( root.hasNode( path ) )
658 Node node = root.getNode( path );
661 // also remove empty container nodes
662 Node parent = node.getParent();
666 while ( !node.hasNodes() );
669 catch ( RepositoryException e )
671 throw new MetadataRepositoryException( e.getMessage(), e );
676 public List<ArtifactMetadata> getArtifactsByDateRange( RepositorySession session, String repoId, Date startTime, Date endTime )
677 throws MetadataRepositoryException
679 final Session jcrSession = getSession( session );
681 List<ArtifactMetadata> artifacts;
683 String q = getArtifactQuery( repoId );
685 if ( startTime != null )
687 q += " AND [whenGathered] >= $start";
689 if ( endTime != null )
691 q += " AND [whenGathered] <= $end";
696 Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
697 ValueFactory valueFactory = jcrSession.getValueFactory();
698 if ( startTime != null )
700 query.bindValue( "start", valueFactory.createValue( createCalendar( startTime ) ) );
702 if ( endTime != null )
704 query.bindValue( "end", valueFactory.createValue( createCalendar( endTime ) ) );
706 QueryResult result = query.execute();
708 artifacts = new ArrayList<>();
709 for ( Node n : JcrUtils.getNodes( result ) )
711 artifacts.add( getArtifactFromNode( repoId, n ) );
714 catch ( RepositoryException e )
716 throw new MetadataRepositoryException( e.getMessage(), e );
723 public List<ArtifactMetadata> getArtifactsByChecksum( RepositorySession session, String repositoryId, String checksum )
724 throws MetadataRepositoryException
726 final Session jcrSession = getSession( session );
727 List<ArtifactMetadata> artifacts;
729 String q = getArtifactQuery( repositoryId ) + " AND ([sha1] = $checksum OR [md5] = $checksum)";
733 Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
734 ValueFactory valueFactory = jcrSession.getValueFactory();
735 query.bindValue( "checksum", valueFactory.createValue( checksum ) );
736 QueryResult result = query.execute();
738 artifacts = new ArrayList<>();
739 for ( Node n : JcrUtils.getNodes( result ) )
741 artifacts.add( getArtifactFromNode( repositoryId, n ) );
744 catch ( RepositoryException e )
746 throw new MetadataRepositoryException( e.getMessage(), e );
751 public List<ArtifactMetadata> runJcrQuery( Session jcrSession, String repositoryId, String q, Map<String, String> bindingParam)
752 throws MetadataRepositoryException
754 return runJcrQuery( jcrSession, repositoryId, q, bindingParam, true );
757 public List<ArtifactMetadata> runJcrQuery( final Session jcrSession, final String repositoryId, final String qParam,
758 final Map<String, String> bindingParam, final boolean checkPath )
759 throws MetadataRepositoryException
763 List<ArtifactMetadata> artifacts;
764 if ( repositoryId != null && checkPath )
766 q += " AND ISDESCENDANTNODE(artifact,'/" + getRepositoryContentPath( repositoryId ) + "')";
769 log.info( "Running JCR Query: {}", q );
773 QueryResult result = runNativeJcrQuery( jcrSession, q, bindingParam );
774 artifacts = new ArrayList<>();
775 RowIterator rows = result.getRows();
776 while ( rows.hasNext() )
778 Row row = rows.nextRow();
779 Node node = row.getNode( "artifact" );
780 artifacts.add( getArtifactFromNode( repositoryId, node ) );
783 catch ( RepositoryException e )
785 throw new MetadataRepositoryException( e.getMessage(), e );
787 log.info( "Artifacts found {}", artifacts.size() );
788 for ( ArtifactMetadata meta : artifacts )
790 log.info( "Artifact: " + meta.getVersion() + " " + meta.getFacetList() );
795 public QueryResult runNativeJcrQuery( final Session jcrSession, final String q, final Map<String, String> bindingParam)
796 throws MetadataRepositoryException
798 Map<String, String> bindings;
799 if (bindingParam==null) {
800 bindings = new HashMap<>( );
802 bindings = bindingParam;
807 Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
808 ValueFactory valueFactory = jcrSession.getValueFactory();
809 for ( Entry<String, String> entry : bindings.entrySet() )
811 query.bindValue( entry.getKey(), valueFactory.createValue( entry.getValue() ) );
813 long start = System.currentTimeMillis( );
814 QueryResult result = query.execute();
815 long end = System.currentTimeMillis( );
816 log.info( "JCR Query ran in {} milliseconds: {}", end - start, q );
819 catch ( RepositoryException e )
821 throw new MetadataRepositoryException( e.getMessage(), e );
826 public List<ArtifactMetadata> getArtifactsByProjectVersionMetadata( RepositorySession session, String key, String value, String repositoryId )
827 throws MetadataRepositoryException
829 final Session jcrSession = getSession( session );
830 final String q = new StringBuilder( QUERY_ARTIFACTS_BY_PROJECT_VERSION_1 ).append( key ).append( QUERY_ARTIFACTS_BY_PROJECT_VERSION_2 ).toString();
831 return runJcrQuery( jcrSession, repositoryId, q, ImmutableMap.of( "value", value ) );
836 public List<ArtifactMetadata> getArtifactsByMetadata( RepositorySession session, String key, String value, String repositoryId )
837 throws MetadataRepositoryException
839 final Session jcrSession = getSession( session );
840 final String q = new StringBuilder( QUERY_ARTIFACTS_BY_METADATA_1 ).append( key ).append( QUERY_ARTIFACTS_BY_METADATA_2 ).toString( );
841 return runJcrQuery( jcrSession, repositoryId, q, ImmutableMap.of( "value", value ) );
846 public List<ArtifactMetadata> getArtifactsByProperty( RepositorySession session, String key, String value, String repositoryId )
847 throws MetadataRepositoryException
849 final Session jcrSession = getSession( session );
850 final String q = new StringBuilder( QUERY_ARTIFACTS_BY_PROPERTY_1 ).append( key ).append( QUERY_ARTIFACTS_BY_PROPERTY_2 ).toString();
851 return runJcrQuery( jcrSession, repositoryId, q, ImmutableMap.of( "value", value ) );
856 public void removeRepository( RepositorySession session, String repositoryId )
857 throws MetadataRepositoryException
859 final Session jcrSession = getSession( session );
862 Node root = jcrSession.getRootNode();
863 String path = getRepositoryPath( repositoryId );
864 if ( root.hasNode( path ) )
866 root.getNode( path ).remove();
869 catch ( RepositoryException e )
871 throw new MetadataRepositoryException( e.getMessage(), e );
876 public List<ArtifactMetadata> getArtifacts( RepositorySession session, String repositoryId )
877 throws MetadataRepositoryException
879 final Session jcrSession = getSession( session );
880 List<ArtifactMetadata> artifacts;
882 String q = getArtifactQuery( repositoryId );
886 Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
887 QueryResult result = query.execute();
889 artifacts = new ArrayList<>();
890 for ( Node n : JcrUtils.getNodes( result ) )
892 if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ) )
894 artifacts.add( getArtifactFromNode( repositoryId, n ) );
898 catch ( RepositoryException e )
900 throw new MetadataRepositoryException( e.getMessage(), e );
905 private static String getArtifactQuery( String repositoryId )
907 return new StringBuilder(QUERY_ARTIFACT_1).append(getRepositoryContentPath( repositoryId )).append(QUERY_ARTIFACT_2).toString();
911 public ProjectMetadata getProject( RepositorySession session, String repositoryId, String namespace, String projectId )
912 throws MetadataResolutionException
914 final Session jcrSession;
917 jcrSession = getSession( session );
919 catch ( MetadataRepositoryException e )
921 throw new MetadataResolutionException( e.getMessage() );
923 ProjectMetadata metadata = null;
927 Node root = jcrSession.getRootNode();
929 // basically just checking it exists
930 String path = getProjectPath( repositoryId, namespace, projectId );
931 if ( root.hasNode( path ) )
933 metadata = new ProjectMetadata();
934 metadata.setId( projectId );
935 metadata.setNamespace( namespace );
938 catch ( RepositoryException e )
940 throw new MetadataResolutionException( e.getMessage(), e );
947 public ProjectVersionMetadata getProjectVersion( RepositorySession session, String repositoryId, String namespace, String projectId,
948 String projectVersion )
949 throws MetadataResolutionException
951 final Session jcrSession;
954 jcrSession = getSession( session );
956 catch ( MetadataRepositoryException e )
958 throw new MetadataResolutionException( e.getMessage() );
960 ProjectVersionMetadata versionMetadata;
964 Node root = jcrSession.getRootNode();
966 String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
967 if ( !root.hasNode( path ) )
972 Node node = root.getNode( path );
974 versionMetadata = new ProjectVersionMetadata();
975 versionMetadata.setId( projectVersion );
976 versionMetadata.setName( getPropertyString( node, "name" ) );
977 versionMetadata.setDescription( getPropertyString( node, "description" ) );
978 versionMetadata.setUrl( getPropertyString( node, "url" ) );
979 versionMetadata.setIncomplete(
980 node.hasProperty( "incomplete" ) && node.getProperty( "incomplete" ).getBoolean() );
982 // FIXME: decide how to treat these in the content repo
983 String scmConnection = getPropertyString( node, "scm.connection" );
984 String scmDeveloperConnection = getPropertyString( node, "scm.developerConnection" );
985 String scmUrl = getPropertyString( node, "scm.url" );
986 if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
989 scm.setConnection( scmConnection );
990 scm.setDeveloperConnection( scmDeveloperConnection );
991 scm.setUrl( scmUrl );
992 versionMetadata.setScm( scm );
995 String ciSystem = getPropertyString( node, "ci.system" );
996 String ciUrl = getPropertyString( node, "ci.url" );
997 if ( ciSystem != null || ciUrl != null )
999 CiManagement ci = new CiManagement();
1000 ci.setSystem( ciSystem );
1002 versionMetadata.setCiManagement( ci );
1005 String issueSystem = getPropertyString( node, "issue.system" );
1006 String issueUrl = getPropertyString( node, "issue.url" );
1007 if ( issueSystem != null || issueUrl != null )
1009 IssueManagement issueManagement = new IssueManagement();
1010 issueManagement.setSystem( issueSystem );
1011 issueManagement.setUrl( issueUrl );
1012 versionMetadata.setIssueManagement( issueManagement );
1015 String orgName = getPropertyString( node, "org.name" );
1016 String orgUrl = getPropertyString( node, "org.url" );
1017 if ( orgName != null || orgUrl != null )
1019 Organization org = new Organization();
1020 org.setName( orgName );
1021 org.setUrl( orgUrl );
1022 versionMetadata.setOrganization( org );
1025 boolean done = false;
1029 String licenseName = getPropertyString( node, "license." + i + ".name" );
1030 String licenseUrl = getPropertyString( node, "license." + i + ".url" );
1031 if ( licenseName != null || licenseUrl != null )
1033 License license = new License();
1034 license.setName( licenseName );
1035 license.setUrl( licenseUrl );
1036 versionMetadata.addLicense( license );
1049 String mailingListName = getPropertyString( node, "mailingList." + i + ".name" );
1050 if ( mailingListName != null )
1052 MailingList mailingList = new MailingList();
1053 mailingList.setName( mailingListName );
1054 mailingList.setMainArchiveUrl( getPropertyString( node, "mailingList." + i + ".archive" ) );
1055 String n = "mailingList." + i + ".otherArchives";
1056 if ( node.hasProperty( n ) )
1058 mailingList.setOtherArchives( Arrays.asList( getPropertyString( node, n ).split( "," ) ) );
1062 mailingList.setOtherArchives( Collections.<String>emptyList() );
1064 mailingList.setPostAddress( getPropertyString( node, "mailingList." + i + ".post" ) );
1065 mailingList.setSubscribeAddress( getPropertyString( node, "mailingList." + i + ".subscribe" ) );
1066 mailingList.setUnsubscribeAddress( getPropertyString( node, "mailingList." + i + ".unsubscribe" ) );
1067 versionMetadata.addMailingList( mailingList );
1076 if ( node.hasNode( "dependencies" ) )
1078 Node dependenciesNode = node.getNode( "dependencies" );
1079 for ( Node n : JcrUtils.getChildNodes( dependenciesNode ) )
1081 if ( n.isNodeType( DEPENDENCY_NODE_TYPE ) )
1083 Dependency dependency = new Dependency();
1084 // FIXME: correct these properties
1085 dependency.setArtifactId( getPropertyString( n, "artifactId" ) );
1086 dependency.setGroupId( getPropertyString( n, "groupId" ) );
1087 dependency.setClassifier( getPropertyString( n, "classifier" ) );
1088 dependency.setOptional( Boolean.valueOf( getPropertyString( n, "optional" ) ) );
1089 dependency.setScope( getPropertyString( n, "scope" ) );
1090 dependency.setSystemPath( getPropertyString( n, "systemPath" ) );
1091 dependency.setType( getPropertyString( n, "type" ) );
1092 dependency.setVersion( getPropertyString( n, "version" ) );
1093 versionMetadata.addDependency( dependency );
1098 retrieveFacetProperties( versionMetadata, node );
1100 catch ( RepositoryException e )
1102 throw new MetadataResolutionException( e.getMessage(), e );
1105 return versionMetadata;
1108 private void retrieveFacetProperties( FacetedMetadata metadata, Node node ) throws RepositoryException
1110 for ( Node n : JcrUtils.getChildNodes( node ) )
1112 if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE ) )
1114 String name = n.getName();
1115 MetadataFacetFactory factory = metadataFacetFactories.get( name );
1116 if ( factory == null )
1118 log.error( "Attempted to load unknown project version metadata facet: {}", name );
1122 MetadataFacet facet = factory.createMetadataFacet();
1123 Map<String, String> map = new HashMap<>();
1124 for ( Property property : JcrUtils.getProperties( n ) )
1126 String p = property.getName();
1127 if ( !p.startsWith( "jcr:" ) )
1129 map.put( p, property.getString() );
1132 facet.fromProperties( map );
1133 metadata.addFacet( facet );
1140 public Collection<String> getArtifactVersions( RepositorySession session, String repositoryId, String namespace, String projectId,
1141 String projectVersion )
1142 throws MetadataResolutionException
1144 final Session jcrSession;
1147 jcrSession = getSession( session );
1149 catch ( MetadataRepositoryException e )
1151 throw new MetadataResolutionException( e.getMessage() );
1153 Set<String> versions = new LinkedHashSet<String>();
1157 Node root = jcrSession.getRootNode();
1159 Node node = root.getNode( getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) );
1161 for ( Node n : JcrUtils.getChildNodes( node ) )
1163 versions.add( n.getProperty( "version" ).getString() );
1166 catch ( PathNotFoundException e )
1168 // ignore repo not found for now
1170 catch ( RepositoryException e )
1172 throw new MetadataResolutionException( e.getMessage(), e );
1179 public Collection<ProjectVersionReference> getProjectReferences( RepositorySession session, String repositoryId, String namespace,
1180 String projectId, String projectVersion )
1181 throws MetadataResolutionException
1183 final Session jcrSession;
1186 jcrSession = getSession( session );
1188 catch ( MetadataRepositoryException e )
1190 throw new MetadataResolutionException( e.getMessage() );
1193 List<ProjectVersionReference> references = new ArrayList<>();
1195 // TODO: bind variables instead
1196 String q = "SELECT * FROM [archiva:dependency] WHERE ISDESCENDANTNODE([/repositories/" + repositoryId
1197 + "/content]) AND [groupId]='" + namespace + "' AND [artifactId]='" + projectId + "'";
1198 if ( projectVersion != null )
1200 q += " AND [version]='" + projectVersion + "'";
1204 Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
1205 QueryResult result = query.execute();
1207 for ( Node n : JcrUtils.getNodes( result ) )
1209 n = n.getParent(); // dependencies grouping element
1211 n = n.getParent(); // project version
1212 String usedByProjectVersion = n.getName();
1214 n = n.getParent(); // project
1215 String usedByProject = n.getName();
1217 n = n.getParent(); // namespace
1218 String usedByNamespace = n.getProperty( "namespace" ).getString();
1220 ProjectVersionReference ref = new ProjectVersionReference();
1221 ref.setNamespace( usedByNamespace );
1222 ref.setProjectId( usedByProject );
1223 ref.setProjectVersion( usedByProjectVersion );
1224 ref.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
1225 references.add( ref );
1228 catch ( RepositoryException e )
1230 throw new MetadataResolutionException( e.getMessage(), e );
1237 public Collection<String> getRootNamespaces( RepositorySession session, String repositoryId )
1238 throws MetadataResolutionException
1240 return getNamespaces(session , repositoryId, null );
1244 public Collection<String> getNamespaces( RepositorySession session, String repositoryId, String baseNamespace )
1245 throws MetadataResolutionException
1247 String path = baseNamespace != null
1248 ? getNamespacePath( repositoryId, baseNamespace )
1249 : getRepositoryContentPath( repositoryId );
1253 return getNodeNames( getSession(session), path, org.apache.archiva.metadata.repository.jcr.JcrConstants.NAMESPACE_NODE_TYPE );
1255 catch ( MetadataRepositoryException e )
1257 throw new MetadataResolutionException( e.getMessage( ) );
1262 public Collection<String> getProjects( RepositorySession session, String repositoryId, String namespace )
1263 throws MetadataResolutionException
1267 return getNodeNames( getSession(session), getNamespacePath( repositoryId, namespace ), org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_NODE_TYPE );
1269 catch ( MetadataRepositoryException e )
1271 throw new MetadataResolutionException( e.getMessage( ) );
1276 public Collection<String> getProjectVersions( RepositorySession session, String repositoryId, String namespace, String projectId )
1277 throws MetadataResolutionException
1281 return getNodeNames( getSession(session), getProjectPath( repositoryId, namespace, projectId ), org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE );
1283 catch ( MetadataRepositoryException e )
1285 throw new MetadataResolutionException( e.getMessage( ) );
1290 public void removeArtifact( RepositorySession session, ArtifactMetadata artifactMetadata, String baseVersion )
1291 throws MetadataRepositoryException
1293 final Session jcrSession = getSession( session );
1294 String repositoryId = artifactMetadata.getRepositoryId();
1298 Node root = jcrSession.getRootNode();
1300 getProjectVersionPath( repositoryId, artifactMetadata.getNamespace(), artifactMetadata.getProject(),
1303 if ( root.hasNode( path ) )
1305 Node node = root.getNode( path );
1307 for ( Node n : JcrUtils.getChildNodes( node ) )
1309 if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ) )
1311 if ( n.hasProperty( "version" ) )
1313 String version = n.getProperty( "version" ).getString();
1314 if ( StringUtils.equals( version, artifactMetadata.getVersion() ) )
1324 catch ( RepositoryException e )
1326 throw new MetadataRepositoryException( e.getMessage(), e );
1334 public void removeProjectVersion( RepositorySession session, String repoId, String namespace, String projectId, String projectVersion )
1335 throws MetadataRepositoryException
1337 final Session jcrSession = getSession( session );
1341 String path = getProjectPath( repoId, namespace, projectId );
1342 Node root = jcrSession.getRootNode();
1344 Node nodeAtPath = root.getNode( path );
1346 for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1348 if ( node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE ) && StringUtils.equals( projectVersion,
1355 catch ( RepositoryException e )
1357 throw new MetadataRepositoryException( e.getMessage(), e );
1362 public void removeArtifact( RepositorySession session, String repositoryId, String namespace, String projectId, String projectVersion,
1364 throws MetadataRepositoryException
1366 final Session jcrSession = getSession( session );
1369 Node root = jcrSession.getRootNode();
1370 String path = getArtifactPath( repositoryId, namespace, projectId, projectVersion, id );
1371 if ( root.hasNode( path ) )
1373 root.getNode( path ).remove();
1378 path = getProjectPath( repositoryId, namespace, projectId );
1380 Node nodeAtPath = root.getNode( path );
1382 for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1384 if ( node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE ) //
1385 && StringUtils.equals( node.getName(), projectVersion ) )
1391 catch ( RepositoryException e )
1393 throw new MetadataRepositoryException( e.getMessage(), e );
1398 public void removeArtifact( RepositorySession session, String repositoryId, String namespace, String project, String projectVersion,
1399 MetadataFacet metadataFacet )
1400 throws MetadataRepositoryException
1402 final Session jcrSession = getSession( session );
1405 Node root = jcrSession.getRootNode();
1406 String path = getProjectVersionPath( repositoryId, namespace, project, projectVersion );
1408 if ( root.hasNode( path ) )
1410 Node node = root.getNode( path );
1412 for ( Node n : JcrUtils.getChildNodes( node ) )
1414 if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ) )
1416 ArtifactMetadata artifactMetadata = getArtifactFromNode( repositoryId, n );
1417 log.debug( "artifactMetadata: {}", artifactMetadata );
1418 MetadataFacet metadataFacetToRemove = artifactMetadata.getFacet( metadataFacet.getFacetId() );
1419 if ( metadataFacetToRemove != null && metadataFacet.equals( metadataFacetToRemove ) )
1427 catch ( RepositoryException e )
1429 throw new MetadataRepositoryException( e.getMessage(), e );
1434 public Collection<ArtifactMetadata> getArtifacts( RepositorySession session, String repositoryId, String namespace, String projectId,
1435 String projectVersion )
1436 throws MetadataResolutionException
1438 final Session jcrSession;
1441 jcrSession = getSession( session );
1443 catch ( MetadataRepositoryException e )
1445 throw new MetadataResolutionException( e.getMessage( ) );
1447 List<ArtifactMetadata> artifacts = new ArrayList<>();
1451 Node root = jcrSession.getRootNode();
1452 String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
1454 if ( root.hasNode( path ) )
1456 Node node = root.getNode( path );
1458 for ( Node n : JcrUtils.getChildNodes( node ) )
1460 if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ) )
1462 artifacts.add( getArtifactFromNode( repositoryId, n ) );
1467 catch ( RepositoryException e )
1469 throw new MetadataResolutionException( e.getMessage(), e );
1477 public boolean canObtainAccess( Class<?> aClass )
1479 return aClass == Session.class;
1482 @SuppressWarnings( "unchecked" )
1484 public <T> T obtainAccess( RepositorySession session, Class<T> aClass )
1485 throws MetadataRepositoryException
1487 if ( aClass == Session.class )
1489 return (T) getSession( session );
1491 throw new IllegalArgumentException(
1492 "Access using " + aClass + " is not supported on the JCR metadata storage" );
1497 throws MetadataRepositoryException
1503 * Exact is ignored as we can't do exact search in any property, we need a key
1506 public List<ArtifactMetadata> searchArtifacts( RepositorySession session, String repositoryId, String text, boolean exact )
1507 throws MetadataRepositoryException
1509 return searchArtifacts( session, repositoryId, null, text, exact );
1513 public List<ArtifactMetadata> searchArtifacts( RepositorySession session, String repositoryId, String key, String text, boolean exact )
1514 throws MetadataRepositoryException
1516 final Session jcrSession = getSession( session );
1517 String theKey = key == null ? "*" : "[" + key + "]";
1518 String projectVersionCondition =
1519 exact ? "(projectVersion." + theKey + " = $value)" : "contains([projectVersion]." + theKey + ", $value)";
1520 String facetCondition = exact ? "(facet." + theKey + " = $value)" : "contains([facet]." + theKey + ", $value)";
1521 String descendantCondition = repositoryId == null ?
1522 " AND [projectVersion].[jcr:path] LIKE '/repositories/%/content/%'" :
1523 " AND ISDESCENDANTNODE(projectVersion,'/" + getRepositoryContentPath( repositoryId ) + "')";
1524 List<ArtifactMetadata> result = new ArrayList<>( );
1525 if (key==null || (key!=null && Arrays.binarySearch( PROJECT_VERSION_VERSION_PROPERTIES, key )>=0))
1527 // We search only for project version properties if the key is a valid property name
1529 "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE
1530 + "] AS projectVersion LEFT OUTER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE
1531 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) WHERE " + projectVersionCondition + descendantCondition;
1532 result.addAll(runJcrQuery( jcrSession, repositoryId, q1, ImmutableMap.of( "value", text ), false ));
1535 "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE
1536 + "] AS projectVersion LEFT OUTER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE
1537 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) LEFT OUTER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE
1538 + "] AS facet ON ISCHILDNODE(facet, projectVersion) WHERE " + facetCondition + descendantCondition;
1539 result.addAll( runJcrQuery( jcrSession, repositoryId, q2, ImmutableMap.of( "value", text ), false ) );
1543 private ArtifactMetadata getArtifactFromNode( String repositoryId, Node artifactNode )
1544 throws RepositoryException
1546 String id = artifactNode.getName();
1548 ArtifactMetadata artifact = new ArtifactMetadata();
1549 artifact.setId( id );
1550 artifact.setRepositoryId( repositoryId == null ? artifactNode.getAncestor( 2 ).getName() : repositoryId );
1552 Node projectVersionNode = artifactNode.getParent();
1553 Node projectNode = projectVersionNode.getParent();
1554 Node namespaceNode = projectNode.getParent();
1556 artifact.setNamespace( namespaceNode.getProperty( "namespace" ).getString() );
1557 artifact.setProject( projectNode.getName() );
1558 artifact.setProjectVersion( projectVersionNode.getName() );
1559 artifact.setVersion( artifactNode.hasProperty( "version" )
1560 ? artifactNode.getProperty( "version" ).getString()
1561 : projectVersionNode.getName() );
1563 if ( artifactNode.hasProperty( JCR_LAST_MODIFIED ) )
1565 artifact.setFileLastModified( artifactNode.getProperty( JCR_LAST_MODIFIED ).getDate().getTimeInMillis() );
1568 if ( artifactNode.hasProperty( "whenGathered" ) )
1570 artifact.setWhenGathered( artifactNode.getProperty( "whenGathered" ).getDate().getTime() );
1573 if ( artifactNode.hasProperty( "size" ) )
1575 artifact.setSize( artifactNode.getProperty( "size" ).getLong() );
1578 if ( artifactNode.hasProperty( "md5" ) )
1580 artifact.setMd5( artifactNode.getProperty( "md5" ).getString() );
1583 if ( artifactNode.hasProperty( "sha1" ) )
1585 artifact.setSha1( artifactNode.getProperty( "sha1" ).getString() );
1588 retrieveFacetProperties( artifact, artifactNode );
1592 private static String getPropertyString( Node node, String name )
1593 throws RepositoryException
1595 return node.hasProperty( name ) ? node.getProperty( name ).getString() : null;
1598 private Collection<String> getNodeNames( Session jcrSession, String path, String nodeType )
1599 throws MetadataResolutionException
1602 List<String> names = new ArrayList<>();
1606 Node root = jcrSession.getRootNode();
1608 Node nodeAtPath = root.getNode( path );
1610 for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
1612 if ( node.isNodeType( nodeType ) )
1614 names.add( node.getName() );
1618 catch ( PathNotFoundException e )
1620 // ignore repo not found for now
1622 catch ( RepositoryException e )
1624 throw new MetadataResolutionException( e.getMessage(), e );
1630 private static String getRepositoryPath( String repositoryId )
1632 return "repositories/" + repositoryId;
1635 private static String getRepositoryContentPath( String repositoryId )
1637 return getRepositoryPath( repositoryId ) + "/content";
1640 private static String getFacetPath( String repositoryId, String facetId )
1642 return getRepositoryPath( repositoryId ) + "/facets/" + facetId;
1645 private static String getNamespacePath( String repositoryId, String namespace )
1647 return getRepositoryContentPath( repositoryId ) + "/" + namespace.replace( '.', '/' );
1650 private static String getProjectPath( String repositoryId, String namespace, String projectId )
1652 return getNamespacePath( repositoryId, namespace ) + "/" + projectId;
1655 private static String getProjectVersionPath( String repositoryId, String namespace, String projectId,
1656 String projectVersion )
1658 return getProjectPath( repositoryId, namespace, projectId ) + "/" + projectVersion;
1661 private static String getArtifactPath( String repositoryId, String namespace, String projectId,
1662 String projectVersion, String id )
1664 return getProjectVersionPath( repositoryId, namespace, projectId, projectVersion ) + "/" + id;
1667 private Node getOrAddNodeByPath( Node baseNode, String name )
1668 throws RepositoryException
1670 return getOrAddNodeByPath( baseNode, name, null );
1673 private Node getOrAddNodeByPath( Node baseNode, String name, String nodeType )
1674 throws RepositoryException
1676 log.debug( "getOrAddNodeByPath " + baseNode + " " + name + " " + nodeType );
1677 Node node = baseNode;
1678 for ( String n : name.split( "/" ) )
1680 node = JcrUtils.getOrAddNode( node, n );
1681 if ( nodeType != null && !node.isNodeType( nodeType ))
1683 node.addMixin( nodeType );
1685 if (!node.hasProperty( "id" )) {
1686 node.setProperty( "id", n );
1692 private static String getFacetPath( String repositoryId, String facetId, String name )
1694 return getFacetPath( repositoryId, facetId ) + "/" + name;
1697 private Node getOrAddRepositoryNode( Session jcrSession, String repositoryId )
1698 throws RepositoryException
1700 log.debug( "getOrAddRepositoryNode " + repositoryId );
1701 Node root = jcrSession.getRootNode();
1702 Node node = JcrUtils.getOrAddNode( root, "repositories" );
1703 log.debug( "Repositories " + node );
1704 node = JcrUtils.getOrAddNode( node, repositoryId, JcrConstants.NT_UNSTRUCTURED );
1705 if (!node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.REPOSITORY_NODE_TYPE )) {
1706 node.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.REPOSITORY_NODE_TYPE );
1708 if (!node.hasProperty( "id" )) {
1709 node.setProperty( "id", repositoryId );
1714 private Node getOrAddRepositoryContentNode( Session jcrSession, String repositoryId )
1715 throws RepositoryException
1717 Node node = getOrAddRepositoryNode( jcrSession, repositoryId );
1718 return JcrUtils.getOrAddNode( node, "content" );
1721 private Node getOrAddNamespaceNode( Session jcrSession, String repositoryId, String namespace )
1722 throws RepositoryException
1724 Node repo = getOrAddRepositoryContentNode( jcrSession, repositoryId );
1725 return getOrAddNodeByPath( repo, namespace.replace( '.', '/' ), org.apache.archiva.metadata.repository.jcr.JcrConstants.NAMESPACE_NODE_TYPE );
1728 private Node getOrAddProjectNode( Session jcrSession, String repositoryId, String namespace, String projectId )
1729 throws RepositoryException
1731 Node namespaceNode = getOrAddNamespaceNode( jcrSession, repositoryId, namespace );
1732 Node node = JcrUtils.getOrAddNode( namespaceNode, projectId );
1733 if (!node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_NODE_TYPE ))
1735 node.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_NODE_TYPE );
1737 if (!node.hasProperty( "id" ))
1739 node.setProperty( "id", projectId );
1744 private Node getOrAddProjectVersionNode( Session jcrSession, String repositoryId, String namespace, String projectId,
1745 String projectVersion )
1746 throws RepositoryException
1748 Node projectNode = getOrAddProjectNode( jcrSession, repositoryId, namespace, projectId );
1749 log.debug( "Project node {}", projectNode );
1750 Node projectVersionNode = JcrUtils.getOrAddNode( projectNode, projectVersion, JcrConstants.NT_UNSTRUCTURED);
1751 if (!projectVersionNode.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE ))
1753 projectVersionNode.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE );
1755 if (!projectVersionNode.hasProperty( "id" ))
1757 projectVersionNode.setProperty( "id", projectVersion );
1760 log.debug( "Project version node {}", projectVersionNode );
1761 return projectVersionNode;
1764 private Node getOrAddArtifactNode( Session jcrSession, String repositoryId, String namespace, String projectId, String projectVersion,
1766 throws RepositoryException
1768 Node versionNode = getOrAddProjectVersionNode( jcrSession, repositoryId, namespace, projectId, projectVersion );
1769 Node node = JcrUtils.getOrAddNode( versionNode, id);
1770 if (!node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ))
1772 node.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE );
1774 if (!node.hasProperty( "id" )) {
1775 node.setProperty( "id", id );
1780 private static Calendar createCalendar( Date time )
1782 Calendar cal = Calendar.getInstance();
1783 cal.setTime( time );
1787 private String join( Collection<String> ids )
1789 if ( ids != null && !ids.isEmpty() )
1791 StringBuilder s = new StringBuilder();
1792 for ( String id : ids )
1797 return s.substring( 0, s.length() - 1 );
1804 public void populateStatistics( RepositorySession repositorySession, MetadataRepository repository, String repositoryId,
1805 RepositoryStatistics repositoryStatistics )
1806 throws MetadataRepositoryException
1808 if ( !( repository instanceof JcrMetadataRepository ) )
1810 throw new MetadataRepositoryException(
1811 "The statistics population is only possible for JcrMetdataRepository implementations" );
1813 Session session = getSession( repositorySession );
1814 // TODO: these may be best as running totals, maintained by observations on the properties in JCR
1818 QueryManager queryManager = session.getWorkspace().getQueryManager();
1820 // TODO: Check, if this is still the case - Switched to Jackrabbit OAK with archiva 3.0
1821 // Former statement: JCR-SQL2 query will not complete on a large repo in Jackrabbit 2.2.0 - see JCR-2835
1822 // Using the JCR-SQL2 variants gives
1823 // "org.apache.lucene.search.BooleanQuery$TooManyClauses: maxClauseCount is set to 1024"
1824 // String whereClause = "WHERE ISDESCENDANTNODE([/repositories/" + repositoryId + "/content])";
1825 // Query query = queryManager.createQuery( "SELECT size FROM [archiva:artifact] " + whereClause,
1826 // Query.JCR_SQL2 );
1827 String whereClause = "WHERE ISDESCENDANTNODE([/repositories/" + repositoryId + "/content])";
1828 Query query = queryManager.createQuery( "SELECT size FROM [archiva:artifact] " + whereClause, Query.JCR_SQL2 );
1830 QueryResult queryResult = query.execute();
1832 Map<String, Integer> totalByType = new HashMap<>();
1833 long totalSize = 0, totalArtifacts = 0;
1834 for ( Row row : JcrUtils.getRows( queryResult ) )
1836 Node n = row.getNode();
1837 totalSize += row.getValue( "size" ).getLong();
1840 if ( n.hasNode( MavenArtifactFacet.FACET_ID ) )
1842 Node facetNode = n.getNode( MavenArtifactFacet.FACET_ID );
1843 type = facetNode.getProperty( "type" ).getString();
1849 Integer prev = totalByType.get( type );
1850 totalByType.put( type, prev != null ? prev + 1 : 1 );
1855 repositoryStatistics.setTotalArtifactCount( totalArtifacts );
1856 repositoryStatistics.setTotalArtifactFileSize( totalSize );
1857 for ( Map.Entry<String, Integer> entry : totalByType.entrySet() )
1859 log.info( "Setting count for type: {} = {}", entry.getKey(), entry.getValue() );
1860 repositoryStatistics.setTotalCountForType( entry.getKey(), entry.getValue() );
1863 // The query ordering is a trick to ensure that the size is correct, otherwise due to lazy init it will be -1
1864 // query = queryManager.createQuery( "SELECT * FROM [archiva:project] " + whereClause, Query.JCR_SQL2 );
1865 query = queryManager.createQuery( "SELECT * FROM [archiva:project] " + whereClause + " ORDER BY [jcr:score]",
1867 repositoryStatistics.setTotalProjectCount( query.execute().getRows().getSize() );
1869 // query = queryManager.createQuery(
1870 // "SELECT * FROM [archiva:namespace] " + whereClause + " AND namespace IS NOT NULL", Query.JCR_SQL2 );
1871 query = queryManager.createQuery(
1872 "SELECT * FROM [archiva:namespace] " + whereClause + " AND namespace IS NOT NULL ORDER BY [jcr:score]",
1874 repositoryStatistics.setTotalGroupCount( query.execute().getRows().getSize() );
1876 catch ( RepositoryException e )
1878 throw new MetadataRepositoryException( e.getMessage(), e );
1883 public Session login() throws RepositoryException
1885 return repository.login(new SimpleCredentials( "admin", "admin".toCharArray() ) );