Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mars receipt exception #96

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,27 @@
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.http.MediaType.APPLICATION_XML_VALUE;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
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 com.elixir.biohackaton.ISAToSRA.biosamples.model.BiosampleAccessionsMap;
import com.elixir.biohackaton.ISAToSRA.biosamples.service.BioSamplesSubmitter;
import com.elixir.biohackaton.ISAToSRA.biosamples.service.MarsReceiptService;
import com.elixir.biohackaton.ISAToSRA.receipt.isamodel.*;
import com.elixir.biohackaton.ISAToSRA.receipt.marsmodel.MarsReceipt;
import com.elixir.biohackaton.ISAToSRA.receipt.MarsReceiptException;
import com.elixir.biohackaton.ISAToSRA.receipt.isamodel.IsaJson;
import com.elixir.biohackaton.ISAToSRA.receipt.isamodel.Study;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;

import java.util.List;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
Expand All @@ -42,33 +48,37 @@ public class BioSampleSubmissionController {
consumes = { APPLICATION_JSON_VALUE, APPLICATION_XML_VALUE })
public String performSubmissionToBioSamplesAndEna(
@RequestBody final String submissionPayload,
@RequestParam(value = "webinjwt") String webinJwt)
throws Exception {
String webinToken;
if (webinJwt != null) {
webinToken = webinJwt;
} else {
throw new RuntimeException("Webin Authentication Token is not provided");
}
@RequestParam(value = "webinjwt") String webinJwt) {
try {
if (webinJwt == null || webinJwt.isEmpty()) {
throw new RuntimeException("Webin Authentication Token is not provided");
}

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

final IsaJson isaJson = this.objectMapper.readValue(submissionPayload, IsaJson.class);
final List<Study> studies = getStudies(isaJson);
final IsaJson isaJson = this.objectMapper.readValue(submissionPayload, IsaJson.class);
final List<Study> studies = getStudies(isaJson);

final BiosampleAccessionsMap accessionsMap = this.bioSamplesSubmitter.createBioSamples(studies, webinToken);
final MarsReceipt marsReceipt = marsReceiptService.convertReceiptToMars(accessionsMap, isaJson);
final BiosampleAccessionsMap accessionsMap = this.bioSamplesSubmitter.createBioSamples(studies, webinJwt);
marsReceiptService.convertReceiptToMars(accessionsMap, isaJson);

return marsReceiptService.convertMarsReceiptToJson(marsReceipt);
return marsReceiptService.convertMarsReceiptToJson();
} catch (final MarsReceiptException e) {
log.error("Mars receipt excption", e);
marsReceiptService.setMarsReceiptErrors(e.getError());
return marsReceiptService.convertMarsReceiptToJson();
} catch (final Exception e) {
log.error("Internal server error", e);
marsReceiptService.setMarsReceiptErrors(e.getMessage());
return marsReceiptService.convertMarsReceiptToJson();
}
}

public List<Study> getStudies(final IsaJson isaJson) {
try {
return isaJson.getInvestigation().getStudies();
} catch (final Exception e) {
log.info("Failed to parse ISA JSON and get studies", e);
throw new MarsReceiptException(e, "Failed to parse ISA JSON and get studies");
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
/** Elixir BioHackathon 2022 */
package com.elixir.biohackaton.ISAToSRA.biosamples.service;

import com.elixir.biohackaton.ISAToSRA.biosamples.model.Attribute;
import com.elixir.biohackaton.ISAToSRA.biosamples.model.BiosampleAccessionsMap;
import com.elixir.biohackaton.ISAToSRA.biosamples.model.Relationship;
import com.elixir.biohackaton.ISAToSRA.biosamples.model.BioSample;
import com.elixir.biohackaton.ISAToSRA.receipt.ReceiptAccessionsMap;
import com.elixir.biohackaton.ISAToSRA.receipt.isamodel.*;

import java.time.Instant;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.hateoas.EntityModel;
import org.springframework.http.HttpEntity;
Expand All @@ -21,10 +18,28 @@
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.elixir.biohackaton.ISAToSRA.biosamples.model.Attribute;
import com.elixir.biohackaton.ISAToSRA.biosamples.model.BioSample;
import com.elixir.biohackaton.ISAToSRA.biosamples.model.BiosampleAccessionsMap;
import com.elixir.biohackaton.ISAToSRA.biosamples.model.Relationship;
import com.elixir.biohackaton.ISAToSRA.receipt.MarsReceiptException;
import com.elixir.biohackaton.ISAToSRA.receipt.ReceiptAccessionsMap;
import com.elixir.biohackaton.ISAToSRA.receipt.isamodel.Category;
import com.elixir.biohackaton.ISAToSRA.receipt.isamodel.Characteristic;
import com.elixir.biohackaton.ISAToSRA.receipt.isamodel.Sample;
import com.elixir.biohackaton.ISAToSRA.receipt.isamodel.Source;
import com.elixir.biohackaton.ISAToSRA.receipt.isamodel.Study;
import com.elixir.biohackaton.ISAToSRA.receipt.isamodel.Value;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class BioSamplesSubmitter {

@Autowired
private MarsReceiptService marsReceiptService;

public BiosampleAccessionsMap createBioSamples(final List<Study> studies, final String webinToken) {
final BiosampleAccessionsMap typeToBioSamplesAccessionMap = new BiosampleAccessionsMap();

Expand All @@ -38,7 +53,7 @@ public BiosampleAccessionsMap createBioSamples(final List<Study> studies, final
}
}

typeToBioSamplesAccessionMap.sourceAccessionsMap.keyName = Source.Fields.name;
typeToBioSamplesAccessionMap.sourceAccessionsMap.isaItemName = Source.Fields.name;
typeToBioSamplesAccessionMap.sourceAccessionsMap.accessionMap.put(
sourceBioSample.getName(),
sourceBioSample.getAccession());
Expand All @@ -51,36 +66,44 @@ public BiosampleAccessionsMap createBioSamples(final List<Study> studies, final
typeToBioSamplesAccessionMap.studyAccessionsMap = new ReceiptAccessionsMap(
Study.Fields.title,
study.getTitle());

study
.getMaterials()
.getSamples()
.forEach(
sample -> {
final BioSample persistedChildSample = this.createAndUpdateChildSampleWithRelationship(
sample,
sourceBioSample.getAccession(),
finalSourceBioSampleOrganismAttribute.getValue(),
webinToken);

if (persistedChildSample != null) {
final Characteristic biosampleAccessionCharacteristic = getBioSampleAccessionCharacteristic(
new AtomicReference<>(persistedChildSample));
final ArrayList<Characteristic> sampleCharacteristics = sample.getCharacteristics() != null
? sample.getCharacteristics()
: new ArrayList<>();
sampleCharacteristics.add(biosampleAccessionCharacteristic);

typeToBioSamplesAccessionMap.sampleAccessionsMap.keyName = Sample.Fields.name;
typeToBioSamplesAccessionMap.sampleAccessionsMap.accessionMap.put(
persistedChildSample.getName(),
persistedChildSample.getAccession());
try {
final BioSample persistedChildSample = this.createAndUpdateChildSampleWithRelationship(
sample,
sourceBioSample.getAccession(),
finalSourceBioSampleOrganismAttribute.getValue(),
webinToken);

if (persistedChildSample != null) {
final Characteristic biosampleAccessionCharacteristic = getBioSampleAccessionCharacteristic(
new AtomicReference<>(persistedChildSample));
final ArrayList<Characteristic> sampleCharacteristics = sample
.getCharacteristics() != null
? sample.getCharacteristics()
: new ArrayList<>();
sampleCharacteristics.add(biosampleAccessionCharacteristic);

typeToBioSamplesAccessionMap.sampleAccessionsMap.isaItemName = Sample.Fields.name;
typeToBioSamplesAccessionMap.sampleAccessionsMap.accessionMap.put(
persistedChildSample.getName(),
persistedChildSample.getAccession());
}
} catch (Exception e) {
throw new MarsReceiptException(e,
"Failed to parse ISA Json and create samples in BioSamples (SAMPLE)",
marsReceiptService.getSampleMarsPath(
Map.entry(Study.Fields.title, study.title),
Map.entry(Sample.Fields.id, sample.id)));
}
});
});
}
} catch (final Exception e) {
throw new RuntimeException("Failed to parse ISA Json and create samples in BioSamples", e);
throw new MarsReceiptException(e, "Failed to parse ISA Json and create samples in BioSamples");
}

return typeToBioSamplesAccessionMap;
Expand All @@ -95,8 +118,8 @@ private BioSample createAndUpdateChildSampleWithRelationship(
.withRelease(Instant.now())
.withAttributes(
List.of(Attribute.build("organism", parentSampleOrganism),
Attribute.build("collection date", "not provided"),
Attribute.build("geographic location (country and/or sea)", "not provided")))
Attribute.build("collection date", "not provided"),
Attribute.build("geographic location (country and/or sea)", "not provided")))
.build();
try {
final EntityModel<BioSample> persistedSampleEntity = this.createSampleInBioSamples(bioSample, webinToken);
Expand All @@ -122,7 +145,7 @@ private BioSample createAndUpdateChildSampleWithRelationship(
return null;
}
} catch (final Exception e) {
throw new RuntimeException("Failed to handle child samples", e);
throw new MarsReceiptException(e, "Failed to handle child samples");
}
}

Expand Down Expand Up @@ -150,8 +173,8 @@ private BioSample createSourceBioSample(final List<Study> studies, final String
final BioSample sourceSample = new BioSample.Builder(source.getName())
.withRelease(Instant.now())
.withAttributes(List.of(organismAttribute.get(),
Attribute.build("collection date", "not provided"),
Attribute.build("geographic location (country and/or sea)", "not provided")))
Attribute.build("collection date", "not provided"),
Attribute.build("geographic location (country and/or sea)", "not provided")))
.build();
final EntityModel<BioSample> persistedParentSampleEntity = this.createSampleInBioSamples(sourceSample,
webinToken);
Expand All @@ -165,7 +188,7 @@ private BioSample createSourceBioSample(final List<Study> studies, final String
sourceCharacteristics.add(biosampleAccessionCharacteristic);
source.setCharacteristics(sourceCharacteristics);
} else {
throw new RuntimeException("Failed to store source sample to BioSamples");
throw new MarsReceiptException("Failed to store source sample to BioSamples");
}
}));

Expand Down Expand Up @@ -204,8 +227,8 @@ private BioSample updateSampleWithRelationshipsToBioSamples(
new ParameterizedTypeReference<>() {
});
return biosamplesResponse.getBody().getContent();
} catch (final Exception ex) {
throw new RuntimeException("Failed to add relationships to child samples", ex);
} catch (final Exception e) {
throw new MarsReceiptException(e, "Failed to add relationships to child samples");
}
}

Expand All @@ -226,8 +249,8 @@ private EntityModel<BioSample> createSampleInBioSamples(
});

return biosamplesResponse.getBody();
} catch (final Exception ex) {
throw new RuntimeException("Failed to create samples in BioSamples", ex);
} catch (final Exception e) {
throw new MarsReceiptException(e, "Failed to create samples in BioSamples");
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
/** Elixir BioHackathon 2022 */
package com.elixir.biohackaton.ISAToSRA.biosamples.service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Service;
import org.springframework.web.servlet.HandlerInterceptor;

import com.elixir.biohackaton.ISAToSRA.biosamples.model.BiosampleAccessionsMap;
import com.elixir.biohackaton.ISAToSRA.receipt.MarsReceiptProvider;
import com.elixir.biohackaton.ISAToSRA.receipt.isamodel.*;
import com.elixir.biohackaton.ISAToSRA.receipt.marsmodel.*;
import com.elixir.biohackaton.ISAToSRA.receipt.isamodel.IsaJson;
import com.elixir.biohackaton.ISAToSRA.receipt.marsmodel.MarsError;
import com.elixir.biohackaton.ISAToSRA.receipt.marsmodel.MarsErrorType;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.stereotype.Service;

@Service
public class MarsReceiptService extends MarsReceiptProvider {
public class MarsReceiptService extends MarsReceiptProvider implements HandlerInterceptor {
private final ObjectMapper jsonMapper = new ObjectMapper();

private void setupJsonMapper() {
Expand All @@ -21,29 +27,44 @@ private void setupJsonMapper() {
}

public MarsReceiptService() {
super("biosamples"); // TODO decide whether to use instead
// https://registry.identifiers.org/registry/biosample
setupJsonMapper();
}

public String convertMarsReceiptToJson(final MarsReceipt marsReceipt) {
// Reset MARS receipt per request
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
resetMarsReceipt();
return HandlerInterceptor.super.preHandle(request, response, handler);
}

public String convertMarsReceiptToJson() {
try {
return jsonMapper.writeValueAsString(marsReceipt);
return jsonMapper.writeValueAsString(getMarsReceipt());
} catch (Exception ex) {
throw new RuntimeException("receipt", ex);
throw new RuntimeException("Receipt", ex);
}
}

public void setMarsReceiptErrors(String... errors) {
super.setMarsReceiptErrors(MarsErrorType.INVALID_METADATA, errors);
}

public void setMarsReceiptErrors(MarsError... errors) {
super.setMarsReceiptErrors(MarsErrorType.INVALID_METADATA, errors);
}

/**
* Converting BioSample receipt to Mars data format
*
* @see
* https://github.com/elixir-europe/MARS/blob/refactor/repository-services/repository-api.md#response
* @see <a href='https://github.com/elixir-europe/MARS/blob/main/repository-services/repository-api.md#response'>Repository API Specification</a>
* @param biosampleAccessionsMap {@link BiosampleAccessionsMap} Receipt from Biosample
* @param isaJson {@link IsaJson} Requested ISA-Json
* @return {@link MarsReceipt} Mars response data
* @param isaJson {@link IsaJson} Requested ISA-Json
*/
public MarsReceipt convertReceiptToMars(final BiosampleAccessionsMap biosampleAccessionsMap, final IsaJson isaJson) {
return buildMarsReceipt(
"biosamples", // https://registry.identifiers.org/registry/biosample
public void convertReceiptToMars(final BiosampleAccessionsMap biosampleAccessionsMap, final IsaJson isaJson) {
buildMarsReceipt(
biosampleAccessionsMap.studyAccessionsMap,
biosampleAccessionsMap.sampleAccessionsMap,
biosampleAccessionsMap.sourceAccessionsMap,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/** Elixir BioHackathon 2022 */
package com.elixir.biohackaton.ISAToSRA.biosamples.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MarsReceiptServiceInterceptorConfig implements WebMvcConfigurer {

@Autowired private MarsReceiptService marsReceiptService;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(marsReceiptService);
}
}
Loading
Loading