Loading src/main/java/it/inaf/oats/vospace/AbstractNodeService.java 0 → 100644 +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); } } } src/main/java/it/inaf/oats/vospace/CopyService.java +43 −22 Original line number Diff line number Diff line Loading @@ -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()); } Loading @@ -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; } } src/main/java/it/inaf/oats/vospace/JobService.java +1 −1 Original line number Diff line number Diff line Loading @@ -165,7 +165,7 @@ public class JobService { private void handleCopyNode(Transfer transfer, String jobId) { copyService.processCopyJob(transfer, jobId); copyService.processCopyNodes(transfer, jobId); } Loading src/main/java/it/inaf/oats/vospace/MoveService.java +4 −30 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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 { Loading @@ -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"); } } } src/main/java/it/inaf/oats/vospace/NodeBranchService.java +5 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading
src/main/java/it/inaf/oats/vospace/AbstractNodeService.java 0 → 100644 +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); } } }
src/main/java/it/inaf/oats/vospace/CopyService.java +43 −22 Original line number Diff line number Diff line Loading @@ -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()); } Loading @@ -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; } }
src/main/java/it/inaf/oats/vospace/JobService.java +1 −1 Original line number Diff line number Diff line Loading @@ -165,7 +165,7 @@ public class JobService { private void handleCopyNode(Transfer transfer, String jobId) { copyService.processCopyJob(transfer, jobId); copyService.processCopyNodes(transfer, jobId); } Loading
src/main/java/it/inaf/oats/vospace/MoveService.java +4 −30 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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 { Loading @@ -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"); } } }
src/main/java/it/inaf/oats/vospace/NodeBranchService.java +5 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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