Commit 35b451bf authored by Nicola Fulvio Calabria's avatar Nicola Fulvio Calabria
Browse files

Added LinkNodes management to PullFromVoSpace

parent bd64b755
Loading
Loading
Loading
Loading
+25 −4
Original line number Diff line number Diff line
@@ -49,6 +49,9 @@ public class UriService {
    @Value("${file-service-url}")
    private String fileServiceUrl;

    @Value("${link-max-depth}")
    private int linkMaxDepth;

    @Autowired
    private NodeDAO nodeDao;

@@ -175,6 +178,8 @@ public class UriService {
                break;

            case pullFromVoSpace:
                // Refresh relative path: it can differ in case of links
                relativePath = NodeUtils.getVosPath(node);
                if (!NodeUtils.checkIfReadable(node, creator, groups)) {
                    throw PermissionDeniedException.forPath(relativePath);
                }
@@ -278,9 +283,25 @@ public class UriService {
    }

    private 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 targetPath = URIUtils.returnVosPathFromNodeURI(linkNode.getTarget(), authority);
        Optional<Node> targetNode = nodeDao.listNode(targetPath);
        return targetNode.orElseThrow(() -> new InternalFaultException("Broken Link to target: " + targetPath));
        
        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;
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -18,4 +18,7 @@ logging.level.org.springframework.web=TRACE

vospace-authority=example.com!vospace

#tune max depth for chained links
link-max-depth=10

file-service-url=http://localhost:8087
+6 −5
Original line number Diff line number Diff line
@@ -114,7 +114,7 @@ public class TransferControllerTest {
    @Test
    public void testPullFromVoSpaceSync() throws Exception {

        Node node = mockPublicDataNode();
        Node node = mockPublicDataNode("vos://example.com!vospace/mynode");
        when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(node));

        String requestBody = getResourceFileContent("pullFromVoSpace.xml");
@@ -198,7 +198,7 @@ public class TransferControllerTest {

    private void testVoSpaceAsyncTransfer(String path, String requestBody) throws Exception {

        Node node = mockPublicDataNode();
        Node node = mockPublicDataNode(path);
        when(nodeDao.listNode(eq(path))).thenReturn(Optional.of(node));

        String redirect = mockMvc.perform(post("/transfers?PHASE=RUN")
@@ -216,7 +216,7 @@ public class TransferControllerTest {
    @Test
    public void testSetJobPhase() throws Exception {

        Node node = mockPublicDataNode();
        Node node = mockPublicDataNode("vos://example.com!vospace/mynode");
        when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(node));

        JobSummary job = getFakePendingJob();
@@ -268,8 +268,9 @@ public class TransferControllerTest {
        assertEquals("PENDING", phase);
    }

    private Node mockPublicDataNode() {
    private Node mockPublicDataNode(String nodeURI) {
        Node node = new DataNode();
        node.setUri(nodeURI);
        Property property = new Property();
        property.setUri("ivo://ivoa.net/vospace/core#publicread");
        property.setValue("true");
@@ -415,7 +416,7 @@ public class TransferControllerTest {
    @Test
    public void testSyncTransferUrlParamsMode() throws Exception {

        Node node = mockPublicDataNode();
        Node node = mockPublicDataNode("vos://example.com!vospace/mynode");
        when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(node));

        mockMvc.perform(get("/synctrans")
+141 −0
Original line number Diff line number Diff line
@@ -8,7 +8,9 @@ package it.inaf.oats.vospace;
import it.inaf.ia2.aa.ServletRapClient;
import it.inaf.ia2.aa.data.User;
import it.inaf.oats.vospace.datamodel.NodeProperties;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.datamodel.Views;
import it.inaf.oats.vospace.exception.InternalFaultException;
import it.inaf.oats.vospace.exception.InvalidArgumentException;
import it.inaf.oats.vospace.exception.NodeBusyException;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
@@ -22,6 +24,7 @@ import javax.servlet.http.HttpServletRequest;
import net.ivoa.xml.uws.v1.JobSummary;
import net.ivoa.xml.vospace.v2.ContainerNode;
import net.ivoa.xml.vospace.v2.DataNode;
import net.ivoa.xml.vospace.v2.LinkNode;
import net.ivoa.xml.vospace.v2.Node;
import net.ivoa.xml.vospace.v2.Param;
import net.ivoa.xml.vospace.v2.Property;
@@ -102,7 +105,10 @@ public class UriServiceTest {
    @Test
    public void testPublicUrl() {
        
        String dataUri = "vos://example.com!vospace/mydata1";

        Node node = new DataNode();
        node.setUri(dataUri);
        Property property = new Property();
        property.setUri(NodeProperties.PUBLIC_READ_URI);
        property.setValue("true");
@@ -119,7 +125,10 @@ public class UriServiceTest {
    @Test
    public void testPrivateUrl() {
        
        String dataUri = "vos://example.com!vospace/mydata1";

        Node node = new DataNode();
        node.setUri(dataUri);
        Property creator = new Property();
        creator.setUri(NodeProperties.CREATOR_URI);
        creator.setValue("user1");
@@ -154,7 +163,10 @@ public class UriServiceTest {
    @Test
    public void testPrivateUrlPermissionDenied() {
        
        String dataUri = "vos://example.com!vospace/mydata1";

        Node node = new DataNode();
        node.setUri(dataUri);
        Property creator = new Property();
        creator.setUri(NodeProperties.CREATOR_URI);
        creator.setValue("user3");
@@ -188,8 +200,10 @@ public class UriServiceTest {

    @Test
    public void testPrivateUrlNodeBusy() {
        String dataUri = "vos://example.com!vospace/mydata1";

        DataNode node = new DataNode();
        node.setUri(dataUri);
        Property creator = new Property();
        creator.setUri(NodeProperties.CREATOR_URI);
        creator.setValue("user1");
@@ -275,6 +289,114 @@ public class UriServiceTest {
        assertEquals("http://file-service/mydata1/mydata2?jobId=job-id2&token=<new-token>", negotiatedTransfer.getProtocols().get(0).getEndpoint());
    }
    
    @Test
    public void pullFromLinkNode() {
        
        // URI of pull target node
        String targetOfPull = "vos://example.com!vospace/mylink1";
        String targetOfLink = "vos://example.com!vospace/mydummydata1";
                
        // Define node properties        
        Property creator = new Property();
        creator.setUri(NodeProperties.CREATOR_URI);
        creator.setValue("user1");
        
        Property readgroup = new Property();
        readgroup.setUri(NodeProperties.GROUP_READ_URI);
        readgroup.setValue("group1");

        // Define link node as target
        LinkNode lnode = new LinkNode();
        lnode.setUri(targetOfPull);
        lnode.getProperties().add(creator);
        lnode.getProperties().add(readgroup);        
        lnode.setTarget(targetOfLink);

        DataNode dnode = new DataNode();
        dnode.setUri(targetOfLink);
        dnode.getProperties().add(creator);
        dnode.getProperties().add(readgroup);

        when(nodeDAO.listNode(eq(NodeUtils.getVosPath(lnode)))).thenReturn(Optional.of(lnode));
        when(nodeDAO.listNode(eq(NodeUtils.getVosPath(dnode)))).thenReturn(Optional.of(dnode));

        User user = mock(User.class);
        when(user.getAccessToken()).thenReturn("<token>");
        when(user.getName()).thenReturn("user1");
        
        when(servletRequest.getUserPrincipal()).thenReturn(user);

        
        when(rapClient.exchangeToken(argThat(req -> {
            assertEquals("<token>", req.getSubjectToken());
            assertEquals("http://file-service/mydummydata1", req.getResource());
            return true;
        }), any())).thenReturn("<new-token>");
        
        JobSummary job = getPullFromVoSpaceJob(targetOfPull);
        Transfer tr = uriService.getTransfer(job);

        Transfer negotiatedTransfer = uriService.getNegotiatedTransfer(job, tr);
        assertEquals("http://file-service" 
                + NodeUtils.getVosPath(dnode) + 
                "?jobId=job-id-pull&token=<new-token>", 
                negotiatedTransfer.getProtocols().get(0).getEndpoint());
    }
    
    @Test
    public void pullFromCircularLinkNode() {
        
        // URI of pull target node
        String targetOfPull = "vos://example.com!vospace/mylink1";
        String targetOfLink = "vos://example.com!vospace/mylink2";
                
        // Define node properties        
        Property creator = new Property();
        creator.setUri(NodeProperties.CREATOR_URI);
        creator.setValue("user1");
        
        Property readgroup = new Property();
        readgroup.setUri(NodeProperties.GROUP_READ_URI);
        readgroup.setValue("group1");

        // Define link node as target
        LinkNode lnode = new LinkNode();
        lnode.setUri(targetOfPull);
        lnode.getProperties().add(creator);
        lnode.getProperties().add(readgroup);        
        lnode.setTarget(targetOfLink);

        LinkNode dnode = new LinkNode();
        dnode.setUri(targetOfLink);
        dnode.getProperties().add(creator);
        dnode.getProperties().add(readgroup);
        // Circular reference
        dnode.setTarget(targetOfPull);

        when(nodeDAO.listNode(eq(NodeUtils.getVosPath(lnode)))).thenReturn(Optional.of(lnode));
        when(nodeDAO.listNode(eq(NodeUtils.getVosPath(dnode)))).thenReturn(Optional.of(dnode));

        User user = mock(User.class);
        when(user.getAccessToken()).thenReturn("<token>");
        when(user.getName()).thenReturn("user1");
        
        when(servletRequest.getUserPrincipal()).thenReturn(user);

        
        when(rapClient.exchangeToken(argThat(req -> {
            assertEquals("<token>", req.getSubjectToken());
            assertEquals("http://file-service/mydummydata1", req.getResource());
            return true;
        }), any())).thenReturn("<new-token>");
        
        JobSummary job = getPullFromVoSpaceJob(targetOfPull);
        Transfer tr = uriService.getTransfer(job);
        
        assertThrows(InternalFaultException.class, () -> {
            uriService.getNegotiatedTransfer(job, tr);
        });
    }
    
    @Test
    public void setNodeRemoteLocationTest() {

@@ -526,4 +648,23 @@ public class UriServiceTest {

        return job;
    }
    
    private JobSummary getPullFromVoSpaceJob(String target) {
        Transfer transfer = new Transfer();
        transfer.setTarget(target);
        transfer.setDirection(JobService.JobDirection.pullFromVoSpace.toString());
        Protocol protocol = new Protocol();
        protocol.setUri("ivo://ivoa.net/vospace/core#httpget");
        transfer.getProtocols().add(protocol);

        JobSummary job = new JobSummary();
        job.setJobId("job-id-pull");

        JobSummary.JobInfo jobInfo = new JobSummary.JobInfo();
        jobInfo.getAny().add(transfer);

        job.setJobInfo(jobInfo);

        return job;
    }
}