Loading src/main/java/it/inaf/oats/vospace/CreateNodeController.java +35 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,9 @@ package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; import it.inaf.oats.vospace.exception.InvalidArgumentException; import it.inaf.oats.vospace.exception.InvalidURIException; import net.ivoa.xml.vospace.v2.LinkNode; import net.ivoa.xml.vospace.v2.Node; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestBody; Loading @@ -14,6 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PutMapping; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @RestController public class CreateNodeController extends BaseNodeController { Loading @@ -23,6 +27,9 @@ public class CreateNodeController extends BaseNodeController { @Autowired private CreateNodeService createNodeService; @Value("${vospace-authority}") private String authority; @PutMapping(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}) Loading @@ -32,8 +39,36 @@ public class CreateNodeController extends BaseNodeController { LOG.debug("createNodeController called for node with URI {} and PATH {}", node.getUri(), path); // Get Node path (and validates it too) String decodedURIPathFromNode = URIUtils.returnVosPathFromNodeURI(node.getUri(), authority); LOG.debug("createNodeController URI: {} decoded as {}", node.getUri(), decodedURIPathFromNode); // Check if payload URI is consistent with http request if (!decodedURIPathFromNode.equals(path)) { throw new InvalidURIException(decodedURIPathFromNode, path); } // validate format of input node this.validateInputNode(node); return createNodeService.createNode(node, path, principal); } private void validateInputNode(Node node) { if (node instanceof LinkNode) { LinkNode linkNode = (LinkNode) node; String target = linkNode.getTarget(); // I validate it here to add context easily if (target == null) { throw new InvalidArgumentException("LinkNode in payload has no target element specified"); } URIUtils.returnVosPathFromNodeURI(linkNode.getTarget(), authority); } } } src/main/java/it/inaf/oats/vospace/CreateNodeService.java +0 −15 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ import it.inaf.oats.vospace.datamodel.NodeProperties; import it.inaf.oats.vospace.datamodel.NodeUtils; import it.inaf.oats.vospace.exception.ContainerNotFoundException; import it.inaf.oats.vospace.exception.DuplicateNodeException; import it.inaf.oats.vospace.exception.InvalidURIException; import it.inaf.oats.vospace.exception.LinkFoundException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.persistence.NodeDAO; Loading @@ -19,7 +18,6 @@ import net.ivoa.xml.vospace.v2.Property; 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.stereotype.Service; import org.springframework.transaction.annotation.EnableTransactionManagement; Loading @@ -30,25 +28,12 @@ public class CreateNodeService { @Autowired private NodeDAO nodeDao; @Value("${vospace-authority}") private String authority; private static final Logger LOG = LoggerFactory.getLogger(CreateNodeService.class); public Node createNode(Node node, String path, User principal) { LOG.debug("createNodeService called for node with URI {} and PATH {}", node.getUri(), path); // Get Node path (and validates it too) String decodedURIPathFromNode = URIUtils.returnVosPathFromNodeURI(node.getUri(), authority); LOG.debug("createNodeService URI: {} decoded as {}", node.getUri(), decodedURIPathFromNode); // Check if payload URI is consistent with http request if (!decodedURIPathFromNode.equals(path)) { throw new InvalidURIException(decodedURIPathFromNode, path); } // Check if another node is already present at specified path // This checks if the user is trying to insert the root node at "/" too if (nodeDao.listNode(path).isPresent()) { Loading src/main/java/it/inaf/oats/vospace/URIUtils.java +5 −1 Original line number Diff line number Diff line Loading @@ -51,6 +51,10 @@ public class URIUtils { String resultPath = null; try { if(nodeURI == null) throw new IllegalArgumentException("URI string is null"); URI uri = new URI(nodeURI); // Check scheme Loading src/test/java/it/inaf/oats/vospace/CreateNodeControllerTest.java +140 −70 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import org.springframework.boot.test.mock.mockito.SpyBean; import net.ivoa.xml.vospace.v2.ContainerNode; import net.ivoa.xml.vospace.v2.LinkNode; import java.util.List; import java.util.Objects; import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; Loading Loading @@ -185,6 +186,63 @@ public class CreateNodeControllerTest { } @Test public void testCreateInternalLinkNode() throws Exception { String requestBody = getResourceFileContent("create-internal-link-node.xml"); when(nodeDao.listNode(eq("/"))) .thenReturn(Optional.of(getContainerParentNode("/"))); mockMvc.perform(put("/nodes/myInternalLink") .header("Authorization", "Bearer user2_token") .content(requestBody) .contentType(MediaType.APPLICATION_XML) .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().isOk()); verifyLinkArguments("vos://example.com!vospace/myDummyDataNode1"); } @Test public void testCreateExternalLinkNode() throws Exception { String requestBody = getResourceFileContent("create-external-link-node.xml"); when(nodeDao.listNode(eq("/"))) .thenReturn(Optional.of(getContainerParentNode("/"))); mockMvc.perform(put("/nodes/myExternalLink") .header("Authorization", "Bearer user2_token") .content(requestBody) .contentType(MediaType.APPLICATION_XML) .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().is4xxClientError()); verifyLinkArguments("vos://external.com!vospace/myDummyDataNode1"); } @Test public void testCreateLinkNodeNoTarget() throws Exception { String requestBody = getResourceFileContent("create-link-node-notarget.xml"); when(nodeDao.listNode(eq("/"))) .thenReturn(Optional.of(getContainerParentNode("/"))); mockMvc.perform(put("/nodes/myNoTargetLink") .header("Authorization", "Bearer user2_token") .content(requestBody) .contentType(MediaType.APPLICATION_XML) .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().is4xxClientError()); verifyLinkArguments(null); } @Test public void testNodeAlreadyExisting() throws Exception { String requestBody = getResourceFileContent("create-unstructured-data-node.xml"); Loading Loading @@ -409,6 +467,18 @@ public class CreateNodeControllerTest { }), any()); } private void verifyLinkArguments(String target) { verify(controller).createNode( argThat(node -> { LinkNode linkNode = (LinkNode) node; Property property = linkNode.getProperties().get(0); return "vos:LinkNode".equals(linkNode.getType()) && "test value".equals(property.getValue()) && "ivo://ivoa.net/vospace/core#description".equals(property.getUri()) && Objects.equals(target, linkNode.getTarget()); }), any()); } protected static String getResourceFileContent(String fileName) throws Exception { try (InputStream in = CreateNodeControllerTest.class.getClassLoader().getResourceAsStream(fileName)) { return new String(in.readAllBytes(), StandardCharsets.UTF_8); Loading src/test/java/it/inaf/oats/vospace/persistence/NodeDAOTest.java +18 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ import java.util.Set; import javax.sql.DataSource; import net.ivoa.xml.vospace.v2.ContainerNode; import net.ivoa.xml.vospace.v2.DataNode; import net.ivoa.xml.vospace.v2.LinkNode; import net.ivoa.xml.vospace.v2.View; import static org.junit.jupiter.api.Assertions.assertEquals; import net.ivoa.xml.vospace.v2.Node; Loading Loading @@ -66,6 +67,23 @@ public class NodeDAOTest { assertEquals(retrievedNode.getProvides().get(0).getUri(), dataNode.getProvides().get(0).getUri()); } @Test public void testCreateLinkNode() { LinkNode linkNode = new LinkNode(); String target = "vos://example.com!vospace/myData1"; linkNode.setUri("vos://example.com!vospace/myLink1"); linkNode.setTarget(target); dao.createNode(linkNode); Node retrievedNode = dao.listNode("/myLink1").get(); assertTrue(retrievedNode instanceof LinkNode); assertEquals(target, ((LinkNode) retrievedNode).getTarget()); } @Test public void testListNode() { ContainerNode root = (ContainerNode) dao.listNode("/").get(); Loading Loading
src/main/java/it/inaf/oats/vospace/CreateNodeController.java +35 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,9 @@ package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; import it.inaf.oats.vospace.exception.InvalidArgumentException; import it.inaf.oats.vospace.exception.InvalidURIException; import net.ivoa.xml.vospace.v2.LinkNode; import net.ivoa.xml.vospace.v2.Node; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestBody; Loading @@ -14,6 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PutMapping; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @RestController public class CreateNodeController extends BaseNodeController { Loading @@ -23,6 +27,9 @@ public class CreateNodeController extends BaseNodeController { @Autowired private CreateNodeService createNodeService; @Value("${vospace-authority}") private String authority; @PutMapping(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}) Loading @@ -32,8 +39,36 @@ public class CreateNodeController extends BaseNodeController { LOG.debug("createNodeController called for node with URI {} and PATH {}", node.getUri(), path); // Get Node path (and validates it too) String decodedURIPathFromNode = URIUtils.returnVosPathFromNodeURI(node.getUri(), authority); LOG.debug("createNodeController URI: {} decoded as {}", node.getUri(), decodedURIPathFromNode); // Check if payload URI is consistent with http request if (!decodedURIPathFromNode.equals(path)) { throw new InvalidURIException(decodedURIPathFromNode, path); } // validate format of input node this.validateInputNode(node); return createNodeService.createNode(node, path, principal); } private void validateInputNode(Node node) { if (node instanceof LinkNode) { LinkNode linkNode = (LinkNode) node; String target = linkNode.getTarget(); // I validate it here to add context easily if (target == null) { throw new InvalidArgumentException("LinkNode in payload has no target element specified"); } URIUtils.returnVosPathFromNodeURI(linkNode.getTarget(), authority); } } }
src/main/java/it/inaf/oats/vospace/CreateNodeService.java +0 −15 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ import it.inaf.oats.vospace.datamodel.NodeProperties; import it.inaf.oats.vospace.datamodel.NodeUtils; import it.inaf.oats.vospace.exception.ContainerNotFoundException; import it.inaf.oats.vospace.exception.DuplicateNodeException; import it.inaf.oats.vospace.exception.InvalidURIException; import it.inaf.oats.vospace.exception.LinkFoundException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.persistence.NodeDAO; Loading @@ -19,7 +18,6 @@ import net.ivoa.xml.vospace.v2.Property; 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.stereotype.Service; import org.springframework.transaction.annotation.EnableTransactionManagement; Loading @@ -30,25 +28,12 @@ public class CreateNodeService { @Autowired private NodeDAO nodeDao; @Value("${vospace-authority}") private String authority; private static final Logger LOG = LoggerFactory.getLogger(CreateNodeService.class); public Node createNode(Node node, String path, User principal) { LOG.debug("createNodeService called for node with URI {} and PATH {}", node.getUri(), path); // Get Node path (and validates it too) String decodedURIPathFromNode = URIUtils.returnVosPathFromNodeURI(node.getUri(), authority); LOG.debug("createNodeService URI: {} decoded as {}", node.getUri(), decodedURIPathFromNode); // Check if payload URI is consistent with http request if (!decodedURIPathFromNode.equals(path)) { throw new InvalidURIException(decodedURIPathFromNode, path); } // Check if another node is already present at specified path // This checks if the user is trying to insert the root node at "/" too if (nodeDao.listNode(path).isPresent()) { Loading
src/main/java/it/inaf/oats/vospace/URIUtils.java +5 −1 Original line number Diff line number Diff line Loading @@ -51,6 +51,10 @@ public class URIUtils { String resultPath = null; try { if(nodeURI == null) throw new IllegalArgumentException("URI string is null"); URI uri = new URI(nodeURI); // Check scheme Loading
src/test/java/it/inaf/oats/vospace/CreateNodeControllerTest.java +140 −70 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import org.springframework.boot.test.mock.mockito.SpyBean; import net.ivoa.xml.vospace.v2.ContainerNode; import net.ivoa.xml.vospace.v2.LinkNode; import java.util.List; import java.util.Objects; import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; Loading Loading @@ -185,6 +186,63 @@ public class CreateNodeControllerTest { } @Test public void testCreateInternalLinkNode() throws Exception { String requestBody = getResourceFileContent("create-internal-link-node.xml"); when(nodeDao.listNode(eq("/"))) .thenReturn(Optional.of(getContainerParentNode("/"))); mockMvc.perform(put("/nodes/myInternalLink") .header("Authorization", "Bearer user2_token") .content(requestBody) .contentType(MediaType.APPLICATION_XML) .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().isOk()); verifyLinkArguments("vos://example.com!vospace/myDummyDataNode1"); } @Test public void testCreateExternalLinkNode() throws Exception { String requestBody = getResourceFileContent("create-external-link-node.xml"); when(nodeDao.listNode(eq("/"))) .thenReturn(Optional.of(getContainerParentNode("/"))); mockMvc.perform(put("/nodes/myExternalLink") .header("Authorization", "Bearer user2_token") .content(requestBody) .contentType(MediaType.APPLICATION_XML) .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().is4xxClientError()); verifyLinkArguments("vos://external.com!vospace/myDummyDataNode1"); } @Test public void testCreateLinkNodeNoTarget() throws Exception { String requestBody = getResourceFileContent("create-link-node-notarget.xml"); when(nodeDao.listNode(eq("/"))) .thenReturn(Optional.of(getContainerParentNode("/"))); mockMvc.perform(put("/nodes/myNoTargetLink") .header("Authorization", "Bearer user2_token") .content(requestBody) .contentType(MediaType.APPLICATION_XML) .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().is4xxClientError()); verifyLinkArguments(null); } @Test public void testNodeAlreadyExisting() throws Exception { String requestBody = getResourceFileContent("create-unstructured-data-node.xml"); Loading Loading @@ -409,6 +467,18 @@ public class CreateNodeControllerTest { }), any()); } private void verifyLinkArguments(String target) { verify(controller).createNode( argThat(node -> { LinkNode linkNode = (LinkNode) node; Property property = linkNode.getProperties().get(0); return "vos:LinkNode".equals(linkNode.getType()) && "test value".equals(property.getValue()) && "ivo://ivoa.net/vospace/core#description".equals(property.getUri()) && Objects.equals(target, linkNode.getTarget()); }), any()); } protected static String getResourceFileContent(String fileName) throws Exception { try (InputStream in = CreateNodeControllerTest.class.getClassLoader().getResourceAsStream(fileName)) { return new String(in.readAllBytes(), StandardCharsets.UTF_8); Loading
src/test/java/it/inaf/oats/vospace/persistence/NodeDAOTest.java +18 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ import java.util.Set; import javax.sql.DataSource; import net.ivoa.xml.vospace.v2.ContainerNode; import net.ivoa.xml.vospace.v2.DataNode; import net.ivoa.xml.vospace.v2.LinkNode; import net.ivoa.xml.vospace.v2.View; import static org.junit.jupiter.api.Assertions.assertEquals; import net.ivoa.xml.vospace.v2.Node; Loading Loading @@ -66,6 +67,23 @@ public class NodeDAOTest { assertEquals(retrievedNode.getProvides().get(0).getUri(), dataNode.getProvides().get(0).getUri()); } @Test public void testCreateLinkNode() { LinkNode linkNode = new LinkNode(); String target = "vos://example.com!vospace/myData1"; linkNode.setUri("vos://example.com!vospace/myLink1"); linkNode.setTarget(target); dao.createNode(linkNode); Node retrievedNode = dao.listNode("/myLink1").get(); assertTrue(retrievedNode instanceof LinkNode); assertEquals(target, ((LinkNode) retrievedNode).getTarget()); } @Test public void testListNode() { ContainerNode root = (ContainerNode) dao.listNode("/").get(); Loading