Loading src/main/java/it/inaf/oats/vospace/JobService.java +28 −13 Original line number Diff line number Diff line package it.inaf.oats.vospace; import it.inaf.oats.vospace.exception.InternalFaultException; import it.inaf.oats.vospace.persistence.JobDAO; 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 org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; Loading Loading @@ -43,35 +45,48 @@ public class JobService { private void startJob(JobSummary job) { switch (getJobType(job)) { Transfer transfer = uriService.getTransfer(job); switch (getJobType(transfer)) { case pullToVoSpace: handlePullToVoSpace(job); handlePullToVoSpace(job, transfer); break; case pullFromVoSpace: case pushToVoSpace: handleVoSpaceUrlsListResult(job); handleVoSpaceUrlsListResult(job, transfer); break; default: throw new UnsupportedOperationException("Not implemented yet"); } } private void handlePullToVoSpace(JobSummary job) { // TODO: check protocol private void handlePullToVoSpace(JobSummary job, Transfer transfer) { for (Protocol protocol : transfer.getProtocols()) { switch (protocol.getUri()) { case "ia2:async-recall": asyncTransfService.startJob(job); return; case "ivo://ivoa.net/vospace/core#httpget": String nodeUri = transfer.getTarget(); String contentUri = protocol.getEndpoint(); uriService.setNodeRemoteLocation(nodeUri, contentUri); uriService.setTransferJobResult(job, transfer); jobDAO.updateJob(job); return; default: throw new InternalFaultException("Unsupported pullToVoSpace protocol: " + protocol.getUri()); } } } private void handleVoSpaceUrlsListResult(JobSummary job) { private void handleVoSpaceUrlsListResult(JobSummary job, Transfer transfer) { job.setPhase(ExecutionPhase.EXECUTING); uriService.setTransferJobResult(job); uriService.setTransferJobResult(job, transfer); jobDAO.updateJob(job); } private JobType getJobType(JobSummary job) { // TODO: check types Transfer transfer = (Transfer) job.getJobInfo().getAny().get(0); private JobType getJobType(Transfer transfer) { return JobType.valueOf(transfer.getDirection()); } Loading src/main/java/it/inaf/oats/vospace/SetNodeController.java 0 → 100644 +95 −0 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.NodeUtils; import it.inaf.oats.vospace.exception.LinkFoundException; import it.inaf.oats.vospace.exception.NodeNotFoundException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.persistence.NodeDAO; import java.util.List; import javax.servlet.http.HttpServletRequest; import net.ivoa.xml.vospace.v2.Node; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class SetNodeController extends BaseNodeController { @Autowired private NodeDAO nodeDao; @Value("${vospace-authority}") private String authority; @PostMapping(value = {"/nodes", "/nodes/**"}, consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}) public Node setNode(@RequestBody Node node, User principal, HttpServletRequest request) { String path = getPath(); //The service SHALL throw a HTTP 404 status code including a NodeNotFound //fault in the entity-body if the target Node does not exist Node toBeModifiedNode = nodeDao.listNode(path) .orElseThrow(() -> new NodeNotFoundException(path)); // The service SHALL throw a HTTP 403 status code including a PermissionDenied fault // in the entity-body if the user does not have permissions to perform the operation if(!NodeUtils.checkIfWritable(toBeModifiedNode, principal.getName(), principal.getGroups())) { throw new PermissionDeniedException(path); } // The service SHALL throw a HTTP 403 status code including a PermissionDenied fault // in the entity-body if the request attempts to modify a read-only Property. // This method cannot be used to modify the Node type. // This method cannot be used to modify the accepts or provides list of Views for the Node. // This method cannot be used to create children of a container Node. // If a parent node in the URI path does not exist then the service SHALL throw a // HTTP 404 status code including a ContainerNotFound fault in the entity-body // For example, given the URI path /a/b/c, the service must throw a HTTP 404 status // code including a ContainerNotFound fault in the entity-body if either /a or /a/b // do not exist. List<String> pathComponents = NodeUtils.subPathComponents(path); if (pathComponents.size() == 0) { // Manage root node throw new PermissionDeniedException("root"); } else { // Manage all precursors in full path for (int i = 0; i < pathComponents.size(); i++) { String tmpPath = pathComponents.get(i); Node mynode = nodeDao.listNode(tmpPath) .orElseThrow(() -> new NodeNotFoundException(tmpPath)); if (mynode.getType().equals("vos:LinkNode") && i < pathComponents.size()-1) // a LinkNode leaf can be deleted throw new LinkFoundException(tmpPath); } } //The service SHOULD throw a HTTP 500 status code including an InternalFault fault // in the entity-body if the operation fails // to be fixed // A HTTP 200 status code and a Node representation in the entity-body The full // expanded record for the node SHALL be returned, including any xsi:type // specific extensions. return node; } } src/main/java/it/inaf/oats/vospace/UriService.java +68 −14 Original line number Diff line number Diff line Loading @@ -5,11 +5,18 @@ import it.inaf.ia2.aa.data.User; import it.inaf.ia2.rap.client.call.TokenExchangeRequest; import it.inaf.oats.vospace.datamodel.NodeProperties; 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.persistence.LocationDAO; import it.inaf.oats.vospace.persistence.NodeDAO; import it.inaf.oats.vospace.persistence.model.Location; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; 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; Loading @@ -31,21 +38,25 @@ public class UriService { @Autowired private NodeDAO nodeDao; @Autowired private LocationDAO locationDAO; @Autowired private HttpServletRequest servletRequest; @Autowired private ServletRapClient rapClient; public void setTransferJobResult(JobSummary job) { public void setTransferJobResult(JobSummary job, Transfer transfer) { List<ResultReference> results = new ArrayList<>(); ResultReference result = new ResultReference(); result.setHref(getEndpoint(job)); result.setHref(getEndpoint(job, transfer)); results.add(result); job.setResults(results); job.setPhase(ExecutionPhase.COMPLETED); } public void setSyncTransferEndpoints(JobSummary job) { Loading @@ -58,22 +69,35 @@ public class UriService { && !"ivo://ivoa.net/vospace/core#httpput".equals(protocol.getUri())) { throw new IllegalStateException("Unsupported protocol " + protocol.getUri()); } protocol.setEndpoint(getEndpoint(job)); protocol.setEndpoint(getEndpoint(job, transfer)); } private String getEndpoint(JobSummary job) { Transfer transfer = getTransfer(job); private String getEndpoint(JobSummary job, Transfer transfer) { String relativePath = transfer.getTarget().substring("vos://".length() + authority.length()); Node node = nodeDao.listNode(relativePath).orElseThrow(() -> new NodeNotFoundException(relativePath)); // TODO build the path according to node type // String endpoint = fileServiceUrl + urlEncodePath(relativePath) + "?jobId=" + job.getJobId(); Location location = locationDAO.getNodeLocation(relativePath).orElseThrow(() -> new InternalFaultException("No registered location found for vos_path " + relativePath)); if (!"true".equals(NodeProperties.getNodePropertiesListByURI(node, NodeProperties.PUBLIC_READ_URI))) { String endpoint; switch (location.getType()) { case PORTAL: String fileName = nodeDao.getNodeOsName(relativePath); endpoint = "http://" + location.getSource().getHostname() + location.getSource().getBasePath(); if (!endpoint.endsWith("/")) { endpoint += "/"; } endpoint += fileName; break; default: endpoint = fileServiceUrl + urlEncodePath(relativePath); } endpoint += "?jobId=" + job.getJobId(); if (!"true".equals(NodeProperties.getNodePropertyAsListByURI(node, NodeProperties.PUBLIC_READ_URI))) { endpoint += "&token=" + getEndpointToken(fileServiceUrl + relativePath); } Loading @@ -85,8 +109,7 @@ public class UriService { String token = ((User) servletRequest.getUserPrincipal()).getAccessToken(); if (token == null) { // TODO: use PermissionDenied VoSpaceException throw new IllegalStateException("Token is null"); throw new PermissionDeniedException("Token is null"); } TokenExchangeRequest exchangeRequest = new TokenExchangeRequest() Loading @@ -97,8 +120,39 @@ public class UriService { return rapClient.exchangeToken(exchangeRequest, servletRequest); } private Transfer getTransfer(JobSummary job) { // TODO add checks on data type public void setNodeRemoteLocation(String nodeUri, String contentUri) { URL url; try { url = new URL(contentUri); } catch (MalformedURLException ex) { throw new InternalFaultException(ex); } Location location = locationDAO.findPortalLocation(url.getHost()).orElseThrow(() -> new InternalFaultException("No registered location found for host " + url.getHost())); String vosPath = nodeUri.replaceAll("vos://[^/]+", ""); String fileName = url.getPath().substring(url.getPath().lastIndexOf("/") + 1); nodeDao.setNodeLocation(vosPath, location.getId(), fileName); } public Transfer getTransfer(JobSummary job) { List<Object> jobPayload = job.getJobInfo().getAny(); if (jobPayload.isEmpty()) { throw new IllegalStateException("Empty job payload for job " + job.getJobId()); } if (jobPayload.size() > 1) { throw new IllegalStateException("Multiple objects in job payload not supported"); } if (!(jobPayload.get(0) instanceof Transfer)) { throw new IllegalStateException(jobPayload.get(0).getClass().getCanonicalName() + " not supported as job payload. Job id: " + job.getJobId()); } return (Transfer) job.getJobInfo().getAny().get(0); } } src/main/java/it/inaf/oats/vospace/exception/InternalFaultException.java +14 −8 Original line number Diff line number Diff line /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package it.inaf.oats.vospace.exception; 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 { private static final Logger LOG = LoggerFactory.getLogger(InternalFaultException.class); public InternalFaultException(String msg) { super("InternalFaultException: " + msg); } public InternalFaultException(Throwable cause) { super("InternalFaultException: " + getMessage(cause)); } private static String getMessage(Throwable cause) { LOG.error("Exception caught", cause); return cause.getMessage() != null ? cause.getMessage() : cause.getClass().getCanonicalName(); } } src/main/java/it/inaf/oats/vospace/persistence/LocationDAO.java 0 → 100644 +113 −0 Original line number Diff line number Diff line package it.inaf.oats.vospace.persistence; import it.inaf.oats.vospace.persistence.model.Location; import it.inaf.oats.vospace.persistence.model.LocationType; import it.inaf.oats.vospace.persistence.model.Storage; import it.inaf.oats.vospace.persistence.model.StorageType; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Supplier; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class LocationDAO { private final JdbcTemplate jdbcTemplate; @Autowired public LocationDAO(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); } public Optional<Location> findPortalLocation(String host) { String sql = "SELECT location_id, location_type, storage_src_id, storage_dest_id,\n" + "storage_id, storage_type, base_path, hostname\n" + "FROM location l\n" + "JOIN storage s ON l.storage_src_id = s.storage_id OR l.storage_dest_id = s.storage_id\n" + "WHERE hostname = ?"; return jdbcTemplate.query(sql, ps -> { ps.setString(1, host); }, rs -> { return getLocation(rs, () -> new IllegalStateException("Found multiple locations for the same hostname")); }); } public Optional<Location> getNodeLocation(String vosPath) { String sql = "SELECT location_id, location_type, storage_src_id, storage_dest_id,\n" + "storage_id, storage_type, base_path, hostname\n" + "FROM location l\n" + "JOIN storage s ON l.storage_src_id = s.storage_id OR l.storage_dest_id = s.storage_id\n" + "WHERE location_id = (\n" + "SELECT location_id FROM node n\n" + "JOIN node_vos_path p ON n.node_id = p.node_id\n" + "WHERE p.vos_path = ?)"; return jdbcTemplate.query(sql, ps -> { ps.setString(1, vosPath); }, rs -> { return getLocation(rs, () -> new IllegalStateException("Found multiple locations for the same vos_path")); }); } private Optional<Location> getLocation(ResultSet rs, Supplier<IllegalStateException> exceptionSupplier) throws SQLException { List<Location> locations = getLocations(rs); if (locations.isEmpty()) { return Optional.empty(); } if (locations.size() > 1) { throw exceptionSupplier.get(); } return Optional.of(locations.get(0)); } private List<Location> getLocations(ResultSet rs) throws SQLException { Map<Integer, Storage> storagesMap = new HashMap<>(); Map<Integer, Location> locationsMap = new HashMap<>(); while (rs.next()) { int locationId = rs.getInt("location_id"); Location location = locationsMap.get(locationId); if (location == null) { location = new Location(); location.setId(locationId); locationsMap.put(locationId, location); } location.setType(LocationType.parse(rs.getString("location_type"))); int storageId = rs.getInt("storage_id"); Storage storage = storagesMap.get(storageId); if (storage == null) { storage = new Storage(); storage.setId(storageId); storagesMap.put(storageId, storage); } storage.setType(StorageType.parse(rs.getString("storage_type"))); storage.setBasePath(rs.getString("base_path")); storage.setHostname(rs.getString("hostname")); Storage storageSrc = storagesMap.get(rs.getInt("storage_src_id")); if (storageSrc != null) { location.setSource(storageSrc); } Storage storageDest = storagesMap.get(rs.getInt("storage_dest_id")); if (storageDest != null) { location.setDestination(storageDest); } } return new ArrayList<>(locationsMap.values()); } } Loading
src/main/java/it/inaf/oats/vospace/JobService.java +28 −13 Original line number Diff line number Diff line package it.inaf.oats.vospace; import it.inaf.oats.vospace.exception.InternalFaultException; import it.inaf.oats.vospace.persistence.JobDAO; 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 org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; Loading Loading @@ -43,35 +45,48 @@ public class JobService { private void startJob(JobSummary job) { switch (getJobType(job)) { Transfer transfer = uriService.getTransfer(job); switch (getJobType(transfer)) { case pullToVoSpace: handlePullToVoSpace(job); handlePullToVoSpace(job, transfer); break; case pullFromVoSpace: case pushToVoSpace: handleVoSpaceUrlsListResult(job); handleVoSpaceUrlsListResult(job, transfer); break; default: throw new UnsupportedOperationException("Not implemented yet"); } } private void handlePullToVoSpace(JobSummary job) { // TODO: check protocol private void handlePullToVoSpace(JobSummary job, Transfer transfer) { for (Protocol protocol : transfer.getProtocols()) { switch (protocol.getUri()) { case "ia2:async-recall": asyncTransfService.startJob(job); return; case "ivo://ivoa.net/vospace/core#httpget": String nodeUri = transfer.getTarget(); String contentUri = protocol.getEndpoint(); uriService.setNodeRemoteLocation(nodeUri, contentUri); uriService.setTransferJobResult(job, transfer); jobDAO.updateJob(job); return; default: throw new InternalFaultException("Unsupported pullToVoSpace protocol: " + protocol.getUri()); } } } private void handleVoSpaceUrlsListResult(JobSummary job) { private void handleVoSpaceUrlsListResult(JobSummary job, Transfer transfer) { job.setPhase(ExecutionPhase.EXECUTING); uriService.setTransferJobResult(job); uriService.setTransferJobResult(job, transfer); jobDAO.updateJob(job); } private JobType getJobType(JobSummary job) { // TODO: check types Transfer transfer = (Transfer) job.getJobInfo().getAny().get(0); private JobType getJobType(Transfer transfer) { return JobType.valueOf(transfer.getDirection()); } Loading
src/main/java/it/inaf/oats/vospace/SetNodeController.java 0 → 100644 +95 −0 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.NodeUtils; import it.inaf.oats.vospace.exception.LinkFoundException; import it.inaf.oats.vospace.exception.NodeNotFoundException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.persistence.NodeDAO; import java.util.List; import javax.servlet.http.HttpServletRequest; import net.ivoa.xml.vospace.v2.Node; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class SetNodeController extends BaseNodeController { @Autowired private NodeDAO nodeDao; @Value("${vospace-authority}") private String authority; @PostMapping(value = {"/nodes", "/nodes/**"}, consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}) public Node setNode(@RequestBody Node node, User principal, HttpServletRequest request) { String path = getPath(); //The service SHALL throw a HTTP 404 status code including a NodeNotFound //fault in the entity-body if the target Node does not exist Node toBeModifiedNode = nodeDao.listNode(path) .orElseThrow(() -> new NodeNotFoundException(path)); // The service SHALL throw a HTTP 403 status code including a PermissionDenied fault // in the entity-body if the user does not have permissions to perform the operation if(!NodeUtils.checkIfWritable(toBeModifiedNode, principal.getName(), principal.getGroups())) { throw new PermissionDeniedException(path); } // The service SHALL throw a HTTP 403 status code including a PermissionDenied fault // in the entity-body if the request attempts to modify a read-only Property. // This method cannot be used to modify the Node type. // This method cannot be used to modify the accepts or provides list of Views for the Node. // This method cannot be used to create children of a container Node. // If a parent node in the URI path does not exist then the service SHALL throw a // HTTP 404 status code including a ContainerNotFound fault in the entity-body // For example, given the URI path /a/b/c, the service must throw a HTTP 404 status // code including a ContainerNotFound fault in the entity-body if either /a or /a/b // do not exist. List<String> pathComponents = NodeUtils.subPathComponents(path); if (pathComponents.size() == 0) { // Manage root node throw new PermissionDeniedException("root"); } else { // Manage all precursors in full path for (int i = 0; i < pathComponents.size(); i++) { String tmpPath = pathComponents.get(i); Node mynode = nodeDao.listNode(tmpPath) .orElseThrow(() -> new NodeNotFoundException(tmpPath)); if (mynode.getType().equals("vos:LinkNode") && i < pathComponents.size()-1) // a LinkNode leaf can be deleted throw new LinkFoundException(tmpPath); } } //The service SHOULD throw a HTTP 500 status code including an InternalFault fault // in the entity-body if the operation fails // to be fixed // A HTTP 200 status code and a Node representation in the entity-body The full // expanded record for the node SHALL be returned, including any xsi:type // specific extensions. return node; } }
src/main/java/it/inaf/oats/vospace/UriService.java +68 −14 Original line number Diff line number Diff line Loading @@ -5,11 +5,18 @@ import it.inaf.ia2.aa.data.User; import it.inaf.ia2.rap.client.call.TokenExchangeRequest; import it.inaf.oats.vospace.datamodel.NodeProperties; 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.persistence.LocationDAO; import it.inaf.oats.vospace.persistence.NodeDAO; import it.inaf.oats.vospace.persistence.model.Location; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; 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; Loading @@ -31,21 +38,25 @@ public class UriService { @Autowired private NodeDAO nodeDao; @Autowired private LocationDAO locationDAO; @Autowired private HttpServletRequest servletRequest; @Autowired private ServletRapClient rapClient; public void setTransferJobResult(JobSummary job) { public void setTransferJobResult(JobSummary job, Transfer transfer) { List<ResultReference> results = new ArrayList<>(); ResultReference result = new ResultReference(); result.setHref(getEndpoint(job)); result.setHref(getEndpoint(job, transfer)); results.add(result); job.setResults(results); job.setPhase(ExecutionPhase.COMPLETED); } public void setSyncTransferEndpoints(JobSummary job) { Loading @@ -58,22 +69,35 @@ public class UriService { && !"ivo://ivoa.net/vospace/core#httpput".equals(protocol.getUri())) { throw new IllegalStateException("Unsupported protocol " + protocol.getUri()); } protocol.setEndpoint(getEndpoint(job)); protocol.setEndpoint(getEndpoint(job, transfer)); } private String getEndpoint(JobSummary job) { Transfer transfer = getTransfer(job); private String getEndpoint(JobSummary job, Transfer transfer) { String relativePath = transfer.getTarget().substring("vos://".length() + authority.length()); Node node = nodeDao.listNode(relativePath).orElseThrow(() -> new NodeNotFoundException(relativePath)); // TODO build the path according to node type // String endpoint = fileServiceUrl + urlEncodePath(relativePath) + "?jobId=" + job.getJobId(); Location location = locationDAO.getNodeLocation(relativePath).orElseThrow(() -> new InternalFaultException("No registered location found for vos_path " + relativePath)); if (!"true".equals(NodeProperties.getNodePropertiesListByURI(node, NodeProperties.PUBLIC_READ_URI))) { String endpoint; switch (location.getType()) { case PORTAL: String fileName = nodeDao.getNodeOsName(relativePath); endpoint = "http://" + location.getSource().getHostname() + location.getSource().getBasePath(); if (!endpoint.endsWith("/")) { endpoint += "/"; } endpoint += fileName; break; default: endpoint = fileServiceUrl + urlEncodePath(relativePath); } endpoint += "?jobId=" + job.getJobId(); if (!"true".equals(NodeProperties.getNodePropertyAsListByURI(node, NodeProperties.PUBLIC_READ_URI))) { endpoint += "&token=" + getEndpointToken(fileServiceUrl + relativePath); } Loading @@ -85,8 +109,7 @@ public class UriService { String token = ((User) servletRequest.getUserPrincipal()).getAccessToken(); if (token == null) { // TODO: use PermissionDenied VoSpaceException throw new IllegalStateException("Token is null"); throw new PermissionDeniedException("Token is null"); } TokenExchangeRequest exchangeRequest = new TokenExchangeRequest() Loading @@ -97,8 +120,39 @@ public class UriService { return rapClient.exchangeToken(exchangeRequest, servletRequest); } private Transfer getTransfer(JobSummary job) { // TODO add checks on data type public void setNodeRemoteLocation(String nodeUri, String contentUri) { URL url; try { url = new URL(contentUri); } catch (MalformedURLException ex) { throw new InternalFaultException(ex); } Location location = locationDAO.findPortalLocation(url.getHost()).orElseThrow(() -> new InternalFaultException("No registered location found for host " + url.getHost())); String vosPath = nodeUri.replaceAll("vos://[^/]+", ""); String fileName = url.getPath().substring(url.getPath().lastIndexOf("/") + 1); nodeDao.setNodeLocation(vosPath, location.getId(), fileName); } public Transfer getTransfer(JobSummary job) { List<Object> jobPayload = job.getJobInfo().getAny(); if (jobPayload.isEmpty()) { throw new IllegalStateException("Empty job payload for job " + job.getJobId()); } if (jobPayload.size() > 1) { throw new IllegalStateException("Multiple objects in job payload not supported"); } if (!(jobPayload.get(0) instanceof Transfer)) { throw new IllegalStateException(jobPayload.get(0).getClass().getCanonicalName() + " not supported as job payload. Job id: " + job.getJobId()); } return (Transfer) job.getJobInfo().getAny().get(0); } }
src/main/java/it/inaf/oats/vospace/exception/InternalFaultException.java +14 −8 Original line number Diff line number Diff line /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package it.inaf.oats.vospace.exception; 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 { private static final Logger LOG = LoggerFactory.getLogger(InternalFaultException.class); public InternalFaultException(String msg) { super("InternalFaultException: " + msg); } public InternalFaultException(Throwable cause) { super("InternalFaultException: " + getMessage(cause)); } private static String getMessage(Throwable cause) { LOG.error("Exception caught", cause); return cause.getMessage() != null ? cause.getMessage() : cause.getClass().getCanonicalName(); } }
src/main/java/it/inaf/oats/vospace/persistence/LocationDAO.java 0 → 100644 +113 −0 Original line number Diff line number Diff line package it.inaf.oats.vospace.persistence; import it.inaf.oats.vospace.persistence.model.Location; import it.inaf.oats.vospace.persistence.model.LocationType; import it.inaf.oats.vospace.persistence.model.Storage; import it.inaf.oats.vospace.persistence.model.StorageType; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Supplier; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class LocationDAO { private final JdbcTemplate jdbcTemplate; @Autowired public LocationDAO(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); } public Optional<Location> findPortalLocation(String host) { String sql = "SELECT location_id, location_type, storage_src_id, storage_dest_id,\n" + "storage_id, storage_type, base_path, hostname\n" + "FROM location l\n" + "JOIN storage s ON l.storage_src_id = s.storage_id OR l.storage_dest_id = s.storage_id\n" + "WHERE hostname = ?"; return jdbcTemplate.query(sql, ps -> { ps.setString(1, host); }, rs -> { return getLocation(rs, () -> new IllegalStateException("Found multiple locations for the same hostname")); }); } public Optional<Location> getNodeLocation(String vosPath) { String sql = "SELECT location_id, location_type, storage_src_id, storage_dest_id,\n" + "storage_id, storage_type, base_path, hostname\n" + "FROM location l\n" + "JOIN storage s ON l.storage_src_id = s.storage_id OR l.storage_dest_id = s.storage_id\n" + "WHERE location_id = (\n" + "SELECT location_id FROM node n\n" + "JOIN node_vos_path p ON n.node_id = p.node_id\n" + "WHERE p.vos_path = ?)"; return jdbcTemplate.query(sql, ps -> { ps.setString(1, vosPath); }, rs -> { return getLocation(rs, () -> new IllegalStateException("Found multiple locations for the same vos_path")); }); } private Optional<Location> getLocation(ResultSet rs, Supplier<IllegalStateException> exceptionSupplier) throws SQLException { List<Location> locations = getLocations(rs); if (locations.isEmpty()) { return Optional.empty(); } if (locations.size() > 1) { throw exceptionSupplier.get(); } return Optional.of(locations.get(0)); } private List<Location> getLocations(ResultSet rs) throws SQLException { Map<Integer, Storage> storagesMap = new HashMap<>(); Map<Integer, Location> locationsMap = new HashMap<>(); while (rs.next()) { int locationId = rs.getInt("location_id"); Location location = locationsMap.get(locationId); if (location == null) { location = new Location(); location.setId(locationId); locationsMap.put(locationId, location); } location.setType(LocationType.parse(rs.getString("location_type"))); int storageId = rs.getInt("storage_id"); Storage storage = storagesMap.get(storageId); if (storage == null) { storage = new Storage(); storage.setId(storageId); storagesMap.put(storageId, storage); } storage.setType(StorageType.parse(rs.getString("storage_type"))); storage.setBasePath(rs.getString("base_path")); storage.setHostname(rs.getString("hostname")); Storage storageSrc = storagesMap.get(rs.getInt("storage_src_id")); if (storageSrc != null) { location.setSource(storageSrc); } Storage storageDest = storagesMap.get(rs.getInt("storage_dest_id")); if (storageDest != null) { location.setDestination(storageDest); } } return new ArrayList<>(locationsMap.values()); } }