Loading vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/client/VOSpaceClient.java +13 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; import java.util.List; import java.util.Scanner; import java.util.concurrent.CompletionException; import java.util.concurrent.ForkJoinPool; Loading @@ -23,6 +24,7 @@ import javax.servlet.http.HttpSession; import javax.xml.bind.JAXB; import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Protocol; import net.ivoa.xml.vospace.v2.Transfer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; Loading Loading @@ -82,6 +84,17 @@ public class VOSpaceClient { return call(request, BodyHandlers.ofInputStream(), 200, res -> unmarshal(res, JobSummary.class)); } public List<Protocol> getDownloadEndpoints(Transfer transfer) { HttpRequest request = getRequest("/synctrans") .header("Accept", useJson ? "application/json" : "text/xml") .header("Content-Type", useJson ? "application/json" : "text/xml") .POST(HttpRequest.BodyPublishers.ofString(marshal(transfer))) .build(); return call(request, BodyHandlers.ofInputStream(), 200, res -> unmarshal(res, Transfer.class)).getProtocols(); } private <T, U> U call(HttpRequest request, HttpResponse.BodyHandler<T> responseBodyHandler, int expectedStatusCode, Function<T, U> responseHandler) { try { return httpClient.sendAsync(request, responseBodyHandler) Loading vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/JobController.java +1 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ public class JobController { transfer.setTarget("vos://" + authority + paths.get(0)); Protocol protocol = new Protocol(); protocol.setUri("ia2:tape-recall"); transfer.getProtocol().add(protocol); transfer.getProtocols().add(protocol); JobSummary job = client.startTransferJob(transfer); Loading vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/NodesController.java +46 −11 Original line number Diff line number Diff line package it.inaf.ia2.vospace.ui.controller; import it.inaf.ia2.vospace.ui.client.VOSpaceClient; import it.inaf.ia2.vospace.ui.service.NodesService; import javax.servlet.http.HttpServletRequest; import net.ivoa.xml.vospace.v2.Transfer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; 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.RestController; @RestController public class NodesController { @Value("${vospace-authority}") private String authority; @Autowired private NodesService nodesService; @Autowired private VOSpaceClient client; @Autowired private HttpServletRequest servletRequest; /** * This is the only API endpoint that returns HTML code instead of JSON. The * reason is that JavaScript frameworks are not very efficient in handling Loading @@ -23,21 +37,42 @@ public class NodesController { * document. */ @GetMapping(value = {"/nodes", "/nodes/**"}, produces = MediaType.TEXT_PLAIN_VALUE) public String listNodes(HttpServletRequest request) throws Exception { public String listNodes() throws Exception { String requestURL = request.getRequestURL().toString(); String[] split = requestURL.split("/nodes/"); String path = getPath("/nodes/"); String path = "/"; if (split.length == 2) { path += split[1]; return nodesService.generateNodesHtml(path); } return nodesService.generateNodesHtml(path); @GetMapping(value = "/download/**") public ResponseEntity<?> directDownload() { String path = getPath("/download/"); Transfer transfer = new Transfer(); transfer.setDirection("pullFromVoSpace"); transfer.setTarget("vos://" + authority + path); String url = client.getDownloadEndpoints(transfer).get(0).getEndpoint(); HttpHeaders headers = new HttpHeaders(); headers.set("Location", url); return new ResponseEntity<>(headers, HttpStatus.SEE_OTHER); } @GetMapping(value = "/download/{path}") public void directDownload(@PathVariable("path") String path) { // TODO: call pullFromVoSpace sync transfer /** * Slash is a special character in defining REST endpoints and trying to * define a PathVariable containing slashes doesn't work, so the endpoint * has been defined using "/nodes/**" instead of "/nodes/{path}" and the * path is extracted manually parsing the request URL. */ protected String getPath(String prefix) { String requestURL = servletRequest.getRequestURL().toString(); String[] split = requestURL.split(prefix); String path = "/"; if (split.length == 2) { path += split[1]; } return path; } } vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/NodesControllerTest.java +9 −7 Original line number Diff line number Diff line Loading @@ -3,26 +3,28 @@ package it.inaf.ia2.vospace.ui.controller; import it.inaf.ia2.vospace.ui.service.NodesService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import static org.mockito.ArgumentMatchers.eq; import org.mockito.InjectMocks; import org.mockito.Mock; import static org.mockito.Mockito.verify; import org.mockito.junit.jupiter.MockitoExtension; 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.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.springframework.test.web.servlet.setup.MockMvcBuilders; @ExtendWith(MockitoExtension.class) @SpringBootTest @AutoConfigureMockMvc public class NodesControllerTest { @Mock @MockBean private NodesService nodesService; @InjectMocks @Autowired private NodesController controller; @Autowired private MockMvc mockMvc; @BeforeEach Loading Loading
vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/client/VOSpaceClient.java +13 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; import java.util.List; import java.util.Scanner; import java.util.concurrent.CompletionException; import java.util.concurrent.ForkJoinPool; Loading @@ -23,6 +24,7 @@ import javax.servlet.http.HttpSession; import javax.xml.bind.JAXB; import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Protocol; import net.ivoa.xml.vospace.v2.Transfer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; Loading Loading @@ -82,6 +84,17 @@ public class VOSpaceClient { return call(request, BodyHandlers.ofInputStream(), 200, res -> unmarshal(res, JobSummary.class)); } public List<Protocol> getDownloadEndpoints(Transfer transfer) { HttpRequest request = getRequest("/synctrans") .header("Accept", useJson ? "application/json" : "text/xml") .header("Content-Type", useJson ? "application/json" : "text/xml") .POST(HttpRequest.BodyPublishers.ofString(marshal(transfer))) .build(); return call(request, BodyHandlers.ofInputStream(), 200, res -> unmarshal(res, Transfer.class)).getProtocols(); } private <T, U> U call(HttpRequest request, HttpResponse.BodyHandler<T> responseBodyHandler, int expectedStatusCode, Function<T, U> responseHandler) { try { return httpClient.sendAsync(request, responseBodyHandler) Loading
vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/JobController.java +1 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ public class JobController { transfer.setTarget("vos://" + authority + paths.get(0)); Protocol protocol = new Protocol(); protocol.setUri("ia2:tape-recall"); transfer.getProtocol().add(protocol); transfer.getProtocols().add(protocol); JobSummary job = client.startTransferJob(transfer); Loading
vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/NodesController.java +46 −11 Original line number Diff line number Diff line package it.inaf.ia2.vospace.ui.controller; import it.inaf.ia2.vospace.ui.client.VOSpaceClient; import it.inaf.ia2.vospace.ui.service.NodesService; import javax.servlet.http.HttpServletRequest; import net.ivoa.xml.vospace.v2.Transfer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; 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.RestController; @RestController public class NodesController { @Value("${vospace-authority}") private String authority; @Autowired private NodesService nodesService; @Autowired private VOSpaceClient client; @Autowired private HttpServletRequest servletRequest; /** * This is the only API endpoint that returns HTML code instead of JSON. The * reason is that JavaScript frameworks are not very efficient in handling Loading @@ -23,21 +37,42 @@ public class NodesController { * document. */ @GetMapping(value = {"/nodes", "/nodes/**"}, produces = MediaType.TEXT_PLAIN_VALUE) public String listNodes(HttpServletRequest request) throws Exception { public String listNodes() throws Exception { String requestURL = request.getRequestURL().toString(); String[] split = requestURL.split("/nodes/"); String path = getPath("/nodes/"); String path = "/"; if (split.length == 2) { path += split[1]; return nodesService.generateNodesHtml(path); } return nodesService.generateNodesHtml(path); @GetMapping(value = "/download/**") public ResponseEntity<?> directDownload() { String path = getPath("/download/"); Transfer transfer = new Transfer(); transfer.setDirection("pullFromVoSpace"); transfer.setTarget("vos://" + authority + path); String url = client.getDownloadEndpoints(transfer).get(0).getEndpoint(); HttpHeaders headers = new HttpHeaders(); headers.set("Location", url); return new ResponseEntity<>(headers, HttpStatus.SEE_OTHER); } @GetMapping(value = "/download/{path}") public void directDownload(@PathVariable("path") String path) { // TODO: call pullFromVoSpace sync transfer /** * Slash is a special character in defining REST endpoints and trying to * define a PathVariable containing slashes doesn't work, so the endpoint * has been defined using "/nodes/**" instead of "/nodes/{path}" and the * path is extracted manually parsing the request URL. */ protected String getPath(String prefix) { String requestURL = servletRequest.getRequestURL().toString(); String[] split = requestURL.split(prefix); String path = "/"; if (split.length == 2) { path += split[1]; } return path; } }
vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/NodesControllerTest.java +9 −7 Original line number Diff line number Diff line Loading @@ -3,26 +3,28 @@ package it.inaf.ia2.vospace.ui.controller; import it.inaf.ia2.vospace.ui.service.NodesService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import static org.mockito.ArgumentMatchers.eq; import org.mockito.InjectMocks; import org.mockito.Mock; import static org.mockito.Mockito.verify; import org.mockito.junit.jupiter.MockitoExtension; 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.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.springframework.test.web.servlet.setup.MockMvcBuilders; @ExtendWith(MockitoExtension.class) @SpringBootTest @AutoConfigureMockMvc public class NodesControllerTest { @Mock @MockBean private NodesService nodesService; @InjectMocks @Autowired private NodesController controller; @Autowired private MockMvc mockMvc; @BeforeEach Loading