Skip to content
LinkService.java 3.75 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.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<ArchiveEntryDescriptor> followLinksForArchiveService(List<String> vosPaths) {
 
        List<LinkNode> linkNodesInPaths = nodeDao.returnLinkNodesInList(vosPaths);
        
        // No links no change
        if(linkNodesInPaths.isEmpty())
            return vosPaths.stream().map(p -> new ArchiveEntryDescriptor(p))
                    .collect(Collectors.toList());
              
        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);
        
        // Generate descriptors from non link vospaths
        List<ArchiveEntryDescriptor> 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<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;
        }
    }

}