Skip to content
LinkService.java 3.08 KiB
Newer Older
/*
 * 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.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<String> followLinksToLinks(List<String> vosPaths) {
 
        List<LinkNode> linkNodesInPaths = nodeDao.returnLinkNodesInList(vosPaths);
        
        // No links no change
        if(linkNodesInPaths.isEmpty())
            return vosPaths;
              
        List<String> linkVosPaths = linkNodesInPaths.stream()
                .map(ln -> NodeUtils.getVosPath(ln)).collect(Collectors.toList());
        
        // Safe copy of argument        
        List<String> resultVosPaths = new ArrayList<>(vosPaths);
        
        resultVosPaths.removeAll(linkVosPaths);
        
        // follow links and add resulting vos paths. The only remaining links
        // are expected to be external (http://... and so on)
        
        resultVosPaths.addAll(linkNodesInPaths.stream()
               .map(ln -> NodeUtils.getVosPath(this.followLink(ln)))
               .collect(Collectors.toList()));
        
        return resultVosPaths;                               
    }
    
    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<Node> 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;
        }
    }

}