Skip to content
Snippets Groups Projects
Commit 0babd77f authored by Nicola Fulvio Calabria's avatar Nicola Fulvio Calabria
Browse files

Minor refactoring + updated constraints to copy paths

parent 0b5b125c
No related branches found
No related tags found
No related merge requests found
...@@ -7,12 +7,12 @@ package it.inaf.oats.vospace; ...@@ -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; ...@@ -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 { ...@@ -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 { ...@@ -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);
}
} }
...@@ -43,7 +43,7 @@ public class MoveService extends AbstractNodeService { ...@@ -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
......
/*
* 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);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment