Skip to content
NodeDAO.java 9.44 KiB
Newer Older
Sara Bertocco's avatar
Sara Bertocco committed
package it.inaf.oats.vospace.persistence;

Sara Bertocco's avatar
Sara Bertocco committed
import net.ivoa.xml.vospace.v2.Node;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
Sara Bertocco's avatar
Sara Bertocco committed
import java.util.List;
import java.util.Optional;
Sara Bertocco's avatar
Sara Bertocco committed
import javax.sql.DataSource;
import net.ivoa.xml.vospace.v2.ContainerNode;
import net.ivoa.xml.vospace.v2.DataNode;
import net.ivoa.xml.vospace.v2.Property;
Sara Bertocco's avatar
Sara Bertocco committed
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
Sara Bertocco's avatar
Sara Bertocco committed
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

/**
 *
 * @author bertocco
 */
@Repository
public class NodeDAO {

    @Value("${vospace-authority}")
    private String authority;
Sara Bertocco's avatar
Sara Bertocco committed

    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public NodeDAO(DataSource dataSource) {
        jdbcTemplate = new JdbcTemplate(dataSource);
    }

   public void createNode(Node myNode) {
        
        // check if parent path exist, else throw HTTP 404 , secondo specifica vospace
        
        /*
            Retrieve the path (ltree) and the relative_path (ltree) of the parent node:
 
            select path, relative_path from node n
            join node_vos_path p on n.node_id = p.node_id
            where p.vos_path = '/path/to/parent’
 
            Then perform the insert using the path and relative_path to fill the parent_path and parent_relative_path columns of the new node.

        */
        
        String nodeURI = myNode.getUri();
        String path = nodeURI.replaceAll("vos://[^/]+", "");
        String parentPath = getParentPath(path);
        
        String sql = "SELECT path, relative_path from "
                + "node n join node_vos_path p on n.node_id = p.node_id "
                + "where p.vos_path = ?";
        
        List<NodePaths> paths = jdbcTemplate.query(conn -> {
              PreparedStatement ps = conn.prepareStatement(sql);
              ps.setString(1, parentPath);
              return ps;
        }, (row, index) -> {
            return getPathsFromResultSet(row);
        });
                   
        if(paths.isEmpty()) {
            throw new IllegalStateException("Unable to find parent node during node creation");
        }     
            
Sara Bertocco's avatar
Sara Bertocco committed
        StringBuilder sb = new StringBuilder();
        sb.append("INSERT INTO node");
        sb.append(" (name, busy_state, owner_id, creator_id, group_read, group_write,");
        sb.append(" is_public,  parent_path, type)");
        sb.append(" VALUES (?, ?, ?, ?, ?, ?, ?, ?, ? )");   
        
        jdbcTemplate.update(conn -> {
            PreparedStatement ps = conn.prepareStatement(sb.toString());
            ps.setString(1, getNodeName(myNode));
            ps.setBoolean(2, getIsBusy(myNode));
            ps.setString(3, getProperty(myNode, getPropertyURI("creator")));
            ps.setString(4, getProperty(myNode, getPropertyURI("creator")));
            ps.setArray(5, fromPropertyToArray(getProperty(myNode, getPropertyURI("groupread"))));
            ps.setArray(6, fromPropertyToArray(getProperty(myNode, getPropertyURI("groupwrite"))));
            ps.setBoolean(7, Boolean.valueOf(getProperty(myNode, getPropertyURI("publicread"))));
            //ps.setBoolean(7, true);
            ps.setObject(8, paths.get(0).parentPath, Types.OTHER);
            ps.setString(9, getProperty(myNode, getPropertyURI("type")));
            return ps;
        });
        
Sara Bertocco's avatar
Sara Bertocco committed
    }
Sara Bertocco's avatar
Sara Bertocco committed

    public Optional<Node> listNode(String path) {
Sara Bertocco's avatar
Sara Bertocco committed

        String sql = "SELECT os.vos_path, n.node_id, type, async_trans, busy_state, owner_id, group_read, group_write, is_public, content_length, created_on, last_modified from node n\n"
                + "JOIN node_vos_path os ON n.node_id = os.node_id\n"
                + "WHERE n.path ~ (" + getFirstLevelChildrenSelector(path) + ")::lquery\n"
                + "OR os.vos_path = ? ORDER BY vos_path";
Sara Bertocco's avatar
Sara Bertocco committed

        List<Node> parentAndChildren = jdbcTemplate.query(conn -> {
Sara Bertocco's avatar
Sara Bertocco committed
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, path);
            ps.setString(2, path);
Sara Bertocco's avatar
Sara Bertocco committed
            return ps;
        }, (row, index) -> {
            return getNodeFromResultSet(row);
Sara Bertocco's avatar
Sara Bertocco committed
        });

        if (parentAndChildren.isEmpty()) {
            return Optional.empty();
        }
        // Query returns parent as first node
        Node node = parentAndChildren.get(0);
        // Fill children
        if (node instanceof ContainerNode && parentAndChildren.size() > 1) {
            ContainerNode parent = (ContainerNode) node;
            for (int i = 1; i < parentAndChildren.size(); i++) {
                parent.getNodes().add(parentAndChildren.get(i));
            }
        }

        return Optional.of(node);
    }

    private String getFirstLevelChildrenSelector(String path) {
        String select = "(SELECT path FROM node WHERE node_id = (SELECT node_id FROM node_vos_path WHERE vos_path = ?))::varchar || '";

        if (!"/".equals(path)) {
            select += ".";
        }
        select += "*{1}'";
        return select;
Sara Bertocco's avatar
Sara Bertocco committed
    }

    private Node getNodeFromResultSet(ResultSet rs) throws SQLException {

        Node node = getTypedNode(rs.getString("type"));
Sonia Zorba's avatar
Sonia Zorba committed
            ((DataNode) node).setBusy(rs.getBoolean("busy_state"));
        node.setUri(getUri(rs.getString("vos_path")));
        List<Property> properties = new ArrayList<>();
        addProperty(getPropertyURI("length"), rs.getString("content_length"),
                properties);
        addProperty(getPropertyURI("btime"), rs.getString("created_on"),
                properties);
        addProperty(getPropertyURI("mtime"), rs.getString("last_modified"),
                properties);

        addProperty(getPropertyURI("groupread"), getGroupsString(rs, "group_read"),

        addProperty(getPropertyURI("groupwrite"), getGroupsString(rs, "group_write"),
        addProperty(getPropertyURI("publicread"), rs.getString("is_public"),
                properties);
        addProperty("urn:async_trans", rs.getString("async_trans"),
                properties);

    private String getPropertyURI(String propertyName) {
        return "ivo://ivoa.net/vospace/core#".concat(propertyName);
    }

    private String getGroupsString(ResultSet rs, String column) throws SQLException {
        Array array = rs.getArray(column);
        if (array == null) {
            return null;
        }
        return String.join(" ", (String[]) array.getArray());
    }

    // If value is null does nothing
    private void addProperty(String uri, String value, List<Property> list) {
        if (value != null) {
            Property prop = new Property();
            prop.setUri(uri);
            prop.setValue(value);
            list.add(prop);
        }
    }

    private Node getTypedNode(String type) {
        Node node;
        switch (type) {
            case "container":
                node = new ContainerNode();
                break;
            case "data":
                node = new DataNode();
                break;
            default:
                throw new UnsupportedOperationException("Node type " + type + " not supported yet");
        }
        return node;
    }

    private String getUri(String path) {
        return "vos://" + authority + path;
    }
        

    private NodePaths getPathsFromResultSet(ResultSet rs) throws SQLException {
       
        NodePaths paths = new NodePaths(rs.getString("path"), rs.getString("relative_path"));
        
        return  paths;
      
    }
    
    private String getNodeName(String path) {
        String[] parsedPath = path.split("/");

        return parsedPath[parsedPath.length -1]; 
        
    }
    
 
    
    private String getNodeName(Node myNode) {
        
        String uri = myNode.getUri();
        return getNodeName(uri);
        
    }  

    
    private boolean getIsBusy(Node myNode) {
        
        if (myNode instanceof DataNode) {
            
            DataNode dataNode = (DataNode)myNode;
            return dataNode.isBusy();
        }
        
        return false;
        
    }
    
    
    private String getParentPath(String path) {
        String[] parsedPath = path.split("/");

        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < parsedPath.length - 1; i++) {
            sb.append("/").append(parsedPath[i]);
        }

        return sb.toString();
    }
    
    
    private String getProperty(Node node, String uri) {
        for (Property property : node.getProperties()) {
            if (uri.equals(property.getUri())) {
                return property.getValue();
            }
        }
        return null;
    }
    
    private Array fromPropertyToArray(String myProperty) {
        
        if (myProperty == null || myProperty.isBlank()) 
        
            return null;
        
        else {
            
            //myProperty.split(" ")
            return null;        
        }
        
    }
    
    
    private class NodePaths {

        private String path;
        private String parentPath;
        
        public NodePaths(String myPath, String myParentPath) {
            
            this.path = myPath;
            this.parentPath = myParentPath;
        
        }       
        
        public String toString() {
            return  parentPath + " " + path;
        }
    }

Sara Bertocco's avatar
Sara Bertocco committed
}