Newer
Older
Sonia Zorba
committed
import java.sql.Array;
import net.ivoa.xml.vospace.v2.Node;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
Sara Bertocco
committed
import java.sql.Types;
import java.util.ArrayList;
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);
}
Sara Bertocco
committed
String nodeURI = myNode.getUri();
String path = nodeURI.replaceAll("vos://[^/]+", "");
String parentPath = getParentPath(path);
String sql = "SELECT path, relative_path from "
Sara Bertocco
committed
+ "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;
Sara Bertocco
committed
}, (row, index) -> {
Sara Bertocco
committed
});
Sara Bertocco
committed
throw new IllegalStateException("Unable to find parent node during node creation");
throw new IllegalStateException("Multiple ltree parent paths found for " + parentPath);
}
Sara Bertocco
committed
sb.append("INSERT INTO node");
sb.append(" (name, busy_state, owner_id, creator_id, group_read, group_write,");
sb.append(" is_public, parent_path, parent_relative_path, type)");
sb.append(" VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ? )");
Sara Bertocco
committed
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(ps, getProperty(myNode, getPropertyURI("groupread"))));
ps.setArray(6, fromPropertyToArray(ps, getProperty(myNode, getPropertyURI("groupwrite"))));
Sara Bertocco
committed
ps.setBoolean(7, Boolean.valueOf(getProperty(myNode, getPropertyURI("publicread"))));
ps.setObject(8, paths.get(0).path, Types.OTHER);
ps.setObject(9, paths.get(0).relativePath, Types.OTHER);
ps.setObject(10, getDbNodeType(myNode), Types.OTHER);
Sara Bertocco
committed
return ps;
});
public Optional<Node> listNode(String path) {
String sql = "SELECT os.vos_path, n.node_id, type, async_trans, busy_state, creator_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<Node> parentAndChildren = jdbcTemplate.query(conn -> {
ps.setString(1, path);
ps.setString(2, path);
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));
}
}
}
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"));
Sonia Zorba
committed
if (node instanceof DataNode) {
((DataNode) node).setBusy(rs.getBoolean("busy_state"));
Sonia Zorba
committed
}
node.setUri(getUri(rs.getString("vos_path")));
List<Property> properties = new ArrayList<>();
Sonia Zorba
committed
addProperty(getPropertyURI("length"), rs.getString("content_length"),
properties);
Sonia Zorba
committed
addProperty(getPropertyURI("btime"), rs.getString("created_on"),
properties);
Sonia Zorba
committed
addProperty(getPropertyURI("creator"), rs.getString("creator_id"),
properties);
addProperty(getPropertyURI("mtime"), rs.getString("last_modified"),
properties);
Sonia Zorba
committed
addProperty(getPropertyURI("groupread"), getGroupsString(rs, "group_read"),
properties);
Sonia Zorba
committed
addProperty(getPropertyURI("groupwrite"), getGroupsString(rs, "group_write"),
properties);
Sonia Zorba
committed
addProperty(getPropertyURI("publicread"), rs.getString("is_public"),
properties);
Sonia Zorba
committed
addProperty("urn:async_trans", rs.getString("async_trans"),
properties);
Sonia Zorba
committed
node.setProperties(properties);
private String getPropertyURI(String propertyName) {
return "ivo://ivoa.net/vospace/core#".concat(propertyName);
}
Sonia Zorba
committed
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;
}
Sara Bertocco
committed
private NodePaths getPathsFromResultSet(ResultSet rs) throws SQLException {
NodePaths paths = new NodePaths(rs.getString("path"), rs.getString("relative_path"));
Sara Bertocco
committed
}
Sara Bertocco
committed
private String getNodeName(String path) {
String[] parsedPath = path.split("/");
Sara Bertocco
committed
}
Sara Bertocco
committed
private String getNodeName(Node myNode) {
String uri = myNode.getUri();
return getNodeName(uri);
Sara Bertocco
committed
private boolean getIsBusy(Node myNode) {
Sara Bertocco
committed
if (myNode instanceof DataNode) {
Sara Bertocco
committed
return dataNode.isBusy();
}
Sara Bertocco
committed
return false;
}
// Copied from CreateNodeController: to be moved in a common utility class
Sara Bertocco
committed
private String getParentPath(String path) {
String[] parsedPath = path.split("[/]+");
if (parsedPath.length < 2 || !parsedPath[0].isEmpty()) {
throw new IllegalArgumentException();
}
Sara Bertocco
committed
StringBuilder sb = new StringBuilder();
Sara Bertocco
committed
for (int i = 1; i < parsedPath.length - 1; i++) {
sb.append(parsedPath[i]);
if (i < parsedPath.length - 2) {
sb.append("/");
}
Sara Bertocco
committed
}
return sb.toString();
}
Sara Bertocco
committed
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(PreparedStatement ps, String myProperty) throws SQLException {
if (myProperty == null || myProperty.isBlank()) {
Sara Bertocco
committed
return null;
} else {
return ps.getConnection().createArrayOf("varchar", myProperty.split(" "));
Sara Bertocco
committed
}
private String getDbNodeType(Node node) {
return "data";
}
throw new UnsupportedOperationException("Unable to retrieve database node type for class " + node.getClass().getCanonicalName());
}
Sara Bertocco
committed
private class NodePaths {
private final String path;
private final String relativePath;
public NodePaths(String myPath, String myRelativePath) {
Sara Bertocco
committed
this.path = myPath;
Sara Bertocco
committed
public String toString() {
Sara Bertocco
committed
}
}