diff --git a/src/main/java/org/breedinginsight/brapi/v2/constants/BrAPIAdditionalInfoFields.java b/src/main/java/org/breedinginsight/brapi/v2/constants/BrAPIAdditionalInfoFields.java index 27179be76..f82a718ed 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/constants/BrAPIAdditionalInfoFields.java +++ b/src/main/java/org/breedinginsight/brapi/v2/constants/BrAPIAdditionalInfoFields.java @@ -23,6 +23,8 @@ public final class BrAPIAdditionalInfoFields { public static final String GERMPLASM_RAW_PEDIGREE = "rawPedigree"; public static final String GERMPLASM_PEDIGREE_BY_NAME = "pedigreeByName"; public static final String GERMPLASM_PEDIGREE_BY_UUID = "pedigreeByUUID"; + public static final String GERMPLASM_FEMALE_PARENT_UUID = "femaleParentUUID"; + public static final String GERMPLASM_MALE_PARENT_UUID = "maleParentUUID"; public static final String GERMPLASM_IMPORT_ENTRY_NUMBER = "importEntryNumber"; public static final String GERMPLASM_FEMALE_PARENT_GID = "femaleParentGid"; public static final String GERMPLASM_MALE_PARENT_GID = "maleParentGid"; 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 3adbb99ff..58f0653bc 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIGermplasmDAO.java +++ b/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIGermplasmDAO.java @@ -158,9 +158,7 @@ private Map processGermplasmForDisplay(List programGermplasmMap = new HashMap<>(); log.trace("processing germ for display: " + programGermplasm); - Map programGermplasmByFullName = new HashMap<>(); for (BrAPIGermplasm germplasm: programGermplasm) { - programGermplasmByFullName.put(germplasm.getGermplasmName(), germplasm); JsonObject additionalInfo = germplasm.getAdditionalInfo(); if (additionalInfo != null && additionalInfo.has(BrAPIAdditionalInfoFields.GERMPLASM_BREEDING_METHOD_ID)) { @@ -192,46 +190,70 @@ private Map processGermplasmForDisplay(List parents = Arrays.asList("",""); - if (germplasm.getPedigree() != null) { - parents = Arrays.asList(germplasm.getPedigree().split("/")); - } - if (parents.size() >= 1) { - if (programGermplasmByFullName.containsKey(parents.get(0))) { - String femaleParentAccessionNumber = programGermplasmByFullName.get(parents.get(0)).getAccessionNumber(); - newPedigreeString = femaleParentAccessionNumber; - namePedigreeString = programGermplasmByFullName.get(parents.get(0)).getDefaultDisplayName(); - uuidPedigreeString = programGermplasmByFullName.get(parents.get(0)).getExternalReferences(). - stream().filter(ref -> ref.getReferenceSource().equals(referenceSource)). - map(ref -> ref.getReferenceID()).findFirst().orElse(""); - additionalInfo.addProperty(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_GID, femaleParentAccessionNumber); - } else if (additionalInfo.has(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN) && additionalInfo.get(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN).getAsBoolean()) { - namePedigreeString = "Unknown"; + + // Get parent germplasm names without program key. + // This is designed so that pedigree="female/" will result in parentNames=["female", ""] + // and pedigree="/male" will result in parentNames=["", "male"]; + // pedigree=null or pedigree="" will result in parentNames=[]. + List parentNames = new ArrayList<>(); + if (pedigree != null) { + // Note: split with limit=-1 applies pattern as many times as possible, allowing capture of leading or trailing empty strings. + for (String name : pedigree.split("/", -1)) { + if (!name.isEmpty()) + { + // Strip program key. + name = Utilities.removeProgramKeyAndUnknownAdditionalData(name, programKey); } + parentNames.add(name); } - if (parents.size() == 2) { - if (programGermplasmByFullName.containsKey(parents.get(1))) { - String maleParentAccessionNumber = programGermplasmByFullName.get(parents.get(1)).getAccessionNumber(); - newPedigreeString += "/" + maleParentAccessionNumber; - namePedigreeString += "/" + programGermplasmByFullName.get(parents.get(1)).getDefaultDisplayName(); - uuidPedigreeString += "/" + programGermplasmByFullName.get(parents.get(1)).getExternalReferences(). - stream().filter(ref -> ref.getReferenceSource().equals(referenceSource)). - map(ref -> ref.getReferenceID()).findFirst().orElse(""); - additionalInfo.addProperty(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_GID, maleParentAccessionNumber); + } + + // Update pedigree info for female parent. + if (parentNames.size() >= 1 && !parentNames.get(0).isEmpty()) + { + gidPedigreeString = additionalInfo.has(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_GID) ? additionalInfo.get(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_GID).getAsString() : ""; + namePedigreeString = parentNames.get(0); + uuidPedigreeString = additionalInfo.has(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_UUID) ? additionalInfo.get(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_UUID).getAsString() : ""; + // Throw a descriptive error if femaleParentUUID is absent. + if (!additionalInfo.has(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_UUID)) { + String programId = "unknown program"; + Optional exRef = Utilities.getExternalReference(germplasm.getExternalReferences(), referenceSource + "/programs"); + if (exRef.isPresent()) { + programId = exRef.get().getReferenceID(); } + log.debug("The germplasm data for program " + programId + " needs to be updated: https://github.com/Breeding-Insight/bi-api/pull/290"); + throw new InternalServerException("Germplasm (" + germplasm.getGermplasmName() + ") has a female parent but femaleParentUUID is missing (Pedigree: " + germplasm.getPedigree() + ")."); } - //Add Unknown germplasm for display - if (additionalInfo.has(BrAPIAdditionalInfoFields.MALE_PARENT_UNKNOWN) && additionalInfo.get(BrAPIAdditionalInfoFields.MALE_PARENT_UNKNOWN).getAsBoolean()) { - namePedigreeString += "/Unknown"; + } else if (additionalInfo.has(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN) && additionalInfo.get(BrAPIAdditionalInfoFields.FEMALE_PARENT_UNKNOWN).getAsBoolean()) { + namePedigreeString = "Unknown"; + } + // Update pedigree info for male parent. + if (parentNames.size() == 2 && !parentNames.get(1).isEmpty()) + { + gidPedigreeString += "/" + (additionalInfo.has(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_GID) ? additionalInfo.get(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_GID).getAsString() : ""); + namePedigreeString += "/" + parentNames.get(1); + uuidPedigreeString += "/" + (additionalInfo.has(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_UUID) ? additionalInfo.get(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_UUID).getAsString() : ""); + // Throw a descriptive error if maleParentUUID is absent. + if (!additionalInfo.has(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_UUID)) { + String programId = "unknown program"; + Optional exRef = Utilities.getExternalReference(germplasm.getExternalReferences(), referenceSource + "/programs"); + if (exRef.isPresent()) { + programId = exRef.get().getReferenceID(); + } + log.debug("The germplasm data for program " + programId + " needs to be updated: https://github.com/Breeding-Insight/bi-api/pull/290"); + throw new InternalServerException("Germplasm (" + germplasm.getGermplasmName() + ") has a male parent but maleParentUUID is missing (Pedigree: " + germplasm.getPedigree() + ")."); } - //For use in individual germplasm display - additionalInfo.addProperty(BrAPIAdditionalInfoFields.GERMPLASM_PEDIGREE_BY_NAME, namePedigreeString); - additionalInfo.addProperty(BrAPIAdditionalInfoFields.GERMPLASM_PEDIGREE_BY_UUID, uuidPedigreeString); + } else if (additionalInfo.has(BrAPIAdditionalInfoFields.MALE_PARENT_UNKNOWN) && additionalInfo.get(BrAPIAdditionalInfoFields.MALE_PARENT_UNKNOWN).getAsBoolean()) { + namePedigreeString += "/Unknown"; + } + //For use in individual germplasm display + additionalInfo.addProperty(BrAPIAdditionalInfoFields.GERMPLASM_PEDIGREE_BY_NAME, namePedigreeString); + additionalInfo.addProperty(BrAPIAdditionalInfoFields.GERMPLASM_PEDIGREE_BY_UUID, uuidPedigreeString); - germplasm.setPedigree(newPedigreeString); + germplasm.setPedigree(gidPedigreeString); BrAPIExternalReference extRef = germplasm.getExternalReferences().stream().filter(reference -> referenceSource.equals(reference.getReferenceSource())).findFirst().orElseThrow(() -> new IllegalStateException("No BI external reference found")); String germplasmId = extRef.getReferenceID(); @@ -293,10 +315,8 @@ public List updateBrAPIGermplasm(List putBrAPIGe try { if (!putBrAPIGermplasmList.isEmpty()) { postFunction = () -> { - putGermplasm(putBrAPIGermplasmList, api); - // Need all program germplasm for processGermplasmForDisplay parents pedigree - List germplasm = getRawGermplasm(programId); - return processGermplasmForDisplay(germplasm, program.getKey()); + List putResponse = putGermplasm(putBrAPIGermplasmList, api); + return processGermplasmForDisplay(putResponse, program.getKey()); }; } return programGermplasmCache.post(programId, postFunction); 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 365236f01..f51f7c1fb 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 @@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.brapi.client.v2.model.exceptions.ApiException; +import org.brapi.v2.model.BrAPIExternalReference; import org.brapi.v2.model.core.BrAPIListSummary; import org.brapi.v2.model.core.request.BrAPIListNewRequest; import org.brapi.v2.model.germ.BrAPIGermplasm; @@ -45,6 +46,7 @@ import org.breedinginsight.model.Program; import org.breedinginsight.model.User; import org.breedinginsight.services.exceptions.ValidatorException; +import org.breedinginsight.utilities.Utilities; import org.jooq.DSLContext; import tech.tablesaw.api.Table; @@ -717,11 +719,20 @@ else if (germplasmIndexByEntryNo.containsKey(germplasm.getFemaleParentEntryNo()) if (commit) { if (femaleParentFound) { brAPIGermplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_GID, femaleParent.getAccessionNumber()); + // Add femaleParentUUID to additionalInfo. + Optional femaleParentUUID = Utilities.getExternalReference(femaleParent.getExternalReferences(), BRAPI_REFERENCE_SOURCE); + if (femaleParentUUID.isPresent()) { + brAPIGermplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_FEMALE_PARENT_UUID, femaleParentUUID.get().getReferenceID()); + } } if (maleParent != null) { brAPIGermplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_GID, maleParent.getAccessionNumber()); - } + // Add maleParentUUID to additionalInfo. + Optional maleParentUUID = Utilities.getExternalReference(maleParent.getExternalReferences(), BRAPI_REFERENCE_SOURCE); + if (maleParentUUID.isPresent()) { + brAPIGermplasm.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_MALE_PARENT_UUID, maleParentUUID.get().getReferenceID()); + } } } } } diff --git a/src/test/java/org/breedinginsight/services/BrAPIGermplasmServiceUnitTest.java b/src/test/java/org/breedinginsight/services/BrAPIGermplasmServiceUnitTest.java index c78100eef..49d55d9e9 100644 --- a/src/test/java/org/breedinginsight/services/BrAPIGermplasmServiceUnitTest.java +++ b/src/test/java/org/breedinginsight/services/BrAPIGermplasmServiceUnitTest.java @@ -36,6 +36,7 @@ import java.util.*; import java.util.stream.Collectors; +import static org.breedinginsight.brapi.v2.constants.BrAPIAdditionalInfoFields.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; @@ -92,6 +93,7 @@ public void getGermplasmListExport() { listResponse.setResult(listDetails); //Create Germplasm + String parentUuid = UUID.randomUUID().toString(); List germplasm = new ArrayList(); BrAPIGermplasm testGermplasm = new BrAPIGermplasm(); testGermplasm.setGermplasmName("Germplasm A [TEST-1]"); @@ -99,13 +101,13 @@ public void getGermplasmListExport() { testGermplasm.setAccessionNumber("1"); testGermplasm.setDefaultDisplayName("Germplasm A"); JsonObject additionalInfo = new JsonObject(); - additionalInfo.addProperty("importEntryNumber", "2"); - additionalInfo.addProperty("breedingMethod", "Allopolyploid"); + additionalInfo.addProperty(GERMPLASM_IMPORT_ENTRY_NUMBER, "2"); + additionalInfo.addProperty(GERMPLASM_BREEDING_METHOD, "Allopolyploid"); testGermplasm.setAdditionalInfo(additionalInfo); List externalRef = new ArrayList<>(); BrAPIExternalReference testReference = new BrAPIExternalReference(); testReference.setReferenceSource(referenceSource); - testReference.setReferenceID(UUID.randomUUID().toString()); + testReference.setReferenceID(parentUuid); externalRef.add(testReference); testGermplasm.setExternalReferences(externalRef); germplasm.add(testGermplasm); @@ -117,8 +119,9 @@ public void getGermplasmListExport() { testGermplasm.setDefaultDisplayName("Germplasm B"); testGermplasm.setPedigree("Germplasm A [TEST-1]"); additionalInfo = new JsonObject(); - additionalInfo.addProperty("importEntryNumber", "3"); - additionalInfo.addProperty("breedingMethod", "Autopolyploid"); + additionalInfo.addProperty(GERMPLASM_IMPORT_ENTRY_NUMBER, "3"); + additionalInfo.addProperty(GERMPLASM_BREEDING_METHOD, "Autopolyploid"); + additionalInfo.addProperty(GERMPLASM_FEMALE_PARENT_UUID, parentUuid); testGermplasm.setAdditionalInfo(additionalInfo); testReference = new BrAPIExternalReference(); testReference.setReferenceSource(referenceSource);