Commit e3c3a2fa authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Implemented basic pullFromVoSpace

parent 2fa69146
Loading
Loading
Loading
Loading
+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);
    }
}
+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();
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -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
+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"));
    }
}
+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());
    }
}