diff --git a/src/main/java/it/inaf/oats/vospace/UriService.java b/src/main/java/it/inaf/oats/vospace/UriService.java index ec649780d09bc9c73f92eeb96849fa94ca789c68..ab05851c5a4a3f90434c044a1ba2629e0fa08b0f 100644 --- a/src/main/java/it/inaf/oats/vospace/UriService.java +++ b/src/main/java/it/inaf/oats/vospace/UriService.java @@ -8,6 +8,7 @@ import it.inaf.oats.vospace.datamodel.NodeProperties; import it.inaf.oats.vospace.datamodel.NodeUtils; import static it.inaf.oats.vospace.datamodel.NodeUtils.urlEncodePath; import it.inaf.oats.vospace.exception.InternalFaultException; +import it.inaf.oats.vospace.exception.InvalidURIException; import it.inaf.oats.vospace.exception.NodeNotFoundException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.exception.ProtocolNotSupportedException; @@ -19,14 +20,13 @@ import it.inaf.oats.vospace.persistence.model.LocationType; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Optional; import javax.servlet.http.HttpServletRequest; import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.uws.v1.ResultReference; +import net.ivoa.xml.vospace.v2.DataNode; import net.ivoa.xml.vospace.v2.Node; -import net.ivoa.xml.vospace.v2.Param; import net.ivoa.xml.vospace.v2.Protocol; import net.ivoa.xml.vospace.v2.Transfer; import org.springframework.beans.factory.annotation.Autowired; @@ -54,12 +54,15 @@ public class UriService { @Autowired private ServletRapClient rapClient; + @Autowired + private CreateNodeController createNodeController; + public void setTransferJobResult(JobSummary job, Transfer transfer) { List<ResultReference> results = new ArrayList<>(); - ResultReference result = new ResultReference(); - result.setHref(getEndpoint(job, transfer)); + ResultReference result = new ResultReference(); + result.setHref(getEndpoint(job, transfer)); results.add(result); job.setResults(results); @@ -81,18 +84,39 @@ public class UriService { protocol.setEndpoint(getEndpoint(job, transfer)); } + private Node getEndpointNode(String relativePath, + JobService.JobType jobType, + User user) { + Optional<Node> optNode = nodeDao.listNode(relativePath); + if (optNode.isPresent()) { + return optNode.get(); + } else { + switch (jobType) { + case pullFromVoSpace: + throw new NodeNotFoundException(relativePath); + case pushToVoSpace: + case pullToVoSpace: + DataNode newNode = new DataNode(); + newNode.setUri(relativePath); + return createNodeController.createNode(newNode, user); + default: + throw new InternalFaultException("No supported job direction specified"); + } + + } + } + private String getEndpoint(JobSummary job, Transfer transfer) { String relativePath = transfer.getTarget().substring("vos://".length() + authority.length()); - Node node = nodeDao.listNode(relativePath).orElseThrow(() -> new NodeNotFoundException(relativePath)); - User user = (User) servletRequest.getUserPrincipal(); String creator = user.getName(); List<String> groups = user.getGroups(); // Check privileges write or read according to job type JobService.JobType jobType = JobType.valueOf(transfer.getDirection()); + Node node = this.getEndpointNode(relativePath, jobType, user); switch (jobType) { case pushToVoSpace: @@ -109,7 +133,7 @@ public class UriService { break; default: - throw new InternalFaultException("No job direction specified"); + throw new InternalFaultException("No supported job direction specified"); } if (NodeUtils.getIsBusy(node)) { diff --git a/src/main/java/it/inaf/oats/vospace/exception/ContainerNotFoundException.java b/src/main/java/it/inaf/oats/vospace/exception/ContainerNotFoundException.java index 7480c2940a9596aa98191907c4b4151e298d4957..d2847872d3f53c01b999efa8b0989ec7a9bde243 100644 --- a/src/main/java/it/inaf/oats/vospace/exception/ContainerNotFoundException.java +++ b/src/main/java/it/inaf/oats/vospace/exception/ContainerNotFoundException.java @@ -1,12 +1,14 @@ package it.inaf.oats.vospace.exception; +import net.ivoa.xml.uws.v1.ErrorSummaryFactory; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(value = HttpStatus.NOT_FOUND) -public class ContainerNotFoundException extends VoSpaceException { +public class ContainerNotFoundException extends VoSpaceErrorSummarizableException { public ContainerNotFoundException(String path) { - super("Container Not Found at path: " + path); + super("Container Not Found at path: " + path, + ErrorSummaryFactory.VOSpaceFault.NODE_NOT_FOUND); } } diff --git a/src/main/java/it/inaf/oats/vospace/exception/LinkFoundException.java b/src/main/java/it/inaf/oats/vospace/exception/LinkFoundException.java index 0f316c144802599cae0a9873c7268f17f5391794..dc4946eb338907019670fb955a003ec82dfc3356 100644 --- a/src/main/java/it/inaf/oats/vospace/exception/LinkFoundException.java +++ b/src/main/java/it/inaf/oats/vospace/exception/LinkFoundException.java @@ -1,12 +1,14 @@ package it.inaf.oats.vospace.exception; +import net.ivoa.xml.uws.v1.ErrorSummaryFactory; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(value = HttpStatus.BAD_REQUEST) -public class LinkFoundException extends VoSpaceException { +public class LinkFoundException extends VoSpaceErrorSummarizableException { public LinkFoundException(String path) { - super("Link Found at path: " + path); + super("Link Found at path: " + path, + ErrorSummaryFactory.VOSpaceFault.INVALID_URI); } } diff --git a/src/test/java/it/inaf/oats/vospace/UriServiceTest.java b/src/test/java/it/inaf/oats/vospace/UriServiceTest.java index 84b865d5649fceb1e2e0d8527f2d4dd37cb53d4f..cef14ed89336bb45457dcac622d0921cbed9e0c3 100644 --- a/src/test/java/it/inaf/oats/vospace/UriServiceTest.java +++ b/src/test/java/it/inaf/oats/vospace/UriServiceTest.java @@ -10,6 +10,7 @@ import it.inaf.oats.vospace.persistence.model.LocationType; import java.util.Optional; import javax.servlet.http.HttpServletRequest; import net.ivoa.xml.uws.v1.JobSummary; +import net.ivoa.xml.vospace.v2.ContainerNode; import net.ivoa.xml.vospace.v2.DataNode; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Property; @@ -21,6 +22,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.springframework.beans.factory.annotation.Autowired; @@ -45,6 +47,9 @@ public class UriServiceTest { @MockBean private ServletRapClient rapClient; + + @MockBean + private CreateNodeController createNodeController; @Autowired private HttpServletRequest servletRequest; @@ -123,6 +128,59 @@ public class UriServiceTest { assertEquals("http://file-service/mydata1?jobId=job-id&token=<new-token>", job.getResults().get(0).getHref()); } + + @Test + public void pushToNonexistentNode() { + + ContainerNode node = new ContainerNode(); + node.setUri("vos://example.com!vospace/mydata1"); + Property creator = new Property(); + creator.setUri(NodeProperties.CREATOR_URI); + creator.setValue("user1"); + node.getProperties().add(creator); + + Property readgroup = new Property(); + readgroup.setUri(NodeProperties.GROUP_READ_URI); + readgroup.setValue("group1"); + node.getProperties().add(readgroup); + + DataNode dnode = new DataNode(); + dnode.setUri("vos://example.com!vospace/mydata1/mydata2"); + dnode.getProperties().add(creator); + dnode.getProperties().add(readgroup); + + Property writegroup = new Property(); + writegroup.setUri(NodeProperties.GROUP_WRITE_URI); + writegroup.setValue("group1"); + dnode.getProperties().add(writegroup); + + when(nodeDAO.listNode(eq("/mydata1"))).thenReturn(Optional.of(node)); + when(nodeDAO.listNode(eq("/mydata1/mydata2"))).thenReturn(Optional.empty()); + + + User user = mock(User.class); + when(user.getAccessToken()).thenReturn("<token>"); + when(user.getName()).thenReturn("user1"); + + when(servletRequest.getUserPrincipal()).thenReturn(user); + + when(rapClient.exchangeToken(argThat(req -> { + assertEquals("<token>", req.getSubjectToken()); + assertEquals("http://file-service/mydata1/mydata2", req.getResource()); + return true; + }), any())).thenReturn("<new-token>"); + + JobSummary job = getPushToVoSpaceJob(); + Transfer tr = uriService.getTransfer(job); + + when(createNodeController.createNode(any(), eq(user))).thenReturn(dnode); + + uriService.setTransferJobResult(job, tr); + + verify(createNodeController, times(1)).createNode(any(), eq(user)); + + assertEquals("http://file-service/mydata1/mydata2?jobId=job-id2&token=<new-token>", job.getResults().get(0).getHref()); + } @Test public void setNodeRemoteLocationTest() { @@ -156,4 +214,20 @@ public class UriServiceTest { return job; } + + private JobSummary getPushToVoSpaceJob() { + Transfer transfer = new Transfer(); + transfer.setTarget("vos://example.com!vospace/mydata1/mydata2"); + transfer.setDirection(JobService.JobType.pushToVoSpace.toString()); + + JobSummary job = new JobSummary(); + job.setJobId("job-id2"); + + JobSummary.JobInfo jobInfo = new JobSummary.JobInfo(); + jobInfo.getAny().add(transfer); + + job.setJobInfo(jobInfo); + + return job; + } }