Commit 5de11833 authored by Matija Obreza's avatar Matija Obreza
Browse files

GLIS DOI: Improved handling of 400 client XML errors

- Catch 400 error, use parsed GLIS XML response
- Use GlisDoiResponse instead of MultiOp
- Accession#initialReceivedDate is required
parent c4b236e4
......@@ -33,7 +33,6 @@ import org.gringlobal.api.v1.ActionController;
import org.gringlobal.api.v1.ApiBaseController;
import org.gringlobal.api.v1.FilteredCRUDController;
import org.gringlobal.api.v1.FilteredPage;
import org.gringlobal.api.v1.MultiOp;
import org.gringlobal.api.v1.Pagination;
import org.gringlobal.custom.elasticsearch.SearchException;
import org.gringlobal.model.Accession;
......@@ -51,7 +50,7 @@ import org.gringlobal.service.DownloadService;
import org.gringlobal.service.filter.AccessionActionFilter;
import org.gringlobal.service.filter.AccessionFilter;
import org.gringlobal.service.glis.impl.GlisDOIRegistrationManager;
import org.gringlobal.service.glis.impl.GlisDOIRegistrationManager.DoiUpdate;
import org.gringlobal.service.glis.impl.GlisDOIRegistrationManager.GlisDoiResponse;
import org.gringlobal.spring.CSVMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
......@@ -221,7 +220,7 @@ public class AccessionController extends FilteredCRUDController<Accession, Acces
* @throws Throwable the problem error
*/
@PostMapping(value = ENDPOINT_ID + "/assign-doi")
public DoiUpdate assignDoiToAccessions(@PathVariable(required = true, name = "id") final long id) throws Throwable {
public GlisDoiResponse assignDoiToAccessions(@PathVariable(required = true, name = "id") final long id) throws Throwable {
return glisDOIRegistrationManager.updateDoiRegistration(crudService.get(id));
}
......@@ -233,7 +232,7 @@ public class AccessionController extends FilteredCRUDController<Accession, Acces
* @throws Exception
*/
@PostMapping(value = "/assign-doi")
public MultiOp<DoiUpdate> assignDoiToAccessions(@RequestBody final List<Long> ids) throws Exception {
public List<GlisDoiResponse> assignDoiToAccessions(@RequestBody final List<Long> ids) throws Exception {
AccessionFilter filter = new AccessionFilter();
filter.id().addAll(ids);
......
......@@ -22,7 +22,6 @@ import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.genesys.glis.v1.api.ManagerApi;
import org.genesys.glis.v1.model.Acquisition;
......@@ -34,11 +33,10 @@ import org.genesys.glis.v1.model.Collection;
import org.genesys.glis.v1.model.Collector;
import org.genesys.glis.v1.model.Location;
import org.genesys.glis.v1.model.PGRFARegistration;
import org.genesys.glis.v1.model.PGRFARegistrationResponse;
import org.genesys.glis.v1.model.PGRFAUpdate;
import org.gringlobal.api.exception.InvalidApiUsageException;
import org.gringlobal.api.exception.NotFoundElement;
import org.gringlobal.api.v1.MultiOp;
import org.gringlobal.api.v1.MultiOp.MultiOpError;
import org.gringlobal.model.Accession;
import org.gringlobal.model.community.AccessionMCPD;
import org.gringlobal.persistence.AccessionRepository;
......@@ -52,9 +50,13 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.HttpClientErrorException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
@Component
public class GlisDOIRegistrationManager {
......@@ -81,26 +83,19 @@ public class GlisDOIRegistrationManager {
@Autowired
private FactoryBean<ManagerApi> managerApiFactory;
public static class DoiUpdate {
public static class GlisDoiResponse {
public long accessionId;
public String accessionNumber;
public String doi;
public String error;
public DoiUpdate(long accessionId, String accessionNumber, String doi) {
public GlisDoiResponse(long accessionId, String accessionNumber, String doi) {
this.accessionId = accessionId;
this.accessionNumber = accessionNumber;
this.doi = doi;
}
}
public static class DoiManagerError extends Exception {
private static final long serialVersionUID = 1L;
public DoiManagerError(String error) {
super(error);
}
}
/**
* Update GLIS DOI Registration Service for one Accession.
*
......@@ -110,15 +105,15 @@ public class GlisDOIRegistrationManager {
*/
@PreAuthorize("@ggceSec.actionAllowed('PassportData', 'ADMINISTRATION')")
@Transactional(readOnly = true)
public DoiUpdate updateDoiRegistration(Accession accession) throws Throwable {
public GlisDoiResponse updateDoiRegistration(Accession accession) throws Throwable {
accession = accessionRepository.getById(accession.getId()); // Reload
var result = updateGlisRegistration(List.of(accession));
var result = updateGlisRegistration(List.of(accession)).get(0);
if (CollectionUtils.isEmpty(result.success)) {
throw result.errors.get(0).error;
if (StringUtils.isNotBlank(result.error)) {
throw new InvalidApiUsageException(result.error);
} else {
return result.success.get(0);
return result;
}
}
......@@ -132,12 +127,12 @@ public class GlisDOIRegistrationManager {
*/
@PreAuthorize("@ggceSec.actionAllowed('PassportData', 'ADMINISTRATION')")
@Transactional(readOnly = true)
public MultiOp<DoiUpdate> updateDoiRegistration(AccessionFilter filter) throws Exception {
public List<GlisDoiResponse> updateDoiRegistration(AccessionFilter filter) throws Exception {
var accessions = accessionService.list(filter, Pageable.unpaged()).getContent();
return updateGlisRegistration(accessions);
}
private MultiOp<DoiUpdate> updateGlisRegistration(List<Accession> accessions) throws Exception {
private List<GlisDoiResponse> updateGlisRegistration(List<Accession> accessions) throws Exception {
var managerApi = createGlisManager();
String glisUsername = appSettingsService.getSetting(APPSETTINGS_GLIS_DOI, "username").getValue();
......@@ -147,17 +142,25 @@ public class GlisDOIRegistrationManager {
String glisInstituteAddress = appSettingsService.getSetting(APPSETTINGS_GLIS_DOI, "InstituteAddress").getValue();
String glisInstituteCountry = appSettingsService.getSetting(APPSETTINGS_GLIS_DOI, "InstituteCtyCode").getValue();
MultiOp<DoiUpdate> result = new MultiOp<>();
result.success = new ArrayList<>();
result.errors = new ArrayList<>();
var result = new ArrayList<GlisDoiResponse>();
AtomicInteger errorCounter = new AtomicInteger(0);
accessions.forEach(accession -> {
XmlMapper xmlMapper = new XmlMapper(); // For reading HTTP 400 errors
for (var accession : accessions) {
var doiUpdate = new GlisDoiResponse(accession.getId(), accession.getAccessionNumber(), accession.getDoi());
result.add(doiUpdate);
// Skip if not web visible
if (! Objects.equals("Y", accession.getIsWebVisible())) {
result.errors.add(new MultiOpError(errorCounter.getAndIncrement(), new Exception("Accession " + accession.getAccessionNumber() + " is not visible to external users")));
return;
doiUpdate.error = "Accession is not visible to external users";
continue;
}
// Skip if acquisition date missing
if (accession.getInitialReceivedDate() == null) {
doiUpdate.error = "Accession initialReceiedDate is not declared";
continue;
}
var accessionMCPD = accessionMCPDConverter.convert(accession);
......@@ -271,10 +274,12 @@ public class GlisDOIRegistrationManager {
breeding.setAncestry(accessionMCPD.ancest);
request.setBreeding(breeding);
if (request instanceof PGRFARegistration) {
var response = managerApi.registerPGRFA((PGRFARegistration) request);
try {
if (request instanceof PGRFARegistration) {
var response = managerApi.registerPGRFA((PGRFARegistration) request);
if (response.getDoi() != null) {
// GLIS DOI API returned 200 OK
assert(response.getDoi() != null);
assert(response.getSampleid().equals(accession.getAccessionNumber()));
// Assign DOI
try {
......@@ -283,29 +288,44 @@ public class GlisDOIRegistrationManager {
a.setDoi(response.getDoi());
return accessionRepository.save(a);
});
result.success.add(new DoiUpdate(saved.getId(), saved.getAccessionNumber(), saved.getDoi()));
doiUpdate.doi = saved.getDoi();
doiUpdate.error = null; // Just in case
} catch (Throwable e) {
result.errors.add(new MultiOpError(errorCounter.getAndIncrement(), e));
doiUpdate.error = e.getMessage();
}
} else {
LOG.warn("Exception in registration accession with acceNumb {}: {}.", accessionMCPD.acceNumb, response.getError());
result.errors.add(new MultiOpError(errorCounter.getAndIncrement(), new DoiManagerError(response.getError())));
}
} else if (request instanceof PGRFAUpdate) {
var response = managerApi.updatePGRFA((PGRFAUpdate) request);
} else if (request instanceof PGRFAUpdate) {
var response = managerApi.updatePGRFA((PGRFAUpdate) request);
if (response.getDoi() != null) {
// GLIS DOI API returned 200 OK
assert(response.getDoi() != null);
assert(response.getSampleid().equals(accession.getAccessionNumber()));
result.success.add(new DoiUpdate(accession.getId(), accession.getAccessionNumber(), accession.getDoi()));
doiUpdate.error = null; // Just in case
}
} catch (HttpClientErrorException e) {
errorCounter.incrementAndGet();
LOG.error("Error calling GLIS API {}: {}", e.getClass(), e.getMessage());
if (e.getResponseHeaders().getContentType().isCompatibleWith(MediaType.APPLICATION_XML)) {
var glisResponse = xmlMapper.readValue(e.getResponseBodyAsString(), PGRFARegistrationResponse.class);
doiUpdate.error = glisResponse.getError();
} else {
LOG.warn("Exception in registration accession with acceNumb {}: {}.", accessionMCPD.acceNumb, response.getError());
result.errors.add(new MultiOpError(errorCounter.getAndIncrement(), new DoiManagerError(response.getError())));
doiUpdate.error = e.getMessage();
}
} catch (Throwable e) {
errorCounter.incrementAndGet();
LOG.error("Error interacting with GLIS API {}: {}", e.getClass(), e.getMessage());
doiUpdate.error = e.getMessage();
}
});
if (errorCounter.get() > 10) {
LOG.warn("Stopping after too many (10) errors.");
break;
}
}
return result;
}
......@@ -316,7 +336,10 @@ public class GlisDOIRegistrationManager {
throw new InvalidApiUsageException("GLIS client not available.");
}
managerApi.getApiClient().setDebugging(true);
if (LOG.isDebugEnabled() || LOG.isTraceEnabled()) {
managerApi.getApiClient().setDebugging(true);
}
try {
String glisUsername = appSettingsService.getSetting(APPSETTINGS_GLIS_DOI, "username").getValue();
appSettingsService.getSetting(APPSETTINGS_GLIS_DOI, "password").getValue();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment