Commit 305d2e29 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Implemented download

parent cb271a5e
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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)
+1 −1
Original line number Diff line number Diff line
@@ -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);

+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
@@ -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;
    }
}
+9 −7
Original line number Diff line number Diff line
@@ -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