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.checksum.ChecksumAlgorithm;
23 import org.apache.archiva.metadata.QueryParameter;
24 import org.apache.archiva.metadata.maven.model.MavenArtifactFacet;
25 import org.apache.archiva.metadata.model.ArtifactMetadata;
26 import org.apache.archiva.metadata.model.CiManagement;
27 import org.apache.archiva.metadata.model.Dependency;
28 import org.apache.archiva.metadata.model.FacetedMetadata;
29 import org.apache.archiva.metadata.model.IssueManagement;
30 import org.apache.archiva.metadata.model.License;
31 import org.apache.archiva.metadata.model.MailingList;
32 import org.apache.archiva.metadata.model.MetadataFacet;
33 import org.apache.archiva.metadata.model.MetadataFacetFactory;
34 import org.apache.archiva.metadata.model.ModelInfo;
35 import org.apache.archiva.metadata.model.Organization;
36 import org.apache.archiva.metadata.model.ProjectMetadata;
37 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
38 import org.apache.archiva.metadata.model.ProjectVersionReference;
39 import org.apache.archiva.metadata.model.Scm;
40 import org.apache.archiva.metadata.repository.AbstractMetadataRepository;
41 import org.apache.archiva.metadata.repository.MetadataRepository;
42 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
43 import org.apache.archiva.metadata.repository.MetadataResolutionException;
44 import org.apache.archiva.metadata.repository.MetadataService;
45 import org.apache.archiva.metadata.repository.MetadataSessionException;
46 import org.apache.archiva.metadata.repository.RepositorySession;
47 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
48 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsProvider;
49 import org.apache.commons.lang3.StringUtils;
50 import org.apache.jackrabbit.commons.JcrUtils;
51 import org.apache.jackrabbit.commons.cnd.CndImporter;
52 import org.apache.jackrabbit.commons.cnd.ParseException;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
56 import javax.jcr.NamespaceRegistry;
57 import javax.jcr.Node;
58 import javax.jcr.NodeIterator;
59 import javax.jcr.PathNotFoundException;
60 import javax.jcr.Property;
61 import javax.jcr.Repository;
62 import javax.jcr.RepositoryException;
63 import javax.jcr.Session;
64 import javax.jcr.SimpleCredentials;
65 import javax.jcr.Value;
66 import javax.jcr.ValueFactory;
67 import javax.jcr.Workspace;
68 import javax.jcr.query.Query;
69 import javax.jcr.query.QueryManager;
70 import javax.jcr.query.QueryResult;
71 import javax.jcr.query.Row;
72 import javax.jcr.query.RowIterator;
73 import java.io.IOException;
74 import java.io.InputStreamReader;
75 import java.io.Reader;
76 import java.time.ZonedDateTime;
77 import java.util.ArrayList;
78 import java.util.Arrays;
79 import java.util.Calendar;
80 import java.util.Collection;
81 import java.util.Collections;
82 import java.util.GregorianCalendar;
83 import java.util.HashMap;
84 import java.util.HashSet;
85 import java.util.Iterator;
86 import java.util.LinkedHashSet;
87 import java.util.List;
89 import java.util.Map.Entry;
90 import java.util.Optional;
92 import java.util.Spliterator;
93 import java.util.function.Consumer;
94 import java.util.function.Function;
95 import java.util.stream.Collectors;
96 import java.util.stream.Stream;
97 import java.util.stream.StreamSupport;
99 import static javax.jcr.Property.JCR_LAST_MODIFIED;
100 import static org.apache.archiva.metadata.repository.jcr.JcrConstants.*;
103 * TODO below: revise storage format for project version metadata
104 * TODO revise reference storage
106 public class JcrMetadataRepository
107 extends AbstractMetadataRepository implements MetadataRepository, RepositoryStatisticsProvider {
110 private static final String QUERY_ARTIFACT_1 = "SELECT * FROM [" + ARTIFACT_NODE_TYPE + "] AS artifact WHERE ISDESCENDANTNODE(artifact,'/";
112 static final String QUERY_ARTIFACTS_BY_PROJECT_VERSION_1 = "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + ARTIFACT_NODE_TYPE
113 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) INNER JOIN [" + FACET_NODE_TYPE
114 + "] AS facet ON ISCHILDNODE(facet, projectVersion) WHERE ([facet].[";
115 static final String QUERY_ARTIFACTS_BY_PROJECT_VERSION_2 = "] = $value)";
117 static final String QUERY_ARTIFACTS_BY_METADATA_1 = "SELECT * FROM [" + ARTIFACT_NODE_TYPE + "] AS artifact INNER JOIN [" + FACET_NODE_TYPE
118 + "] AS facet ON ISCHILDNODE(facet, artifact) WHERE ([facet].[";
119 static final String QUERY_ARTIFACTS_BY_METADATA_2 = "] = $value)";
121 static final String QUERY_ARTIFACTS_BY_PROPERTY_1 = "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + ARTIFACT_NODE_TYPE
122 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) WHERE ([projectVersion].[";
123 static final String QUERY_ARTIFACTS_BY_PROPERTY_2 = "] = $value)";
126 private static final String QUERY_ARTIFACT_2 = "')";
128 private Logger log = LoggerFactory.getLogger(JcrMetadataRepository.class);
130 private Repository repository;
132 public JcrMetadataRepository(MetadataService metadataService, Repository repository)
133 throws RepositoryException {
134 super(metadataService);
135 this.repository = repository;
139 public static void initializeNodeTypes(Session session)
140 throws RepositoryException {
142 // TODO: consider using namespaces for facets instead of the current approach:
143 // (if used, check if actually called by normal injection)
144 // for ( String facetId : metadataFacetFactories.keySet() )
146 // session.getWorkspace().getNamespaceRegistry().registerNamespace( facetId, facetId );
148 Workspace workspace = session.getWorkspace();
149 NamespaceRegistry registry = workspace.getNamespaceRegistry();
151 if (!Arrays.asList(registry.getPrefixes()).contains("archiva")) {
152 registry.registerNamespace("archiva", "http://archiva.apache.org/jcr/");
156 Reader cndReader = new InputStreamReader(
157 Thread.currentThread().getContextClassLoader().getResourceAsStream("org/apache/archiva/metadata/repository/jcr/jcr-schema.cnd"))) {
158 CndImporter.registerNodeTypes(cndReader, session);
159 } catch (ParseException e) {
161 } catch (IOException e) {
167 private Session getSession(RepositorySession repositorySession) throws MetadataRepositoryException {
168 if (repositorySession instanceof JcrRepositorySession) {
169 return ((JcrRepositorySession) repositorySession).getJcrSession();
171 throw new MetadataRepositoryException("The given session object is not a JcrSession instance: " + repositorySession.getClass().getName());
176 public void updateProject(RepositorySession session, String repositoryId, ProjectMetadata project)
177 throws MetadataRepositoryException {
178 final Session jcrSession = getSession(session);
179 updateProject(jcrSession, repositoryId, project.getNamespace(), project.getId());
182 private void updateProject(Session jcrSession, String repositoryId, String namespace, String projectId)
183 throws MetadataRepositoryException {
184 updateNamespace(jcrSession, repositoryId, namespace);
187 getOrAddProjectNode(jcrSession, repositoryId, namespace, projectId);
188 } catch (RepositoryException e) {
189 throw new MetadataRepositoryException(e.getMessage(), e);
194 public void updateArtifact(RepositorySession session, String repositoryId, String namespace, String projectId, String projectVersion,
195 ArtifactMetadata artifactMeta)
196 throws MetadataRepositoryException {
197 final Session jcrSession = getSession(session);
198 updateNamespace(session, repositoryId, namespace);
202 getOrAddArtifactNode(jcrSession, repositoryId, namespace, projectId, projectVersion, artifactMeta.getId());
204 node.setProperty("id", artifactMeta.getId());
205 Calendar cal = GregorianCalendar.from(artifactMeta.getFileLastModified());
206 node.setProperty(JCR_LAST_MODIFIED, cal);
208 cal = GregorianCalendar.from(artifactMeta.getWhenGathered());
209 node.setProperty("whenGathered", cal);
211 node.setProperty("size", artifactMeta.getSize());
214 Node cslistNode = getOrAddNodeByPath(node, "checksums", CHECKSUMS_FOLDER_TYPE, true);
215 NodeIterator nit = cslistNode.getNodes("*");
216 while (nit.hasNext()) {
217 Node csNode = nit.nextNode();
218 if (csNode.isNodeType(CHECKSUM_NODE_TYPE)) {
222 for (Map.Entry<ChecksumAlgorithm, String> entry : artifactMeta.getChecksums().entrySet()) {
223 String type = entry.getKey().name();
224 Node csNode = cslistNode.addNode(type, CHECKSUM_NODE_TYPE);
225 csNode.setProperty("type", type);
226 csNode.setProperty("value", entry.getValue());
229 node.setProperty("version", artifactMeta.getVersion());
231 // iterate over available facets to update/add/remove from the artifactMetadata
232 for (String facetId : metadataService.getSupportedFacets()) {
233 MetadataFacet metadataFacet = artifactMeta.getFacet(facetId);
234 if (metadataFacet == null) {
237 if (node.hasNode(facetId)) {
238 node.getNode(facetId).remove();
240 if (metadataFacet != null) {
241 // recreate, to ensure properties are removed
242 Node n = node.addNode(facetId, FACET_NODE_TYPE);
243 n.setProperty("facetId", facetId);
245 for (Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet()) {
246 n.setProperty(entry.getKey(), entry.getValue());
250 } catch (RepositoryException e) {
251 throw new MetadataRepositoryException(e.getMessage(), e);
256 public void updateProjectVersion(RepositorySession session, String repositoryId, String namespace, String projectId,
257 ProjectVersionMetadata versionMetadata)
258 throws MetadataRepositoryException {
259 final Session jcrSession = getSession(session);
260 updateProject(jcrSession, repositoryId, namespace, projectId);
264 getOrAddProjectVersionNode(jcrSession, repositoryId, namespace, projectId, versionMetadata.getId());
265 versionNode.setProperty("id", versionMetadata.getId());
266 versionNode.setProperty("name", StringUtils.isEmpty(versionMetadata.getName()) ? "" : versionMetadata.getName());
267 versionNode.setProperty("description", StringUtils.isEmpty(versionMetadata.getDescription()) ? "" : versionMetadata.getDescription());
268 versionNode.setProperty("url", versionMetadata.getUrl());
269 versionNode.setProperty("incomplete", versionMetadata.isIncomplete());
271 // FIXME: decide how to treat these in the content repo
272 if (versionMetadata.getScm() != null) {
273 versionNode.setProperty("scm.connection", versionMetadata.getScm().getConnection());
274 versionNode.setProperty("scm.developerConnection", versionMetadata.getScm().getDeveloperConnection());
275 versionNode.setProperty("scm.url", versionMetadata.getScm().getUrl());
277 if (versionMetadata.getCiManagement() != null) {
278 versionNode.setProperty("ci.system", versionMetadata.getCiManagement().getSystem());
279 versionNode.setProperty("ci.url", versionMetadata.getCiManagement().getUrl());
281 if (versionMetadata.getIssueManagement() != null) {
282 versionNode.setProperty("issue.system", versionMetadata.getIssueManagement().getSystem());
283 versionNode.setProperty("issue.url", versionMetadata.getIssueManagement().getUrl());
285 if (versionMetadata.getOrganization() != null) {
286 versionNode.setProperty("org.name", versionMetadata.getOrganization().getName());
287 versionNode.setProperty("org.url", versionMetadata.getOrganization().getUrl());
290 Node licensesNode = JcrUtils.getOrAddNode(versionNode, "licenses", LICENSES_FOLDER_TYPE);
291 Set<String> licNames = new HashSet<>();
292 for (License license : versionMetadata.getLicenses()) {
293 Node licNode = JcrUtils.getOrAddNode(licensesNode, license.getName(), LICENSE_NODE_TYPE);
294 licNode.setProperty("index", i);
295 licNode.setProperty("name", license.getName());
296 licNode.setProperty("url", license.getUrl());
297 licNames.add(license.getName());
300 NodeIterator nodeIterator = licensesNode.getNodes();
301 while (nodeIterator.hasNext()) {
302 Node n = nodeIterator.nextNode();
303 if (!licNames.contains(n.getName())) {
308 Node mailinglistsListNode = JcrUtils.getOrAddNode(versionNode, "mailinglists", MAILINGLISTS_FOLDER_TYPE);
309 Set<String> listNames = new HashSet<>();
310 for (MailingList mailingList : versionMetadata.getMailingLists()) {
311 final String name = mailingList.getName();
312 Node mailNode = JcrUtils.getOrAddNode(mailinglistsListNode, mailingList.getName(), MAILINGLIST_NODE_TYPE);
313 mailNode.setProperty("index", i);
314 mailNode.setProperty("archive", mailingList.getMainArchiveUrl());
315 mailNode.setProperty("name", mailingList.getName());
316 mailNode.setProperty("post", mailingList.getPostAddress());
317 mailNode.setProperty("unsubscribe", mailingList.getUnsubscribeAddress());
318 mailNode.setProperty("subscribe", mailingList.getSubscribeAddress());
319 mailNode.setProperty("otherArchives",
320 join(mailingList.getOtherArchives()));
324 nodeIterator = mailinglistsListNode.getNodes();
325 while (nodeIterator.hasNext()) {
326 Node n = nodeIterator.nextNode();
327 if (!listNames.contains(n.getName())) {
331 if (!versionMetadata.getDependencies().isEmpty()) {
332 Node dependenciesNode = JcrUtils.getOrAddNode(versionNode, "dependencies", DEPENDENCIES_FOLDER_TYPE);
334 for (Dependency dependency : versionMetadata.getDependencies()) {
335 // Note that we deliberately don't alter the namespace path - not enough dependencies for
336 // number of nodes at a given depth to be an issue. Similarly, we don't add subnodes for each
337 // component of the ID as that creates extra depth and causes a great cost in space and memory
339 // FIXME: change to artifact's ID - this is constructed by the Maven 2 format for now.
340 // This won't support types where the extension doesn't match the type.
341 // (see also Maven2RepositoryStorage#readProjectVersionMetadata construction of POM)
343 dependency.getNamespace() + ";" + dependency.getArtifactId() + "-" + dependency.getVersion();
344 if (dependency.getClassifier() != null) {
345 id += "-" + dependency.getClassifier();
347 id += "." + dependency.getType();
349 Node n = JcrUtils.getOrAddNode(dependenciesNode, id, DEPENDENCY_NODE_TYPE);
350 n.setProperty("id", id);
352 n.setProperty("namespace", dependency.getNamespace());
353 n.setProperty("artifactId", dependency.getArtifactId());
354 n.setProperty("version", dependency.getVersion());
355 n.setProperty("type", dependency.getType());
356 n.setProperty("classifier", dependency.getClassifier());
357 n.setProperty("scope", dependency.getScope());
358 n.setProperty("systemPath", dependency.getSystemPath());
359 n.setProperty("optional", dependency.isOptional());
360 n.setProperty("projectId", dependency.getProjectId());
362 Node refNode = findArtifactNode(jcrSession, dependency.getNamespace(),
363 dependency.getProjectId(), dependency.getVersion(), dependency.getArtifactId());
365 n.setProperty("link", refNode.getPath());
368 // node has no native content at this time, just facets
369 // no need to list a type as it's implied by the path. Parents are Maven specific.
371 // FIXME: add scope, systemPath, type, version, classifier & maven2 specific IDs as a facet
372 // (should also have been added to the Dependency)
374 // TODO: add a property that is a weak reference to the originating artifact, creating it if
375 // necessary (without adding the archiva:artifact mixin so that it doesn't get listed as an
376 // artifact, which gives a different meaning to "incomplete" which is a known local project
377 // that doesn't have metadata yet but has artifacts). (Though we may want to give it the
378 // artifact mixin and another property to identify all non-local artifacts for the closure
383 for (MetadataFacet facet : versionMetadata.getFacetList()) {
384 // recreate, to ensure properties are removed
385 if (versionNode.hasNode(facet.getFacetId())) {
386 versionNode.getNode(facet.getFacetId()).remove();
388 Node n = versionNode.addNode(facet.getFacetId(), FACET_NODE_TYPE);
390 for (Map.Entry<String, String> entry : facet.toProperties().entrySet()) {
391 n.setProperty(entry.getKey(), entry.getValue());
394 } catch (RepositoryException e) {
395 throw new MetadataRepositoryException(e.getMessage(), e);
399 private void updateNamespace(Session jcrSession, String repositoryId, String namespace) throws MetadataRepositoryException {
401 Node node = getOrAddNamespaceNode(jcrSession, repositoryId, namespace);
402 node.setProperty("id", namespace);
403 node.setProperty("namespace", namespace);
404 } catch (RepositoryException e) {
405 throw new MetadataRepositoryException(e.getMessage(), e);
410 public void updateNamespace(RepositorySession session, String repositoryId, String namespace)
411 throws MetadataRepositoryException {
412 updateNamespace(getSession(session), repositoryId, namespace);
416 public void removeProject(RepositorySession session, String repositoryId, String namespace, String projectId)
417 throws MetadataRepositoryException {
418 final Session jcrSession = getSession(session);
420 Node root = jcrSession.getRootNode();
421 String namespacePath = getNamespacePath(repositoryId, namespace);
423 if (root.hasNode(namespacePath)) {
424 Iterator<Node> nodeIterator = JcrUtils.getChildNodes(root.getNode(namespacePath)).iterator();
425 while (nodeIterator.hasNext()) {
426 Node node = nodeIterator.next();
427 if (node.isNodeType(org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_MIXIN_TYPE) && projectId.equals(node.getName())) {
433 } catch (RepositoryException e) {
434 throw new MetadataRepositoryException(e.getMessage(), e);
441 public boolean hasMetadataFacet(RepositorySession session, String repositoryId, String facetId)
442 throws MetadataRepositoryException {
443 final Session jcrSession = getSession(session);
445 Node node = jcrSession.getRootNode().getNode(getFacetPath(repositoryId, facetId));
446 return node.getNodes().hasNext();
447 } catch (PathNotFoundException e) {
448 // ignored - the facet doesn't exist, so return false
450 } catch (RepositoryException e) {
451 throw new MetadataRepositoryException(e.getMessage(), e);
456 public List<String> getMetadataFacets(RepositorySession session, String repositoryId, String facetId)
457 throws MetadataRepositoryException {
458 final Session jcrSession = getSession(session);
459 List<String> facets = new ArrayList<>();
462 // no need to construct node-by-node here, as we'll find in the next instance, the facet names have / and
463 // are paths themselves
464 Node node = jcrSession.getRootNode().getNode(getFacetPath(repositoryId, facetId));
466 // TODO: this is a bit awkward. Might be better to review the purpose of this function - why is the list of
468 recurse(facets, "", node);
469 } catch (PathNotFoundException e) {
470 // ignored - the facet doesn't exist, so return the empty list
471 } catch (RepositoryException e) {
472 throw new MetadataRepositoryException(e.getMessage(), e);
477 private <T> Spliterator<T> createResultSpliterator(QueryResult result, Function<Row, T> converter) throws MetadataRepositoryException {
478 final RowIterator rowIterator;
480 rowIterator = result.getRows();
481 } catch (RepositoryException e) {
482 throw new MetadataRepositoryException(e.getMessage(), e);
484 return new Spliterator<T>() {
486 public boolean tryAdvance(Consumer<? super T> action) {
487 while (rowIterator.hasNext()) {
488 T item = converter.apply(rowIterator.nextRow());
498 public Spliterator<T> trySplit() {
503 public long estimateSize() {
508 public int characteristics() {
509 return ORDERED + NONNULL;
514 private StringBuilder appendQueryParams(StringBuilder query, String selector, String defaultProperty, QueryParameter queryParameter) {
515 if (queryParameter.getSortFields().size() == 0) {
516 query.append(" ORDER BY [").append(selector).append("].[").append(defaultProperty).append("]");
517 if (queryParameter.isAscending()) {
518 query.append(" ASC");
520 query.append(" DESC");
523 query.append(" ORDER BY");
524 for (String property : queryParameter.getSortFields()) {
525 query.append(" [").append(selector).append("].[").append(property).append("]");
526 if (queryParameter.isAscending()) {
527 query.append(" ASC");
529 query.append(" DESC");
536 private <T extends MetadataFacet> Function<Row, Optional<T>> getFacetFromRowFunc(MetadataFacetFactory<T> factory, String repositoryId) {
537 return (Row row) -> {
539 Node node = row.getNode("facet");
540 if (node.hasProperty("archiva:name")) {
541 String facetName = node.getProperty("archiva:name").getString();
542 return Optional.ofNullable(createFacetFromNode(factory, node, repositoryId, facetName));
544 return Optional.empty();
546 } catch (RepositoryException e) {
547 log.error("Exception encountered {}", e.getMessage());
548 return Optional.empty();
554 public <T extends MetadataFacet> Stream<T> getMetadataFacetStream(RepositorySession session, String repositoryId, Class<T> facetClazz, QueryParameter queryParameter) throws MetadataRepositoryException {
555 final Session jcrSession = getSession(session);
556 final MetadataFacetFactory<T> factory = metadataService.getFactory(facetClazz);
557 final String facetId = factory.getFacetId();
558 final String facetPath = '/' + getFacetPath(repositoryId, facetId);
559 StringBuilder query = new StringBuilder("SELECT * FROM [");
560 query.append(FACET_NODE_TYPE).append("] AS facet WHERE ISDESCENDANTNODE(facet, [")
561 .append(facetPath).append("]) AND [facet].[archiva:name] IS NOT NULL");
562 appendQueryParams(query, "facet", "archiva:name", queryParameter);
563 String q = query.toString();
564 Map<String, String> params = new HashMap<>();
565 QueryResult result = runNativeJcrQuery(jcrSession, q, params, queryParameter.getOffset(), queryParameter.getLimit());
566 final Function<Row, Optional<T>> rowFunc = getFacetFromRowFunc(factory, repositoryId);
567 return StreamSupport.stream(createResultSpliterator(result, rowFunc), false).filter(Optional::isPresent).map(Optional::get);
571 private void recurse(List<String> facets, String prefix, Node node)
572 throws RepositoryException {
573 for (Node n : JcrUtils.getChildNodes(node)) {
574 String name = prefix + "/" + n.getName();
576 recurse(facets, name, n);
578 // strip leading / first
579 facets.add(name.substring(1));
586 public <T extends MetadataFacet> T getMetadataFacet(RepositorySession session, String repositoryId, Class<T> clazz, String name) throws MetadataRepositoryException {
587 if (!metadataService.supportsFacet(clazz)) {
588 log.warn("The required metadata class is not supported: " + clazz);
591 final Session jcrSession = getSession(session);
592 final MetadataFacetFactory<T> factory = getFacetFactory(clazz);
593 final String facetId = factory.getFacetId();
595 Node root = jcrSession.getRootNode();
596 Node node = root.getNode(getFacetPath(repositoryId, facetId, name));
598 if (getSupportedFacets().size() == 0) {
602 return createFacetFromNode(factory, node, repositoryId, name);
603 } catch (PathNotFoundException e) {
604 // ignored - the facet doesn't exist, so return null
605 } catch (RepositoryException e) {
606 throw new MetadataRepositoryException(e.getMessage(), e);
611 private <T extends MetadataFacet> T createFacetFromNode(final MetadataFacetFactory<T> factory, final Node node) throws RepositoryException {
612 return createFacetFromNode(factory, node, null, null);
615 private <T extends MetadataFacet> T createFacetFromNode(final MetadataFacetFactory<T> factory, final Node node,
616 final String repositoryId, final String name) throws RepositoryException {
617 if (factory != null) {
619 if (repositoryId != null) {
620 metadataFacet = factory.createMetadataFacet(repositoryId, name);
622 metadataFacet = factory.createMetadataFacet();
624 Map<String, String> map = new HashMap<>();
625 for (Property property : JcrUtils.getProperties(node)) {
626 String p = property.getName();
627 if (!p.startsWith("jcr:")) {
628 map.put(p, property.getString());
631 metadataFacet.fromProperties(map);
632 return metadataFacet;
638 public void addMetadataFacet(RepositorySession session, String repositoryId, MetadataFacet metadataFacet)
639 throws MetadataRepositoryException {
640 final Session jcrSession = getSession(session);
642 Node repo = getOrAddRepositoryNode(jcrSession, repositoryId);
643 Node facets = JcrUtils.getOrAddNode(repo, "facets", FACETS_FOLDER_TYPE);
645 String id = metadataFacet.getFacetId();
646 Node facetNode = JcrUtils.getOrAddNode(facets, id, FACET_ID_CONTAINER_TYPE);
647 if (!facetNode.hasProperty("id")) {
648 facetNode.setProperty("id", id);
651 Node facetInstance = getOrAddNodeByPath(facetNode, metadataFacet.getName(), FACET_NODE_TYPE, true);
652 if (!facetInstance.hasProperty("archiva:facetId")) {
653 facetInstance.setProperty("archiva:facetId", id);
654 facetInstance.setProperty("archiva:name", metadataFacet.getName());
657 for (Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet()) {
658 facetInstance.setProperty(entry.getKey(), entry.getValue());
661 } catch (RepositoryException | MetadataSessionException e) {
662 throw new MetadataRepositoryException(e.getMessage(), e);
667 public void removeNamespace(RepositorySession session, String repositoryId, String projectId)
668 throws MetadataRepositoryException {
669 final Session jcrSession = getSession(session);
671 Node root = jcrSession.getRootNode();
672 String path = getNamespacePath(repositoryId, projectId);
673 if (root.hasNode(path)) {
674 Node node = root.getNode(path);
675 if (node.isNodeType(NAMESPACE_MIXIN_TYPE)) {
679 } catch (RepositoryException e) {
680 throw new MetadataRepositoryException(e.getMessage(), e);
685 public void removeMetadataFacets(RepositorySession session, String repositoryId, String facetId)
686 throws MetadataRepositoryException {
687 final Session jcrSession = getSession(session);
689 Node root = jcrSession.getRootNode();
690 String path = getFacetPath(repositoryId, facetId);
691 if (root.hasNode(path)) {
692 root.getNode(path).remove();
694 } catch (RepositoryException e) {
695 throw new MetadataRepositoryException(e.getMessage(), e);
700 public void removeMetadataFacet(RepositorySession session, String repositoryId, String facetId, String name)
701 throws MetadataRepositoryException {
702 final Session jcrSession = getSession(session);
704 Node root = jcrSession.getRootNode();
705 String path = getFacetPath(repositoryId, facetId, name);
706 if (root.hasNode(path)) {
707 Node node = root.getNode(path);
709 // also remove empty container nodes
710 Node parent = node.getParent();
714 while (!node.hasNodes());
716 } catch (RepositoryException e) {
717 throw new MetadataRepositoryException(e.getMessage(), e);
721 private StringBuilder buildArtifactByDateRangeQuery(String repoId, ZonedDateTime startTime, ZonedDateTime endTime,
722 QueryParameter queryParameter) {
723 StringBuilder q = getArtifactQuery(repoId);
725 if (startTime != null) {
726 q.append(" AND [artifact].[whenGathered] >= $start");
728 if (endTime != null) {
729 q.append(" AND [artifact].[whenGathered] <= $end");
731 appendQueryParams(q, "artifact", "whenGathered", queryParameter);
735 private QueryResult queryArtifactByDateRange(Session jcrSession, String repositoryId,
736 ZonedDateTime startTime, ZonedDateTime endTime,
737 QueryParameter queryParameter) throws MetadataRepositoryException {
738 String q = buildArtifactByDateRangeQuery(repositoryId, startTime, endTime, queryParameter).toString();
741 Query query = jcrSession.getWorkspace().getQueryManager().createQuery(q, Query.JCR_SQL2);
742 query.setOffset(queryParameter.getOffset());
743 query.setLimit(queryParameter.getLimit());
744 ValueFactory valueFactory = jcrSession.getValueFactory();
745 if (startTime != null) {
746 query.bindValue("start", valueFactory.createValue(createCalendar(startTime.withZoneSameInstant(ModelInfo.STORAGE_TZ))));
748 if (endTime != null) {
749 query.bindValue("end", valueFactory.createValue(createCalendar(endTime.withZoneSameInstant(ModelInfo.STORAGE_TZ))));
751 return query.execute();
752 } catch (RepositoryException e) {
753 throw new MetadataRepositoryException(e.getMessage(), e);
758 public List<ArtifactMetadata> getArtifactsByDateRange(RepositorySession session, String repoId, ZonedDateTime startTime, ZonedDateTime endTime, QueryParameter queryParameter)
759 throws MetadataRepositoryException {
760 final Session jcrSession = getSession(session);
762 List<ArtifactMetadata> artifacts;
764 QueryResult result = queryArtifactByDateRange(jcrSession, repoId, startTime, endTime, queryParameter);
766 artifacts = new ArrayList<>();
767 for (Node n : JcrUtils.getNodes(result)) {
768 artifacts.add(getArtifactFromNode(repoId, n));
770 } catch (RepositoryException e) {
771 throw new MetadataRepositoryException(e.getMessage(), e);
776 private Function<Row, Optional<ArtifactMetadata>> getArtifactFromRowFunc(final String repositoryId) {
777 return (Row row) -> {
779 return Optional.of(getArtifactFromNode(repositoryId, row.getNode("artifact")));
780 } catch (RepositoryException e) {
781 return Optional.empty();
787 public Stream<ArtifactMetadata> getArtifactByDateRangeStream(RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime, QueryParameter queryParameter) throws MetadataRepositoryException {
788 final Session jcrSession = getSession(session);
789 final QueryResult result = queryArtifactByDateRange(jcrSession, repositoryId, startTime, endTime, queryParameter);
790 final Function<Row, Optional<ArtifactMetadata>> rowFunc = getArtifactFromRowFunc(repositoryId);
791 return StreamSupport.stream(createResultSpliterator(result, rowFunc), false).filter(Optional::isPresent).map(Optional::get);
796 public List<ArtifactMetadata> getArtifactsByChecksum(RepositorySession session, String repositoryId, String checksum)
797 throws MetadataRepositoryException {
798 final Session jcrSession = getSession(session);
799 List<ArtifactMetadata> artifacts;
801 String q = getArtifactQuery(repositoryId).append(" AND ([artifact].[checksums/*/value] = $checksum)").toString();
804 Query query = jcrSession.getWorkspace().getQueryManager().createQuery(q, Query.JCR_SQL2);
805 ValueFactory valueFactory = jcrSession.getValueFactory();
806 query.bindValue("checksum", valueFactory.createValue(checksum));
807 QueryResult result = query.execute();
809 artifacts = new ArrayList<>();
810 for (Node n : JcrUtils.getNodes(result)) {
811 artifacts.add(getArtifactFromNode(repositoryId, n));
813 } catch (RepositoryException e) {
814 throw new MetadataRepositoryException(e.getMessage(), e);
819 public List<ArtifactMetadata> runJcrQuery(Session jcrSession, String repositoryId, String q, Map<String, String> bindingParam)
820 throws MetadataRepositoryException {
821 return runJcrQuery(jcrSession, repositoryId, q, bindingParam, true);
824 public List<ArtifactMetadata> runJcrQuery(final Session jcrSession, final String repositoryId, final String qParam,
825 final Map<String, String> bindingParam, final boolean checkPath)
826 throws MetadataRepositoryException {
829 List<ArtifactMetadata> artifacts;
830 if (repositoryId != null && checkPath) {
831 q += " AND ISDESCENDANTNODE(artifact,'/" + getRepositoryContentPath(repositoryId) + "')";
834 log.info("Running JCR Query: {}", q);
837 QueryResult result = runNativeJcrQuery(jcrSession, q, bindingParam);
838 artifacts = new ArrayList<>();
839 RowIterator rows = result.getRows();
840 while (rows.hasNext()) {
841 Row row = rows.nextRow();
842 Node node = row.getNode("artifact");
843 artifacts.add(getArtifactFromNode(repositoryId, node));
845 } catch (RepositoryException e) {
846 throw new MetadataRepositoryException(e.getMessage(), e);
848 log.info("Artifacts found {}", artifacts.size());
849 for (ArtifactMetadata meta : artifacts) {
850 log.info("Artifact: " + meta.getVersion() + " " + meta.getFacetList());
855 public QueryResult runNativeJcrQuery(final Session jcrSession, final String q, final Map<String, String> bindingParam) throws MetadataRepositoryException {
856 return runNativeJcrQuery(jcrSession, q, bindingParam, 0, Long.MAX_VALUE);
859 public QueryResult runNativeJcrQuery(final Session jcrSession, final String q, final Map<String, String> bindingParam, long offset, long maxEntries)
860 throws MetadataRepositoryException {
861 Map<String, String> bindings;
862 if (bindingParam == null) {
863 bindings = new HashMap<>();
865 bindings = bindingParam;
869 log.debug("Query: offset={}, limit={}, query={}", offset, maxEntries, q);
870 Query query = jcrSession.getWorkspace().getQueryManager().createQuery(q, Query.JCR_SQL2);
871 query.setLimit(maxEntries);
872 query.setOffset(offset);
873 ValueFactory valueFactory = jcrSession.getValueFactory();
874 for (Entry<String, String> entry : bindings.entrySet()) {
875 log.debug("Binding: {}={}", entry.getKey(), entry.getValue());
876 Value value = valueFactory.createValue(entry.getValue());
877 log.debug("Binding value {}={}", entry.getKey(), value);
878 query.bindValue(entry.getKey(), value);
880 long start = System.currentTimeMillis();
881 log.debug("Execute query {}", query);
882 QueryResult result = query.execute();
883 long end = System.currentTimeMillis();
884 log.info("JCR Query ran in {} milliseconds: {}", end - start, q);
886 } catch (RepositoryException e) {
887 throw new MetadataRepositoryException(e.getMessage(), e);
892 public List<ArtifactMetadata> getArtifactsByProjectVersionFacet(RepositorySession session, String key, String value, String repositoryId)
893 throws MetadataRepositoryException {
894 final Session jcrSession = getSession(session);
895 final String q = new StringBuilder(QUERY_ARTIFACTS_BY_PROJECT_VERSION_1).append(key).append(QUERY_ARTIFACTS_BY_PROJECT_VERSION_2).toString();
896 Map<String, String> parameterMap = new HashMap<>();
897 parameterMap.put("value", value);
898 parameterMap = Collections.unmodifiableMap(parameterMap);
899 return runJcrQuery(jcrSession, repositoryId, q, parameterMap);
904 public List<ArtifactMetadata> getArtifactsByAttribute(RepositorySession session, String key, String value, String repositoryId)
905 throws MetadataRepositoryException {
906 final Session jcrSession = getSession(session);
907 final String q = new StringBuilder(QUERY_ARTIFACTS_BY_METADATA_1).append(key).append(QUERY_ARTIFACTS_BY_METADATA_2).toString();
908 Map<String, String> parameterMap = new HashMap<>();
909 parameterMap.put("value", value);
910 parameterMap = Collections.unmodifiableMap(parameterMap);
911 return runJcrQuery(jcrSession, repositoryId, q, parameterMap);
916 public List<ArtifactMetadata> getArtifactsByProjectVersionAttribute(RepositorySession session, String key, String value, String repositoryId)
917 throws MetadataRepositoryException {
918 final Session jcrSession = getSession(session);
919 final String q = new StringBuilder(QUERY_ARTIFACTS_BY_PROPERTY_1).append(key).append(QUERY_ARTIFACTS_BY_PROPERTY_2).toString();
920 Map<String, String> parameterMap = new HashMap<>();
921 parameterMap.put("value", value);
922 parameterMap = Collections.unmodifiableMap(parameterMap);
923 return runJcrQuery(jcrSession, repositoryId, q, parameterMap);
928 public void removeRepository(RepositorySession session, String repositoryId)
929 throws MetadataRepositoryException {
930 final Session jcrSession = getSession(session);
932 Node root = jcrSession.getRootNode();
933 String path = getRepositoryPath(repositoryId);
934 if (root.hasNode(path)) {
935 root.getNode(path).remove();
937 } catch (RepositoryException e) {
938 throw new MetadataRepositoryException(e.getMessage(), e);
943 public List<ArtifactMetadata> getArtifacts(RepositorySession session, String repositoryId)
944 throws MetadataRepositoryException {
945 final Session jcrSession = getSession(session);
946 List<ArtifactMetadata> artifacts;
948 String q = getArtifactQuery(repositoryId).toString();
951 Query query = jcrSession.getWorkspace().getQueryManager().createQuery(q, Query.JCR_SQL2);
952 QueryResult result = query.execute();
954 artifacts = new ArrayList<>();
955 for (Node n : JcrUtils.getNodes(result)) {
956 if (n.isNodeType(ARTIFACT_NODE_TYPE)) {
957 artifacts.add(getArtifactFromNode(repositoryId, n));
960 } catch (RepositoryException e) {
961 throw new MetadataRepositoryException(e.getMessage(), e);
966 private static StringBuilder getArtifactQuery(String repositoryId) {
967 return new StringBuilder(QUERY_ARTIFACT_1).append(getRepositoryContentPath(repositoryId)).append(QUERY_ARTIFACT_2);
971 public ProjectMetadata getProject(RepositorySession session, String repositoryId, String namespace, String projectId)
972 throws MetadataResolutionException {
973 final Session jcrSession;
975 jcrSession = getSession(session);
976 } catch (MetadataRepositoryException e) {
977 throw new MetadataResolutionException(e.getMessage());
979 ProjectMetadata metadata = null;
982 Node root = jcrSession.getRootNode();
984 // basically just checking it exists
985 String path = getProjectPath(repositoryId, namespace, projectId);
986 if (root.hasNode(path)) {
987 metadata = new ProjectMetadata();
988 metadata.setId(projectId);
989 metadata.setNamespace(namespace);
991 } catch (RepositoryException e) {
992 throw new MetadataResolutionException(e.getMessage(), e);
998 private static Optional<License> getLicense(Node licenseNode) {
1000 String licenseName = licenseNode.getName();
1001 String licenseUrl = getPropertyString(licenseNode, "url");
1002 License license = new License();
1003 license.setName(licenseName);
1004 license.setUrl(licenseUrl);
1005 return Optional.of(license);
1006 } catch (RepositoryException e) {
1007 return Optional.empty();
1011 private static Optional<MailingList> getMailinglist(Node mailinglistNode) {
1013 String mailingListName = mailinglistNode.getName();
1014 MailingList mailinglist = new MailingList();
1015 mailinglist.setName(mailingListName);
1016 mailinglist.setMainArchiveUrl(getPropertyString(mailinglistNode, "archive"));
1017 String n = "otherArchives";
1018 if (mailinglistNode.hasProperty(n)) {
1019 mailinglist.setOtherArchives(Arrays.asList(getPropertyString(mailinglistNode, n).split(",")));
1021 mailinglist.setOtherArchives(Collections.<String>emptyList());
1023 mailinglist.setPostAddress(getPropertyString(mailinglistNode, "post"));
1024 mailinglist.setSubscribeAddress(getPropertyString(mailinglistNode, "subscribe"));
1025 mailinglist.setUnsubscribeAddress(getPropertyString(mailinglistNode, "unsubscribe"));
1026 return Optional.of(mailinglist);
1027 } catch (RepositoryException e) {
1028 return Optional.empty();
1034 public ProjectVersionMetadata getProjectVersion(RepositorySession session, String repositoryId, String namespace, String projectId,
1035 String projectVersion)
1036 throws MetadataResolutionException {
1037 final Session jcrSession;
1039 jcrSession = getSession(session);
1040 } catch (MetadataRepositoryException e) {
1041 throw new MetadataResolutionException(e.getMessage());
1043 ProjectVersionMetadata versionMetadata;
1046 Node root = jcrSession.getRootNode();
1048 String path = getProjectVersionPath(repositoryId, namespace, projectId, projectVersion);
1049 if (!root.hasNode(path)) {
1053 Node node = root.getNode(path);
1055 versionMetadata = new ProjectVersionMetadata();
1056 versionMetadata.setId(projectVersion);
1057 versionMetadata.setName(getPropertyString(node, "name"));
1058 versionMetadata.setDescription(getPropertyString(node, "description"));
1059 versionMetadata.setUrl(getPropertyString(node, "url"));
1060 versionMetadata.setIncomplete(
1061 node.hasProperty("incomplete") && node.getProperty("incomplete").getBoolean());
1063 // FIXME: decide how to treat these in the content repo
1064 String scmConnection = getPropertyString(node, "scm.connection");
1065 String scmDeveloperConnection = getPropertyString(node, "scm.developerConnection");
1066 String scmUrl = getPropertyString(node, "scm.url");
1067 if (scmConnection != null || scmDeveloperConnection != null || scmUrl != null) {
1068 Scm scm = new Scm();
1069 scm.setConnection(scmConnection);
1070 scm.setDeveloperConnection(scmDeveloperConnection);
1072 versionMetadata.setScm(scm);
1075 String ciSystem = getPropertyString(node, "ci.system");
1076 String ciUrl = getPropertyString(node, "ci.url");
1077 if (ciSystem != null || ciUrl != null) {
1078 CiManagement ci = new CiManagement();
1079 ci.setSystem(ciSystem);
1081 versionMetadata.setCiManagement(ci);
1084 String issueSystem = getPropertyString(node, "issue.system");
1085 String issueUrl = getPropertyString(node, "issue.url");
1086 if (issueSystem != null || issueUrl != null) {
1087 IssueManagement issueManagement = new IssueManagement();
1088 issueManagement.setSystem(issueSystem);
1089 issueManagement.setUrl(issueUrl);
1090 versionMetadata.setIssueManagement(issueManagement);
1093 String orgName = getPropertyString(node, "org.name");
1094 String orgUrl = getPropertyString(node, "org.url");
1095 if (orgName != null || orgUrl != null) {
1096 Organization org = new Organization();
1097 org.setName(orgName);
1099 versionMetadata.setOrganization(org);
1102 if (node.hasNode("licenses")) {
1103 Node licensesListNode = node.getNode("licenses");
1104 List<License> licenseList = StreamSupport.stream(JcrUtils.getChildNodes(licensesListNode).spliterator(),false)
1105 .map(JcrMetadataRepository::getLicense).filter(Optional::isPresent)
1106 .map(Optional::get).sorted().collect(Collectors.toList());
1107 versionMetadata.setLicenses(licenseList);
1109 if (node.hasNode("mailinglists")) {
1110 Node mailinglistsListNode = node.getNode("mailinglists");
1111 List<MailingList> mailinglistList = StreamSupport.stream(JcrUtils.getChildNodes(mailinglistsListNode).spliterator(), false)
1112 .map(JcrMetadataRepository::getMailinglist)
1113 .filter(Optional::isPresent)
1115 .sorted().collect(Collectors.toList());
1116 versionMetadata.setMailingLists(mailinglistList);
1119 if (node.hasNode("dependencies")) {
1120 Node dependenciesNode = node.getNode("dependencies");
1121 for (Node n : JcrUtils.getChildNodes(dependenciesNode)) {
1122 if (n.isNodeType(DEPENDENCY_NODE_TYPE)) {
1123 Dependency dependency = new Dependency();
1124 // FIXME: correct these properties
1125 dependency.setNamespace(getPropertyString(n, "namespace"));
1126 dependency.setProjectId(getPropertyString(n, "projectId"));
1127 dependency.setVersion(getPropertyString(n, "version"));
1128 dependency.setArtifactId(getPropertyString(n, "artifactId"));
1129 dependency.setClassifier(getPropertyString(n, "classifier"));
1130 dependency.setOptional(Boolean.valueOf(getPropertyString(n, "optional")));
1131 dependency.setScope(getPropertyString(n, "scope"));
1132 dependency.setSystemPath(getPropertyString(n, "systemPath"));
1133 dependency.setType(getPropertyString(n, "type"));
1134 versionMetadata.addDependency(dependency);
1139 retrieveFacetProperties(versionMetadata, node);
1140 } catch (RepositoryException e) {
1141 throw new MetadataResolutionException(e.getMessage(), e);
1144 return versionMetadata;
1147 private void retrieveFacetProperties(FacetedMetadata metadata, Node node) throws RepositoryException {
1148 for (Node n : JcrUtils.getChildNodes(node)) {
1149 if (n.isNodeType(FACET_NODE_TYPE)) {
1150 String name = n.getName();
1151 MetadataFacetFactory factory = metadataService.getFactory(name);
1152 if (factory == null) {
1153 log.error("Attempted to load unknown project version metadata facet: {}", name);
1155 MetadataFacet facet = createFacetFromNode(factory, n);
1156 metadata.addFacet(facet);
1163 public List<String> getArtifactVersions(RepositorySession session, String repositoryId, String namespace, String projectId,
1164 String projectVersion)
1165 throws MetadataResolutionException {
1166 final Session jcrSession;
1168 jcrSession = getSession(session);
1169 } catch (MetadataRepositoryException e) {
1170 throw new MetadataResolutionException(e.getMessage());
1172 Set<String> versions = new LinkedHashSet<String>();
1175 Node root = jcrSession.getRootNode();
1177 Node node = root.getNode(getProjectVersionPath(repositoryId, namespace, projectId, projectVersion));
1179 for (Node n : JcrUtils.getChildNodes(node)) {
1180 versions.add(n.getProperty("version").getString());
1182 } catch (PathNotFoundException e) {
1183 // ignore repo not found for now
1184 } catch (RepositoryException e) {
1185 throw new MetadataResolutionException(e.getMessage(), e);
1188 return new ArrayList<>(versions);
1192 public List<ProjectVersionReference> getProjectReferences(RepositorySession session, String repositoryId, String namespace,
1193 String projectId, String projectVersion)
1194 throws MetadataResolutionException {
1195 final Session jcrSession;
1197 jcrSession = getSession(session);
1198 } catch (MetadataRepositoryException e) {
1199 throw new MetadataResolutionException(e.getMessage());
1202 List<ProjectVersionReference> references = new ArrayList<>();
1204 // TODO: bind variables instead
1205 String q = "SELECT * FROM [archiva:dependency] WHERE ISDESCENDANTNODE([/repositories/" + repositoryId
1206 + "/content]) AND [namespace]='" + namespace + "' AND [artifactId]='" + projectId + "'";
1207 if (projectVersion != null) {
1208 q += " AND [version]='" + projectVersion + "'";
1211 Query query = jcrSession.getWorkspace().getQueryManager().createQuery(q, Query.JCR_SQL2);
1212 QueryResult result = query.execute();
1214 for (Node n : JcrUtils.getNodes(result)) {
1215 n = n.getParent(); // dependencies grouping element
1217 n = n.getParent(); // project version
1218 String usedByProjectVersion = n.getName();
1220 n = n.getParent(); // project
1221 String usedByProject = n.getName();
1223 n = n.getParent(); // namespace
1224 String usedByNamespace = n.getProperty("namespace").getString();
1226 ProjectVersionReference ref = new ProjectVersionReference();
1227 ref.setNamespace(usedByNamespace);
1228 ref.setProjectId(usedByProject);
1229 ref.setProjectVersion(usedByProjectVersion);
1230 ref.setReferenceType(ProjectVersionReference.ReferenceType.DEPENDENCY);
1231 references.add(ref);
1233 } catch (RepositoryException e) {
1234 throw new MetadataResolutionException(e.getMessage(), e);
1241 public List<String> getRootNamespaces(RepositorySession session, String repositoryId)
1242 throws MetadataResolutionException {
1243 return this.getChildNamespaces(session, repositoryId, null);
1247 public List<String> getChildNamespaces(RepositorySession session, String repositoryId, String baseNamespace)
1248 throws MetadataResolutionException {
1249 String path = baseNamespace != null
1250 ? getNamespacePath(repositoryId, baseNamespace)
1251 : getRepositoryContentPath(repositoryId);
1254 return getNodeNames(getSession(session), path, NAMESPACE_MIXIN_TYPE);
1255 } catch (MetadataRepositoryException e) {
1256 throw new MetadataResolutionException(e.getMessage());
1261 public List<String> getProjects(RepositorySession session, String repositoryId, String namespace)
1262 throws MetadataResolutionException {
1264 return getNodeNames(getSession(session), getNamespacePath(repositoryId, namespace), org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_MIXIN_TYPE);
1265 } catch (MetadataRepositoryException e) {
1266 throw new MetadataResolutionException(e.getMessage());
1271 public List<String> getProjectVersions(RepositorySession session, String repositoryId, String namespace, String projectId)
1272 throws MetadataResolutionException {
1274 return getNodeNames(getSession(session), getProjectPath(repositoryId, namespace, projectId), PROJECT_VERSION_NODE_TYPE);
1275 } catch (MetadataRepositoryException e) {
1276 throw new MetadataResolutionException(e.getMessage());
1281 public void removeTimestampedArtifact(RepositorySession session, ArtifactMetadata artifactMetadata, String baseVersion)
1282 throws MetadataRepositoryException {
1283 final Session jcrSession = getSession(session);
1284 String repositoryId = artifactMetadata.getRepositoryId();
1287 Node root = jcrSession.getRootNode();
1289 getProjectVersionPath(repositoryId, artifactMetadata.getNamespace(), artifactMetadata.getProject(),
1292 if (root.hasNode(path)) {
1293 Node node = root.getNode(path);
1295 for (Node n : JcrUtils.getChildNodes(node)) {
1296 if (n.isNodeType(ARTIFACT_NODE_TYPE)) {
1297 if (n.hasProperty("version")) {
1298 String version = n.getProperty("version").getString();
1299 if (StringUtils.equals(version, artifactMetadata.getVersion())) {
1307 } catch (RepositoryException e) {
1308 throw new MetadataRepositoryException(e.getMessage(), e);
1316 public void removeProjectVersion(RepositorySession session, String repoId, String namespace, String projectId, String projectVersion)
1317 throws MetadataRepositoryException {
1318 final Session jcrSession = getSession(session);
1321 String path = getProjectPath(repoId, namespace, projectId);
1322 Node root = jcrSession.getRootNode();
1324 Node nodeAtPath = root.getNode(path);
1326 for (Node node : JcrUtils.getChildNodes(nodeAtPath)) {
1327 if (node.isNodeType(PROJECT_VERSION_NODE_TYPE) && StringUtils.equals(projectVersion,
1332 } catch (RepositoryException e) {
1333 throw new MetadataRepositoryException(e.getMessage(), e);
1338 public void removeArtifact(RepositorySession session, String repositoryId, String namespace, String projectId, String projectVersion,
1340 throws MetadataRepositoryException {
1341 final Session jcrSession = getSession(session);
1343 Node root = jcrSession.getRootNode();
1344 String path = getArtifactPath(repositoryId, namespace, projectId, projectVersion, id);
1345 if (root.hasNode(path)) {
1346 root.getNode(path).remove();
1351 path = getProjectPath(repositoryId, namespace, projectId);
1353 Node nodeAtPath = root.getNode(path);
1355 for (Node node : JcrUtils.getChildNodes(nodeAtPath)) {
1356 if (node.isNodeType(PROJECT_VERSION_NODE_TYPE) //
1357 && StringUtils.equals(node.getName(), projectVersion)) {
1361 } catch (RepositoryException e) {
1362 throw new MetadataRepositoryException(e.getMessage(), e);
1367 public void removeFacetFromArtifact(RepositorySession session, String repositoryId, String namespace, String project, String projectVersion,
1368 MetadataFacet metadataFacet)
1369 throws MetadataRepositoryException {
1370 final Session jcrSession = getSession(session);
1372 Node root = jcrSession.getRootNode();
1373 String path = getProjectVersionPath(repositoryId, namespace, project, projectVersion);
1375 if (root.hasNode(path)) {
1376 Node node = root.getNode(path);
1378 for (Node n : JcrUtils.getChildNodes(node)) {
1379 if (n.isNodeType(ARTIFACT_NODE_TYPE)) {
1380 ArtifactMetadata artifactMetadata = getArtifactFromNode(repositoryId, n);
1381 log.debug("artifactMetadata: {}", artifactMetadata);
1382 MetadataFacet metadataFacetToRemove = artifactMetadata.getFacet(metadataFacet.getFacetId());
1383 if (metadataFacetToRemove != null && metadataFacet.equals(metadataFacetToRemove)) {
1389 } catch (RepositoryException e) {
1390 throw new MetadataRepositoryException(e.getMessage(), e);
1395 public List<ArtifactMetadata> getArtifacts(RepositorySession session, String repositoryId, String namespace, String projectId,
1396 String projectVersion)
1397 throws MetadataResolutionException {
1398 final Session jcrSession;
1400 jcrSession = getSession(session);
1401 } catch (MetadataRepositoryException e) {
1402 throw new MetadataResolutionException(e.getMessage());
1404 List<ArtifactMetadata> artifacts = new ArrayList<>();
1407 Node root = jcrSession.getRootNode();
1408 String path = getProjectVersionPath(repositoryId, namespace, projectId, projectVersion);
1410 if (root.hasNode(path)) {
1411 Node node = root.getNode(path);
1413 for (Node n : JcrUtils.getChildNodes(node)) {
1414 if (n.isNodeType(ARTIFACT_NODE_TYPE)) {
1415 artifacts.add(getArtifactFromNode(repositoryId, n));
1419 } catch (RepositoryException e) {
1420 throw new MetadataResolutionException(e.getMessage(), e);
1429 throws MetadataRepositoryException {
1434 * Exact is ignored as we can't do exact search in any property, we need a key
1437 public List<ArtifactMetadata> searchArtifacts(RepositorySession session, String repositoryId, String text, boolean exact)
1438 throws MetadataRepositoryException {
1439 return searchArtifacts(session, repositoryId, null, text, exact);
1443 public List<ArtifactMetadata> searchArtifacts(RepositorySession session, String repositoryId, String key, String text, boolean exact)
1444 throws MetadataRepositoryException {
1445 final Session jcrSession = getSession(session);
1446 String theKey = key == null ? "*" : "[" + key + "]";
1447 String projectVersionCondition =
1448 exact ? "(projectVersion." + theKey + " = $value)" : "contains([projectVersion]." + theKey + ", $value)";
1449 String facetCondition = exact ? "(facet." + theKey + " = $value)" : "contains([facet]." + theKey + ", $value)";
1450 String descendantCondition = repositoryId == null ?
1451 " AND [projectVersion].[jcr:path] LIKE '/repositories/%/content/%'" :
1452 " AND ISDESCENDANTNODE(projectVersion,'/" + getRepositoryContentPath(repositoryId) + "')";
1453 List<ArtifactMetadata> result = new ArrayList<>();
1454 if (key == null || (key != null && Arrays.binarySearch(PROJECT_VERSION_VERSION_PROPERTIES, key) >= 0)) {
1455 // We search only for project version properties if the key is a valid property name
1457 "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE
1458 + "] AS projectVersion LEFT OUTER JOIN [" + ARTIFACT_NODE_TYPE
1459 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) WHERE " + projectVersionCondition + descendantCondition;
1460 Map<String, String> parameterMap = new HashMap<>();
1461 parameterMap.put("value", text);
1462 parameterMap = Collections.unmodifiableMap(parameterMap);
1463 result.addAll(runJcrQuery(jcrSession, repositoryId, q1, parameterMap, false));
1466 "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE
1467 + "] AS projectVersion LEFT OUTER JOIN [" + ARTIFACT_NODE_TYPE
1468 + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) LEFT OUTER JOIN [" + FACET_NODE_TYPE
1469 + "] AS facet ON ISCHILDNODE(facet, projectVersion) WHERE " + facetCondition + descendantCondition;
1470 Map<String, String> parameterMap = new HashMap<>();
1471 parameterMap.put("value", text);
1472 parameterMap = Collections.unmodifiableMap(parameterMap);
1473 result.addAll(runJcrQuery(jcrSession, repositoryId, q2, parameterMap, false));
1477 private ArtifactMetadata getArtifactFromNode(String repositoryId, Node artifactNode)
1478 throws RepositoryException {
1479 String id = artifactNode.getName();
1481 ArtifactMetadata artifact = new ArtifactMetadata();
1483 artifact.setRepositoryId(repositoryId == null ? artifactNode.getAncestor(2).getName() : repositoryId);
1485 Node projectVersionNode = artifactNode.getParent();
1486 Node projectNode = projectVersionNode.getParent();
1487 Node namespaceNode = projectNode.getParent();
1489 artifact.setNamespace(namespaceNode.getProperty("namespace").getString());
1490 artifact.setProject(projectNode.getName());
1491 artifact.setProjectVersion(projectVersionNode.getName());
1492 artifact.setVersion(artifactNode.hasProperty("version")
1493 ? artifactNode.getProperty("version").getString()
1494 : projectVersionNode.getName());
1496 if (artifactNode.hasProperty(JCR_LAST_MODIFIED)) {
1497 artifact.setFileLastModified(artifactNode.getProperty(JCR_LAST_MODIFIED).getDate().getTimeInMillis());
1500 if (artifactNode.hasProperty("whenGathered")) {
1501 Calendar cal = artifactNode.getProperty("whenGathered").getDate();
1502 artifact.setWhenGathered(ZonedDateTime.ofInstant(cal.toInstant(), cal.getTimeZone().toZoneId()));
1505 if (artifactNode.hasProperty("size")) {
1506 artifact.setSize(artifactNode.getProperty("size").getLong());
1509 Node cslistNode = getOrAddNodeByPath(artifactNode, "checksums");
1510 NodeIterator csNodeIt = cslistNode.getNodes("*");
1511 while (csNodeIt.hasNext()) {
1512 Node csNode = csNodeIt.nextNode();
1513 if (csNode.isNodeType(CHECKSUM_NODE_TYPE)) {
1514 addChecksum(artifact, csNode);
1518 retrieveFacetProperties(artifact, artifactNode);
1522 private void addChecksum(ArtifactMetadata artifact, Node n) {
1524 ChecksumAlgorithm alg = ChecksumAlgorithm.valueOf(n.getProperty("type").getString());
1525 String value = n.getProperty("value").getString();
1526 artifact.setChecksum(alg, value);
1527 } catch (Throwable e) {
1528 log.error("Could not set checksum from node {}", n);
1532 private static String getPropertyString(Node node, String name)
1533 throws RepositoryException {
1534 return node.hasProperty(name) ? node.getProperty(name).getString() : null;
1537 private List<String> getNodeNames(Session jcrSession, String path, String nodeType)
1538 throws MetadataResolutionException {
1540 List<String> names = new ArrayList<>();
1543 Node root = jcrSession.getRootNode();
1545 Node nodeAtPath = root.getNode(path);
1547 for (Node node : JcrUtils.getChildNodes(nodeAtPath)) {
1548 if (node.isNodeType(nodeType)) {
1549 names.add(node.getName());
1552 } catch (PathNotFoundException e) {
1553 // ignore repo not found for now
1554 } catch (RepositoryException e) {
1555 throw new MetadataResolutionException(e.getMessage(), e);
1561 private static String getRepositoryPath(String repositoryId) {
1562 return "repositories/" + repositoryId;
1565 private static String getRepositoryContentPath(String repositoryId) {
1566 return getRepositoryPath(repositoryId) + "/content";
1569 private static String getFacetPath(String repositoryId, String facetId) {
1570 return StringUtils.isEmpty(facetId) ? getRepositoryPath(repositoryId) + "/facets" :
1571 getRepositoryPath(repositoryId) + "/facets/" + facetId;
1574 private static String getNamespacePath(String repositoryId, String namespace) {
1575 return getRepositoryContentPath(repositoryId) + "/" + namespace.replace('.', '/');
1578 private static String getProjectPath(String repositoryId, String namespace, String projectId) {
1579 return getNamespacePath(repositoryId, namespace) + "/" + projectId;
1582 private static String getProjectVersionPath(String repositoryId, String namespace, String projectId,
1583 String projectVersion) {
1584 return getProjectPath(repositoryId, namespace, projectId) + "/" + projectVersion;
1587 private static String getArtifactPath(String repositoryId, String namespace, String projectId,
1588 String projectVersion, String id) {
1589 return getProjectVersionPath(repositoryId, namespace, projectId, projectVersion) + "/" + id;
1592 private Node getOrAddNodeByPath(Node baseNode, String name)
1593 throws RepositoryException {
1594 return getOrAddNodeByPath(baseNode, name, null);
1597 private Node getOrAddNodeByPath(Node baseNode, String name, String nodeType) throws RepositoryException {
1598 return getOrAddNodeByPath(baseNode, name, nodeType, false);
1601 private Node getOrAddNodeByPath(Node baseNode, String name, String nodeType, boolean primaryType)
1602 throws RepositoryException {
1603 log.debug("getOrAddNodeByPath " + baseNode + " " + name + " " + nodeType);
1604 Node node = baseNode;
1605 for (String n : name.split("/")) {
1606 if (nodeType != null && primaryType) {
1607 node = JcrUtils.getOrAddNode(node, n, nodeType);
1609 node = JcrUtils.getOrAddNode(node, n);
1610 if (nodeType != null && !node.isNodeType(nodeType)) {
1611 node.addMixin(nodeType);
1614 if (!node.hasProperty("id")) {
1615 node.setProperty("id", n);
1621 private Node getOrAddNodeByPath(Node baseNode, String name, String primaryType, String... mixinTypes)
1622 throws RepositoryException {
1623 log.debug("getOrAddNodeByPath baseNode={}, name={}, primary={}, mixin={}", baseNode, name, primaryType, mixinTypes);
1624 Node node = baseNode;
1625 for (String n : name.split("/")) {
1626 node = JcrUtils.getOrAddNode(node, n, primaryType);
1627 for (String mixin : mixinTypes) {
1628 if (mixin != null && !node.isNodeType(mixin)) {
1629 node.addMixin(mixin);
1633 if (!node.hasProperty("id")) {
1634 node.setProperty("id", n);
1640 private static String getFacetPath(String repositoryId, String facetId, String name) {
1641 return getFacetPath(repositoryId, facetId) + "/" + name;
1644 private Node getOrAddRepositoryNode(Session jcrSession, String repositoryId)
1645 throws RepositoryException {
1646 log.debug("getOrAddRepositoryNode " + repositoryId);
1647 Node root = jcrSession.getRootNode();
1648 Node node = JcrUtils.getOrAddNode(root, "repositories");
1649 log.debug("Repositories " + node);
1650 node = JcrUtils.getOrAddNode(node, repositoryId, REPOSITORY_NODE_TYPE);
1651 if (!node.hasProperty("id")) {
1652 node.setProperty("id", repositoryId);
1657 private Node getOrAddRepositoryContentNode(Session jcrSession, String repositoryId)
1658 throws RepositoryException {
1659 Node node = getOrAddRepositoryNode(jcrSession, repositoryId);
1660 return JcrUtils.getOrAddNode(node, "content", CONTENT_NODE_TYPE);
1663 private Node getOrAddNamespaceNode(Session jcrSession, String repositoryId, String namespace)
1664 throws RepositoryException {
1665 Node repo = getOrAddRepositoryContentNode(jcrSession, repositoryId);
1666 return getOrAddNodeByPath(repo, namespace.replace('.', '/'), FOLDER_TYPE, NAMESPACE_MIXIN_TYPE);
1669 private Node getOrAddProjectNode(Session jcrSession, String repositoryId, String namespace, String projectId)
1670 throws RepositoryException {
1671 Node namespaceNode = getOrAddNamespaceNode(jcrSession, repositoryId, namespace);
1672 Node node = JcrUtils.getOrAddNode(namespaceNode, projectId, FOLDER_TYPE);
1673 if (!node.isNodeType(PROJECT_MIXIN_TYPE)) {
1674 node.addMixin(PROJECT_MIXIN_TYPE);
1676 if (!node.hasProperty("id")) {
1677 node.setProperty("id", projectId);
1682 private Node getOrAddProjectVersionNode(Session jcrSession, String repositoryId, String namespace, String projectId,
1683 String projectVersion)
1684 throws RepositoryException {
1685 Node projectNode = getOrAddProjectNode(jcrSession, repositoryId, namespace, projectId);
1686 log.debug("Project node {}", projectNode);
1687 Node projectVersionNode = JcrUtils.getOrAddNode(projectNode, projectVersion, PROJECT_VERSION_NODE_TYPE);
1688 if (!projectVersionNode.hasProperty("id")) {
1689 projectVersionNode.setProperty("id", projectVersion);
1692 log.debug("Project version node {}", projectVersionNode);
1693 return projectVersionNode;
1696 private Node getOrAddArtifactNode(Session jcrSession, String repositoryId, String namespace, String projectId, String projectVersion,
1698 throws RepositoryException {
1699 Node versionNode = getOrAddProjectVersionNode(jcrSession, repositoryId, namespace, projectId, projectVersion);
1700 Node node = JcrUtils.getOrAddNode(versionNode, id, ARTIFACT_NODE_TYPE);
1701 if (!node.hasProperty("id")) {
1702 node.setProperty("id", id);
1707 private Node findArtifactNode(Session jcrSession, String namespace, String projectId,
1708 String projectVersion, String id) throws RepositoryException {
1710 if (namespace==null || projectId==null||projectVersion==null||id==null) {
1713 Node root = jcrSession.getRootNode();
1714 Node node = JcrUtils.getOrAddNode(root, "repositories");
1715 for (Node n : JcrUtils.getChildNodes(node)) {
1716 String repositoryId = n.getName();
1717 Node repo = getOrAddRepositoryContentNode(jcrSession, repositoryId);
1718 Node nsNode = JcrUtils.getNodeIfExists(repo, StringUtils.replaceChars(namespace, '.', '/'));
1720 Node projNode = JcrUtils.getNodeIfExists(nsNode, projectId);
1721 if (projNode !=null ) {
1722 Node projVersionNode = JcrUtils.getNodeIfExists(projNode, projectVersion);
1723 if (projVersionNode != null) {
1724 return JcrUtils.getNodeIfExists(projVersionNode, id);
1733 private static Calendar createCalendar(ZonedDateTime time) {
1734 return GregorianCalendar.from(time);
1737 private String join(Collection<String> ids) {
1738 if (ids != null && !ids.isEmpty()) {
1739 StringBuilder s = new StringBuilder();
1740 for (String id : ids) {
1744 return s.substring(0, s.length() - 1);
1751 public void populateStatistics(RepositorySession repositorySession, MetadataRepository repository, String repositoryId,
1752 RepositoryStatistics repositoryStatistics)
1753 throws MetadataRepositoryException {
1754 if (!(repository instanceof JcrMetadataRepository)) {
1755 throw new MetadataRepositoryException(
1756 "The statistics population is only possible for JcrMetdataRepository implementations");
1758 Session session = getSession(repositorySession);
1759 // TODO: these may be best as running totals, maintained by observations on the properties in JCR
1762 QueryManager queryManager = session.getWorkspace().getQueryManager();
1764 // TODO: Check, if this is still the case - Switched to Jackrabbit OAK with archiva 3.0
1765 // Former statement: JCR-SQL2 query will not complete on a large repo in Jackrabbit 2.2.0 - see JCR-2835
1766 // Using the JCR-SQL2 variants gives
1767 // "org.apache.lucene.search.BooleanQuery$TooManyClauses: maxClauseCount is set to 1024"
1768 // String whereClause = "WHERE ISDESCENDANTNODE([/repositories/" + repositoryId + "/content])";
1769 // Query query = queryManager.createQuery( "SELECT size FROM [archiva:artifact] " + whereClause,
1770 // Query.JCR_SQL2 );
1771 String whereClause = "WHERE ISDESCENDANTNODE([/repositories/" + repositoryId + "/content])";
1772 Query query = queryManager.createQuery("SELECT type,size FROM [" + ARTIFACT_NODE_TYPE + "] " + whereClause, Query.JCR_SQL2);
1774 QueryResult queryResult = query.execute();
1776 Map<String, Integer> totalByType = new HashMap<>();
1777 long totalSize = 0, totalArtifacts = 0;
1778 for (Row row : JcrUtils.getRows(queryResult)) {
1779 Node n = row.getNode();
1780 log.debug("Result node {}", n);
1781 totalSize += row.getValue("size").getLong();
1784 if (n.hasNode(MavenArtifactFacet.FACET_ID)) {
1785 Node facetNode = n.getNode(MavenArtifactFacet.FACET_ID);
1786 type = facetNode.getProperty("type").getString();
1790 Integer prev = totalByType.get(type);
1791 totalByType.put(type, prev != null ? prev + 1 : 1);
1796 repositoryStatistics.setTotalArtifactCount(totalArtifacts);
1797 repositoryStatistics.setTotalArtifactFileSize(totalSize);
1798 for (Map.Entry<String, Integer> entry : totalByType.entrySet()) {
1799 log.info("Setting count for type: {} = {}", entry.getKey(), entry.getValue());
1800 repositoryStatistics.setTotalCountForType(entry.getKey(), entry.getValue());
1803 // The query ordering is a trick to ensure that the size is correct, otherwise due to lazy init it will be -1
1804 // query = queryManager.createQuery( "SELECT * FROM [archiva:project] " + whereClause, Query.JCR_SQL2 );
1805 query = queryManager.createQuery("SELECT * FROM [archiva:project] " + whereClause + " ORDER BY [jcr:score]",
1807 repositoryStatistics.setTotalProjectCount(query.execute().getRows().getSize());
1809 // query = queryManager.createQuery(
1810 // "SELECT * FROM [archiva:namespace] " + whereClause + " AND namespace IS NOT NULL", Query.JCR_SQL2 );
1811 query = queryManager.createQuery(
1812 "SELECT * FROM [archiva:namespace] " + whereClause + " AND namespace IS NOT NULL ORDER BY [jcr:score]",
1814 repositoryStatistics.setTotalGroupCount(query.execute().getRows().getSize());
1815 } catch (RepositoryException e) {
1816 throw new MetadataRepositoryException(e.getMessage(), e);
1821 public Session login() throws RepositoryException {
1822 return repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
1825 private static boolean isArtifactNodeType(Node n) {
1827 return n != null && n.isNodeType(ARTIFACT_NODE_TYPE);
1828 } catch (RepositoryException e) {
1833 private Optional<ArtifactMetadata> getArtifactOptional(final String repositoryId, final Node n) {
1835 return Optional.ofNullable(getArtifactFromNode(repositoryId, n));
1836 } catch (RepositoryException e) {
1837 return Optional.empty();
1841 private Optional<ArtifactMetadata> getArtifactOptional(final String repositoryId, final Row row) {
1843 return Optional.of(getArtifactFromNode(repositoryId, row.getNode("artifact")));
1844 } catch (RepositoryException e) {
1845 return Optional.empty();
1850 public Stream<ArtifactMetadata> getArtifactStream(final RepositorySession session, final String repositoryId,
1851 final String namespace, final String projectId, final String projectVersion,
1852 final QueryParameter queryParameter) throws MetadataResolutionException {
1853 final Session jcrSession;
1855 jcrSession = getSession(session);
1856 } catch (MetadataRepositoryException e) {
1857 throw new MetadataResolutionException(e.getMessage());
1861 Node root = jcrSession.getRootNode();
1862 String path = getProjectVersionPath(repositoryId, namespace, projectId, projectVersion);
1864 if (root.hasNode(path)) {
1865 Node node = root.getNode(path);
1866 return StreamSupport.stream(JcrUtils.getChildNodes(node).spliterator(), false).filter(JcrMetadataRepository::isArtifactNodeType)
1867 .map(n -> getArtifactOptional(repositoryId, n))
1868 .map(Optional::get).skip(queryParameter.getOffset()).limit(queryParameter.getLimit());
1870 return Stream.empty();
1872 } catch (RepositoryException e) {
1873 throw new MetadataResolutionException(e.getMessage(), e);
1878 public Stream<ArtifactMetadata> getArtifactStream(final RepositorySession session, final String repositoryId,
1879 final QueryParameter queryParameter) throws MetadataResolutionException {
1880 final Session jcrSession;
1882 jcrSession = getSession(session);
1883 } catch (MetadataRepositoryException e) {
1884 throw new MetadataResolutionException(e.getMessage(), e);
1886 List<ArtifactMetadata> artifacts;
1888 String q = getArtifactQuery(repositoryId).toString();
1891 Query query = jcrSession.getWorkspace().getQueryManager().createQuery(q, Query.JCR_SQL2);
1892 QueryResult result = query.execute();
1894 return StreamSupport.stream(createResultSpliterator(result, getArtifactFromRowFunc(repositoryId)), false)
1895 .filter(Optional::isPresent).map(Optional::get)
1896 .skip(queryParameter.getOffset()).limit(queryParameter.getLimit());
1898 } catch (RepositoryException | MetadataRepositoryException e) {
1899 throw new MetadataResolutionException(e.getMessage(), e);