Loading src/main/java/it/inaf/oats/vospace/DeleteNodeController.java +7 −41 Original line number Diff line number Diff line Loading @@ -27,10 +27,10 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class DeleteNodeController extends BaseNodeController { private static final Logger LOG = LoggerFactory.getLogger(DeleteNodeController.class); @Autowired private NodeDAO nodeDAO; DeleteNodeService deleteNodeService; private static final Logger LOG = LoggerFactory.getLogger(DeleteNodeController.class); @DeleteMapping(value = {"/nodes", "/nodes/**"}, produces = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}) Loading @@ -39,44 +39,10 @@ public class DeleteNodeController extends BaseNodeController { String path = getPath(); LOG.debug("deleteNode called for path {}", path); // Check if the node is present, // if the node does not exist the service SHALL throw a HTTP 404 status code // including a NodeNotFound fault in the entity-body // If note present, got it Node toBeDeletedNode = nodeDAO.listNode(path) .orElseThrow(() -> new NodeNotFoundException(path)); // If a parent node in the URI path is a LinkNode, the service SHALL throw // a HTTP 400 status code including a LinkFound fault in the entity-body. // For example, given the URI path /a/b/c, the service must throw a HTTP 400 // status code including a LinkFound fault in the entity-body if either /a // or /a/b are LinkNodes. List<String> pathComponents = NodeUtils.subPathComponents(path); if (pathComponents.isEmpty()) { // Manage root node throw PermissionDeniedException.forPath("/"); } else { // Manage all precursors in full path for (int i = 0; i < pathComponents.size(); i++) { String tmpPath = pathComponents.get(i); Node mynode = nodeDAO.listNode(tmpPath) .orElseThrow(() -> new NodeNotFoundException(tmpPath)); if (mynode.getType().equals("vos:LinkNode") && i < pathComponents.size()-1) // a LinkNode leaf can be deleted throw new LinkFoundException(tmpPath); } } if (!NodeUtils.checkIfWritable(toBeDeletedNode, principal.getName(), principal.getGroups())) { throw PermissionDeniedException.forPath(path); } try { nodeDAO.deleteNode(path); deleteNodeService.doPreliminaryChecks(path); deleteNodeService.deleteNode(path, principal); return ResponseEntity.ok("Node deleted"); } catch(Exception ex) { return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST); Loading src/main/java/it/inaf/oats/vospace/DeleteNodeService.java 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package it.inaf.oats.vospace; import it.inaf.oats.vospace.datamodel.NodeUtils; import it.inaf.oats.vospace.exception.LinkFoundException; import it.inaf.oats.vospace.exception.NodeNotFoundException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.persistence.NodeDAO; import java.util.List; import net.ivoa.xml.vospace.v2.Node; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.Isolation; import it.inaf.ia2.aa.data.User; import org.springframework.transaction.annotation.Transactional; /** * * @author Nicola Fulvio Calabria <nicola.calabria at inaf.it> */ @Service @EnableTransactionManagement public class DeleteNodeService { @Autowired protected NodeDAO nodeDao; @Value("${vospace-authority}") protected String authority; @Transactional(rollbackFor = { Exception.class }, isolation = Isolation.REPEATABLE_READ) public void deleteNode(String path, User principal) { Node toBeDeletedNode = nodeDao.listNode(path) .orElseThrow(() -> new NodeNotFoundException(path)); if (!NodeUtils.checkIfWritable(toBeDeletedNode, principal.getName(), principal.getGroups())) { throw PermissionDeniedException.forPath(path); } nodeDao.deleteNode(path); } public void doPreliminaryChecks(String path) throws Exception { // Check if the node is present, // if the node does not exist the service SHALL throw a HTTP 404 status code // including a NodeNotFound fault in the entity-body // If note present, got it nodeDao.listNode(path) .orElseThrow(() -> new NodeNotFoundException(path)); // If a parent node in the URI path is a LinkNode, the service SHALL throw // a HTTP 400 status code including a LinkFound fault in the entity-body. // For example, given the URI path /a/b/c, the service must throw a HTTP 400 // status code including a LinkFound fault in the entity-body if either /a // or /a/b are LinkNodes. List<String> pathComponents = NodeUtils.subPathComponents(path); if (pathComponents.isEmpty()) { // Manage root node throw PermissionDeniedException.forPath("/"); } else { // Manage all precursors in full path for (int i = 0; i < pathComponents.size(); i++) { String tmpPath = pathComponents.get(i); Node mynode = nodeDao.listNode(tmpPath) .orElseThrow(() -> new NodeNotFoundException(tmpPath)); if (mynode.getType().equals("vos:LinkNode") && i < pathComponents.size()-1) // a LinkNode leaf can be deleted throw new LinkFoundException(tmpPath); } } } } src/main/java/it/inaf/oats/vospace/ImmutableService.java 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; import it.inaf.oats.vospace.persistence.NodeDAO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * * @author Nicola Fulvio Calabria <nicola.calabria at inaf.it> */ @Service @EnableTransactionManagement public class ImmutableService { @Autowired protected NodeDAO nodeDao; @Value("${vospace-authority}") protected String authority; @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.REPEATABLE_READ) public void setBranchImmutable(String rootNodeURI, boolean setImmutable, User user) { String rootNodeVosPath = URIUtils.returnVosPathFromNodeURI(rootNodeURI, authority); // Check if branch is busy } } src/main/java/it/inaf/oats/vospace/MoveService.java +6 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,11 @@ public class MoveService extends AbstractNodeService { throw new NodeBusyException(sourcePath); } // TODO create immutable node exception flavor if (nodeDao.isBranchImmutable(sourceId)) { throw new InternalFaultException("Source branch contains immutable nodes"); } if (!nodeDao.isBranchWritable(sourceId, user.getName(), user.getGroups())) { throw PermissionDeniedException.forPath(sourcePath); } Loading @@ -84,6 +89,7 @@ public class MoveService extends AbstractNodeService { if(snd.isPermissionDenied()) throw PermissionDeniedException.forPath(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); if(!snd.isImmutable()) throw new InternalFaultException("Destination is immutable: " + destinationPath); destinationNodeLtreePath = snd.getDestinationNodeLtreePath(); Loading src/main/java/it/inaf/oats/vospace/persistence/NodeDAO.java +10 −2 Original line number Diff line number Diff line Loading @@ -257,6 +257,7 @@ public class NodeDAO { + "n.creator_id <> ?) AS is_permission_denied,\n" + "n.type = 'container' AS is_container,\n" + "n.job_id IS NOT NULL AS busy_state\n" + "n.immutable AS is_immutable\n" + "FROM node n \n" + "LEFT JOIN location loc ON loc.location_id = n.location_id\n" + "WHERE n.node_id = id_from_vos_path(?)\n"; Loading Loading @@ -286,8 +287,9 @@ public class NodeDAO { Boolean isBusy = rs.getBoolean("busy_state"); Boolean isPermissionDenied = rs.getBoolean("is_permission_denied"); Boolean isSticky = rs.getBoolean("is_sticky"); Boolean isImmutable = rs.getBoolean("is_immutable"); ShortNodeDescriptor result = new ShortNodeDescriptor(nodePath, isContainer, isWritable, isBusy, isPermissionDenied, isSticky); ShortNodeDescriptor result = new ShortNodeDescriptor(nodePath, isContainer, isWritable, isBusy, isPermissionDenied, isSticky, isImmutable); return Optional.of(result); }); Loading Loading @@ -766,14 +768,16 @@ public class NodeDAO { private final boolean busy; private final boolean permissionDenied; private final boolean sticky; private final boolean immutable; public ShortNodeDescriptor(String nodeLtreePath, boolean container, boolean writable, boolean busy, boolean permissionDenied, boolean sticky) { public ShortNodeDescriptor(String nodeLtreePath, boolean container, boolean writable, boolean busy, boolean permissionDenied, boolean sticky, boolean immutable) { this.nodeLtreePath = nodeLtreePath; this.container = container; this.writable = writable; this.busy = busy; this.permissionDenied = permissionDenied; this.sticky = sticky; this.immutable = immutable; } public String getDestinationNodeLtreePath() { Loading @@ -784,6 +788,10 @@ public class NodeDAO { return container; } public boolean isImmutable() { return immutable; } public boolean isWritable() { return writable; } Loading Loading
src/main/java/it/inaf/oats/vospace/DeleteNodeController.java +7 −41 Original line number Diff line number Diff line Loading @@ -27,10 +27,10 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class DeleteNodeController extends BaseNodeController { private static final Logger LOG = LoggerFactory.getLogger(DeleteNodeController.class); @Autowired private NodeDAO nodeDAO; DeleteNodeService deleteNodeService; private static final Logger LOG = LoggerFactory.getLogger(DeleteNodeController.class); @DeleteMapping(value = {"/nodes", "/nodes/**"}, produces = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}) Loading @@ -39,44 +39,10 @@ public class DeleteNodeController extends BaseNodeController { String path = getPath(); LOG.debug("deleteNode called for path {}", path); // Check if the node is present, // if the node does not exist the service SHALL throw a HTTP 404 status code // including a NodeNotFound fault in the entity-body // If note present, got it Node toBeDeletedNode = nodeDAO.listNode(path) .orElseThrow(() -> new NodeNotFoundException(path)); // If a parent node in the URI path is a LinkNode, the service SHALL throw // a HTTP 400 status code including a LinkFound fault in the entity-body. // For example, given the URI path /a/b/c, the service must throw a HTTP 400 // status code including a LinkFound fault in the entity-body if either /a // or /a/b are LinkNodes. List<String> pathComponents = NodeUtils.subPathComponents(path); if (pathComponents.isEmpty()) { // Manage root node throw PermissionDeniedException.forPath("/"); } else { // Manage all precursors in full path for (int i = 0; i < pathComponents.size(); i++) { String tmpPath = pathComponents.get(i); Node mynode = nodeDAO.listNode(tmpPath) .orElseThrow(() -> new NodeNotFoundException(tmpPath)); if (mynode.getType().equals("vos:LinkNode") && i < pathComponents.size()-1) // a LinkNode leaf can be deleted throw new LinkFoundException(tmpPath); } } if (!NodeUtils.checkIfWritable(toBeDeletedNode, principal.getName(), principal.getGroups())) { throw PermissionDeniedException.forPath(path); } try { nodeDAO.deleteNode(path); deleteNodeService.doPreliminaryChecks(path); deleteNodeService.deleteNode(path, principal); return ResponseEntity.ok("Node deleted"); } catch(Exception ex) { return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST); Loading
src/main/java/it/inaf/oats/vospace/DeleteNodeService.java 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package it.inaf.oats.vospace; import it.inaf.oats.vospace.datamodel.NodeUtils; import it.inaf.oats.vospace.exception.LinkFoundException; import it.inaf.oats.vospace.exception.NodeNotFoundException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.persistence.NodeDAO; import java.util.List; import net.ivoa.xml.vospace.v2.Node; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.Isolation; import it.inaf.ia2.aa.data.User; import org.springframework.transaction.annotation.Transactional; /** * * @author Nicola Fulvio Calabria <nicola.calabria at inaf.it> */ @Service @EnableTransactionManagement public class DeleteNodeService { @Autowired protected NodeDAO nodeDao; @Value("${vospace-authority}") protected String authority; @Transactional(rollbackFor = { Exception.class }, isolation = Isolation.REPEATABLE_READ) public void deleteNode(String path, User principal) { Node toBeDeletedNode = nodeDao.listNode(path) .orElseThrow(() -> new NodeNotFoundException(path)); if (!NodeUtils.checkIfWritable(toBeDeletedNode, principal.getName(), principal.getGroups())) { throw PermissionDeniedException.forPath(path); } nodeDao.deleteNode(path); } public void doPreliminaryChecks(String path) throws Exception { // Check if the node is present, // if the node does not exist the service SHALL throw a HTTP 404 status code // including a NodeNotFound fault in the entity-body // If note present, got it nodeDao.listNode(path) .orElseThrow(() -> new NodeNotFoundException(path)); // If a parent node in the URI path is a LinkNode, the service SHALL throw // a HTTP 400 status code including a LinkFound fault in the entity-body. // For example, given the URI path /a/b/c, the service must throw a HTTP 400 // status code including a LinkFound fault in the entity-body if either /a // or /a/b are LinkNodes. List<String> pathComponents = NodeUtils.subPathComponents(path); if (pathComponents.isEmpty()) { // Manage root node throw PermissionDeniedException.forPath("/"); } else { // Manage all precursors in full path for (int i = 0; i < pathComponents.size(); i++) { String tmpPath = pathComponents.get(i); Node mynode = nodeDao.listNode(tmpPath) .orElseThrow(() -> new NodeNotFoundException(tmpPath)); if (mynode.getType().equals("vos:LinkNode") && i < pathComponents.size()-1) // a LinkNode leaf can be deleted throw new LinkFoundException(tmpPath); } } } }
src/main/java/it/inaf/oats/vospace/ImmutableService.java 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; import it.inaf.oats.vospace.persistence.NodeDAO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; /** * * @author Nicola Fulvio Calabria <nicola.calabria at inaf.it> */ @Service @EnableTransactionManagement public class ImmutableService { @Autowired protected NodeDAO nodeDao; @Value("${vospace-authority}") protected String authority; @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.REPEATABLE_READ) public void setBranchImmutable(String rootNodeURI, boolean setImmutable, User user) { String rootNodeVosPath = URIUtils.returnVosPathFromNodeURI(rootNodeURI, authority); // Check if branch is busy } }
src/main/java/it/inaf/oats/vospace/MoveService.java +6 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,11 @@ public class MoveService extends AbstractNodeService { throw new NodeBusyException(sourcePath); } // TODO create immutable node exception flavor if (nodeDao.isBranchImmutable(sourceId)) { throw new InternalFaultException("Source branch contains immutable nodes"); } if (!nodeDao.isBranchWritable(sourceId, user.getName(), user.getGroups())) { throw PermissionDeniedException.forPath(sourcePath); } Loading @@ -84,6 +89,7 @@ public class MoveService extends AbstractNodeService { if(snd.isPermissionDenied()) throw PermissionDeniedException.forPath(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); if(!snd.isImmutable()) throw new InternalFaultException("Destination is immutable: " + destinationPath); destinationNodeLtreePath = snd.getDestinationNodeLtreePath(); Loading
src/main/java/it/inaf/oats/vospace/persistence/NodeDAO.java +10 −2 Original line number Diff line number Diff line Loading @@ -257,6 +257,7 @@ public class NodeDAO { + "n.creator_id <> ?) AS is_permission_denied,\n" + "n.type = 'container' AS is_container,\n" + "n.job_id IS NOT NULL AS busy_state\n" + "n.immutable AS is_immutable\n" + "FROM node n \n" + "LEFT JOIN location loc ON loc.location_id = n.location_id\n" + "WHERE n.node_id = id_from_vos_path(?)\n"; Loading Loading @@ -286,8 +287,9 @@ public class NodeDAO { Boolean isBusy = rs.getBoolean("busy_state"); Boolean isPermissionDenied = rs.getBoolean("is_permission_denied"); Boolean isSticky = rs.getBoolean("is_sticky"); Boolean isImmutable = rs.getBoolean("is_immutable"); ShortNodeDescriptor result = new ShortNodeDescriptor(nodePath, isContainer, isWritable, isBusy, isPermissionDenied, isSticky); ShortNodeDescriptor result = new ShortNodeDescriptor(nodePath, isContainer, isWritable, isBusy, isPermissionDenied, isSticky, isImmutable); return Optional.of(result); }); Loading Loading @@ -766,14 +768,16 @@ public class NodeDAO { private final boolean busy; private final boolean permissionDenied; private final boolean sticky; private final boolean immutable; public ShortNodeDescriptor(String nodeLtreePath, boolean container, boolean writable, boolean busy, boolean permissionDenied, boolean sticky) { public ShortNodeDescriptor(String nodeLtreePath, boolean container, boolean writable, boolean busy, boolean permissionDenied, boolean sticky, boolean immutable) { this.nodeLtreePath = nodeLtreePath; this.container = container; this.writable = writable; this.busy = busy; this.permissionDenied = permissionDenied; this.sticky = sticky; this.immutable = immutable; } public String getDestinationNodeLtreePath() { Loading @@ -784,6 +788,10 @@ public class NodeDAO { return container; } public boolean isImmutable() { return immutable; } public boolean isWritable() { return writable; } Loading