/* * This file is part of vospace-rest * Copyright (C) 2021 Istituto Nazionale di Astrofisica * SPDX-License-Identifier: GPL-3.0-or-later */ package it.inaf.oats.vospace; import it.inaf.oats.vospace.datamodel.NodeUtils; import it.inaf.oats.vospace.exception.InternalFaultException; import it.inaf.oats.vospace.parent.exchange.ArchiveEntryDescriptor; import it.inaf.oats.vospace.persistence.NodeDAO; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import net.ivoa.xml.vospace.v2.LinkNode; import net.ivoa.xml.vospace.v2.Node; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service public class LinkService { @Value("${vospace-authority}") private String authority; @Value("${link-max-depth}") private int linkMaxDepth; @Autowired private NodeDAO nodeDao; // Returns a new list = the list in argument with paths of links to links are substituted with // their actual destination vos path. Only links to external resources // (http:// ... ) should remain public List followLinksForArchiveService(List vosPaths) { List linkNodesInPaths = nodeDao.returnLinkNodesInList(vosPaths); // No links no change if(linkNodesInPaths.isEmpty()) return vosPaths.stream().map(p -> new ArchiveEntryDescriptor(p)) .collect(Collectors.toList()); List linkVosPaths = linkNodesInPaths.stream() .map(ln -> NodeUtils.getVosPath(ln)).collect(Collectors.toList()); // Safe copy of argument List resultVosPaths = new ArrayList<>(vosPaths); resultVosPaths.removeAll(linkVosPaths); // Generate descriptors from non link vospaths List resultDescriptors = resultVosPaths.stream().map(p -> new ArchiveEntryDescriptor(p)) .collect(Collectors.toList()); // Add descriptors from links resultDescriptors.addAll( linkNodesInPaths.stream().map(p -> getLinkNodeArchiveEntryDescriptor(p)) .collect(Collectors.toList()) ); return resultDescriptors; } private ArchiveEntryDescriptor getLinkNodeArchiveEntryDescriptor(LinkNode node){ String vosPath = NodeUtils.getVosPath(node); String targetNodeVosPath = NodeUtils.getVosPath(this.followLink(node)); return new ArchiveEntryDescriptor(vosPath, targetNodeVosPath); } public Node followLink(LinkNode linkNode) { return this.followLinkRecursive(linkNode, 0); } private Node followLinkRecursive(LinkNode linkNode, int depth) { if (depth >= linkMaxDepth) { throw new InternalFaultException("Max link depth reached at link node: " + NodeUtils.getVosPath(linkNode)); } String linkTarget = linkNode.getTarget(); if (URIUtils.isURIInternal(linkTarget)) { String targetPath = URIUtils.returnVosPathFromNodeURI(linkTarget, authority); Optional targetNodeOpt = nodeDao.listNode(targetPath); Node targetNode = targetNodeOpt.orElseThrow(() -> new InternalFaultException("Broken Link to target: " + targetPath)); if (targetNode instanceof LinkNode) { return this.followLinkRecursive(linkNode, ++depth); } else { return targetNode; } } else { return linkNode; } } }