diff --git a/src/main/java/org/breedinginsight/brapi/v2/GermplasmController.java b/src/main/java/org/breedinginsight/brapi/v2/GermplasmController.java index d91f4ed57..bed1f4a40 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/GermplasmController.java +++ b/src/main/java/org/breedinginsight/brapi/v2/GermplasmController.java @@ -28,6 +28,7 @@ import org.breedinginsight.api.model.v1.validators.SearchValid; import org.breedinginsight.brapi.v1.controller.BrapiVersion; import org.breedinginsight.brapi.v1.model.request.query.BrapiQuery; +import org.breedinginsight.brapi.v2.constants.BrAPIAdditionalInfoFields; import org.breedinginsight.brapi.v2.dao.BrAPIGermplasmDAO; import org.breedinginsight.brapi.v2.model.request.query.GermplasmQuery; import org.breedinginsight.utilities.Utilities; @@ -223,14 +224,14 @@ public HttpResponse getGermplasmPedigreeInfo( response = pedigreeResponse.getBody(); //Add nodes for unknown parents if applicable - if (germplasm.getAdditionalInfo().has("femaleParentUnknown") && germplasm.getAdditionalInfo().get("femaleParentUnknown").getAsBoolean()) { + if (germplasm.getAdditionalInfo().has(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN) && germplasm.getAdditionalInfo().get(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN).getAsBoolean()) { BrAPIPedigreeNodeParents unknownFemale = new BrAPIPedigreeNodeParents(); unknownFemale.setGermplasmDbId(germplasm.getGermplasmDbId()+"-F-Unknown"); unknownFemale.setGermplasmName("Unknown"); unknownFemale.setParentType(BrAPIParentType.FEMALE); returnNode.addParentsItem(unknownFemale); } - if (germplasm.getAdditionalInfo().has("maleParentUnknown") && germplasm.getAdditionalInfo().get("maleParentUnknown").getAsBoolean()) { + if (germplasm.getAdditionalInfo().has(BrAPIAdditionalInfoFields.MALE_PARENT_UNKNOWN) && germplasm.getAdditionalInfo().get(BrAPIAdditionalInfoFields.MALE_PARENT_UNKNOWN).getAsBoolean()) { BrAPIPedigreeNodeParents unknownMale = new BrAPIPedigreeNodeParents(); unknownMale.setGermplasmDbId(germplasm.getGermplasmDbId()+"-M-Unknown"); unknownMale.setGermplasmName("Unknown"); diff --git a/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIGermplasmDAO.java b/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIGermplasmDAO.java index 14ffdf6b3..3adbb99ff 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIGermplasmDAO.java +++ b/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIGermplasmDAO.java @@ -187,7 +187,10 @@ private Map processGermplasmForDisplay(List processGermplasmForDisplay(List ref.getReferenceSource().equals(referenceSource)). map(ref -> ref.getReferenceID()).findFirst().orElse(""); additionalInfo.addProperty(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_GID, femaleParentAccessionNumber); - } else if (additionalInfo.has("femaleParentUnknown") && additionalInfo.get("femaleParentUnknown").getAsBoolean()) { + } else if (additionalInfo.has(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN) && additionalInfo.get(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN).getAsBoolean()) { namePedigreeString = "Unknown"; } } @@ -221,7 +224,7 @@ private Map processGermplasmForDisplay(List processGermplasmForDisplay(List + private String processBreedbasePedigree(String pedigree) { + + if (pedigree != null) { + if (pedigree.equals("NA/NA")) { + return ""; + } + + // Technically processGermplasmForDisplay should handle ok without stripping these NAs but will strip anyways + // for consistency. + // We only allow the /NA case for single parent as we require a female parent in the pedigree + // keep the leading slash, will be handled by processGermplasmForDisplay + if (pedigree.endsWith("/NA")) { + return pedigree.substring(0, pedigree.length()-2); + } + + // shouldn't have this case in our data but just in case + if (pedigree.startsWith("NA/")) { + return pedigree.substring(2); + } + } + return pedigree; + } + public List createBrAPIGermplasm(List postBrAPIGermplasmList, UUID programId, ImportUpload upload) { GermplasmApi api = brAPIEndpointProvider.get(programDAO.getCoreClient(programId), GermplasmApi.class); var program = programDAO.fetchOneById(programId); @@ -262,8 +293,10 @@ public List updateBrAPIGermplasm(List putBrAPIGe try { if (!putBrAPIGermplasmList.isEmpty()) { postFunction = () -> { - List postResponse = putGermplasm(putBrAPIGermplasmList, api); - return processGermplasmForDisplay(postResponse, program.getKey()); + putGermplasm(putBrAPIGermplasmList, api); + // Need all program germplasm for processGermplasmForDisplay parents pedigree + List germplasm = getRawGermplasm(programId); + return processGermplasmForDisplay(germplasm, program.getKey()); }; } return programGermplasmCache.post(programId, postFunction); diff --git a/src/main/java/org/breedinginsight/brapps/importer/model/base/Germplasm.java b/src/main/java/org/breedinginsight/brapps/importer/model/base/Germplasm.java index 725bb9e44..9ccd129f1 100644 --- a/src/main/java/org/breedinginsight/brapps/importer/model/base/Germplasm.java +++ b/src/main/java/org/breedinginsight/brapps/importer/model/base/Germplasm.java @@ -22,6 +22,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.apache.commons.lang3.StringUtils; import org.brapi.v2.model.BrAPIExternalReference; import org.brapi.v2.model.core.BrAPIListTypes; import org.brapi.v2.model.core.request.BrAPIListNewRequest; @@ -30,7 +31,6 @@ import org.breedinginsight.brapi.v2.constants.BrAPIAdditionalInfoFields; import org.breedinginsight.brapps.importer.model.config.*; import org.breedinginsight.brapps.importer.services.ExternalReferenceSource; -import org.breedinginsight.dao.db.tables.pojos.BreedingMethodEntity; import org.breedinginsight.dao.db.tables.pojos.ProgramBreedingMethodEntity; import org.breedinginsight.model.Program; import org.breedinginsight.model.User; @@ -156,12 +156,22 @@ public static String constructGermplasmListName(String listName, Program program return String.format("%s [%s-germplasm]", listName, program.getKey()); } - public void updateBrAPIGermplasm(BrAPIGermplasm germplasm, Program program, UUID listId, boolean commit) { + public void updateBrAPIGermplasm(BrAPIGermplasm germplasm, Program program, UUID listId, boolean commit, boolean updatePedigree) { - germplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_GID, getFemaleParentDBID()); - germplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_GID, getMaleParentDBID()); - germplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_ENTRY_NO, getFemaleParentEntryNo()); - germplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_ENTRY_NO, getMaleParentEntryNo()); + if (updatePedigree) { + if (!StringUtils.isBlank(getFemaleParentDBID())) { + germplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_GID, getFemaleParentDBID()); + } + if (!StringUtils.isBlank(getMaleParentDBID())) { + germplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_GID, getMaleParentDBID()); + } + if (!StringUtils.isBlank(getFemaleParentEntryNo())) { + germplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_ENTRY_NO, getFemaleParentEntryNo()); + } + if (!StringUtils.isBlank(getMaleParentEntryNo())) { + germplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_ENTRY_NO, getMaleParentEntryNo()); + } + } // Append synonyms to germplasm that don't already exist // Synonym comparison is based on name and type @@ -178,7 +188,12 @@ public void updateBrAPIGermplasm(BrAPIGermplasm germplasm, Program program, UUID // Add germplasm to the new list JsonObject listEntryNumbers = germplasm.getAdditionalInfo().getAsJsonObject(BrAPIAdditionalInfoFields.GERMPLASM_LIST_ENTRY_NUMBERS); + if(listEntryNumbers == null) { + listEntryNumbers = new JsonObject(); + germplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_LIST_ENTRY_NUMBERS, listEntryNumbers); + } listEntryNumbers.addProperty(listId.toString(), entryNo); + germplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_IMPORT_ENTRY_NUMBER, entryNo); //so the preview UI shows correctly // TODO: figure out why clear this out: brapi-server germplasm.setBreedingMethodDbId(null); @@ -203,20 +218,11 @@ public void setUpdateCommitFields(BrAPIGermplasm germplasm, String programKey) { } } - public boolean pedigreesEqual(BrAPIGermplasm brAPIGermplasm) { - JsonElement femaleGid = brAPIGermplasm.getAdditionalInfo().get(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_GID); - String brapiFemaleGid = femaleGid != null ? femaleGid.getAsString() : null; - JsonElement maleGid = brAPIGermplasm.getAdditionalInfo().get(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_GID); - String brapiMaleGid = maleGid != null ? maleGid.getAsString() : null; - JsonElement femaleEntryNo = brAPIGermplasm.getAdditionalInfo().get(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_ENTRY_NO); - String brapiFemaleEntryNo = femaleEntryNo != null ? femaleEntryNo.getAsString() : null; - JsonElement maleEntryNo = brAPIGermplasm.getAdditionalInfo().get(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_ENTRY_NO); - String brapiMaleEntryNo = maleEntryNo != null ? maleEntryNo.getAsString() : null; - - return ((getFemaleParentDBID() == null && brapiFemaleGid == null) || (getFemaleParentDBID() != null && getFemaleParentDBID().equals(brapiFemaleGid))) && - ((getMaleParentDBID() == null && brapiMaleGid == null) || (getMaleParentDBID() != null && getMaleParentDBID().equals(brapiMaleGid))) && - ((getFemaleParentEntryNo() == null && brapiFemaleEntryNo == null) || (getFemaleParentEntryNo() != null && getFemaleParentEntryNo().equals(brapiFemaleEntryNo))) && - ((getMaleParentEntryNo() == null && brapiMaleEntryNo == null) || (getMaleParentEntryNo() != null && getMaleParentEntryNo().equals(brapiMaleEntryNo))); + public boolean pedigreeExists() { + return StringUtils.isNotBlank(getFemaleParentDBID()) || + StringUtils.isNotBlank(getMaleParentDBID()) || + StringUtils.isNotBlank(getFemaleParentEntryNo()) || + StringUtils.isNotBlank(getMaleParentEntryNo()); } public BrAPIGermplasm constructBrAPIGermplasm(ProgramBreedingMethodEntity breedingMethod, User user, UUID listId) { diff --git a/src/main/java/org/breedinginsight/brapps/importer/services/processors/GermplasmProcessor.java b/src/main/java/org/breedinginsight/brapps/importer/services/processors/GermplasmProcessor.java index cc4d8f476..98746aab2 100644 --- a/src/main/java/org/breedinginsight/brapps/importer/services/processors/GermplasmProcessor.java +++ b/src/main/java/org/breedinginsight/brapps/importer/services/processors/GermplasmProcessor.java @@ -16,9 +16,6 @@ */ package org.breedinginsight.brapps.importer.services.processors; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import io.micronaut.context.annotation.Property; import io.micronaut.context.annotation.Prototype; import io.micronaut.http.HttpStatus; @@ -30,7 +27,6 @@ import org.brapi.v2.model.core.BrAPIListSummary; import org.brapi.v2.model.core.request.BrAPIListNewRequest; import org.brapi.v2.model.germ.BrAPIGermplasm; -import org.brapi.v2.model.germ.BrAPIGermplasmSynonyms; import org.breedinginsight.api.model.v1.response.ValidationError; import org.breedinginsight.api.model.v1.response.ValidationErrors; import org.breedinginsight.brapi.v2.constants.BrAPIAdditionalInfoFields; @@ -82,10 +78,10 @@ public class GermplasmProcessor implements Processor { List updatedGermplasmList; List existingGermplasms; - List existingParentGermplasms; List> postOrder = new ArrayList<>(); BrAPIListNewRequest importList = new BrAPIListNewRequest(); + public static String missingDbIdsMsg = "The following GIDs were not found in the database: %s."; public static String missingParentalDbIdsMsg = "The following parental GIDs were not found in the database: %s."; public static String missingParentalEntryNoMsg = "The following parental entry numbers were not found in the database: %s."; public static String badBreedMethodsMsg = "Invalid breeding method"; @@ -116,17 +112,20 @@ public GermplasmProcessor(BrAPIGermplasmService brAPIGermplasmService, DSLContex public void getExistingBrapiData(List importRows, Program program) throws ApiException { // Get all of our objects specified in the data file by their unique attributes - Set germplasmDBIDs = new HashSet<>(); + Map germplasmDBIDs = new HashMap<>(); for (int i = 0; i < importRows.size(); i++) { BrAPIImport germplasmImport = importRows.get(i); if (germplasmImport.getGermplasm() != null) { // Retrieve parent dbids to assess if already in db if (germplasmImport.getGermplasm().getFemaleParentDBID() != null) { - germplasmDBIDs.add(germplasmImport.getGermplasm().getFemaleParentDBID()); + germplasmDBIDs.put(germplasmImport.getGermplasm().getFemaleParentDBID(), true); } if (germplasmImport.getGermplasm().getMaleParentDBID() != null) { - germplasmDBIDs.add(germplasmImport.getGermplasm().getMaleParentDBID()); + germplasmDBIDs.put(germplasmImport.getGermplasm().getMaleParentDBID(), true); + } + if (germplasmImport.getGermplasm().getAccessionNumber() != null) { + germplasmDBIDs.put(germplasmImport.getGermplasm().getAccessionNumber(), false); } //Retrieve entry numbers of file for comparison with parent entry numbers @@ -141,20 +140,20 @@ public void getExistingBrapiData(List importRows, Program program) // If parental DBID, should also be in database existingGermplasms = new ArrayList<>(); - List missingDbIds = new ArrayList<>(germplasmDBIDs); + List missingParentalDbIds = germplasmDBIDs.entrySet().stream().filter(Map.Entry::getValue).map(Map.Entry::getKey).collect(Collectors.toList()); + List missingDbIds = germplasmDBIDs.entrySet().stream().filter(entry -> !entry.getValue()).map(Map.Entry::getKey).collect(Collectors.toList()); if (germplasmDBIDs.size() > 0) { try { - existingParentGermplasms = brAPIGermplasmService.getRawGermplasmByAccessionNumber(new ArrayList<>(germplasmDBIDs), program.getId()); - List existingDbIds = existingParentGermplasms.stream() + existingGermplasms = brAPIGermplasmService.getRawGermplasmByAccessionNumber(new ArrayList<>(germplasmDBIDs.keySet()), program.getId()); + List existingDbIds = existingGermplasms.stream() .map(germplasm -> germplasm.getAccessionNumber()) .collect(Collectors.toList()); + missingParentalDbIds.removeAll(existingDbIds); missingDbIds.removeAll(existingDbIds); - existingParentGermplasms.forEach(existingGermplasm -> { + existingGermplasms.forEach(existingGermplasm -> { germplasmByAccessionNumber.put(existingGermplasm.getAccessionNumber(), new PendingImportObject<>(ImportObjectState.EXISTING, existingGermplasm)); }); - //Since parent germplasms need to be present for check re circular dependencies - existingGermplasms.addAll(existingParentGermplasms); } catch (ApiException e) { // We shouldn't get an error back from our services. If we do, nothing the user can do about it throw new InternalServerException(e.toString(), e); @@ -163,8 +162,10 @@ public void getExistingBrapiData(List importRows, Program program) // Get existing germplasm names List dbGermplasm = brAPIGermplasmService.getGermplasmByDisplayName(new ArrayList<>(fileGermplasmByName.keySet()), program.getId()); - dbGermplasm.stream().forEach(germplasm -> dbGermplasmByName.put(germplasm.getDefaultDisplayName(), germplasm)); - dbGermplasm.stream().forEach(germplasm -> dbGermplasmByAccessionNo.put(germplasm.getAccessionNumber(), germplasm)); + dbGermplasm.forEach(germplasm -> { + dbGermplasmByName.put(germplasm.getDefaultDisplayName(), germplasm); + dbGermplasmByAccessionNo.put(germplasm.getAccessionNumber(), germplasm); + }); // Check for existing germplasm lists Boolean listNameDup = false; @@ -184,12 +185,20 @@ public void getExistingBrapiData(List importRows, Program program) } //Remove id indicating unknown parent + missingParentalDbIds.remove("0"); missingDbIds.remove("0"); // Parent reference checks - if (missingDbIds.size() > 0) { + if (missingParentalDbIds.size() > 0) { throw new HttpStatusException(HttpStatus.UNPROCESSABLE_ENTITY, String.format(missingParentalDbIdsMsg, + arrayOfStringFormatter.apply(missingParentalDbIds))); + } + + //GID existence check + if (missingDbIds.size() > 0) { + throw new HttpStatusException(HttpStatus.UNPROCESSABLE_ENTITY, + String.format(missingDbIdsMsg, arrayOfStringFormatter.apply(missingDbIds))); } @@ -273,77 +282,11 @@ public Map process(List importRows //todo double check what dbgermplasmbyaccessionNo actually getting //TODO maybe make separate method for cleanliness - if (germplasm != null) { - //Fetch and update existing germplasm - BrAPIGermplasm existingGermplasm; - - // Have GID so updating an existing germplasm record - if (germplasm.getAccessionNumber() != null) { - if (dbGermplasmByAccessionNo.containsKey(germplasm.getAccessionNumber()) ) { - existingGermplasm = dbGermplasmByAccessionNo.get(germplasm.getAccessionNumber()); - } else { - ValidationError ve = new ValidationError("GID", missingGID, HttpStatus.NOT_FOUND); - validationErrors.addError(i+2, ve ); // +2 instead of +1 to account for the column header row. - continue; - } - - // Error conditions: - // has existing pedigree and file pedigree is different - // Valid conditions: - // no existing pedigree and file different pedigree (not blank though, will fail other validations) - // existing pedigree and file pedigree same - - if (!StringUtils.isBlank(existingGermplasm.getPedigree()) && !germplasm.pedigreesEqual(existingGermplasm) ) { - ValidationError ve = new ValidationError("Pedigree", pedigreeAlreadyExists, HttpStatus.UNPROCESSABLE_ENTITY); - validationErrors.addError(i+2, ve ); // +2 instead of +1 to account for the column header row. - continue; - } - - validatePedigree(germplasm, i+2, validationErrors); - - germplasm.updateBrAPIGermplasm(existingGermplasm, program, importListId, commit); - - updatedGermplasmList.add(existingGermplasm); - mappedImportRow.setGermplasm(new PendingImportObject<>(ImportObjectState.EXISTING, existingGermplasm)); - - importList.addDataItem(existingGermplasm.getGermplasmName()); - - } else { - // Get the breeding method database object - ProgramBreedingMethodEntity breedingMethod = null; - if (germplasm.getBreedingMethod() != null) { - if (breedingMethods.containsKey(germplasm.getBreedingMethod())) { - breedingMethod = breedingMethods.get(germplasm.getBreedingMethod()); - } else { - List breedingMethodResults = breedingMethodDAO.findByNameOrAbbreviation(germplasm.getBreedingMethod(), program.getId()); - if (breedingMethodResults.size() > 0) { - breedingMethods.put(germplasm.getBreedingMethod(), breedingMethodResults.get(0)); - breedingMethod = breedingMethods.get(germplasm.getBreedingMethod()); - } else { - ValidationError ve = new ValidationError("Breeding Method", badBreedMethodsMsg, HttpStatus.UNPROCESSABLE_ENTITY); - validationErrors.addError(i + 2, ve); // +2 instead of +1 to account for the column header row. - badBreedingMethods.add(germplasm.getBreedingMethod()); - breedingMethod = null; - } - } - } - - validatePedigree(germplasm, i + 2, validationErrors); - - BrAPIGermplasm newGermplasm = germplasm.constructBrAPIGermplasm(program, breedingMethod, user, commit, BRAPI_REFERENCE_SOURCE, nextVal, importListId); - - newGermplasmList.add(newGermplasm); - // Assign status of the germplasm - if (fileGermplasmByName.get(newGermplasm.getDefaultDisplayName()) > 1 || dbGermplasmByName.containsKey(newGermplasm.getDefaultDisplayName())) { - mappedImportRow.setGermplasm(new PendingImportObject<>(ImportObjectState.EXISTING, newGermplasm)); - } else { - mappedImportRow.setGermplasm(new PendingImportObject<>(ImportObjectState.NEW, newGermplasm)); - } - - importList.addDataItem(newGermplasm.getGermplasmName()); - } + // Have GID so updating an existing germplasm record + if (germplasm.getAccessionNumber() != null) { + processExistingGermplasm(germplasm, validationErrors, importRows, program, importListId, commit, mappedImportRow, i); } else { - mappedImportRow.setGermplasm(null); + processNewGermplasm(germplasm, validationErrors, breedingMethods, badBreedingMethods, program, importListId, commit, mappedImportRow, i, user, nextVal); } mappedBrAPIImport.put(i, mappedImportRow); } @@ -377,6 +320,181 @@ public Map process(List importRows return getStatisticsMap(importRows); } + private void processNewGermplasm(Germplasm germplasm, ValidationErrors validationErrors, Map breedingMethods, + List badBreedingMethods, + Program program, UUID importListId, boolean commit, PendingImport mappedImportRow, int i, User user, Supplier nextVal) { + // Get the breeding method database object + ProgramBreedingMethodEntity breedingMethod = null; + if (germplasm.getBreedingMethod() != null) { + if (breedingMethods.containsKey(germplasm.getBreedingMethod())) { + breedingMethod = breedingMethods.get(germplasm.getBreedingMethod()); + } else { + List breedingMethodResults = breedingMethodDAO.findByNameOrAbbreviation(germplasm.getBreedingMethod(), program.getId()); + if (breedingMethodResults.size() > 0) { + breedingMethods.put(germplasm.getBreedingMethod(), breedingMethodResults.get(0)); + breedingMethod = breedingMethods.get(germplasm.getBreedingMethod()); + } else { + ValidationError ve = new ValidationError("Breeding Method", badBreedMethodsMsg, HttpStatus.UNPROCESSABLE_ENTITY); + validationErrors.addError(i + 2, ve); // +2 instead of +1 to account for the column header row. + badBreedingMethods.add(germplasm.getBreedingMethod()); + } + } + } + + validatePedigree(germplasm, i + 2, validationErrors); + + BrAPIGermplasm newGermplasm = germplasm.constructBrAPIGermplasm(program, breedingMethod, user, commit, BRAPI_REFERENCE_SOURCE, nextVal, importListId); + + newGermplasmList.add(newGermplasm); + // Assign status of the germplasm + if (fileGermplasmByName.get(newGermplasm.getDefaultDisplayName()) > 1 || dbGermplasmByName.containsKey(newGermplasm.getDefaultDisplayName())) { + mappedImportRow.setGermplasm(new PendingImportObject<>(ImportObjectState.EXISTING, newGermplasm)); + } else { + mappedImportRow.setGermplasm(new PendingImportObject<>(ImportObjectState.NEW, newGermplasm)); + } + + importList.addDataItem(newGermplasm.getGermplasmName()); + } + + private boolean processExistingGermplasm(Germplasm germplasm, ValidationErrors validationErrors, List importRows, Program program, UUID importListId, boolean commit, PendingImport mappedImportRow, int rowIndex) { + BrAPIGermplasm existingGermplasm; + String gid = germplasm.getAccessionNumber(); + if (germplasmByAccessionNumber.containsKey(gid)) { + existingGermplasm = germplasmByAccessionNumber.get(gid).getBrAPIObject(); + } else { + //should be caught in getExistingBrapiData + ValidationError ve = new ValidationError("GID", String.format(missingGID, gid), HttpStatus.NOT_FOUND); + validationErrors.addError(rowIndex+2, ve ); // +2 instead of +1 to account for the column header row. + return false; + } + + // Error conditions: + // has existing pedigree and file pedigree is different and not empty + // Valid conditions: + // no existing pedigree and file different pedigree + // existing pedigree and file pedigree same + // existing pedigree and file pedigree empty + if(hasPedigree(existingGermplasm) && germplasm.pedigreeExists()) { + if(!arePedigreesEqual(existingGermplasm, germplasm, importRows)) { + ValidationError ve = new ValidationError("Pedigree", pedigreeAlreadyExists, HttpStatus.UNPROCESSABLE_ENTITY); + validationErrors.addError(rowIndex + 2, ve); // +2 instead of +1 to account for the column header row. + return false; + } + } + + if(germplasm.pedigreeExists()) { + validatePedigree(germplasm, rowIndex + 2, validationErrors); + } + + germplasm.updateBrAPIGermplasm(existingGermplasm, program, importListId, commit, true); + + updatedGermplasmList.add(existingGermplasm); + mappedImportRow.setGermplasm(new PendingImportObject<>(ImportObjectState.MUTATED, existingGermplasm)); + importList.addDataItem(existingGermplasm.getGermplasmName()); + + + return true; + } + + private boolean canUpdatePedigree(BrAPIGermplasm existingGermplasm, Germplasm germplasm) { + return !hasPedigreeString(existingGermplasm) && germplasm.pedigreeExists(); + } + + private boolean hasPedigreeString(BrAPIGermplasm germplasm) { + return StringUtils.isNotBlank(germplasm.getPedigree()); + } + + private boolean hasPedigree(BrAPIGermplasm germplasm) { + return StringUtils.isNotBlank(germplasm.getPedigree()) + || germplasm.getAdditionalInfo().has(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_GID) + || germplasm.getAdditionalInfo().has(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_GID) + || (germplasm.getAdditionalInfo().has(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN) && + germplasm.getAdditionalInfo().get(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN).getAsBoolean()) + || (germplasm.getAdditionalInfo().has(BrAPIAdditionalInfoFields.MALE_PARENT_UNKNOWN) && + germplasm.getAdditionalInfo().get(BrAPIAdditionalInfoFields.MALE_PARENT_UNKNOWN).getAsBoolean()); + } + + /** + * Compare an existing germplasm's pedigree to the incoming germplasm's pedigree to ensure they are the same.

+ * Assumes that an empty value for a given parent in the incoming germplasm is equal to the existing germplasm.

+ * Assumes that the existing germplasm has pedigree + * @param existingGermplasm the existing germplasm with pedigree + * @param germplasm the germplasm record coming in the file + * @param importRows all records coming in the file. Needed to look up GID of a parent referenced by entry number in the file + * @return true if the two germplasm pedigrees are effectively equal, false otherwise + */ + private boolean arePedigreesEqual(BrAPIGermplasm existingGermplasm, Germplasm germplasm, List importRows) { + if(germplasm.pedigreeExists()) { + StringBuilder existingPedigreeGIDString = new StringBuilder(); + String existingFemalePedigree = getParentId(existingGermplasm, existingPedigreeGIDString, BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_GID, BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN); + existingPedigreeGIDString.append("/"); + String existingMalePedigree = getParentId(existingGermplasm, existingPedigreeGIDString, BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_GID, BrAPIAdditionalInfoFields.MALE_PARENT_UNKNOWN); + + StringBuilder germplasmPedigreeGIDString = new StringBuilder(); + if (StringUtils.isNotBlank(germplasm.getFemaleParentDBID())) { + germplasmPedigreeGIDString.append(germplasm.getFemaleParentDBID()); + } else if (StringUtils.isNotBlank(germplasm.getFemaleParentEntryNo())) { + Integer femaleParentIdx = germplasmIndexByEntryNo.get(germplasm.getFemaleParentEntryNo()); + BrAPIImport femaleParentRow = importRows.get(femaleParentIdx); + BrAPIGermplasm femaleGerm = dbGermplasmByName.get(femaleParentRow.getGermplasm() + .getGermplasmName()); + if (femaleGerm != null) { + germplasmPedigreeGIDString.append(femaleGerm.getAccessionNumber()); + } else { + germplasmPedigreeGIDString.append("-1"); + } + } else { + germplasmPedigreeGIDString.append(existingFemalePedigree); + } + germplasmPedigreeGIDString.append("/"); + if (StringUtils.isNotBlank(germplasm.getMaleParentDBID())) { + germplasmPedigreeGIDString.append(germplasm.getMaleParentDBID()); + } else if (StringUtils.isNotBlank(germplasm.getMaleParentEntryNo())) { + Integer maleParentIdx = germplasmIndexByEntryNo.get(germplasm.getMaleParentEntryNo()); + BrAPIImport maleParentRow = importRows.get(maleParentIdx); + BrAPIGermplasm maleGerm = dbGermplasmByName.get(maleParentRow.getGermplasm() + .getGermplasmName()); + if (maleGerm != null) { + germplasmPedigreeGIDString.append(maleGerm.getAccessionNumber()); + } else { + germplasmPedigreeGIDString.append("-1"); + } + } else { + germplasmPedigreeGIDString.append(existingMalePedigree); + } + + return existingPedigreeGIDString.toString().equals(germplasmPedigreeGIDString.toString()); + } else { + return true; + } + } + + private String getParentId(BrAPIGermplasm existingGermplasm, StringBuilder pedigreeGIDString, String gidAdditionaInfoField, String unknownAdditionalInfoField) { + if (existingGermplasm.getAdditionalInfo() + .has(gidAdditionaInfoField)) { + pedigreeGIDString.append(existingGermplasm.getAdditionalInfo() + .get(gidAdditionaInfoField) + .getAsString()); + return existingGermplasm.getAdditionalInfo() + .get(gidAdditionaInfoField) + .getAsString(); + } else if (existingGermplasm.getAdditionalInfo() + .has(unknownAdditionalInfoField) && existingGermplasm.getAdditionalInfo() + .get(unknownAdditionalInfoField) + .getAsBoolean()) { + pedigreeGIDString.append("0"); + return "0"; + } + return ""; + } + + private boolean canUpdatePedigreeNoEqualsCheck(BrAPIGermplasm existingGermplasm, Germplasm germplasm) { + + + return StringUtils.isBlank(existingGermplasm.getPedigree()) && + germplasm.pedigreeExists(); + } + private Map getStatisticsMap(List importRows) { ImportPreviewStatistics germplasmStats = ImportPreviewStatistics.builder() @@ -439,8 +557,8 @@ private void createPostOrder() { List pedigreeArray = List.of(germplasm.getPedigree().split("/")); String femaleParent = pedigreeArray.get(0); String maleParent = pedigreeArray.size() > 1 ? pedigreeArray.get(1) : null; - if (created.contains(femaleParent) || germplasm.getAdditionalInfo().get("femaleParentUnknown").getAsBoolean()) { - if (maleParent == null || created.contains(maleParent) || germplasm.getAdditionalInfo().get("maleParentUnknown").getAsBoolean()) { + if (created.contains(femaleParent) || germplasm.getAdditionalInfo().get(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN).getAsBoolean()) { + if (maleParent == null || created.contains(maleParent) || germplasm.getAdditionalInfo().get(BrAPIAdditionalInfoFields.MALE_PARENT_UNKNOWN).getAsBoolean()) { createList.add(germplasm); } } @@ -448,7 +566,7 @@ private void createPostOrder() { totalRecorded += createList.size(); if (createList.size() > 0) { - created.addAll(createList.stream().map(brAPIGermplasm -> brAPIGermplasm.getGermplasmName()).collect(Collectors.toList())); + created.addAll(createList.stream().map(BrAPIGermplasm::getGermplasmName).collect(Collectors.toList())); postOrder.add(createList); } else if (totalRecorded < newGermplasmList.size()) { // We ran into circular dependencies, throw an error @@ -531,13 +649,16 @@ public void constructPedigreeString(List importRows, Map importRows, Map existingPedigree = existingGermplasms.stream() - .filter(g -> g.equals(brapiGermplasm) && StringUtils.isBlank(g.getPedigree())) - .findFirst(); + // no existing pedigree and pedigree not empty + // pedigrees will be equal at this point from prior processing code if being updated so don't check that + if (canUpdatePedigree(brAPIGermplasm, germplasm)) { - if (existingPedigree.isEmpty()) { - mappedBrAPIImport.get(i).getGermplasm().getBrAPIObject().setPedigree(pedigreeString.length() > 0 ? pedigreeString.toString() : null); + brAPIGermplasm.setPedigree(pedigreeString.length() > 0 ? pedigreeString.toString() : null); //Simpler to just always add boolean, but consider for logic that previous imported values won't have that additional info value - mappedBrAPIImport.get(i).getGermplasm().getBrAPIObject().putAdditionalInfoItem(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN, femaleParentUnknown); - mappedBrAPIImport.get(i).getGermplasm().getBrAPIObject().putAdditionalInfoItem(BrAPIAdditionalInfoFields.MALE_PARENT_UNKNOWN, maleParentUnknown); + brAPIGermplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN, femaleParentUnknown); + brAPIGermplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.MALE_PARENT_UNKNOWN, maleParentUnknown); + + if (commit) { + if (femaleParentFound) { + brAPIGermplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_GID, femaleParent.getAccessionNumber()); + } + + if (maleParent != null) { + brAPIGermplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_GID, maleParent.getAccessionNumber()); + } + } } } }