Commit f919f87c authored by Nicola Fulvio Calabria's avatar Nicola Fulvio Calabria
Browse files

Refactored Delete

parent fb5a87c6
Loading
Loading
Loading
Loading
+7 −41
Original line number Diff line number Diff line
@@ -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})
@@ -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);
+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);
                            
            }
                    
        }
    }
}
+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
        
    }

}
+6 −0
Original line number Diff line number Diff line
@@ -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);
            }           
@@ -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();
                
+10 −2
Original line number Diff line number Diff line
@@ -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";
@@ -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);
        });
@@ -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() {
@@ -784,6 +788,10 @@ public class NodeDAO {
            return container;
        }

        public boolean isImmutable() {
            return immutable;
        }

        public boolean isWritable() {
            return writable;
        }