Skip to content
Snippets Groups Projects
Commit 623b48b9 authored by Sara Bertocco's avatar Sara Bertocco
Browse files

setNode added

parent c3e356d6
No related branches found
No related tags found
No related merge requests found
......@@ -10,9 +10,12 @@ import it.inaf.oats.vospace.persistence.NodeDAO;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import net.ivoa.xml.vospace.v2.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
......@@ -20,6 +23,8 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
public class SetNodeController extends BaseNodeController {
private static final Logger LOG = LoggerFactory.getLogger(SetNodeController.class);
@Autowired
private NodeDAO nodeDao;
......@@ -29,9 +34,10 @@ public class SetNodeController extends BaseNodeController {
@PostMapping(value = {"/nodes", "/nodes/**"},
consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE},
produces = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE})
public Node setNode(@RequestBody Node node, User principal, HttpServletRequest request) {
public ResponseEntity<Node> setNode(@RequestBody Node node, User principal, HttpServletRequest request) {
String path = getPath();
LOG.debug("setNode called for path {}", path);
//The service SHALL throw a HTTP 404 status code including a NodeNotFound
//fault in the entity-body if the target Node does not exist
......@@ -48,10 +54,15 @@ public class SetNodeController extends BaseNodeController {
// The service SHALL throw a HTTP 403 status code including a PermissionDenied fault
// in the entity-body if the request attempts to modify a read-only Property.
// This method cannot be used to modify the Node type.
String storedNodeType = toBeModifiedNode.getType();
String newNodeType = node.getType();
if(!storedNodeType.equals(newNodeType)) {
LOG.debug("setNode trying to modify type. Stored ", storedNodeType + ", requested " + newNodeType);
throw new PermissionDeniedException(path);
}
// This method cannot be used to modify the accepts or provides list of Views for the Node.
// This method cannot be used to create children of a container Node.
// For this case, throws exception in NodeDAO
// This method cannot be used to create children of a container Node. (Non capisco, Sara)
// If a parent node in the URI path does not exist then the service SHALL throw a
// HTTP 404 status code including a ContainerNotFound fault in the entity-body
......@@ -79,16 +90,15 @@ public class SetNodeController extends BaseNodeController {
}
//The service SHOULD throw a HTTP 500 status code including an InternalFault fault
// in the entity-body if the operation fails
// Done in NodeDAO
// to be fixed
// A HTTP 200 status code and a Node representation in the entity-body The full
// expanded record for the node SHALL be returned, including any xsi:type
// specific extensions.
return node;
return ResponseEntity.ok(nodeDao.setNode(node));
}
......
package it.inaf.oats.vospace.persistence;
import it.inaf.oats.vospace.DeleteNodeController;
import it.inaf.oats.vospace.datamodel.NodeProperties;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.exception.InternalFaultException;
import it.inaf.oats.vospace.exception.NodeNotFoundException;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
import java.sql.Array;
import net.ivoa.xml.vospace.v2.Node;
import java.sql.PreparedStatement;
......@@ -22,6 +25,8 @@ import net.ivoa.xml.vospace.v2.DataNode;
import net.ivoa.xml.vospace.v2.Property;
import net.ivoa.xml.vospace.v2.StructuredDataNode;
import net.ivoa.xml.vospace.v2.View;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
......@@ -30,6 +35,8 @@ import org.springframework.stereotype.Repository;
@Repository
public class NodeDAO {
private static final Logger LOG = LoggerFactory.getLogger(DeleteNodeController.class);
@Value("${vospace-authority}")
private String authority;
......@@ -46,17 +53,7 @@ public class NodeDAO {
String path = nodeURI.replaceAll("vos://[^/]+", "");
String parentPath = NodeUtils.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);
});
List<NodePaths> paths = getNodePathsFromDB(nodeURI);
if (paths.isEmpty()) {
throw new IllegalStateException("Unable to find parent node during node creation");
......@@ -126,6 +123,101 @@ public class NodeDAO {
return Optional.of(node);
}
public Node setNode(Node newNode) {
// Verify that the node is in the database
String nodeURI = newNode.getUri();
List<NodePaths> paths = getNodePathsFromDB(nodeURI);
if (paths.isEmpty()) {
throw new IllegalStateException("Unable to find node during node update");
}
if (paths.size() > 1) {
throw new IllegalStateException("Multiple ltree parent paths during node update");
}
// This method cannot be used to modify the accepts or provides list of Views for the Node.
// Only DataNodes has Views (see VOSpace Data Model
// Check if trying to change views getting Views (if present) of the modified node
if (newNode instanceof DataNode) {
DataNode dataNode = (DataNode)newNode;
List<View> requestedAcceptedViews = dataNode.getAccepts();
List<View> savedAcceptedViews = getAcceptedViewsFromDB(paths.get(0).getPath());
// Get the Views of the saved node
List<View> requestedProvidedViews = dataNode.getProvides();
List<View> savedProvidedViews = getProvidedViewsFromDB(paths.get(0).getPath());
if (!requestedAcceptedViews.isEmpty()) {
//se sono non nulle, devo fare i controlli, altrimenti di sicuro l'utente non sta chiedendo di cambiarle
// Check if requestedAcceptedViews are different from the already stored
if (!checkIfViewsAreEquals(requestedAcceptedViews,savedAcceptedViews)) {
LOG.debug("setNode trying to modify accepted Views.");
throw new PermissionDeniedException("Trying to modify accepted views");
}
}
if (!requestedProvidedViews.isEmpty()) {
//se sono non nulle, devo fare i controlli, altrimenti di sicuro l'utente non sta chiedendo di cambiarle
// Check if requestedAcceptedViews are different from the already stored
if (!checkIfViewsAreEquals(requestedProvidedViews,savedProvidedViews)) {
LOG.debug("setNode trying to modify provided Views.");
throw new PermissionDeniedException("Trying to modify provided views");
}
}
}
StringBuilder sb = new StringBuilder();
sb.append("UPDATE node");
sb.append(" SET owner_id = ?, group_read = ?, group_write = ?, is_public = ? " );
sb.append(" FROM node_vos_path p WHERE p.vos_path = ? AND p.node_id = node.node_id ");
jdbcTemplate.update(conn -> {
PreparedStatement ps = conn.prepareStatement(sb.toString());
int i = 0;
ps.setString(++i, NodeProperties.getPropertiesStringByURI(newNode, NodeProperties.getPropertyURI("creator")));
ps.setArray(++i, fromPropertyToArray(ps, NodeProperties.getPropertiesStringByURI(newNode, NodeProperties.getPropertyURI("groupread"))));
ps.setArray(++i, fromPropertyToArray(ps, NodeProperties.getPropertiesStringByURI(newNode, NodeProperties.getPropertyURI("groupwrite"))));
ps.setBoolean(++i, Boolean.valueOf(NodeProperties.getPropertiesStringByURI(newNode, NodeProperties.getPropertyURI("publicread"))));
ps.setString(++i, paths.get(0).getPath());
return ps;
});
return newNode;
}
private Optional<Node> getNode(String path) {
String sql = "SELECT node_id, type, async_trans, sticky, busy_state, creator_id, group_read, group_write,\n"
+ "is_public, content_length, created_on, last_modified, accept_views, provide_views \n"
+ "FROM node WHERE path = ?";
List<Node> nodes = jdbcTemplate.query(conn -> {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, path);
return ps;
}, (row, index) -> {
return getNodeFromResultSet(row);
});
if (nodes.isEmpty()) {
return Optional.empty();
}
// Query returns the node (can be container or data)
Node node = nodes.get(0);
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 || '";
......@@ -322,10 +414,11 @@ public class NodeDAO {
return null;
}
private List<View> getViews(Array array) throws SQLException {
private List<View> getViews(Array array) {
if (array == null) {
return null;
}
try {
return Arrays.stream((String[]) array.getArray())
.map(uri -> {
View view = new View();
......@@ -333,6 +426,100 @@ public class NodeDAO {
return view;
})
.collect(Collectors.toList());
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
private boolean checkIfViewsAreEquals(List<View> viewsA, List<View> viewsB) {
boolean viewsAreEqual = true;
if ((viewsA == null || viewsA.isEmpty()) &&
(viewsB == null || viewsB.isEmpty()))
return true;
if ((viewsA == null || viewsA.isEmpty()) ||
(viewsB == null || viewsB.isEmpty()))
return false;
if( viewsA.size() != viewsB.size())
return false;
for(int i = 0; i < viewsA.size(); i++) {
String viewUriA = viewsA.get(i).getUri();
boolean found = false;
for(int j = 0; j < viewsB.size(); j++) {
String viewUriB = viewsB.get(i).getUri();
if (viewUriA.compareTo(viewUriB) == 0) {
found = true;
}
}
if(found == false) {
viewsAreEqual = false;
break;
}
}
return viewsAreEqual;
}
private List<View> getAcceptedViewsFromDB(String nodePath) {
return getViewsFromDB(nodePath, "accept_views");
}
private List<View> getProvidedViewsFromDB(String nodePath) {
return getViewsFromDB(nodePath, "provide_views");
}
private List<View> getViewsFromDB(String nodePath, String viewType) {
String sql = "SELECT accept_views FROM node WHERE node_id = "
+ "(SELECT node_id FROM node_vos_path WHERE vos_path = ?)";
Array results = jdbcTemplate.query(sql, ps -> {
ps.setString(1, nodePath);
}, (rs) -> {
if(rs.next())
return rs.getArray("accept_views");
else
return null;
});
return getViews(results);
}
private List<NodePaths> getNodePathsFromDB(String nodeURI) {
//String nodeURI = myNode.getUri();
String path = nodeURI.replaceAll("vos://[^/]+", "");
String parentPath = NodeUtils.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);
});
return paths;
}
private class NodePaths {
......@@ -350,5 +537,14 @@ public class NodeDAO {
public String toString() {
return relativePath + " " + path;
}
public String getPath() {
return this.path;
}
public String getRelativePath() {
return this.relativePath;
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment