package it.inaf.oats.vospace.persistence; import java.sql.Array; import net.ivoa.xml.vospace.v2.Node; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Optional; 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; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; /** * * @author bertocco */ @Repository public class NodeDAO { @Value("${vospace-authority}") private String authority; private final JdbcTemplate jdbcTemplate; @Autowired public NodeDAO(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); } public Node createNode(Node myNode) { StringBuilder sb = new StringBuilder(); sb.append("INSERT INTO "); sb.append("NodeProperty"); sb.append(" (nodeID,propertyURI,propertyValue) SELECT ?, ?, ?"); sb.append(" WHERE NOT EXISTS (SELECT * FROM NodeProperty"); sb.append(" WHERE nodeID=? and propertyURI=?)"); String sqlQuery = sb.toString(); return myNode; } public Optional listNode(String path) { 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"; List parentAndChildren = jdbcTemplate.query(conn -> { PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, path); ps.setString(2, path); return ps; }, (row, index) -> { return getNodeFromResultSet(row); }); 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; } private Node getNodeFromResultSet(ResultSet rs) throws SQLException { Node node = getTypedNode(rs.getString("type")); if (node instanceof DataNode) { ((DataNode) node).setBusy(rs.getBoolean("busy_state")); } node.setUri(getUri(rs.getString("vos_path"))); List 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"), properties); addProperty(getPropertyURI("groupwrite"), getGroupsString(rs, "group_write"), properties); addProperty(getPropertyURI("publicread"), rs.getString("is_public"), properties); addProperty("urn:async_trans", rs.getString("async_trans"), properties); node.setProperties(properties); return node; } 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 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; } }