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 e037cb96e..7fe94de1f 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/constants/BrAPIAdditionalInfoFields.java +++ b/src/main/java/org/breedinginsight/brapi/v2/constants/BrAPIAdditionalInfoFields.java @@ -32,4 +32,8 @@ public final class BrAPIAdditionalInfoFields { public static final String GERMPLASM_BREEDING_METHOD_ID = "breedingMethodId"; public static final String GERMPLASM_BREEDING_METHOD = "breedingMethod"; public static final String CREATED_DATE = "createdDate"; + public static final String DEFAULT_OBSERVATION_LEVEL = "defaultObservationLevel"; + public static final String OBSERVATION_LEVEL = "observationLevel"; + public static final String EXPERIMENT_TYPE = "experimentType"; + public static final String EXPERIMENT_NUMBER = "experimentNumber"; } diff --git a/src/main/java/org/breedinginsight/brapps/importer/controllers/UploadController.java b/src/main/java/org/breedinginsight/brapps/importer/controllers/UploadController.java index a0da96dd6..f9d55bd20 100644 --- a/src/main/java/org/breedinginsight/brapps/importer/controllers/UploadController.java +++ b/src/main/java/org/breedinginsight/brapps/importer/controllers/UploadController.java @@ -35,6 +35,7 @@ import org.breedinginsight.brapps.importer.services.FileImportService; import org.breedinginsight.services.exceptions.*; +import javax.annotation.Nullable; import javax.inject.Inject; import java.util.Map; import java.util.UUID; @@ -110,7 +111,7 @@ public HttpResponse> getUploadData(@PathVariable UUID p @AddMetadata @ProgramSecured(roles = {ProgramSecuredRole.BREEDER, ProgramSecuredRole.SYSTEM_ADMIN}) public HttpResponse> commitData(@PathVariable UUID programId, @PathVariable UUID mappingId, - @PathVariable UUID uploadId, @Body Map userInput) { + @PathVariable UUID uploadId, @Body @Nullable Map userInput) { try { AuthenticatedUser actingUser = securityService.getUser(); ImportResponse result = fileImportService.updateUpload(programId, uploadId, actingUser, userInput, true); diff --git a/src/main/java/org/breedinginsight/brapps/importer/daos/BrAPISeasonDAO.java b/src/main/java/org/breedinginsight/brapps/importer/daos/BrAPISeasonDAO.java new file mode 100644 index 000000000..235c752fb --- /dev/null +++ b/src/main/java/org/breedinginsight/brapps/importer/daos/BrAPISeasonDAO.java @@ -0,0 +1,73 @@ +package org.breedinginsight.brapps.importer.daos; + +import lombok.extern.slf4j.Slf4j; +import org.brapi.client.v2.ApiResponse; +import org.brapi.client.v2.model.exceptions.ApiException; +import org.brapi.client.v2.model.queryParams.core.SeasonQueryParams; +import org.brapi.client.v2.modules.core.ListsApi; +import org.brapi.client.v2.modules.core.SeasonsApi; +import org.brapi.v2.model.BrAPIExternalReference; +import org.brapi.v2.model.BrAPIResponse; +import org.brapi.v2.model.BrAPIResponseResult; +import org.brapi.v2.model.core.BrAPIListSummary; +import org.brapi.v2.model.core.BrAPIListTypes; +import org.brapi.v2.model.core.BrAPISeason; +import org.brapi.v2.model.core.request.BrAPIListNewRequest; +import org.brapi.v2.model.core.request.BrAPIListSearchRequest; +import org.brapi.v2.model.core.response.BrAPIListsSingleResponse; +import org.brapi.v2.model.core.response.BrAPISeasonListResponse; +import org.brapi.v2.model.core.response.BrAPISeasonListResponseResult; +import org.brapi.v2.model.pheno.BrAPIObservation; +import org.breedinginsight.brapps.importer.model.ImportUpload; +import org.breedinginsight.daos.ProgramDAO; +import org.breedinginsight.utilities.BrAPIDAOUtil; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +@Slf4j +public class BrAPISeasonDAO { + + private ProgramDAO programDAO; + private ImportDAO importDAO; + + @Inject + public BrAPISeasonDAO(ProgramDAO programDAO, ImportDAO importDAO) { + this.programDAO = programDAO; + this.importDAO = importDAO; + } + + public List getSeasonByYear(String year, UUID programId) throws ApiException { + SeasonsApi api = new SeasonsApi(programDAO.getCoreClient(programId)); + SeasonQueryParams queryParams = + SeasonQueryParams.builder() + .year( year ) + .pageSize( 10000 ) + .build(); + List seasons = new ArrayList<>(); + ApiResponse apiResponse = api.seasonsGet( queryParams ); + BrAPISeasonListResponse seasonListResponse = apiResponse.getBody(); + BrAPISeasonListResponseResult result = seasonListResponse.getResult(); + seasons = result.getData(); + + return seasons; + } + + public BrAPISeason addOneSeason(BrAPISeason season, UUID programId) throws ApiException { + BrAPISeason resultSeason = null; + SeasonsApi api = new SeasonsApi(programDAO.getCoreClient(programId)); + + ApiResponse apiResponse = api.seasonsPost(Arrays.asList(season)); + BrAPISeasonListResponse seasonListResponse = apiResponse.getBody(); + BrAPISeasonListResponseResult result = seasonListResponse.getResult(); + List seasons = result.getData(); + if (seasons.size() > 0) { + resultSeason = seasons.get(0); + } + return resultSeason; + } + +} diff --git a/src/main/java/org/breedinginsight/brapps/importer/daos/BrAPIStudyDAO.java b/src/main/java/org/breedinginsight/brapps/importer/daos/BrAPIStudyDAO.java index ab9197666..3752a394b 100644 --- a/src/main/java/org/breedinginsight/brapps/importer/daos/BrAPIStudyDAO.java +++ b/src/main/java/org/breedinginsight/brapps/importer/daos/BrAPIStudyDAO.java @@ -16,6 +16,7 @@ */ package org.breedinginsight.brapps.importer.daos; +import io.micronaut.context.annotation.Property; import org.brapi.client.v2.model.exceptions.ApiException; import org.brapi.client.v2.modules.core.StudiesApi; import org.brapi.v2.model.core.BrAPIStudy; @@ -32,6 +33,8 @@ @Singleton public class BrAPIStudyDAO { + @Property(name = "brapi.server.reference-source") + private String BRAPI_REFERENCE_SOURCE; private ProgramDAO programDAO; private ImportDAO importDAO; @@ -54,6 +57,19 @@ public List getStudyByName(List studyNames, Program program) ); } + public List getStudiesByExperimentID(UUID experimentID, Program program ) throws ApiException { + BrAPIStudySearchRequest studySearch = new BrAPIStudySearchRequest(); + studySearch.programDbIds(List.of(program.getBrapiProgram().getProgramDbId())); + studySearch.addExternalReferenceIDsItem(experimentID.toString()); + studySearch.addExternalReferenceSourcesItem(BRAPI_REFERENCE_SOURCE + "/trials"); + StudiesApi api = new StudiesApi(programDAO.getCoreClient(program.getId())); + return BrAPIDAOUtil.search( + api::searchStudiesPost, + api::searchStudiesSearchResultsDbIdGet, + studySearch + ); + } + public List createBrAPIStudy(List brAPIStudyList, UUID programId, ImportUpload upload) throws ApiException { StudiesApi api = new StudiesApi(programDAO.getCoreClient(programId)); return BrAPIDAOUtil.post(brAPIStudyList, upload, api::studiesPost, importDAO::update); diff --git a/src/main/java/org/breedinginsight/brapps/importer/model/imports/experimentObservation/ExperimentObservation.java b/src/main/java/org/breedinginsight/brapps/importer/model/imports/experimentObservation/ExperimentObservation.java index f7cd41151..a5888f645 100644 --- a/src/main/java/org/breedinginsight/brapps/importer/model/imports/experimentObservation/ExperimentObservation.java +++ b/src/main/java/org/breedinginsight/brapps/importer/model/imports/experimentObservation/ExperimentObservation.java @@ -20,10 +20,14 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.brapi.v2.model.BrAPIExternalReference; import org.brapi.v2.model.core.*; import org.brapi.v2.model.pheno.*; +import org.breedinginsight.brapi.v2.constants.BrAPIAdditionalInfoFields; import org.breedinginsight.brapps.importer.model.config.*; import org.breedinginsight.brapps.importer.model.imports.BrAPIImport; +import org.breedinginsight.brapps.importer.services.ExternalReferenceSource; +import org.breedinginsight.model.BrAPIConstants; import org.breedinginsight.model.Program; import org.breedinginsight.utilities.Utilities; @@ -106,11 +110,14 @@ public class ExperimentObservation implements BrAPIImport { @ImportFieldMetadata(id="ObsUnitID", name="Observation Unit ID", description = "A database generated unique identifier for experimental observation units") private String ObsUnitID; - public BrAPITrial constructBrAPITrial(Program program, boolean commit) { + public BrAPITrial constructBrAPITrial(Program program, boolean commit, String referenceSource, UUID id, String expSeqValue) { BrAPIProgram brapiProgram = program.getBrapiProgram(); BrAPITrial trial = new BrAPITrial(); if( commit ){ - trial.setTrialName( getTrialNameWithProgramKey( program )); + trial.setTrialName( Utilities.appendProgramKey(getExpTitle(), program.getKey() )); + + // Set external reference + trial.setExternalReferences(getTrialExternalReferences(program, referenceSource, id)); } else{ trial.setTrialName( getExpTitle() ); @@ -120,14 +127,11 @@ public BrAPITrial constructBrAPITrial(Program program, boolean commit) { trial.setProgramDbId(brapiProgram.getProgramDbId()); trial.setProgramName(brapiProgram.getProgramName()); - // TODO: Get to a constant - trial.putAdditionalInfoItem("defaultObservationLevel", getExpUnit()); - trial.putAdditionalInfoItem("experimentType", getExpType()); - return trial; - } + trial.putAdditionalInfoItem( BrAPIAdditionalInfoFields.DEFAULT_OBSERVATION_LEVEL, getExpUnit()); + trial.putAdditionalInfoItem( BrAPIAdditionalInfoFields.EXPERIMENT_TYPE, getExpType()); + trial.putAdditionalInfoItem( BrAPIAdditionalInfoFields.EXPERIMENT_NUMBER, expSeqValue); - public String getTrialNameWithProgramKey(Program program){ - return String.format("%s [%s]", getExpTitle(), program.getKey()); + return trial; } public BrAPILocation constructBrAPILocation() { @@ -136,10 +140,19 @@ public BrAPILocation constructBrAPILocation() { return location; } - public BrAPIStudy constructBrAPIStudy(Program program, Supplier nextVal, boolean commit) { + public BrAPIStudy constructBrAPIStudy( + Program program, + boolean commit, + String referenceSource, + String expSequenceValue, + UUID trialId, + UUID id) { BrAPIStudy study = new BrAPIStudy(); if ( commit ){ - study.setStudyName(Utilities.appendProgramKey(getEnv(), program.getKey(), nextVal.get().toString())); + study.setStudyName(Utilities.appendProgramKey(getEnv(), program.getKey(), expSequenceValue)); + + // Set external reference + study.setExternalReferences(getStudyExternalReferences(program, referenceSource, trialId, id)); } else { study.setStudyName(getEnv()); @@ -149,43 +162,61 @@ public BrAPIStudy constructBrAPIStudy(Program program, Supplier next study.setLocationName(getEnvLocation()); study.setTrialName(getExpTitle()); - List seasonsList= new ArrayList<>(); - seasonsList.add(getEnvYear()); - study.setSeasons(seasonsList); - /* - TODO: Not used + List seasonList = new ArrayList<>(); + seasonList.add( getEnvYear() ); + study.setSeasons( seasonList ); + + String designType = "Analysis"; // to support the BRApi server, the design type must be one of the following: + // 'CRD','Alpha','MAD','Lattice','Augmented','RCBD','p-rep','splitplot','greenhouse','Westcott', or 'Analysis' + // For now it will be hardcoded to 'Analysis' BrAPIStudyExperimentalDesign design = new BrAPIStudyExperimentalDesign(); - design.setPUI(getExperimentalDesignPUI()); + design.setPUI(designType); + design.setDescription(designType); study.setExperimentalDesign(design); - */ return study; } - public BrAPIObservationUnit constructBrAPIObservationUnit(Program program, Supplier nextVal, boolean commit) { + public BrAPIObservationUnit constructBrAPIObservationUnit( + Program program, + Supplier nextVal, + boolean commit, + String germplasmName, + String referenceSource, + UUID trialID, + UUID studyID, + UUID id + ) { BrAPIObservationUnit observationUnit = new BrAPIObservationUnit(); if( commit){ observationUnit.setObservationUnitName( Utilities.appendProgramKey(getExpUnitId(), program.getKey(), nextVal.get().toString())); + + // Set external reference + observationUnit.setExternalReferences(getObsUnitExternalReferences(program, referenceSource, trialID, studyID, id)); } else { observationUnit.setObservationUnitName(getExpUnitId()); } observationUnit.setStudyName(getEnv()); - // TODO: Set the germplasm - //observationUnit.setGermplasmName(getGermplasm().getReferenceValue()); + if(germplasmName==null){ + germplasmName = getGermplasmName(); + } + observationUnit.setGermplasmName(germplasmName); BrAPIObservationUnitPosition position = new BrAPIObservationUnitPosition(); BrAPIObservationUnitLevelRelationship level = new BrAPIObservationUnitLevelRelationship(); - level.setLevelName(getExpUnit()); + level.setLevelName("plot"); //BreedBase only accepts "plot" or "plant" + level.setLevelCode( getExpUnitId() ); position.setObservationLevel(level); + observationUnit.putAdditionalInfoItem(BrAPIAdditionalInfoFields.OBSERVATION_LEVEL, getExpUnit()); // Exp Unit List levelRelationships = new ArrayList<>(); if( getExpReplicateNo() !=null ) { BrAPIObservationUnitLevelRelationship repLvl = new BrAPIObservationUnitLevelRelationship(); - repLvl.setLevelName("replicate"); + repLvl.setLevelName(BrAPIConstants.REPLICATE.getValue()); repLvl.setLevelCode(getExpReplicateNo()); levelRelationships.add(repLvl); } @@ -193,7 +224,7 @@ public BrAPIObservationUnit constructBrAPIObservationUnit(Program program, Suppl // Block number if( getExpBlockNo() != null ) { BrAPIObservationUnitLevelRelationship repLvl = new BrAPIObservationUnitLevelRelationship(); - repLvl.setLevelName("block"); + repLvl.setLevelName( BrAPIConstants.REPLICATE.getValue() ); repLvl.setLevelCode(getExpBlockNo()); levelRelationships.add(repLvl); } @@ -227,4 +258,39 @@ public BrAPIObservationUnit constructBrAPIObservationUnit(Program program, Suppl return observationUnit; } + private List getBrAPIExternalReferences( + Program program, String referenceSourceBaseName, UUID trialId, UUID studyId, UUID obsUnitId) { + List refs = new ArrayList<>(); + + addReference(refs, program.getId(), referenceSourceBaseName, ExternalReferenceSource.PROGRAMS); + if( trialId != null ) { addReference(refs, trialId, referenceSourceBaseName, ExternalReferenceSource.TRIALS); } + if( studyId != null ) { addReference(refs, studyId, referenceSourceBaseName, ExternalReferenceSource.STUDIES); } + if( obsUnitId != null ) { addReference(refs, obsUnitId, referenceSourceBaseName, ExternalReferenceSource.OBSERVATION_UNITS); } + + return refs; + } + + private List getTrialExternalReferences( + Program program, String referenceSourceBaseName, UUID trialId) { + return getBrAPIExternalReferences(program, referenceSourceBaseName, trialId, null, null); + } + private List getStudyExternalReferences( + Program program, String referenceSourceBaseName, UUID trialId, UUID studyId) { + return getBrAPIExternalReferences(program, referenceSourceBaseName, trialId, studyId, null); + } + private List getObsUnitExternalReferences( + Program program, String referenceSourceBaseName, UUID trialId, UUID studyId, UUID obsUnitId) { + return getBrAPIExternalReferences(program, referenceSourceBaseName, trialId, studyId, null); + } + + + private void addReference(List refs, UUID uuid, String referenceBaseNameSource, ExternalReferenceSource refSourceName) { + BrAPIExternalReference reference; + reference = new BrAPIExternalReference(); + reference.setReferenceSource( String.format("%s/%s", referenceBaseNameSource, refSourceName.getName()) ); + reference.setReferenceID(uuid.toString()); + refs.add(reference); + } + } + diff --git a/src/main/java/org/breedinginsight/brapps/importer/model/response/PendingImportObject.java b/src/main/java/org/breedinginsight/brapps/importer/model/response/PendingImportObject.java index 9bdad5570..c7619df80 100644 --- a/src/main/java/org/breedinginsight/brapps/importer/model/response/PendingImportObject.java +++ b/src/main/java/org/breedinginsight/brapps/importer/model/response/PendingImportObject.java @@ -30,9 +30,12 @@ public class PendingImportObject { private T brAPIObject; private UUID id; - public PendingImportObject(ImportObjectState state, T brAPIObject) { + public PendingImportObject(ImportObjectState state, T brAPIObject, UUID id) { this.state = state; this.brAPIObject = brAPIObject; - this.id = UUID.randomUUID(); + this.id = id; + } + public PendingImportObject(ImportObjectState state, T brAPIObject) { + this(state, brAPIObject, UUID.randomUUID()); } } diff --git a/src/main/java/org/breedinginsight/brapps/importer/services/ExternalReferenceSource.java b/src/main/java/org/breedinginsight/brapps/importer/services/ExternalReferenceSource.java new file mode 100644 index 000000000..376cc1290 --- /dev/null +++ b/src/main/java/org/breedinginsight/brapps/importer/services/ExternalReferenceSource.java @@ -0,0 +1,18 @@ +package org.breedinginsight.brapps.importer.services; + +import lombok.Getter; + +@Getter +public enum ExternalReferenceSource { + PROGRAMS("programs"), + TRIALS("trials"), + STUDIES("studies"), + OBSERVATION_UNITS("observationunits"); + + private String name; + + ExternalReferenceSource(String name) { + this.name = name; + } +} + diff --git a/src/main/java/org/breedinginsight/brapps/importer/services/processors/ExperimentProcessor.java b/src/main/java/org/breedinginsight/brapps/importer/services/processors/ExperimentProcessor.java index 541160028..3e82e87b1 100644 --- a/src/main/java/org/breedinginsight/brapps/importer/services/processors/ExperimentProcessor.java +++ b/src/main/java/org/breedinginsight/brapps/importer/services/processors/ExperimentProcessor.java @@ -19,11 +19,14 @@ import io.micronaut.context.annotation.Property; import io.micronaut.context.annotation.Prototype; import io.micronaut.http.HttpStatus; +import io.micronaut.http.exceptions.HttpStatusException; import io.micronaut.http.server.exceptions.InternalServerException; 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.BrAPILocation; +import org.brapi.v2.model.core.BrAPISeason; import org.brapi.v2.model.core.BrAPIStudy; import org.brapi.v2.model.core.BrAPITrial; import org.brapi.v2.model.germ.BrAPIGermplasm; @@ -31,10 +34,7 @@ import org.breedinginsight.api.model.v1.response.ValidationError; import org.breedinginsight.api.model.v1.response.ValidationErrors; import org.breedinginsight.brapi.v2.dao.BrAPIGermplasmDAO; -import org.breedinginsight.brapps.importer.daos.BrAPILocationDAO; -import org.breedinginsight.brapps.importer.daos.BrAPIObservationUnitDAO; -import org.breedinginsight.brapps.importer.daos.BrAPIStudyDAO; -import org.breedinginsight.brapps.importer.daos.BrAPITrialDAO; +import org.breedinginsight.brapps.importer.daos.*; import org.breedinginsight.brapps.importer.model.ImportUpload; import org.breedinginsight.brapps.importer.model.imports.experimentObservation.ExperimentObservation; import org.breedinginsight.brapps.importer.model.imports.BrAPIImport; @@ -42,6 +42,7 @@ import org.breedinginsight.brapps.importer.model.response.ImportObjectState; import org.breedinginsight.brapps.importer.model.response.ImportPreviewStatistics; import org.breedinginsight.brapps.importer.model.response.PendingImportObject; +import org.breedinginsight.brapps.importer.services.ExternalReferenceSource; import org.breedinginsight.model.Program; import org.breedinginsight.model.User; import org.breedinginsight.services.exceptions.ValidatorException; @@ -63,20 +64,25 @@ public class ExperimentProcessor implements Processor { @Property(name = "brapi.server.reference-source") private String BRAPI_REFERENCE_SOURCE; + private DSLContext dsl; private BrAPITrialDAO brapiTrialDAO; private BrAPILocationDAO brAPILocationDAO; private BrAPIStudyDAO brAPIStudyDAO; private BrAPIObservationUnitDAO brAPIObservationUnitDAO; - private final BrAPIGermplasmDAO brAPIGermplasmDAO; + private final BrAPIGermplasmDAO brAPIGermplasmDAO; + private BrAPISeasonDAO brAPISeasonDAO; + + // used to make the yearsToSeasonDbId() function more efficient + private Map yearToSeasonDbIdCache = new HashMap<>(); //These BrapiData-objects are initially populated by the getExistingBrapiData() method, // then updated by the getNewBrapiData() method. private Map> trialByNameNoScope = null; private Map> locationByName = null; private Map> studyByNameNoScope = null; - // It is assumed that there are no pre-existing observation units for the given environment (so this will not be - // intitalized by getExistingBrapiData + // It is assumed that there are no preexisting Observation Units for the given environment (so this will not be + // initialized by getExistingBrapiData() ) private Map> observationUnitByNameNoScope = null; // existingGermplasmByGID is populated by getExistingBrapiData(), but not updated by the getNewBrapiData() method private Map> existingGermplasmByGID = null; @@ -87,12 +93,14 @@ public ExperimentProcessor(DSLContext dsl, BrAPILocationDAO brAPILocationDAO, BrAPIStudyDAO brAPIStudyDAO, BrAPIObservationUnitDAO brAPIObservationUnitDAO, + BrAPISeasonDAO brAPISeasonDAO, BrAPIGermplasmDAO brAPIGermplasmDAO) { this.dsl = dsl; this.brapiTrialDAO = brapiTrialDAO; this.brAPILocationDAO = brAPILocationDAO; this.brAPIStudyDAO = brAPIStudyDAO; this.brAPIObservationUnitDAO = brAPIObservationUnitDAO; + this.brAPISeasonDAO = brAPISeasonDAO; this.brAPIGermplasmDAO = brAPIGermplasmDAO; } @@ -101,6 +109,7 @@ public ExperimentProcessor(DSLContext dsl, * @param importRows * @param program */ + @Override public void getExistingBrapiData(List importRows, Program program) { List experimentImportRows = importRows.stream() @@ -108,15 +117,16 @@ public void getExistingBrapiData(List importRows, Program program) .collect(Collectors.toList()); this.trialByNameNoScope = initialize_trialByNameNoScope( program, experimentImportRows ); - this.locationByName = initialize_uniqueLocationNames ( program, experimentImportRows ); + this.locationByName = initialize_uniqueLocationNames( program, experimentImportRows ); this.studyByNameNoScope = initialize_studyByNameNoScope( program, experimentImportRows ); - this.observationUnitByNameNoScope = initialize_observationUnitByNameNoScope( program, experimentImportRows ); + // All of the Observation Units will be new. None will be preexisting. + this.observationUnitByNameNoScope = new HashMap<>(); this.existingGermplasmByGID = initialize_existingGermplasmByGID( program, experimentImportRows ); } /** * @param importRows - one element of the list for every row of the import file. - * @param mappedBrAPIImport - passed in by reference and modified within this program (this will latter be passed to the front end for the preview) + * @param mappedBrAPIImport - passed in by reference and modified within this program (this will later be passed to the front end for the preview) * @param program * @param user * @param commit - true when the data should be saved (ie when the user has pressed the "Commit" button) @@ -145,12 +155,12 @@ public Map process( mappedImportRow.setTrial( this.trialByNameNoScope.get( importRow.getExpTitle() ) ); mappedImportRow.setLocation( this.locationByName.get( importRow.getEnvLocation() ) ); mappedImportRow.setStudy( this.studyByNameNoScope.get( importRow.getEnv() ) ); - mappedImportRow.setObservationUnit( this.observationUnitByNameNoScope.get( importRow.getExpUnitId() ) ); - PendingImportObject germplasmPIO = getGidPio(importRow, mappedImportRow); + mappedImportRow.setObservationUnit( this.observationUnitByNameNoScope.get( createObservationUnitKey( importRow ) ) ); + PendingImportObject germplasmPIO = getGidPOI(importRow); mappedImportRow.setGermplasm( germplasmPIO ); if (! StringUtils.isBlank( importRow.getGid() )) { // if GID is blank, don't bother to check if it is valid. - validateGermplam(importRow,validationErrors, i, germplasmPIO); + validateGermplasm(importRow,validationErrors, i, germplasmPIO); } // Construct Observations -- Done in another card mappedBrAPIImport.put(i, mappedImportRow); @@ -169,28 +179,47 @@ public Map process( private void getNewBrapiData(List importRows, Program program, boolean commit) { - //TODO retrieve sequanceName from the program table. - String studySequenceName = ""; - Supplier studyNextVal = () -> dsl.nextval(studySequenceName.toLowerCase()); - String opsUnitSequenceName = ""; - Supplier obsUnitNextVal = () -> dsl.nextval(opsUnitSequenceName.toLowerCase()); - for (int i = 0; i < importRows.size(); i++) { - ExperimentObservation importRow = (ExperimentObservation) importRows.get(i); + String obsUnitSequenceName = program.getObsUnitSequence(); + if (obsUnitSequenceName == null) { + log.error(String.format("Program, %s, is missing a value in the obsUnit sequence column.", program.getName())); + throw new HttpStatusException(HttpStatus.UNPROCESSABLE_ENTITY, "Program is not properly configured for observation unit import"); + } + Supplier obsUnitNextVal = () -> dsl.nextval(obsUnitSequenceName.toLowerCase()); + + // It is assumed, at this point, that there is only one experiment per import-file + String expSeqValue = null; + if (commit) { + String expUnitSequenceName = program.getExpSequence(); + if (expUnitSequenceName == null) { + log.error(String.format("Program, %s, is missing a value in the exp sequence column.", program.getName())); + throw new HttpStatusException(HttpStatus.UNPROCESSABLE_ENTITY, "Program is not properly configured for experiment import"); + } + expSeqValue = dsl.nextval(expUnitSequenceName.toLowerCase()).toString(); + } + + for (BrAPIImport row : importRows) { + ExperimentObservation importRow = (ExperimentObservation) row; - PendingImportObject trialPIO = createTrialPIO(program, commit, importRow); - this.trialByNameNoScope.put( importRow.getExpTitle(), trialPIO ); + PendingImportObject trialPIO = createTrialPIO(program, commit, importRow, expSeqValue); + this.trialByNameNoScope.put(importRow.getExpTitle(), trialPIO); PendingImportObject locationPIO = createLocationPIO(importRow); - this.locationByName.put( importRow.getEnvLocation(), locationPIO ); + this.locationByName.put(importRow.getEnvLocation(), locationPIO); - PendingImportObject studyPIO = createStudyPIO(program, commit, studyNextVal, importRow); - this.studyByNameNoScope.put( importRow.getEnv(),studyPIO ); + PendingImportObject studyPIO = createStudyPIO(program, commit, expSeqValue, importRow); + this.studyByNameNoScope.put(importRow.getEnv(), studyPIO); PendingImportObject obsUnitPIO = createObsUnitPIO(program, commit, obsUnitNextVal, importRow); - this.observationUnitByNameNoScope.put( importRow.getExpUnitId(), obsUnitPIO ); + String key = createObservationUnitKey(importRow); + this.observationUnitByNameNoScope.put(key, obsUnitPIO); } } + private String createObservationUnitKey(ExperimentObservation importRow) { + String key = importRow.getEnv() + importRow.getExpUnitId(); + return key; + } + private ValidationErrors validateFields(List importRows, ValidationErrors validationErrors) { HashSet uniqueStudyAndObsUnit = new HashSet<>(); for (int i = 0; i < importRows.size(); i++) { @@ -201,8 +230,21 @@ private ValidationErrors validateFields(List importRows, Validation return validationErrors; } - private void validateUniqueObsUnits(ValidationErrors validationErrors, HashSet uniqueStudyAndObsUnit, int i, ExperimentObservation importRow) { - String envIdPlusStudyId = importRow.getEnv() + importRow.getExpUnitId(); + /** + * Validate that the the observation unit is unique within a study. + *
+ * SIDE EFFECTS: validationErrors and uniqueStudyAndObsUnit can be modified. + * @param validationErrors can be modified as a side effect. + * @param uniqueStudyAndObsUnit can be modified as a side effect. + * @param i counter that is always two less the file row being validated + * @param importRow the data row being validated + */ + private void validateUniqueObsUnits( + ValidationErrors validationErrors, + HashSet uniqueStudyAndObsUnit, + int i, + ExperimentObservation importRow) { + String envIdPlusStudyId = createObservationUnitKey( importRow ); if( uniqueStudyAndObsUnit.contains( envIdPlusStudyId )){ String errorMessage = String.format("The ID (%s) is not unique within the environment(%s)", importRow.getExpUnitId(), importRow.getEnv()); this.addRowError("Exp Unit ID", errorMessage, validationErrors, i); @@ -258,10 +300,10 @@ private void validateConditionallyRequired(ValidationErrors validationErrors, in } } - private void validateRequiredCell(String value, String columHeader, String errorMessage, ValidationErrors validationErrors, int i) { + private void validateRequiredCell(String value, String columnHeader, String errorMessage, ValidationErrors validationErrors, int i) { if ( StringUtils.isBlank( value )) { addRowError( - columHeader, + columnHeader, errorMessage, validationErrors, i ) ; @@ -282,11 +324,11 @@ private Map getStatisticsMap(List HashSet environmentNameCounter = new HashSet<>(); // set of unique environment names HashSet obsUnitsIDCounter = new HashSet<>(); // set of unique observation unit ID's HashSet gidCounter = new HashSet<>(); // set of unique GID's - for (int i = 0; i < importRows.size(); i++) { - ExperimentObservation importRow = (ExperimentObservation) importRows.get(i); + for (BrAPIImport row : importRows) { + ExperimentObservation importRow = (ExperimentObservation) row; // Collect date for stats. addIfNotNull(environmentNameCounter, importRow.getEnv()); - addIfNotNull(obsUnitsIDCounter, importRow.getExpUnitId()); + addIfNotNull(obsUnitsIDCounter, createObservationUnitKey( importRow )); addIfNotNull(gidCounter, importRow.getGid()); } ImportPreviewStatistics environmentStats = ImportPreviewStatistics.builder() @@ -306,8 +348,8 @@ private Map getStatisticsMap(List ); } - private void validateGermplam(ExperimentObservation importRow, ValidationErrors validationErrors, int i, PendingImportObject germplasmPIO) { - // error if GID is not blank but GID dose not already exist + private void validateGermplasm(ExperimentObservation importRow, ValidationErrors validationErrors, int i, PendingImportObject germplasmPIO) { + // error if GID is not blank but GID does not already exist if( !StringUtils.isBlank( importRow.getGid()) && germplasmPIO == null ) { addRowError( "GID", @@ -317,7 +359,7 @@ private void validateGermplam(ExperimentObservation importRow, ValidationErrors } } - private PendingImportObject getGidPio(ExperimentObservation importRow, PendingImport mappedImportRow) { + private PendingImportObject getGidPOI(ExperimentObservation importRow) { if( this.existingGermplasmByGID.containsKey( importRow.getGid() )){ return existingGermplasmByGID.get(importRow.getGid()); } @@ -328,24 +370,42 @@ private PendingImportObject getGidPio(ExperimentObservation impo private PendingImportObject createObsUnitPIO(Program program, boolean commit, Supplier obsUnitNextVal, ExperimentObservation importRow) { PendingImportObject pio = null; - if( observationUnitByNameNoScope.containsKey( importRow.getExpUnitId() ) ) { - pio = observationUnitByNameNoScope.get(importRow.getExpUnitId() ) ; + if( this.observationUnitByNameNoScope.containsKey( createObservationUnitKey( importRow ) ) ) { + pio = observationUnitByNameNoScope.get( createObservationUnitKey( importRow ) ) ; } else{ - BrAPIObservationUnit newObservationUnit = importRow.constructBrAPIObservationUnit(program, obsUnitNextVal, commit); + String germplasmName = ""; + if( this.existingGermplasmByGID.get( importRow.getGid() ) != null) { + germplasmName = this.existingGermplasmByGID.get(importRow.getGid()).getBrAPIObject().getGermplasmName(); + } + PendingImportObject trialPIO = this.trialByNameNoScope.get(importRow.getExpTitle()); + UUID trialID = trialPIO.getId(); + PendingImportObject studyPIO = this.studyByNameNoScope.get(importRow.getEnv()); + UUID studyID = studyPIO.getId(); + UUID id = UUID.randomUUID(); + BrAPIObservationUnit newObservationUnit = importRow.constructBrAPIObservationUnit(program, obsUnitNextVal, commit, germplasmName, BRAPI_REFERENCE_SOURCE, trialID, studyID, id); pio = new PendingImportObject<>(ImportObjectState.NEW, newObservationUnit); } return pio; } - private PendingImportObject createStudyPIO(Program program, boolean commit, Supplier studyNextVal, ExperimentObservation importRow ) { + private PendingImportObject createStudyPIO(Program program, boolean commit, String expSeqenceValue, ExperimentObservation importRow) { PendingImportObject pio = null; if( studyByNameNoScope.containsKey( importRow.getEnv()) ) { pio = studyByNameNoScope.get( importRow.getEnv() ) ; } else{ - BrAPIStudy newStudy = importRow.constructBrAPIStudy(program, studyNextVal, commit); - pio = new PendingImportObject<>(ImportObjectState.NEW, newStudy); + PendingImportObject trialPIO = this.trialByNameNoScope.get(importRow.getExpTitle()); + UUID trialID = trialPIO.getId(); + UUID id = UUID.randomUUID(); + BrAPIStudy newStudy = importRow.constructBrAPIStudy(program, commit, BRAPI_REFERENCE_SOURCE, expSeqenceValue, trialID, id); + + if( commit) { + String seasonID = this.yearsToSeasonDbId(newStudy.getSeasons(), program.getId()); + newStudy.setSeasons(Arrays.asList(seasonID)); + } + + pio = new PendingImportObject<>(ImportObjectState.NEW, newStudy, id); } return pio; } @@ -362,14 +422,15 @@ private PendingImportObject createLocationPIO(ExperimentObservati return pio; } - private PendingImportObject createTrialPIO(Program program, boolean commit, ExperimentObservation importRow) { + private PendingImportObject createTrialPIO(Program program, boolean commit, ExperimentObservation importRow, String expSeqValue) { PendingImportObject pio = null; if( trialByNameNoScope.containsKey( importRow.getExpTitle()) ) { pio = trialByNameNoScope.get( importRow.getExpTitle() ) ; } else { - BrAPITrial newTrial = importRow.constructBrAPITrial(program, commit); - pio = new PendingImportObject<>(ImportObjectState.NEW, newTrial); + UUID id = UUID.randomUUID(); + BrAPITrial newTrial = importRow.constructBrAPITrial(program, commit, BRAPI_REFERENCE_SOURCE, id, expSeqValue); + pio = new PendingImportObject<>(ImportObjectState.NEW, newTrial, id); } return pio; } @@ -382,10 +443,104 @@ public void validateDependencies(Map mappedBrAPIImport) @Override public void postBrapiData(Map mappedBrAPIImport, Program program, ImportUpload upload) { + List newTrials = ProcessorData.getNewObjects(this.trialByNameNoScope); + List newLocations = ProcessorData.getNewObjects(this.locationByName); + List newStudies = ProcessorData.getNewObjects(this.studyByNameNoScope); + List newObservationUnits = ProcessorData.getNewObjects(this.observationUnitByNameNoScope); + + try { + List createdTrials = new ArrayList<>(brapiTrialDAO.createBrAPITrial(newTrials, program.getId(), upload)); + + // set the DbId to the for each newly created trial + for ( BrAPITrial createdTrial: createdTrials ) { + String createdTrialName = createdTrial.getTrialName(); + String createdTrialName_no_key = Utilities.removeProgramKey( createdTrialName, program.getKey() ); + PendingImportObject pi = this.trialByNameNoScope.get(createdTrialName_no_key); + BrAPITrial listedTrial = pi.getBrAPIObject(); + String dbid = createdTrial.getTrialDbId(); + listedTrial.setTrialDbId( dbid ); + } + brAPILocationDAO.createBrAPILocation(newLocations, program.getId(), upload); + + updateStudyDependencyValues(mappedBrAPIImport,program.getKey()); + List createdStudies = new ArrayList<>(); + createdStudies.addAll( brAPIStudyDAO.createBrAPIStudy(newStudies, program.getId(), upload) ); + + // set the DbId to the for each newly created study + for( BrAPIStudy createdStudy : createdStudies){ + String createdStudy_name_no_key = Utilities.removeProgramKeyAndUnknownAdditionalData( createdStudy.getStudyName(), program.getKey() ); + PendingImportObject pi = this.studyByNameNoScope.get( createdStudy_name_no_key ); + BrAPIStudy brAPIStudy = pi.getBrAPIObject(); + brAPIStudy.setStudyDbId( createdStudy.getStudyDbId() ); + } + + updateObsUnitDependencyValues(program.getKey()); + brAPIObservationUnitDAO.createBrAPIObservationUnits(newObservationUnits, program.getId(), upload); + } catch (ApiException e) { + log.error(e.getResponseBody()); + throw new InternalServerException(e.toString(), e); + } + } - private void updateDependencyValues(Map mappedBrAPIImport) { - // TODO + private void updateObsUnitDependencyValues(String programKey) { + + // update study DbIds + this.studyByNameNoScope.values().stream() + .filter(Objects::nonNull) + .distinct() + .map(PendingImportObject::getBrAPIObject) + .forEach(study -> updateStudyDbId(study, programKey)); + + // update germplasm DbIds + this.existingGermplasmByGID.values().stream() + .filter(Objects::nonNull) + .distinct() + .map(PendingImportObject::getBrAPIObject) + .forEach(this::updateGermplasmDbId); + } + + private void updateStudyDbId(BrAPIStudy study, String programKey) { + this.observationUnitByNameNoScope.values().stream() + .filter(obsUnit -> obsUnit.getBrAPIObject().getStudyName().equals( Utilities.removeProgramKeyAndUnknownAdditionalData( study.getStudyName(), programKey ) )) + .forEach(obsUnit -> obsUnit.getBrAPIObject().setStudyDbId(study.getStudyDbId())); + } + + private void updateGermplasmDbId(BrAPIGermplasm germplasm) { + this.observationUnitByNameNoScope.values().stream() + .filter(obsUnit -> obsUnit.getBrAPIObject().getGermplasmName() != null && + obsUnit.getBrAPIObject().getGermplasmName().equals(germplasm.getGermplasmName())) + .forEach(obsUnit -> obsUnit.getBrAPIObject().setGermplasmDbId(germplasm.getGermplasmDbId())); + } + + + private void updateStudyDependencyValues(Map mappedBrAPIImport, String programKey) { + // update location DbIds in studies for all distinct locations + mappedBrAPIImport.values().stream() + .map(PendingImport::getLocation) + .filter(Objects::nonNull) + .distinct() + .map(PendingImportObject::getBrAPIObject) + .forEach(this::updateStudyLocationDbId); + + // update trial DbIds in studies for all distinct trials + this.trialByNameNoScope.values().stream() + .filter(Objects::nonNull) + .distinct() + .map(PendingImportObject::getBrAPIObject) + .forEach(trait -> this.updateTrialDbId(trait, programKey)); + } + + private void updateStudyLocationDbId(BrAPILocation location) { + this.studyByNameNoScope.values().stream() + .filter(study -> study.getBrAPIObject().getLocationName().equals(location.getLocationName())) + .forEach(study -> study.getBrAPIObject().setLocationDbId(location.getLocationDbId())); + } + + private void updateTrialDbId(BrAPITrial trial, String programKey) { + this.studyByNameNoScope.values().stream() + .filter(study -> study.getBrAPIObject().getTrialName().equals(Utilities.removeProgramKey(trial.getTrialName(), programKey ) ) ) + .forEach(study -> study.getBrAPIObject().setTrialDbId(trial.getTrialDbId())); } @Override @@ -393,7 +548,6 @@ public String getName() { return NAME; } - //TODO should this method be moved to BrAPIExperimentService.java private ArrayList getGermplasmByAccessionNumber( List germplasmAccessionNumbers, UUID programId) throws ApiException { @@ -413,69 +567,51 @@ private ArrayList getGermplasmByAccessionNumber( private Map> initialize_existingGermplasmByGID(Program program, List experimentImportRows) { Map> existingGermplasmByGID = new HashMap<>(); - List uniqueGermplasmGID = experimentImportRows.stream() - .map(experimentImport -> experimentImport.getGid()) + List uniqueGermplasmGIDs = experimentImportRows.stream() + .map(ExperimentObservation::getGid) .distinct() .collect(Collectors.toList()); List existingGermplasms; try { - existingGermplasms = this.getGermplasmByAccessionNumber(uniqueGermplasmGID, program.getId()); - existingGermplasms.forEach(existingGermplasm -> { - existingGermplasmByGID.put(existingGermplasm.getAccessionNumber(), new PendingImportObject<>(ImportObjectState.EXISTING, existingGermplasm)); - }); + existingGermplasms = this.getGermplasmByAccessionNumber(uniqueGermplasmGIDs, program.getId()); + existingGermplasms.forEach(existingGermplasm -> existingGermplasmByGID.put(existingGermplasm.getAccessionNumber(), new PendingImportObject<>(ImportObjectState.EXISTING, existingGermplasm))); return existingGermplasmByGID; } 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); } } - private Map> initialize_observationUnitByNameNoScope(Program program, List experimentImportRows) { - Map> observationUnitByNameNoScope = new HashMap<>(); - List uniqueObservationUnitNames = experimentImportRows.stream() - .map(experimentImport -> experimentImport.getExpUnitId()) - .distinct() - .filter(name -> null !=name) - .collect(Collectors.toList()); - - // check for existing observation units. Don't want to update existing, just create new. - // TODO: do we allow adding observations to existing studies? yes, but not updating - // ignore all data for observation units existing in system + private Map> initialize_studyByNameNoScope(Program program, List experimentImportRows) { + Map> studyByNameNoScope = new HashMap<>(); - List existingObservationUnits; - try { - existingObservationUnits = brAPIObservationUnitDAO.getObservationUnitByName(uniqueObservationUnitNames, program); - existingObservationUnits.forEach(existingObservationUnit -> { - // update mapped brapi import, does in process - observationUnitByNameNoScope.put(existingObservationUnit.getObservationUnitName(), new PendingImportObject<>(ImportObjectState.EXISTING, existingObservationUnit)); - }); - return observationUnitByNameNoScope; - } 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); + if( this.trialByNameNoScope.size()!=1){ + return studyByNameNoScope; + } + ExperimentObservation experimentObservation = experimentImportRows.get(0); + + PendingImportObject trial = this.trialByNameNoScope.get(experimentObservation.getExpTitle()); + List experimentRefs = trial.getBrAPIObject().getExternalReferences(); + Optional experimentIDRef = experimentRefs.stream() + .filter(this::isTrialRefSource) + .findFirst(); + if( experimentIDRef.isEmpty()){ + throw new InternalServerException("An Experiment ID was not found any of the external references"); } - } - private Map> initialize_studyByNameNoScope(Program program, List experimentImportRows) { - Map> studyByNameNoScope = new HashMap<>(); - List uniqueStudyNames = experimentImportRows.stream() - .map(experimentImport -> experimentImport.getEnv()) - .distinct() - .filter(name -> null !=name) - .collect(Collectors.toList()); + //get experimentID + String experimentIDStr = experimentIDRef.get().getReferenceID(); List existingStudies; try { - existingStudies = brAPIStudyDAO.getStudyByName(uniqueStudyNames, program); + existingStudies = brAPIStudyDAO.getStudiesByExperimentID(UUID.fromString(experimentIDStr), program); existingStudies.forEach(existingStudy -> { - String studySequence = null; - if ((existingStudy.getAdditionalInfo()!=null) && (existingStudy.getAdditionalInfo().get("studySequence") != null )) { - studySequence = existingStudy.getAdditionalInfo().get("studySequence").getAsString(); - } + + existingStudy.setStudyName(Utilities.removeProgramKeyAndUnknownAdditionalData(existingStudy.getStudyName(), program.getKey())); studyByNameNoScope.put( - Utilities.removeProgramKey(existingStudy.getStudyName(), program.getKey(), studySequence), + existingStudy.getStudyName(), new PendingImportObject<>(ImportObjectState.EXISTING, existingStudy)); }); return studyByNameNoScope; @@ -488,9 +624,9 @@ private Map> initialize_studyByNameNoSco private Map> initialize_uniqueLocationNames(Program program, List experimentImportRows) { Map> locationByName = new HashMap<>(); List uniqueLocationNames = experimentImportRows.stream() - .map(experimentImport -> experimentImport.getEnvLocation()) + .map(ExperimentObservation::getEnvLocation) .distinct() - .filter(name -> null !=name) + .filter(Objects::nonNull) .collect(Collectors.toList()); List existingLocations; @@ -508,19 +644,20 @@ private Map> initialize_uniqueLocatio private Map> initialize_trialByNameNoScope(Program program, List experimentImportRows) { Map> trialByNameNoScope = new HashMap<>(); + String programKey = program.getKey(); List uniqueTrialNames = experimentImportRows.stream() - .map(experimentImport -> experimentImport.getExpTitle()) - .distinct(). - filter(name -> null !=name) + .map(experimentImport -> Utilities.appendProgramKey( experimentImport.getExpTitle(), programKey, null) ) + .distinct() + .filter(Objects::nonNull) .collect(Collectors.toList()); List existingTrials; -log.info(uniqueTrialNames.toString()); try { existingTrials = brapiTrialDAO.getTrialByName(uniqueTrialNames, program); existingTrials.forEach(existingTrial -> { + existingTrial.setTrialName(Utilities.removeProgramKey(existingTrial.getTrialName(), program.getKey())); trialByNameNoScope.put( - Utilities.removeProgramKey(existingTrial.getTrialName(), program.getKey()), + existingTrial.getTrialName(), new PendingImportObject<>(ImportObjectState.EXISTING, existingTrial)); }); return trialByNameNoScope; @@ -529,7 +666,61 @@ private Map> initialize_trialByNameNoSco throw new InternalServerException(e.toString(), e); } } + private String simpleStudyName(String scopedName){ + return scopedName.replaceFirst(" \\[.*\\]", ""); + } + /** + * Converts year String to SeasonDbId + *
+ * NOTE: This assumes that the only Season records of interest are ones + * with a blank name or a name that is the same as the year. + * + * @param years this only looks at the first year of the list. + * @param programId the program ID. + * @return the DbId of the season-record associated with the first year + * of the 'years' list (see NOTE above) + */ + private String yearsToSeasonDbId(List years, UUID programId) { + String year = years.get(0); + String dbID = null; + if (this.yearToSeasonDbIdCache.containsKey(year) ){ // get it from cache if possable + dbID = this.yearToSeasonDbIdCache.get(year); + } + else{ + dbID = this.yearToSeasonDbIdFromDatabase(year,programId); + this.yearToSeasonDbIdCache.put(year, dbID); + } + return dbID; + } + private String yearToSeasonDbIdFromDatabase(String year, UUID programId) { + BrAPISeason targetSeason = null; + List seasons; + try { + seasons = this.brAPISeasonDAO.getSeasonByYear(year, programId); + for( BrAPISeason season : seasons){ + if(null == season.getSeasonName() || season.getSeasonName().isBlank() || season.getSeasonName().equals(year)){ + targetSeason = season; + break; + } + } + if (targetSeason == null){ + BrAPISeason newSeason = new BrAPISeason(); + newSeason.setYear( Integer.parseInt(year) ); + newSeason.setSeasonName( year ); + targetSeason = this.brAPISeasonDAO.addOneSeason( newSeason, programId ); + } + + } catch (ApiException e) { + log.error(e.getResponseBody(), e);; + } + String seasonDbId = (targetSeason==null) ? null : targetSeason.getSeasonDbId(); + return seasonDbId; + } + + private boolean isTrialRefSource(BrAPIExternalReference brAPIExternalReference) { + return brAPIExternalReference.getReferenceSource().equals( String.format("%s/%s", BRAPI_REFERENCE_SOURCE, ExternalReferenceSource.TRIALS.getName()) ); + } } \ No newline at end of file diff --git a/src/main/java/org/breedinginsight/brapps/importer/services/processors/StudyProcessor.java b/src/main/java/org/breedinginsight/brapps/importer/services/processors/StudyProcessor.java index ff9b1d6ea..39cca38a8 100644 --- a/src/main/java/org/breedinginsight/brapps/importer/services/processors/StudyProcessor.java +++ b/src/main/java/org/breedinginsight/brapps/importer/services/processors/StudyProcessor.java @@ -157,7 +157,7 @@ private void updateDependencyValues(Map mappedBrAPIImpor } private void updateLocationDbId(BrAPILocation location) { - studyByName.values().stream() + this.studyByName.values().stream() .filter(study -> study.getBrAPIObject().getLocationName().equals(location.getLocationName())) .forEach(study -> study.getBrAPIObject().setLocationDbId(location.getLocationDbId())); } diff --git a/src/main/java/org/breedinginsight/model/BrAPIConstants.java b/src/main/java/org/breedinginsight/model/BrAPIConstants.java index 47ba71804..03860a4df 100644 --- a/src/main/java/org/breedinginsight/model/BrAPIConstants.java +++ b/src/main/java/org/breedinginsight/model/BrAPIConstants.java @@ -3,7 +3,9 @@ import com.fasterxml.jackson.annotation.JsonValue; public enum BrAPIConstants { - SYSTEM_DEFAULT("System Default"); + SYSTEM_DEFAULT("System Default"), + REPLICATE( "replicate"), + BLOCK( "bolck"); private String value; diff --git a/src/main/java/org/breedinginsight/model/Program.java b/src/main/java/org/breedinginsight/model/Program.java index b7c23e108..9ffbb6d60 100644 --- a/src/main/java/org/breedinginsight/model/Program.java +++ b/src/main/java/org/breedinginsight/model/Program.java @@ -90,6 +90,8 @@ public static Program parseSQLRecord(Record record, ProgramTable programTable) { .updatedBy(record.getValue(programTable.UPDATED_BY)) .active(record.getValue(programTable.ACTIVE)) .germplasmSequence(record.getValue(programTable.GERMPLASM_SEQUENCE)) + .expSequence( record.getValue(programTable.EXP_SEQUENCE)) + .obsUnitSequence(( record.getValue(programTable.OBS_UNIT_SEQUENCE))) .build(); return program; diff --git a/src/main/java/org/breedinginsight/services/ProgramService.java b/src/main/java/org/breedinginsight/services/ProgramService.java index e482fdf79..70f218049 100644 --- a/src/main/java/org/breedinginsight/services/ProgramService.java +++ b/src/main/java/org/breedinginsight/services/ProgramService.java @@ -59,6 +59,8 @@ public class ProgramService { private static final String PROGRAM_NAME_IN_USE = "PROGRAM_NAME_IN_USE"; private static final String PROGRAM_KEY_IN_USE = "PROGRAM_KEY_IN_USE"; private static final String GERMPLASM_SEQUENCE_TEMPLATE = "%s_germplasm_sequence"; + private static final String OBS_UNIT_SEQUENCE_TEMPLATE = "%s_obs_unit_sequence"; + private static final String EXP_SEQUENCE_TEMPLATE = "%s_exp_sequence"; @Inject public ProgramService(ProgramDAO dao, ProgramOntologyDAO programOntologyDAO, ProgramObservationLevelDAO programObservationLevelDAO, @@ -161,6 +163,14 @@ public Program create(ProgramRequest programRequest, AuthenticatedUser actingUse String germplasm_sequence_name = String.format(GERMPLASM_SEQUENCE_TEMPLATE, programRequest.getKey()).toLowerCase(); dsl.createSequence(germplasm_sequence_name).execute(); + // Create experiment sequence + String exp_sequence_name = String.format(EXP_SEQUENCE_TEMPLATE, programRequest.getKey()).toLowerCase(); + dsl.createSequence(exp_sequence_name).execute(); + + // Create obs unit sequence + String obs_unit_sequence_name = String.format(OBS_UNIT_SEQUENCE_TEMPLATE, programRequest.getKey()).toLowerCase(); + dsl.createSequence(obs_unit_sequence_name).execute(); + // Parse and create the program object ProgramEntity programEntity = ProgramEntity.builder() .name(programRequest.getName()) @@ -171,6 +181,8 @@ public Program create(ProgramRequest programRequest, AuthenticatedUser actingUse .brapiUrl(brapiUrl) .key(programRequest.getKey()) .germplasmSequence(germplasm_sequence_name) + .expSequence( exp_sequence_name ) + .obsUnitSequence( obs_unit_sequence_name ) .createdBy(actingUser.getId()) .updatedBy(actingUser.getId()) .build(); diff --git a/src/main/java/org/breedinginsight/utilities/Utilities.java b/src/main/java/org/breedinginsight/utilities/Utilities.java index 229b6a90f..f79af13fb 100644 --- a/src/main/java/org/breedinginsight/utilities/Utilities.java +++ b/src/main/java/org/breedinginsight/utilities/Utilities.java @@ -64,6 +64,10 @@ public static String appendProgramKey(String original, String programKey, String } } + public static String appendProgramKey( String original, String programKey ){ + return appendProgramKey( original, programKey, null); + } + /** * Remove program key from a string. Returns a new value instead of altering original string. * @@ -92,4 +96,10 @@ public static String removeProgramKey(String original, String programKey, String public static String removeProgramKey(String original, String programKey) { return removeProgramKey(original, programKey, null); } + + public static String removeProgramKeyAndUnknownAdditionalData(String original, String programKey) { + String keyValueRegEx = String.format(" \\[%s\\-.*\\]", programKey); + String stripped = original.replaceAll(keyValueRegEx, ""); + return stripped; + } } diff --git a/src/main/resources/db/migration/V0.5.36__create_obs_unit_sequence.sql b/src/main/resources/db/migration/V0.5.36__create_obs_unit_sequence.sql new file mode 100644 index 000000000..f0bed3308 --- /dev/null +++ b/src/main/resources/db/migration/V0.5.36__create_obs_unit_sequence.sql @@ -0,0 +1,34 @@ +/* + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * 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. + */ + +alter table program add column obs_unit_sequence text; + +do +$$ +declare +f record; +begin +for f in select * from program +loop + if f.key is NULL then + RAISE EXCEPTION 'Programs must have a key associated with them'; + end if; + execute format('create sequence %s_obs_unit_sequence',f.key); + update program set obs_unit_sequence = format('%s_obs_unit_sequence', f.key) where id = f.id; +end loop; +end; +$$ \ No newline at end of file diff --git a/src/main/resources/db/migration/V0.5.37__create_experiment_sequence.sql b/src/main/resources/db/migration/V0.5.37__create_experiment_sequence.sql new file mode 100644 index 000000000..1d2b97e83 --- /dev/null +++ b/src/main/resources/db/migration/V0.5.37__create_experiment_sequence.sql @@ -0,0 +1,34 @@ +/* + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * 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. + */ + +alter table program add column exp_sequence text; + +do +$$ +declare +f record; +begin +for f in select * from program +loop + if f.key is NULL then + RAISE EXCEPTION 'Programs must have a key associated with them'; + end if; + execute format('create sequence %s_exp_sequence',f.key); + update program set exp_sequence = format('%s_exp_sequence', f.key) where id = f.id; +end loop; +end; +$$ \ No newline at end of file