Commit 0babd77f authored by Nicola Fulvio Calabria's avatar Nicola Fulvio Calabria
Browse files

Minor refactoring + updated constraints to copy paths

parent 0b5b125c
Loading
Loading
Loading
Loading
+28 −7
Original line number Original line Diff line number Diff line
@@ -7,12 +7,12 @@ package it.inaf.oats.vospace;


import it.inaf.ia2.aa.data.User;
import it.inaf.ia2.aa.data.User;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.exception.InvalidArgumentException;
import it.inaf.oats.vospace.exception.NodeBusyException;
import it.inaf.oats.vospace.exception.NodeBusyException;
import it.inaf.oats.vospace.exception.NodeNotFoundException;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
import it.inaf.oats.vospace.persistence.NodeDAO.ShortNodeDescriptor;
import it.inaf.oats.vospace.persistence.NodeDAO.ShortNodeDescriptor;
import java.util.Optional;
import java.util.Optional;
import net.ivoa.xml.vospace.v2.Transfer;
import net.ivoa.xml.vospace.v2.Transfer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.CannotSerializeTransactionException;
import org.springframework.dao.CannotSerializeTransactionException;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@@ -23,9 +23,6 @@ import org.springframework.transaction.annotation.Transactional;
@EnableTransactionManagement
@EnableTransactionManagement
public class CopyService extends AbstractNodeService {
public class CopyService extends AbstractNodeService {


    @Autowired
    private NodeBranchService nodeBranchService;

    @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.REPEATABLE_READ)
    @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.REPEATABLE_READ)
    public String processCopyNodes(Transfer transfer, String jobId, User user) {
    public String processCopyNodes(Transfer transfer, String jobId, User user) {


@@ -42,13 +39,19 @@ public class CopyService extends AbstractNodeService {
        this.validatePath(destinationPath);
        this.validatePath(destinationPath);


        if (sourcePath.equals(destinationPath)) {
        if (sourcePath.equals(destinationPath)) {
            return null;
            throw new IllegalArgumentException("Cannot copy node to itself");
        }

        // Check if destination is subpath of source
        // Linux-like: "cannot copy to a subdirectory of itself" 
        if (destinationPath.startsWith(sourcePath + "/")) {
            throw new IllegalArgumentException("Cannot copy node to a subdirectory of its own path");
        }
        }


        try {
        try {


            // check source branch for read and lock it
            // check source branch for read and lock it
            nodeBranchService.checkBranchForReadAndLock(sourcePath, jobId, user);
            this.checkBranchForReadAndLock(sourcePath, jobId, user);


            // Check destination
            // Check destination
            Optional<ShortNodeDescriptor> destShortNodeDescriptor
            Optional<ShortNodeDescriptor> destShortNodeDescriptor
@@ -86,4 +89,22 @@ public class CopyService extends AbstractNodeService {


    }
    }


    private void checkBranchForReadAndLock(String sourcePath, String jobId, User user) {

        // Get source node
        Optional<Long> sourceIdOpt = nodeDao.getNodeId(sourcePath);
        long sourceId = sourceIdOpt.orElseThrow(() -> new NodeNotFoundException(sourcePath));

        if (nodeDao.isBranchBusy(sourceId)) {
            throw new NodeBusyException(sourcePath);
        }

        if (!nodeDao.isBranchReadable(sourceId, user.getName(), user.getGroups())) {
            throw new PermissionDeniedException(sourcePath);
        }

        nodeDao.setBranchJobId(sourceId, jobId);

    }

}
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -43,7 +43,7 @@ public class MoveService extends AbstractNodeService {
        this.validatePath(destinationPath);
        this.validatePath(destinationPath);


        if (sourcePath.equals(destinationPath)) {
        if (sourcePath.equals(destinationPath)) {
            return;
            throw new IllegalArgumentException("Cannot move node to itself");
        }
        }
        
        
        // Check if destination is subpath of source
        // Check if destination is subpath of source
+0 −71
Original line number Original line Diff line number Diff line
/*
 * 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.ia2.aa.data.User;
import it.inaf.oats.vospace.datamodel.NodeUtils;
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.NodeNotFoundException;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
import it.inaf.oats.vospace.persistence.NodeDAO;
import it.inaf.oats.vospace.persistence.NodeDAO.ShortNodeDescriptor;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import net.ivoa.xml.vospace.v2.Transfer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.CannotSerializeTransactionException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@EnableTransactionManagement
public class NodeBranchService {

    @Autowired
    private NodeDAO nodeDao;

    @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.REPEATABLE_READ,
            propagation = Propagation.REQUIRED)
    public void checkBranchForReadAndLock(String sourcePath, String jobId, User user) {

        try {
            // Get source node
            Optional<Long> sourceIdOpt = nodeDao.getNodeId(sourcePath);
            long sourceId = sourceIdOpt.orElseThrow(() -> new NodeNotFoundException(sourcePath));

            if (nodeDao.isBranchBusy(sourceId)) {
                throw new NodeBusyException(sourcePath);
            }

            if (!nodeDao.isBranchReadable(sourceId, user.getName(), user.getGroups())) {                
                throw new PermissionDeniedException(sourcePath);
            }
            
            this.lockBranch(sourceId, jobId);

        } catch (CannotSerializeTransactionException ex) {
            // Concurrent transactions attempted to modify this set of nodes            
            throw new NodeBusyException(sourcePath);
        }
    } 
    
    private void lockBranch(Long sourceRootId, String jobId) {

        nodeDao.setBranchJobId(sourceRootId, jobId);

    }
    
    public void unlockNodes(String jobId) {
        nodeDao.releaseBusyNodesByJobId(jobId);
    }

}