Skip to content
Snippets Groups Projects
Commit e37671ea authored by Nicola Fulvio Calabria's avatar Nicola Fulvio Calabria
Browse files

Task #3603 completed

parent dd18567a
Branches
Tags
No related merge requests found
......@@ -19,7 +19,7 @@ public class JobService {
@Autowired
private TapeService tapeService;
enum JobType {
public enum JobType {
pullToVoSpace,
pullFromVoSpace,
pushToVoSpace,
......
......@@ -7,6 +7,8 @@ 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.uws.v1.Jobs;
import net.ivoa.xml.uws.v1.ShortJobDescription;
import net.ivoa.xml.vospace.v2.Transfer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
......@@ -19,6 +21,9 @@ 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;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.List;
@RestController
public class TransferController {
......@@ -103,6 +108,41 @@ public class TransferController {
return ResponseEntity.ok(jobDAO.getJob(jobId).get().getPhase().toString());
}
@GetMapping(value = "/transfers", produces = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<?> getTransfers(
@RequestParam(value = "PHASE", required = false) Optional<List<ExecutionPhase>> phase,
@RequestParam(value = "AFTER", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Optional<LocalDateTime> after,
@RequestParam(value = "LAST", required = false) Optional<Integer> last,
@RequestParam(value = "direction", required = false) Optional<List<JobService.JobType>> direction,
User principal) {
if(last.isPresent())
{
if(last.get() <= 0)
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}
String userId = principal.getName();
List<ExecutionPhase> phaseList;
if (phase.isPresent()) {
phaseList = phase.get();
} else {
phaseList = List.of();
}
List<JobService.JobType> directionList;
if (direction.isPresent()) {
directionList = direction.get();
} else {
directionList = List.of();
}
Jobs jobs = jobDAO.getJobs(userId, phaseList, directionList, after, last);
return ResponseEntity.ok(jobs);
}
private JobSummary newJobSummary(Transfer transfer, User principal) {
String jobId = UUID.randomUUID().toString().replace("-", "");
......
......@@ -3,19 +3,29 @@ package it.inaf.oats.vospace.persistence;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.sql.Timestamp;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import java.util.Optional;
import javax.sql.DataSource;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import net.ivoa.xml.uws.v1.ExecutionPhase;
import net.ivoa.xml.uws.v1.JobSummary;
import net.ivoa.xml.uws.v1.ShortJobDescription;
import net.ivoa.xml.uws.v1.ResultReference;
import net.ivoa.xml.uws.v1.Jobs;
import it.inaf.oats.vospace.JobService;
import net.ivoa.xml.vospace.v2.Transfer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.time.LocalDateTime;
import java.math.BigDecimal;
@Repository
public class JobDAO {
......@@ -105,6 +115,106 @@ public class JobDAO {
return jobSummary;
}
public Jobs getJobs(String userId,
List<ExecutionPhase> phaseList,
List<JobService.JobType> directionList,
Optional<LocalDateTime> after,
Optional<Integer> last
) {
Jobs jobs = new Jobs();
jobs.setVersion("1.1");
List<ShortJobDescription> sjdList = jobs.getJobref();
// Query db to fill ShortJobDescription list
ArrayList<Object> queryParams = new ArrayList<>();
ArrayList<Integer> queryParamTypes = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb.append("SELECT * FROM job");
sb.append(" WHERE owner_id = ?");
queryParams.add(userId);
queryParamTypes.add(Types.VARCHAR);
// Fill conditions on execution phase
if (phaseList.isEmpty()) {
sb.append(" AND phase NOT IN (?)");
queryParams.add(ExecutionPhase.ARCHIVED);
queryParamTypes.add(Types.OTHER);
} else {
sb.append(" AND phase IN (");
for (int i = 0; i < phaseList.size(); i++) {
sb.append("?");
queryParams.add(phaseList.get(i));
queryParamTypes.add(Types.OTHER);
if (i < phaseList.size() - 1) {
sb.append(",");
}
}
sb.append(")");
}
// Fill conditions on type list
if (!directionList.isEmpty()) {
sb.append(" AND job_type IN (");
for (int i = 0; i < directionList.size(); i++) {
sb.append("?");
queryParams.add(directionList.get(i));
queryParamTypes.add(Types.OTHER);
if (i < directionList.size() - 1) {
sb.append(",");
}
}
sb.append(")");
}
// Fill conditions on creation date
if (after.isPresent()) {
sb.append(" AND creation_time > ?");
queryParams.add(after.get());
queryParamTypes.add(Types.TIMESTAMP);
}
sb.append(" ORDER BY creation_time DESC");
if (last.isPresent()) {
sb.append(" LIMIT ?");
//sb.append(last.get().toString());
queryParams.add(last.get());
queryParamTypes.add(Types.INTEGER);
}
String sql = sb.toString();
// Perform query
jdbcTemplate.query(sql,
(ps) -> {
for (int i = 0; i < queryParams.size(); i++) {
ps.setObject(i + 1, queryParams.get(i),
queryParamTypes.get(i));
}
},
(rs) -> {
sjdList.add(getShortJobDescriptionFromCurrentRow(rs));
}
);
return jobs;
}
private ShortJobDescription getShortJobDescriptionFromCurrentRow(ResultSet rs)
throws SQLException {
ShortJobDescription sjd = new ShortJobDescription();
sjd.setId(rs.getString("job_id"));
sjd.setOwnerId(rs.getString("owner_id"));
sjd.setType(rs.getString("job_type"));
sjd.setPhase(ExecutionPhase.fromValue(rs.getString("phase")));
sjd.setCreationTime(
toXMLGregorianCalendar(rs.getTimestamp("creation_time")));
return sjd;
}
private Object getJobPayload(String jobType, String json) {
try {
// TODO: switch on jobType
......@@ -145,4 +255,27 @@ public class JobDAO {
throw new RuntimeException(ex);
}
}
public static XMLGregorianCalendar toXMLGregorianCalendar(Timestamp t)
{
XMLGregorianCalendar cal = null;
try{
cal = DatatypeFactory.newInstance().newXMLGregorianCalendar();
LocalDateTime ldt = t.toLocalDateTime();
cal.setYear(ldt.getYear());
cal.setMonth(ldt.getMonthValue());
cal.setDay(ldt.getDayOfMonth());
cal.setHour(ldt.getHour());
cal.setMinute(ldt.getMinute());
cal.setSecond(ldt.getSecond());
cal.setFractionalSecond(new BigDecimal("0." + ldt.getNano()));
} catch(Exception e) {
e.printStackTrace();
}
return cal;
}
}
......@@ -6,9 +6,13 @@ import it.inaf.oats.vospace.persistence.JobDAO;
import it.inaf.oats.vospace.persistence.NodeDAO;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Optional;
import net.ivoa.xml.uws.v1.ExecutionPhase;
import net.ivoa.xml.uws.v1.JobSummary;
import net.ivoa.xml.uws.v1.Jobs;
import net.ivoa.xml.uws.v1.ShortJobDescription;
import net.ivoa.xml.vospace.v2.DataNode;
import net.ivoa.xml.vospace.v2.Node;
import net.ivoa.xml.vospace.v2.Property;
......@@ -36,6 +40,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
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;
import java.util.List;
@SpringBootTest
@AutoConfigureMockMvc
......@@ -192,6 +197,51 @@ public class TransferControllerTest {
verify(jobDao, times(1)).getJob(eq("123"));
}
@Test
public void testGetJobs() throws Exception {
when(jobDao.getJobs(eq("user1"), any(), any(), any(), any()))
.thenReturn(this.getFakeJobs());
mockMvc.perform(get("/transfers")
.header("Authorization", "Bearer user1_token")
.param("LAST", "-3")
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is4xxClientError());
String xml2 = mockMvc.perform(get("/transfers")
.header("Authorization", "Bearer user1_token")
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
}
private Jobs getFakeJobs() {
Jobs jobs = new Jobs();
jobs.setVersion("1.1");
List<ShortJobDescription> sjdList = jobs.getJobref();
sjdList.add(getFakeSJD1());
return jobs;
}
private ShortJobDescription getFakeSJD1() {
ShortJobDescription sjd = new ShortJobDescription();
sjd.setId("pippo1");
sjd.setPhase(ExecutionPhase.QUEUED);
sjd.setOwnerId("user1");
sjd.setType(JobService.JobType.pullFromVoSpace.toString());
LocalDateTime now = LocalDateTime.now();
Timestamp ts = Timestamp.valueOf(now);
sjd.setCreationTime(JobDAO.toXMLGregorianCalendar(ts));
return sjd;
}
private JobSummary getFakePendingJob() {
JobSummary job = new JobSummary();
job.setPhase(ExecutionPhase.PENDING);
......
package it.inaf.oats.vospace.persistence;
import it.inaf.oats.vospace.JobService;
import java.util.List;
import javax.sql.DataSource;
import net.ivoa.xml.uws.v1.ExecutionPhase;
import net.ivoa.xml.uws.v1.JobSummary;
import net.ivoa.xml.vospace.v2.ContainerNode;
import net.ivoa.xml.uws.v1.ShortJobDescription;
import net.ivoa.xml.vospace.v2.Transfer;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
......@@ -14,6 +16,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.Optional;
import java.time.LocalDateTime;
import java.time.Month;
import net.ivoa.xml.uws.v1.Jobs;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {DataSourceConfig.class})
......@@ -54,4 +60,119 @@ public class JobDAOTest {
assertEquals(ExecutionPhase.EXECUTING, dao.getJob("123").get().getPhase());
}
@Test
public void testJobsList() {
// Check no arguments
String user = "user1";
List<ExecutionPhase> phaseList = List.of();
List<JobService.JobType> directionList = List.of();
Optional<LocalDateTime> after = Optional.ofNullable(null);
Optional<Integer> last = Optional.ofNullable(null);
Jobs jobs = dao.getJobs(user, phaseList, directionList, after, last);
assertTrue(jobs != null);
List<ShortJobDescription> sjdList = jobs.getJobref();
assertTrue(sjdList != null);
assertTrue(!sjdList.isEmpty());
assertTrue(
sjdList.stream().noneMatch(
(i) -> {
return i.getPhase().equals(ExecutionPhase.ARCHIVED);
}
)
);
assertEquals(3, sjdList.size());
}
@Test
public void testJobsListLimit() {
// Check no arguments
String user = "user1";
List<ExecutionPhase> phaseList = List.of();
List<JobService.JobType> directionList = List.of();
Optional<LocalDateTime> after = Optional.ofNullable(null);
Optional<Integer> last = Optional.of(2);
Jobs jobs = dao.getJobs(user, phaseList, directionList, after, last);
List<ShortJobDescription> sjdList = jobs.getJobref();
assertEquals(2, sjdList.size());
}
@Test
public void testJobsPhase() {
// Check no arguments
String user = "user1";
List<ExecutionPhase> phaseList
= List.of(ExecutionPhase.PENDING, ExecutionPhase.EXECUTING);
List<JobService.JobType> directionList = List.of();
Optional<LocalDateTime> after = Optional.ofNullable(null);
Optional<Integer> last = Optional.ofNullable(null);
Jobs jobs = dao.getJobs(user, phaseList, directionList, after, last);
List<ShortJobDescription> sjdList = jobs.getJobref();
assertEquals(sjdList.size(), 2);
assertEquals("pippo5", sjdList.get(0).getId());
assertEquals("pippo2", sjdList.get(1).getId());
}
@Test
public void testJobsDirection() {
// Check no arguments
String user = "user1";
List<ExecutionPhase> phaseList = List.of();
List<JobService.JobType> directionList
= List.of(JobService.JobType.pullFromVoSpace,
JobService.JobType.pullToVoSpace);
Optional<LocalDateTime> after = Optional.ofNullable(null);
Optional<Integer> last = Optional.ofNullable(null);
Jobs jobs = dao.getJobs(user, phaseList, directionList, after, last);
List<ShortJobDescription> sjdList = jobs.getJobref();
assertEquals(2, sjdList.size());
assertEquals("pippo3", sjdList.get(0).getId());
assertEquals("pippo2", sjdList.get(1).getId());
}
@Test
public void testJobsAfter() {
// Check no arguments
String user = "user1";
List<ExecutionPhase> phaseList = List.of();
List<JobService.JobType> directionList = List.of();
LocalDateTime ldt
= LocalDateTime.of(2013, Month.FEBRUARY, 7, 18, 15);
Optional<LocalDateTime> after = Optional.of(ldt);
Optional<Integer> last = Optional.ofNullable(null);
Jobs jobs = dao.getJobs(user, phaseList, directionList, after, last);
List<ShortJobDescription> sjdList = jobs.getJobref();
assertEquals(2, sjdList.size());
assertEquals("pippo5", sjdList.get(0).getId());
assertEquals("pippo3", sjdList.get(1).getId());
}
@Test
public void testJobsAllchecks() {
// Check no arguments
String user = "user1";
List<ExecutionPhase> phaseList = List.of(ExecutionPhase.QUEUED,
ExecutionPhase.PENDING);
List<JobService.JobType> directionList =
List.of(JobService.JobType.pullFromVoSpace,
JobService.JobType.pullToVoSpace);
LocalDateTime ldt
= LocalDateTime.of(2013, Month.FEBRUARY, 7, 18, 15);
Optional<LocalDateTime> after = Optional.of(ldt);
Optional<Integer> last = Optional.of(2);
Jobs jobs = dao.getJobs(user, phaseList, directionList, after, last);
List<ShortJobDescription> sjdList = jobs.getJobref();
assertEquals(1, sjdList.size());
assertEquals("pippo3", sjdList.get(0).getId());
}
}
......@@ -11,3 +11,12 @@ INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creat
INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id, is_public) VALUES ('', NULL, 'test2', 'container', 'user2', 'user2', true); -- /test2
INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id, is_public) VALUES ('5', '', 'f4', 'container', 'user2', 'user2', true); -- /test2/f4 (rel: /f4)
INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id, is_public) VALUES ('5', '', 'f5', 'container', 'user2', 'user2', true); -- /test2/f5 (rel: /f5)
DELETE FROM job;
INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo1', 'user1', 'pullFromVoSpace', 'ARCHIVED', NULL, NULL, '2011-06-22 19:10:25', NULL, NULL);
INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo2', 'user1', 'pullToVoSpace', 'PENDING', NULL, NULL, '2012-06-22 19:10:25', NULL, NULL);
INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo3', 'user1', 'pullFromVoSpace', 'QUEUED', NULL, NULL, '2013-06-22 19:10:25', NULL, NULL);
INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo4', 'user2', 'copyNode', 'PENDING', NULL, NULL, '2014-06-22 19:10:25', NULL, NULL);
INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo5', 'user1', 'pushToVoSpace', 'EXECUTING', NULL, NULL, '2015-06-22 19:10:25', NULL, NULL);
INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo6', 'user2', 'pullFromVoSpace', 'PENDING', NULL, NULL, '2015-06-22 19:10:25', NULL, NULL);
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment