Commit b5568d5b authored by Matija Obreza's avatar Matija Obreza

REST: upsert API call returns update result per accession

parent e889fb90
......@@ -28,7 +28,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
public interface BatchRESTService {
boolean upsertAccessionData(FaoInstitute institute, Map<AccessionHeaderJson, ObjectNode> batch) throws RESTApiException;
List<UpsertResponse> upsertAccessionData(FaoInstitute institute, Map<AccessionHeaderJson, ObjectNode> batch) throws RESTApiException;
void upsertAccessionNames(FaoInstitute institute, List<AccessionNamesJson> batch)throws RESTApiException;
......
/**
* Copyright 2015 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
package org.genesys2.server.service;
import java.io.Serializable;
import java.util.UUID;
/**
* Upsert response
*/
public class UpsertResponse implements Serializable {
private static final long serialVersionUID = 3266359129838078166L;
private String instCode;
private String acceNumb;
private String genus;
private String error;
private UpsertResult result;
public static class UpsertResult {
private Type action = Type.NOOP;
private UUID uuid;
public static enum Type {
NOOP, INSERT, UPDATE, DELETE
}
/**
* @param action
* UPSERT or INSERT or DELETE
*/
public UpsertResult(Type action) {
this.action = action;
}
public Type getAction() {
return action;
}
public void setAction(Type action) {
this.action = action;
}
public UUID getUuid() {
return uuid;
}
public void setUUID(UUID uuid) {
this.uuid = uuid;
}
}
public UpsertResponse(String instCode, String acceNumb, String genus) {
this.instCode = instCode;
this.acceNumb = acceNumb;
this.genus = genus;
}
public String getInstCode() {
return instCode;
}
public String getAcceNumb() {
return acceNumb;
}
public String getGenus() {
return genus;
}
public String getError() {
return error;
}
public UpsertResult getResult() {
return result;
}
public void setResult(UpsertResult result) {
this.result = result;
}
public void setError(String error) {
this.error = error;
}
}
......@@ -50,7 +50,8 @@ import org.genesys2.server.service.GeoService;
import org.genesys2.server.service.InstituteService;
import org.genesys2.server.service.OrganizationService;
import org.genesys2.server.service.TaxonomyService;
import org.genesys2.server.servlet.controller.rest.PleaseRetryException;
import org.genesys2.server.service.UpsertResponse;
import org.genesys2.server.service.UpsertResponse.UpsertResult;
import org.genesys2.server.servlet.controller.rest.model.AccessionAliasJson;
import org.genesys2.server.servlet.controller.rest.model.AccessionHeaderJson;
import org.genesys2.server.servlet.controller.rest.model.AccessionNamesJson;
......@@ -137,11 +138,13 @@ public class BatchRESTServiceImpl implements BatchRESTService {
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#institute, 'WRITE') or hasPermission(#institute, 'CREATE')")
public boolean upsertAccessionData(FaoInstitute institute, Map<AccessionHeaderJson, ObjectNode> batch) throws RESTApiException {
public List<UpsertResponse> upsertAccessionData(FaoInstitute institute, Map<AccessionHeaderJson, ObjectNode> batch) throws RESTApiException {
LOG.info("Batch processing " + batch.size() + " entries for " + institute.getCode());
final boolean useUniqueAcceNumbs = institute.hasUniqueAcceNumbs();
final List<UpsertResponse> upsertResponses = new ArrayList<UpsertResponse>();
final List<Accession> toSave = new ArrayList<Accession>();
final List<AccessionCollect> toSaveColl = new ArrayList<AccessionCollect>();
final List<AccessionCollect> toRemoveColl = new ArrayList<AccessionCollect>();
......@@ -180,20 +183,18 @@ public class BatchRESTServiceImpl implements BatchRESTService {
LOG.debug("Loading accession " + dataJson);
}
UpsertResponse upsertResponse = new UpsertResponse(dataJson.instCode, dataJson.acceNumb, dataJson.genus);
upsertResponses.add(upsertResponse);
UpsertResult upsertResult = null;
if (!institute.getCode().equals(dataJson.instCode)) {
throw new RuntimeException("Accession does not belong to instCode=" + institute.getCode() + " acn=" + dataJson);
throw new RESTApiException("Accession does not belong to instCode=" + institute.getCode() + " acn=" + dataJson);
}
Accession accession = CollectionUtils.find(loaded, new Predicate<Accession>() {
@Override
public boolean evaluate(Accession a) {
if (useUniqueAcceNumbs) {
return a.getAccessionName().equalsIgnoreCase(dataJson.acceNumb);
} else {
return a.getAccessionName().equalsIgnoreCase(dataJson.acceNumb) && a.getTaxonomy().getGenus().equalsIgnoreCase(dataJson.genus);
}
}
});
Accession accession = loaded.stream()
.filter(a -> useUniqueAcceNumbs ? (a.getAccessionName().equalsIgnoreCase(dataJson.acceNumb))
: (a.getAccessionName().equalsIgnoreCase(dataJson.acceNumb) && a.getTaxonomy().getGenus().equalsIgnoreCase(dataJson.genus)))
.findFirst().orElse(null);
boolean updated = false;
......@@ -214,9 +215,14 @@ public class BatchRESTServiceImpl implements BatchRESTService {
}
updated = true;
upsertResult = new UpsertResult(UpsertResult.Type.INSERT);
} else {
if (LOG.isTraceEnabled())
LOG.trace("*** Updating accession " + dataJson);
upsertResult = new UpsertResult(UpsertResult.Type.UPDATE);
upsertResult.setUUID(accession.getUuid());
}
if (accession.getAccessionId().getId() == null || useUniqueAcceNumbs && accnJson.get(Api1Constants.Accession.GENUS) != null
......@@ -321,7 +327,7 @@ public class BatchRESTServiceImpl implements BatchRESTService {
updated = true;
}
}
value = accnJson.get(Api1Constants.Accession.ACCEURL);
if (value != null) {
if (!value.isNull() && !value.isTextual()) {
......@@ -500,11 +506,34 @@ public class BatchRESTServiceImpl implements BatchRESTService {
if (updated) {
toSave.add(accession);
}
// Set upsert result
upsertResponse.setResult(upsertResult);
}
if (toSave.size() > 0) {
LOG.info("Storing " + toSave.size() + " accessions.");
genesysService.saveAccessions(institute, toSave);
List<Accession> savedData = genesysService.saveAccessions(institute, toSave);
// Iterate savedData to extract UUIDs
upsertResponses.stream().forEach(response -> {
Accession accession = savedData.stream()
.filter(a -> useUniqueAcceNumbs ? (a.getAccessionName()
.equalsIgnoreCase(response.getAcceNumb()))
: (a.getAccessionName().equalsIgnoreCase(response.getAcceNumb())
&& a.getTaxonomy().getGenus().equalsIgnoreCase(response.getGenus())))
.findFirst().orElse(null);
UpsertResult result = response.getResult();
if (accession != null) {
if (result.getUuid() == null) {
result.setAction(UpsertResult.Type.INSERT);
} else {
result.setAction(UpsertResult.Type.UPDATE);
}
result.setUUID(accession.getUuid());
}
});
}
if (toSaveColl.size() > 0) {
......@@ -548,7 +577,7 @@ public class BatchRESTServiceImpl implements BatchRESTService {
updateAccessionAliases(collNumbs, AliasType.COLLNUMB, false);
LOG.info("Done saving data");
return toSave.size() > 0 || toSaveColl.size() > 0 || toSaveGeo.size() > 0 || toSaveBreed.size() > 0 || toSaveExch.size() > 0;
return upsertResponses;
}
private boolean updateStorage(AccessionData accession, ObjectNode accnJson) throws RESTApiDataTypeException {
......@@ -736,7 +765,12 @@ public class BatchRESTServiceImpl implements BatchRESTService {
* @throws RESTApiException
*/
private boolean updateTaxonomy(AccessionData accession, JsonNode accnJson) throws RESTApiException {
boolean updated = false;
if (accession.getTaxonomy() != null && (!accnJson.has(Api1Constants.Accession.GENUS_NEW) && !accnJson.has(Api1Constants.Accession.SPECIES))) {
if (LOG.isWarnEnabled())
LOG.warn("Not updating taxonomy without newGenus or species data");
return false;
}
// Do not persist this one, temporary use
final Taxonomy2 taxonomy = accession.getTaxonomy();
......@@ -761,15 +795,17 @@ public class BatchRESTServiceImpl implements BatchRESTService {
if (ensuredTaxonomy == null) {
LOG.warn("Could not find taxonomy for upsert " + current);
throw new PleaseRetryException("Could not find taxonomy " + current.getTaxonName());
// throw new PleaseRetryException("Could not find taxonomy " +
// current.getTaxonName());
throw new RESTApiException("Could not find taxonomy. Provide GENUS, SPECIES, SPAUTHOR, SUBTAXA and SUBTAUTHOR fields");
}
if (!ensuredTaxonomy.sameAs(taxonomy)) {
if (!ensuredTaxonomy.sameAs(accession.getTaxonomy())) {
accession.setTaxonomy(ensuredTaxonomy);
updated = true;
return true;
} else {
return false;
}
return updated;
}
/**
......@@ -880,7 +916,7 @@ public class BatchRESTServiceImpl implements BatchRESTService {
}
if (toSave.size() > 0) {
// LOG.info("Saving aliases count=" + toSave.size());
// LOG.info("Saving aliases count=" + toSave.size());
genesysService.saveAliases(toSave);
}
if (toRemove.size() > 0) {
......@@ -916,7 +952,7 @@ public class BatchRESTServiceImpl implements BatchRESTService {
LOG.warn("No such accession " + dataJson);
continue;
}
// LOG.info("Updating " + dataJson + " with=" + dataJson.aliases);
// LOG.info("Updating " + dataJson + " with=" + dataJson.aliases);
final List<AccessionAliasJson> aliases = dataJson.aliases;
final List<AccessionAlias> existingAliases = genesysService.listAccessionAliases(accession.getAccessionId());
......
......@@ -30,7 +30,6 @@ import org.genesys2.server.model.impl.FaoInstitute;
import org.genesys2.server.model.json.AccessionJson;
import org.genesys2.server.model.json.Api1Constants;
import org.genesys2.server.service.BatchRESTService;
import org.genesys2.server.service.CropService;
import org.genesys2.server.service.ElasticService;
import org.genesys2.server.service.FilterConstants;
import org.genesys2.server.service.GenesysFilterService;
......@@ -39,6 +38,7 @@ import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.GeoService;
import org.genesys2.server.service.InstituteService;
import org.genesys2.server.service.TaxonomyService;
import org.genesys2.server.service.UpsertResponse;
import org.genesys2.server.service.impl.FilterHandler;
import org.genesys2.server.service.impl.FilterHandler.AppliedFilter;
import org.genesys2.server.service.impl.FilterHandler.AppliedFilters;
......@@ -84,9 +84,6 @@ public class AccessionController extends RestController {
@Autowired
private GenesysFilterService filterService;
@Autowired
private CropService cropService;
@Autowired
BatchRESTService batchRESTService;
......@@ -198,8 +195,9 @@ public class AccessionController extends RestController {
* @throws RESTApiException
*/
@RequestMapping(value = "/{instCode}/upsert", method = { RequestMethod.POST, RequestMethod.PUT }, produces = { MediaType.APPLICATION_JSON_VALUE })
public @ResponseBody String upsertInstituteAccession(@PathVariable("instCode") String instCode, @RequestBody String content)
public @ResponseBody Object upsertInstituteAccession(@PathVariable("instCode") String instCode, @RequestBody String content)
throws JsonProcessingException, IOException, RESTApiException {
// User's permission to WRITE to this WIEWS institute are checked in
// BatchRESTService.
final FaoInstitute institute = instituteService.getInstitute(instCode);
......@@ -234,11 +232,17 @@ public class AccessionController extends RestController {
// persisted
batchRESTService.ensureTaxonomies(institute, batch);
// Step 2: Upsert data
batchRESTService.upsertAccessionData(institute, batch);
List<UpsertResponse> response = null;
try {
response = batchRESTService.upsertAccessionData(institute, batch);
} catch (RESTApiException e) {
LOG.info("Retrying upsert one by one due to " + e.getMessage());
response = upsertAccessionData1by1(institute, batch);
}
// Force update institute#accessionCount (outside previous
// transaction)
genesysService.updateAccessionCount(institute);
return JSON_OK;
return response;
} catch (PleaseRetryException | HibernateOptimisticLockingFailureException
| org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException e) {
LOG.info("Will retry upsert. Error: " + e.getMessage());
......@@ -246,7 +250,34 @@ public class AccessionController extends RestController {
}
}
throw new RESTApiException("Could not upsert accession data.", cause);
throw new RESTApiException("Could not upsert accession data. " + cause.getMessage(), cause);
}
private List<UpsertResponse> upsertAccessionData1by1(FaoInstitute institute, Map<AccessionHeaderJson, ObjectNode> batch) {
LOG.info("Attempting insert 1 by 1");
final Map<AccessionHeaderJson, ObjectNode> batchOfOne = new HashMap<AccessionHeaderJson, ObjectNode>();
List<UpsertResponse> response = new ArrayList<UpsertResponse>();
for (AccessionHeaderJson acceJ : batch.keySet()) {
try {
batchOfOne.clear();
batchOfOne.put(acceJ, batch.get(acceJ));
UpsertResponse accessionResponse = batchRESTService.upsertAccessionData(institute, batchOfOne).get(0);
response.add(accessionResponse);
} catch (RESTApiException e) {
if (LOG.isInfoEnabled()) {
LOG.info("Error upserting " + acceJ.instCode + ": " + e.getMessage());
}
UpsertResponse accessionResponse = new UpsertResponse(acceJ.instCode, acceJ.acceNumb, acceJ.genus);
accessionResponse.setError(e.getMessage());
response.add(accessionResponse);
}
}
return response;
}
/**
......
Markdown is supported
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