Commit 9e209dc2 authored by Nicola Fulvio Calabria's avatar Nicola Fulvio Calabria
Browse files

Advancement in copyNode implementation + some refactoring

parent d3f861c1
Loading
Loading
Loading
Loading
+49 −0
Original line number 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.oats.vospace.exception.InternalFaultException;
import it.inaf.oats.vospace.exception.NodeBusyException;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
import it.inaf.oats.vospace.persistence.NodeDAO;
import it.inaf.oats.vospace.persistence.NodeDAO.ShortNodeDescriptor;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

public abstract class AbstractNodeService {
    
    @Autowired
    protected NodeDAO nodeDao;

    @Value("${vospace-authority}")
    protected String authority;
    
    @Autowired
    protected HttpServletRequest servletRequest;    

    protected void validatePath(String path) {
        if (path.equals("/")) {
            throw new IllegalArgumentException("Cannot move root node or to root node");
        }
    }

    protected void validateDestinationContainer(ShortNodeDescriptor snd, String destinationVosPath) {
        if (snd.isBusy()) {
            throw new NodeBusyException(destinationVosPath);
        }
        if (snd.isPermissionDenied()) {
            throw new PermissionDeniedException(destinationVosPath);
        }
        if (!snd.isWritable()) {
            throw new InternalFaultException("Destination is not writable: " + destinationVosPath);
        }
        if (!snd.isContainer()) {
            throw new InternalFaultException("Existing destination is not a container: " + destinationVosPath);
        }

    }
}
+43 −22
Original line number Diff line number Diff line
@@ -28,21 +28,13 @@ import org.springframework.transaction.annotation.Transactional;

@Service
@EnableTransactionManagement
public class CopyService {

    @Autowired
    private NodeDAO nodeDao;

    @Value("${vospace-authority}")
    private String authority;

    @Autowired
    private HttpServletRequest servletRequest;
public class CopyService extends AbstractNodeService {

    @Autowired
    private NodeBranchService nodeBranchService;

    public void processCopyJob(Transfer transfer, String jobId) {
    @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.REPEATABLE_READ)
    public List<String> processCopyNodes(Transfer transfer, String jobId) {
        if (transfer.getTarget().size() != 1) {
            throw new InvalidArgumentException("Invalid target size for copyNode: " + transfer.getTarget().size());
        }
@@ -60,20 +52,49 @@ public class CopyService {
        this.validatePath(destinationPath);

        if (sourcePath.equals(destinationPath)) {
            return;
            return List.of();
        }

        List<String> copiedNodesPaths = null;
        try {

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

        nodeDao.copyBranch(sourcePath, destinationPath, jobId);        
            // Check destination
            Optional<ShortNodeDescriptor> destShortNodeDescriptor
                    = nodeDao.getShortNodeDescriptor(destinationPath, user.getName(), user.getGroups());

            if (destShortNodeDescriptor.isPresent()) {
                this.validateDestinationContainer(destShortNodeDescriptor.get(), destinationPath);
                copiedNodesPaths = nodeDao.copyBranch(
                        sourcePath,
                        destinationPath + "/" + NodeUtils.getNodeName(sourcePath),
                        jobId);

            } else {
                // Check if parent exists
                String destinationParentPath = NodeUtils.getParentPath(destinationPath);
                Optional<ShortNodeDescriptor> destShortNodeDescriptorParent
                        = nodeDao.getShortNodeDescriptor(destinationParentPath, user.getName(), user.getGroups());
                if (destShortNodeDescriptorParent.isPresent()) {
                    this.validateDestinationContainer(destShortNodeDescriptorParent.get(), destinationParentPath);
                    copiedNodesPaths = nodeDao.copyBranch(sourcePath,
                            destinationPath, jobId);

                } else {
                    throw new UnsupportedOperationException("Creation of destination upon copy not supported");
                }

            }

    private void validatePath(String path) {
        if (path.equals("/")) {
            throw new IllegalArgumentException("Cannot move root node or to root node");
        } catch (CannotSerializeTransactionException ex) {
            // Concurrent transactions attempted to modify this set of nodes            
            throw new NodeBusyException(sourcePath);
        }

        return copiedNodesPaths;

    }

}
+1 −1
Original line number Diff line number Diff line
@@ -165,7 +165,7 @@ public class JobService {
    
    private void handleCopyNode(Transfer transfer, String jobId)
    {
        copyService.processCopyJob(transfer, jobId);
        copyService.processCopyNodes(transfer, jobId);
    }
    

+4 −30
Original line number Diff line number Diff line
@@ -7,18 +7,13 @@ 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;
@@ -27,16 +22,7 @@ import org.springframework.transaction.annotation.Transactional;

@Service
@EnableTransactionManagement
public class MoveService {

    @Autowired
    private NodeDAO nodeDao;

    @Value("${vospace-authority}")
    private String authority;
    
    @Autowired
    private HttpServletRequest servletRequest;
public class MoveService extends AbstractNodeService {
        
    @Transactional(rollbackFor = { Exception.class }, isolation = Isolation.REPEATABLE_READ)
    public void processMoveJob(Transfer transfer) {
@@ -88,12 +74,7 @@ public class MoveService {
            if (destShortNodeDescriptor.isPresent()) {
                // When the destination is an existing ContainerNode, the source SHALL be placed under it (i.e., within the container)
                ShortNodeDescriptor snd = destShortNodeDescriptor.get();                
                
                if(snd.isBusy()) throw new NodeBusyException(destinationPath);
                if(snd.isPermissionDenied()) throw new PermissionDeniedException(destinationPath);                                                
                if(!snd.isWritable()) throw new InternalFaultException("Destination is not writable: "+ destinationPath);
                if(!snd.isContainer()) throw new InternalFaultException("Existing destination is not a container: " + destinationPath);
                
                this.validateDestinationContainer(snd, destinationPath);                
                destinationNodeLtreePath = snd.getDestinationNodeLtreePath();
                
            } else {
@@ -119,11 +100,4 @@ public class MoveService {
        }
    }  

    
    private void validatePath(String path) {        
        if (path.equals("/")) {            
            throw new IllegalArgumentException("Cannot move root node or to root node");
        }
    }  

}
+5 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ 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
@@ -35,7 +36,8 @@ public class NodeBranchService {
    @Autowired
    private HttpServletRequest servletRequest;

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

        // Extract User permissions from servlet request
Loading