Commit b0f23cd8 authored by Nicola Fulvio Calabria's avatar Nicola Fulvio Calabria
Browse files

Task #3637 - Added Fault management for transfer services up to 3/6

redmine subtasks
parent eff3f2ab
Loading
Loading
Loading
Loading
+52 −23
Original line number Diff line number Diff line
@@ -6,8 +6,10 @@ import net.ivoa.xml.uws.v1.ExecutionPhase;
import net.ivoa.xml.uws.v1.JobSummary;
import net.ivoa.xml.vospace.v2.Protocol;
import net.ivoa.xml.vospace.v2.Transfer;
import net.ivoa.xml.uws.v1.ErrorSummaryFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import it.inaf.oats.vospace.exception.VoSpaceErrorSummarizableException;

@Service
public class JobService {
@@ -61,30 +63,45 @@ public class JobService {
    }

    private void handlePullToVoSpace(JobSummary job, Transfer transfer) {

        try {
            for (Protocol protocol : transfer.getProtocols()) {
                switch (protocol.getUri()) {
                    case "ia2:async-recall":
                        asyncTransfService.startJob(job);
                        // ASK IF IT's OK neglect phase update.
                        return;
                    case "ivo://ivoa.net/vospace/core#httpget":
                        String nodeUri = transfer.getTarget();
                        String contentUri = protocol.getEndpoint();
                        uriService.setNodeRemoteLocation(nodeUri, contentUri);
                        uriService.setTransferJobResult(job, transfer);
                        job.setPhase(ExecutionPhase.COMPLETED);
                        jobDAO.updateJob(job);
                        return;
                    default:
                        throw new InternalFaultException("Unsupported pullToVoSpace protocol: " + protocol.getUri());
                }
            }
        } catch (VoSpaceErrorSummarizableException e) {
            job.setPhase(ExecutionPhase.ERROR);
            job.setErrorSummary(ErrorSummaryFactory.newErrorSummary(e.getFault()));
            jobDAO.updateJob(job);
        }
    }

    private void handleVoSpaceUrlsListResult(JobSummary job, Transfer transfer) {
        try {
            job.setPhase(ExecutionPhase.EXECUTING);
            uriService.setTransferJobResult(job, transfer);
            job.setPhase(ExecutionPhase.COMPLETED);
            // Need to catch other exceptions too to avoid inconsistent job status
        } catch (VoSpaceErrorSummarizableException e) {
            job.setPhase(ExecutionPhase.ERROR);
            job.setErrorSummary(ErrorSummaryFactory.newErrorSummary(e.getFault()));
        } finally {
            jobDAO.updateJob(job);
        }
    }

    private JobType getJobType(Transfer transfer) {
        return JobType.valueOf(transfer.getDirection());
@@ -92,11 +109,23 @@ public class JobService {

    /**
     * Synchronous transfer endpoint creates a job that is immediately set to
     * completed.
     * COMPLETED or to ERROR in case some fault occurred.
     *
     * In case of ERROR, Protocols are stripped from job representation in
     * compliance with specifications
     *
     */
    public void createSyncJobResult(JobSummary job) {
        job.setPhase(ExecutionPhase.COMPLETED);
        try {
            uriService.setSyncTransferEndpoints(job);
            job.setPhase(ExecutionPhase.COMPLETED);
            // Need to catch other exceptions too to avoid inconsistent job status
        } catch (VoSpaceErrorSummarizableException e) {
            job.setPhase(ExecutionPhase.ERROR);
            uriService.getTransfer(job).getProtocols().clear();
            job.setErrorSummary(ErrorSummaryFactory.newErrorSummary(e.getFault()));
        } finally {
            jobDAO.createJob(job);
        }
    }
}
+10 −7
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.datamodel.NodeProperties;
import it.inaf.oats.vospace.persistence.JobDAO;
import java.util.Optional;
import java.util.UUID;
@@ -9,6 +10,7 @@ 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.vospace.v2.Transfer;
import net.ivoa.xml.vospace.v2.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -23,6 +25,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@RestController
public class TransferController {
@@ -115,11 +118,11 @@ public class TransferController {
            @RequestParam(value = "direction", required = false) Optional<List<JobService.JobType>> direction,
            User principal) {

        if(last.isPresent())
        {
            if(last.get() <= 0) 
        if (last.isPresent()) {
            if (last.get() <= 0) {
                return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
            }
        }

        String userId = principal.getName();

+43 −6
Original line number Diff line number Diff line
@@ -3,11 +3,15 @@ package it.inaf.oats.vospace;
import it.inaf.ia2.aa.ServletRapClient;
import it.inaf.ia2.aa.data.User;
import it.inaf.ia2.rap.client.call.TokenExchangeRequest;
import it.inaf.oats.vospace.JobService.JobType;
import it.inaf.oats.vospace.datamodel.NodeProperties;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import static it.inaf.oats.vospace.datamodel.NodeUtils.urlEncodePath;
import it.inaf.oats.vospace.exception.InternalFaultException;
import it.inaf.oats.vospace.exception.NodeNotFoundException;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
import it.inaf.oats.vospace.exception.ProtocolNotSupportedException;
import it.inaf.oats.vospace.exception.NodeBusyException;
import it.inaf.oats.vospace.persistence.LocationDAO;
import it.inaf.oats.vospace.persistence.NodeDAO;
import it.inaf.oats.vospace.persistence.model.Location;
@@ -15,12 +19,14 @@ import it.inaf.oats.vospace.persistence.model.LocationType;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
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.ResultReference;
import net.ivoa.xml.vospace.v2.Node;
import net.ivoa.xml.vospace.v2.Param;
import net.ivoa.xml.vospace.v2.Protocol;
import net.ivoa.xml.vospace.v2.Transfer;
import org.springframework.beans.factory.annotation.Autowired;
@@ -57,7 +63,8 @@ public class UriService {
        results.add(result);

        job.setResults(results);
        job.setPhase(ExecutionPhase.COMPLETED);
        // Moved phase setting to caller method for ERROR management
        // job.setPhase(ExecutionPhase.COMPLETED);
    }

    public void setSyncTransferEndpoints(JobSummary job) {
@@ -68,7 +75,8 @@ public class UriService {

        if (!"ivo://ivoa.net/vospace/core#httpget".equals(protocol.getUri())
                && !"ivo://ivoa.net/vospace/core#httpput".equals(protocol.getUri())) {
            throw new IllegalStateException("Unsupported protocol " + protocol.getUri());
            // throw new IllegalStateException("Unsupported protocol " + protocol.getUri());
            throw new ProtocolNotSupportedException(protocol.getUri());
        }
        protocol.setEndpoint(getEndpoint(job, transfer));
    }
@@ -79,6 +87,35 @@ public class UriService {

        Node node = nodeDao.listNode(relativePath).orElseThrow(() -> new NodeNotFoundException(relativePath));
        
        User user = (User) servletRequest.getUserPrincipal();
        String creator = user.getName();
        List<String> groups = user.getGroups();

        // Check privileges write or read according to job type
        JobService.JobType jobType = JobType.valueOf(transfer.getDirection());

        switch (jobType) {
            case pushToVoSpace:
            case pullToVoSpace:
                if (!NodeUtils.checkIfWritable(node, creator, groups)) {
                    throw new PermissionDeniedException(relativePath);
                }
                break;

            case pullFromVoSpace:
                if (!NodeUtils.checkIfReadable(node, creator, groups)) {
                    throw new PermissionDeniedException(relativePath);
                }
                break;

            default:
                throw new InternalFaultException("No job direction specified");
        }

        if (NodeUtils.getIsBusy(node)) {
            throw new NodeBusyException(relativePath);
        }

        Location location = locationDAO.getNodeLocation(relativePath).orElse(null);

        String endpoint;
+4 −2
Original line number Diff line number Diff line
package it.inaf.oats.vospace.exception;

import net.ivoa.xml.uws.v1.ErrorSummaryFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value = HttpStatus.CONFLICT)
public class DuplicateNodeException extends VoSpaceException {
public class DuplicateNodeException extends VoSpaceErrorSummarizableException {

    public DuplicateNodeException(String path) {
        super("Duplicate Node at path: " + path);
        super("Duplicate Node at path: " + path,
                ErrorSummaryFactory.VOSpaceFault.DUPLICATE_NODE);
    }
}
+6 −3
Original line number Diff line number Diff line
package it.inaf.oats.vospace.exception;

import net.ivoa.xml.uws.v1.ErrorSummaryFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)   // Status code 500
public class InternalFaultException extends VoSpaceException {
public class InternalFaultException extends VoSpaceErrorSummarizableException {

    private static final Logger LOG = LoggerFactory.getLogger(InternalFaultException.class);

    public InternalFaultException(String msg) {
        super("InternalFaultException: " + msg);
        super("InternalFaultException: " + msg,
                ErrorSummaryFactory.VOSpaceFault.INTERNAL_FAULT);
    }

    public InternalFaultException(Throwable cause) {
        super("InternalFaultException: " + getMessage(cause));
        super("InternalFaultException: " + getMessage(cause),
                ErrorSummaryFactory.VOSpaceFault.INTERNAL_FAULT);
    }

    private static String getMessage(Throwable cause) {
Loading