Loading src/main/java/it/inaf/oats/vospace/TransferController.java +77 −5 Original line number Diff line number Diff line package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; import it.inaf.oats.vospace.persistence.JobDAO; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import net.ivoa.xml.uws.v1.ExecutionPhase; import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.vospace.v2.Transfer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class TransferController { @PostMapping(value = "/transfer", @Autowired private JobDAO jobDAO; @Autowired private HttpServletRequest request; @Autowired private UriService uriService; @PostMapping(value = "/transfers", consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}) public Transfer postTransfer(@RequestBody Transfer transfer) { return transfer; public ResponseEntity<?> postTransfer(@RequestBody Transfer transfer, User principal) { String jobId = UUID.randomUUID().toString().replace("-", ""); JobSummary jobSummary = new JobSummary(); jobSummary.setJobId(jobId); jobSummary.setOwnerId(principal.getName()); jobSummary.setPhase(ExecutionPhase.PENDING); JobSummary.JobInfo jobInfo = new JobSummary.JobInfo(); jobInfo.getAny().add(transfer); jobSummary.setJobInfo(jobInfo); jobDAO.createJob(jobSummary); return getJobRedirect(jobId); } @GetMapping(value = "/transfers/{jobId}", produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}) public ResponseEntity<JobSummary> getJob(@PathVariable("jobId") String jobId) { return jobDAO.getJob(jobId).map(j -> ResponseEntity.ok(j)).orElse(ResponseEntity.notFound().build()); } @PostMapping(value = "/transfers/{jobId}/phase") public ResponseEntity<?> setJobPhase(@PathVariable("jobId") String jobId, @RequestParam("PHASE") String phase, User principal) { return jobDAO.getJob(jobId).map(job -> { if (!job.getOwnerId().equals(principal.getName())) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } // TODO: check allowed job phase transitions switch (phase) { case "RUN": job.setPhase(ExecutionPhase.EXECUTING); uriService.setTransferJobResult(job); jobDAO.updateJob(job); break; case "ABORT": throw new UnsupportedOperationException("Not implemented yet"); default: throw new IllegalArgumentException("Invalid phase parameter: " + phase); } return getJobRedirect(job.getJobId()); }).orElse(ResponseEntity.notFound().build()); } private ResponseEntity<?> getJobRedirect(String jobId) { HttpHeaders headers = new HttpHeaders(); headers.set("Location", request.getContextPath() + "/transfers/" + jobId); return new ResponseEntity<>(headers, HttpStatus.SEE_OTHER); } } src/main/java/it/inaf/oats/vospace/UriService.java 0 → 100644 +52 −0 Original line number Diff line number Diff line package it.inaf.oats.vospace; import it.inaf.oats.vospace.persistence.NodeDAO; import java.util.ArrayList; import java.util.List; import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.uws.v1.ResultReference; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Transfer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service public class UriService { @Value("${vospace-authority}") private String authority; @Value("${file-service-url}") private String fileServiceUrl; @Autowired private NodeDAO nodeDao; public void setTransferJobResult(JobSummary job) { List<ResultReference> results = new ArrayList<>(); ResultReference result = new ResultReference(); result.setHref(getUri(job)); results.add(result); job.setResults(results); } private String getUri(JobSummary job) { // TODO add checks on data type Transfer transfer = (Transfer) job.getJobInfo().getAny().get(0); String relativePath = transfer.getTarget().substring("vos://".length() + authority.length()); // TODO handle node not found Node node = nodeDao.listNode(relativePath).get(); // TODO build the path according to node type // // TODO add token for authenticated access return fileServiceUrl + relativePath + "?jobId=" + job.getJobId(); } } src/main/resources/application.properties +2 −0 Original line number Diff line number Diff line Loading @@ -34,3 +34,5 @@ logging.level.org.springframework.web=TRACE #logging.file=path/to/log/file.log vospace-authority=example.com!vospace file-service-url=http://localhost:8087 No newline at end of file src/test/java/it/inaf/oats/vospace/TransferControllerTest.java 0 → 100644 +52 −0 Original line number Diff line number Diff line package it.inaf.oats.vospace; import static it.inaf.oats.vospace.VOSpaceXmlTestUtil.loadDocument; import it.inaf.oats.vospace.persistence.JobDAO; import java.util.Optional; import net.ivoa.xml.uws.v1.JobSummary; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.eq; 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; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.w3c.dom.Document; @SpringBootTest @AutoConfigureMockMvc public class TransferControllerTest { @MockBean private JobDAO dao; @Autowired private MockMvc mockMvc; @Test public void testGetJob() throws Exception { JobSummary job = new JobSummary(); when(dao.getJob(eq("123"))).thenReturn(Optional.of(job)); String xml = mockMvc.perform(get("/transfers/123") .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); Document doc = loadDocument(xml); assertEquals("uws:job", doc.getDocumentElement().getNodeName()); verify(dao, times(1)).getJob(eq("123")); } } src/test/java/it/inaf/oats/vospace/UriServiceTest.java 0 → 100644 +52 −0 Original line number Diff line number Diff line package it.inaf.oats.vospace; import it.inaf.oats.vospace.persistence.NodeDAO; import java.util.Optional; import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.vospace.v2.DataNode; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Transfer; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.TestPropertySource; @SpringBootTest @AutoConfigureMockMvc @TestPropertySource(properties = {"vospace-authority=example.com!vospace", "file-service-url=http://file-service"}) public class UriServiceTest { @MockBean private NodeDAO dao; @Autowired private UriService transferService; @Test public void testSimpleUrl() { Node node = new DataNode(); when(dao.listNode(eq("/mydata1"))).thenReturn(Optional.of(node)); Transfer transfer = new Transfer(); transfer.setTarget("vos://example.com!vospace/mydata1"); JobSummary job = new JobSummary(); job.setJobId("job-id"); JobSummary.JobInfo jobInfo = new JobSummary.JobInfo(); jobInfo.getAny().add(transfer); job.setJobInfo(jobInfo); transferService.setTransferJobResult(job); assertEquals("http://file-service/mydata1?jobId=job-id", job.getResults().get(0).getHref()); } } Loading
src/main/java/it/inaf/oats/vospace/TransferController.java +77 −5 Original line number Diff line number Diff line package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; import it.inaf.oats.vospace.persistence.JobDAO; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import net.ivoa.xml.uws.v1.ExecutionPhase; import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.vospace.v2.Transfer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class TransferController { @PostMapping(value = "/transfer", @Autowired private JobDAO jobDAO; @Autowired private HttpServletRequest request; @Autowired private UriService uriService; @PostMapping(value = "/transfers", consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}) public Transfer postTransfer(@RequestBody Transfer transfer) { return transfer; public ResponseEntity<?> postTransfer(@RequestBody Transfer transfer, User principal) { String jobId = UUID.randomUUID().toString().replace("-", ""); JobSummary jobSummary = new JobSummary(); jobSummary.setJobId(jobId); jobSummary.setOwnerId(principal.getName()); jobSummary.setPhase(ExecutionPhase.PENDING); JobSummary.JobInfo jobInfo = new JobSummary.JobInfo(); jobInfo.getAny().add(transfer); jobSummary.setJobInfo(jobInfo); jobDAO.createJob(jobSummary); return getJobRedirect(jobId); } @GetMapping(value = "/transfers/{jobId}", produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}) public ResponseEntity<JobSummary> getJob(@PathVariable("jobId") String jobId) { return jobDAO.getJob(jobId).map(j -> ResponseEntity.ok(j)).orElse(ResponseEntity.notFound().build()); } @PostMapping(value = "/transfers/{jobId}/phase") public ResponseEntity<?> setJobPhase(@PathVariable("jobId") String jobId, @RequestParam("PHASE") String phase, User principal) { return jobDAO.getJob(jobId).map(job -> { if (!job.getOwnerId().equals(principal.getName())) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } // TODO: check allowed job phase transitions switch (phase) { case "RUN": job.setPhase(ExecutionPhase.EXECUTING); uriService.setTransferJobResult(job); jobDAO.updateJob(job); break; case "ABORT": throw new UnsupportedOperationException("Not implemented yet"); default: throw new IllegalArgumentException("Invalid phase parameter: " + phase); } return getJobRedirect(job.getJobId()); }).orElse(ResponseEntity.notFound().build()); } private ResponseEntity<?> getJobRedirect(String jobId) { HttpHeaders headers = new HttpHeaders(); headers.set("Location", request.getContextPath() + "/transfers/" + jobId); return new ResponseEntity<>(headers, HttpStatus.SEE_OTHER); } }
src/main/java/it/inaf/oats/vospace/UriService.java 0 → 100644 +52 −0 Original line number Diff line number Diff line package it.inaf.oats.vospace; import it.inaf.oats.vospace.persistence.NodeDAO; import java.util.ArrayList; import java.util.List; import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.uws.v1.ResultReference; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Transfer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service public class UriService { @Value("${vospace-authority}") private String authority; @Value("${file-service-url}") private String fileServiceUrl; @Autowired private NodeDAO nodeDao; public void setTransferJobResult(JobSummary job) { List<ResultReference> results = new ArrayList<>(); ResultReference result = new ResultReference(); result.setHref(getUri(job)); results.add(result); job.setResults(results); } private String getUri(JobSummary job) { // TODO add checks on data type Transfer transfer = (Transfer) job.getJobInfo().getAny().get(0); String relativePath = transfer.getTarget().substring("vos://".length() + authority.length()); // TODO handle node not found Node node = nodeDao.listNode(relativePath).get(); // TODO build the path according to node type // // TODO add token for authenticated access return fileServiceUrl + relativePath + "?jobId=" + job.getJobId(); } }
src/main/resources/application.properties +2 −0 Original line number Diff line number Diff line Loading @@ -34,3 +34,5 @@ logging.level.org.springframework.web=TRACE #logging.file=path/to/log/file.log vospace-authority=example.com!vospace file-service-url=http://localhost:8087 No newline at end of file
src/test/java/it/inaf/oats/vospace/TransferControllerTest.java 0 → 100644 +52 −0 Original line number Diff line number Diff line package it.inaf.oats.vospace; import static it.inaf.oats.vospace.VOSpaceXmlTestUtil.loadDocument; import it.inaf.oats.vospace.persistence.JobDAO; import java.util.Optional; import net.ivoa.xml.uws.v1.JobSummary; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.eq; 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; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.w3c.dom.Document; @SpringBootTest @AutoConfigureMockMvc public class TransferControllerTest { @MockBean private JobDAO dao; @Autowired private MockMvc mockMvc; @Test public void testGetJob() throws Exception { JobSummary job = new JobSummary(); when(dao.getJob(eq("123"))).thenReturn(Optional.of(job)); String xml = mockMvc.perform(get("/transfers/123") .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); Document doc = loadDocument(xml); assertEquals("uws:job", doc.getDocumentElement().getNodeName()); verify(dao, times(1)).getJob(eq("123")); } }
src/test/java/it/inaf/oats/vospace/UriServiceTest.java 0 → 100644 +52 −0 Original line number Diff line number Diff line package it.inaf.oats.vospace; import it.inaf.oats.vospace.persistence.NodeDAO; import java.util.Optional; import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.vospace.v2.DataNode; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Transfer; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.TestPropertySource; @SpringBootTest @AutoConfigureMockMvc @TestPropertySource(properties = {"vospace-authority=example.com!vospace", "file-service-url=http://file-service"}) public class UriServiceTest { @MockBean private NodeDAO dao; @Autowired private UriService transferService; @Test public void testSimpleUrl() { Node node = new DataNode(); when(dao.listNode(eq("/mydata1"))).thenReturn(Optional.of(node)); Transfer transfer = new Transfer(); transfer.setTarget("vos://example.com!vospace/mydata1"); JobSummary job = new JobSummary(); job.setJobId("job-id"); JobSummary.JobInfo jobInfo = new JobSummary.JobInfo(); jobInfo.getAny().add(transfer); job.setJobInfo(jobInfo); transferService.setTransferJobResult(job); assertEquals("http://file-service/mydata1?jobId=job-id", job.getResults().get(0).getHref()); } }