Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

package org.breedinginsight.brapi.v2.dao;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonObject;
import io.micronaut.context.annotation.Property;
import io.micronaut.http.HttpStatus;
Expand All @@ -27,7 +29,9 @@
import org.brapi.client.v2.model.queryParams.germplasm.GermplasmQueryParams;
import org.brapi.client.v2.modules.germplasm.GermplasmApi;
import org.brapi.v2.model.BrAPIExternalReference;
import org.brapi.v2.model.core.BrAPIListItemWithFullItem;
import org.brapi.v2.model.core.BrAPIProgram;
import org.brapi.v2.model.core.response.BrAPIListItemsListResponse;
import org.brapi.v2.model.germ.BrAPIGermplasm;
import org.brapi.v2.model.germ.BrAPIGermplasmSynonyms;
import org.brapi.v2.model.germ.request.BrAPIGermplasmSearchRequest;
Expand All @@ -45,6 +49,7 @@
import org.breedinginsight.utilities.Utilities;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.*;
import java.util.stream.Collectors;
Expand All @@ -56,6 +61,8 @@ public class BrAPIGermplasmDAO {
private final ProgramDAO programDAO;
private final ImportDAO importDAO;
private final BrAPIDAOUtil brAPIDAOUtil;
private final ObjectMapper objectMapper;
private final BrAPIListDAO brAPIListDAO;

@Property(name = "brapi.server.reference-source")
private String referenceSource;
Expand All @@ -72,12 +79,16 @@ public BrAPIGermplasmDAO(ProgramDAO programDAO,
ImportDAO importDAO,
BrAPIDAOUtil brAPIDAOUtil,
BrAPIEndpointProvider brAPIEndpointProvider,
@Property(name = "brapi.cache.fetch-page-size") int brapiFetchPageSize) {
@Property(name = "brapi.cache.fetch-page-size") int brapiFetchPageSize,
ObjectMapper objectMapper,
BrAPIListDAO brAPIListDAO) {
this.programDAO = programDAO;
this.importDAO = importDAO;
this.brAPIDAOUtil = brAPIDAOUtil;
this.brAPIEndpointProvider = brAPIEndpointProvider;
this.brapiMaxPageSize = brapiFetchPageSize;
this.objectMapper = objectMapper;
this.brAPIListDAO = brAPIListDAO;
}

/**
Expand Down Expand Up @@ -427,13 +438,20 @@ public List<BrAPIGermplasm> getGermplasmByRawName(List<String> germplasmNames, U
.collect(Collectors.toList());
}

public BrAPIGermplasmListResponse searchGermplasmByRawName(List<String> germplasmNames, UUID programId, GermplasmQuery germplasmQuery) throws ApiException {
public BrAPIListItemsListResponse<BrAPIGermplasm> searchGermplasmByList(String listDbId, UUID programId, GermplasmQuery germplasmQuery) throws ApiException {
Program program = new Program(programDAO.fetchOneById(programId));

BrAPIGermplasmSearchRequest searchRequest = new BrAPIGermplasmSearchRequest();
searchRequest.setGermplasmNames(germplasmNames);
BrAPIGermplasmSearchRequest searchRequest = buildSearchRequest(program, null, germplasmQuery);

// Because the list item search endpoint is generalized, a typed BrAPISearchRequest won't work, so convert it to JsonNode.
// The search request type is derived by the client/prod server based off of the type of the submitted list dbId.
JsonNode listRequestBody = objectMapper.valueToTree(searchRequest);

BrAPIListItemsListResponse<BrAPIGermplasm> response = brAPIListDAO.searchBrAPIListItemsByList(listDbId, programId, listRequestBody);

processGermplasmForDisplay(response.getResult().getData().stream().map(BrAPIListItemWithFullItem::getItem).collect(Collectors.toList()), program);

return brapiGermplasmSearchReturnResponse(program, searchRequest, germplasmQuery);
return response;
}

public List<BrAPIGermplasm> brapiGermplasmSearchReturnList(Program program,
Expand Down
47 changes: 38 additions & 9 deletions src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIListDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.breedinginsight.brapi.v2.dao;

import com.fasterxml.jackson.databind.JsonNode;
import io.micronaut.http.HttpResponse;
import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;
Expand All @@ -27,14 +28,13 @@
import org.brapi.v2.model.BrAPIExternalReference;
import org.brapi.v2.model.BrAPIResponse;
import org.brapi.v2.model.BrAPIResponseResult;
import org.brapi.v2.model.core.BrAPIListItemWithFullItem;
import org.brapi.v2.model.core.BrAPIListSummary;
import org.brapi.v2.model.core.BrAPIListTypes;
import org.brapi.v2.model.core.request.BrAPIListNewRequest;
import org.brapi.v2.model.core.request.BrAPIListSearchRequest;
import org.brapi.v2.model.core.response.BrAPIListDetails;
import org.brapi.v2.model.core.response.BrAPIListsListResponse;
import org.brapi.v2.model.core.response.BrAPIListsListResponseResult;
import org.brapi.v2.model.core.response.BrAPIListsSingleResponse;
import org.brapi.v2.model.core.response.*;
import org.brapi.v2.model.germ.BrAPIGermplasm;
import org.breedinginsight.brapps.importer.daos.ImportDAO;
import org.breedinginsight.brapps.importer.model.ImportUpload;
import org.breedinginsight.daos.ProgramDAO;
Expand Down Expand Up @@ -71,7 +71,7 @@ public BrAPIListDAO(ProgramDAO programDAO,
}

public List<BrAPIListSummary> getListsByName(List<String> listNames, UUID programId) throws ApiException {
if(listNames.isEmpty()) {
if (listNames.isEmpty()) {
return Collections.emptyList();
}

Expand Down Expand Up @@ -122,11 +122,11 @@ private List<BrAPIListSummary> processListsForProgram(List<BrAPIListSummary> pro
// check that all lists were created via the BI UI in case the BrAPI service silently ignores the search by
// externalReference source and ID
List<BrAPIListSummary> filteredLists = new ArrayList<>();
for (BrAPIListSummary list: programLists) {
for (BrAPIListSummary list : programLists) {
if (list.getExternalReferences() == null || list.getExternalReferences().size() == 0) {
continue;
} else {
for (BrAPIExternalReference ref: list.getExternalReferences()) {
for (BrAPIExternalReference ref : list.getExternalReferences()) {
if (ref.getReferenceID().equals(externalReferenceId.toString()) &&
ref.getReferenceSource().equals(externalReferenceSource)) {
filteredLists.add(list);
Expand All @@ -136,6 +136,7 @@ private List<BrAPIListSummary> processListsForProgram(List<BrAPIListSummary> pro
}
return filteredLists;
}

public List<String> updateBrAPIList(String brAPIListDbId, BrAPIListDetails mutatedList, UUID programId) throws ApiException {
ListsApi api = brAPIEndpointProvider.get(programDAO.getCoreClient(programId), ListsApi.class);
BrAPIListNewRequest request = new BrAPIListNewRequest();
Expand All @@ -160,7 +161,7 @@ public List<String> updateBrAPIList(String brAPIListDbId, BrAPIListDetails mutat
log.error(Utilities.generateApiExceptionLogMessage(e));
throw e;
}
if(response != null) {
if (response != null) {
BrAPIListsSingleResponse body = response.getBody();
if (body == null) {
throw new ApiException("Response is missing body", 0, response.getHeaders(), null);
Expand Down Expand Up @@ -188,7 +189,7 @@ public List<BrAPIListSummary> createBrAPILists(List<BrAPIListNewRequest> brapiLi
log.warn(Utilities.generateApiExceptionLogMessage(e));
throw e;
}
if(response != null) {
if (response != null) {
BrAPIResponse<BrAPIListsListResponseResult> body = response.getBody();
if (body == null) {
throw new ApiException("Response is missing body", 0, response.getHeaders(), null);
Expand Down Expand Up @@ -220,4 +221,32 @@ public HttpResponse<String> deleteBrAPIList(String listDbId, UUID programId, boo
return brAPIDAOUtil.makeCall(brapiRequest);
}

public <T> BrAPIListItemsListResponse<T> searchBrAPIListItemsByList(String listDbId, UUID programId, JsonNode requestBody) throws ApiException {
ListsApi api = brAPIEndpointProvider.get(programDAO.getCoreClient(programId), ListsApi.class);
// Do manually, it doesn't like List<Object> to List<BrAPIListNewRequest> for some reason
ApiResponse<BrAPIListItemsListResponse<T>> response;
try {
response = api.searchListItemsByList(listDbId, requestBody);
} catch (ApiException e) {
log.warn(Utilities.generateApiExceptionLogMessage(e));
throw e;
}

if (response != null) {
BrAPIResponse<BrAPIListItemsListResponseResult<T>> body = response.getBody();
if (body == null) {
throw new ApiException("Response is missing body", 0, response.getHeaders(), null);
}
BrAPIResponseResult<BrAPIListItemWithFullItem<T>> result = body.getResult();
if (result == null) {
throw new ApiException("Response body is missing result", 0, response.getHeaders(), response.getBody().toString());
}
if (result.getData() == null) {
throw new ApiException("Response result is missing data", 0, response.getHeaders(), response.getBody().toString());
}
return response.getBody();
}

throw new ApiException("No response for BrAPI list item search");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
import org.brapi.client.v2.model.exceptions.ApiException;
import org.brapi.v2.model.BrAPIExternalReference;
import lombok.extern.slf4j.Slf4j;
import org.brapi.v2.model.core.BrAPIListItemWithFullItem;
import org.brapi.v2.model.core.request.BrAPIListNewRequest;
import org.brapi.v2.model.core.response.BrAPIListDetails;
import org.brapi.v2.model.core.response.BrAPIListItemsListResponse;
import org.brapi.v2.model.core.response.BrAPIListsSingleResponse;
import org.brapi.v2.model.germ.BrAPIGermplasm;
import org.brapi.v2.model.germ.BrAPIGermplasmSynonyms;
import org.brapi.v2.model.germ.response.BrAPIGermplasmListResponse;
import org.brapi.v2.model.germ.response.BrAPIGermplasmListResponseResult;
import org.breedinginsight.brapi.v2.constants.BrAPIAdditionalInfoFields;
import org.breedinginsight.brapi.v2.dao.BrAPIListDAO;
import org.breedinginsight.brapi.v2.model.request.query.GermplasmQuery;
Expand Down Expand Up @@ -172,96 +175,40 @@ public BrAPIGermplasmListResponse getGermplasmByList(UUID programId, GermplasmQu
if(Objects.nonNull(listResponse) && Objects.nonNull(listResponse.getResult())) {

// get the list ID stored in the list external references
UUID listId = getGermplasmListId(listResponse.getResult());
// TODO: See if this can be removed/replaced with actual BrAPI list db id
UUID biGermplasmListId = getGermplasmListId(listResponse.getResult());

// get list BrAPI germplasm variables.
// The order of these germplasm names are the exact order/entry number in the list that was imported.
List<String> germplasmNamesFromBrapiList = listResponse.getResult().getData();
// Required for the actual data search in BrAPI
String brapiListDbId = listResponse.getResult().getListDbId();

BrAPIGermplasmListResponse germplasmSearchResponse = germplasmDAO.searchGermplasmByRawName(germplasmNamesFromBrapiList, programId, germplasmQuery);
BrAPIListItemsListResponse<BrAPIGermplasm> listSearchResponse = germplasmDAO.searchGermplasmByList(brapiListDbId, programId, germplasmQuery);

List<BrAPIGermplasm> germplasm = germplasmSearchResponse.getResult().getData();
Map<String, BrAPIGermplasm> germplasmByGid = new HashMap<>();
List<BrAPIListItemWithFullItem<BrAPIGermplasm>> listItemsWithFullItem = listSearchResponse.getResult().getData();

if (germplasm == null || germplasm.isEmpty()) {
return germplasmSearchResponse;
}

for (BrAPIGermplasm g : germplasm) {
// set the list ID in the germplasm additional info
g.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_LIST_ID, listId);
// Add to map.
germplasmByGid.put(g.getAccessionNumber(), g);
}

// Extract gids from list names
List<String> gids = germplasmNamesFromBrapiList.stream().map(Utilities::extractGid).collect(Collectors.toList());

// Build list from BrAPI list that preserves ordering and duplicates and assigns sequential entry numbers.
List<BrAPIGermplasm> orderByEntryNumber = new ArrayList<>();

Program program = programService.getById(programId).orElseThrow(() -> new DoesNotExistException("Could not find program: " + programId));

for (String gid : gids) {
BrAPIGermplasm germ = germplasmByGid.get(gid);
listItemsWithFullItem.forEach(li -> {
li.getItem().putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_LIST_ID, biGermplasmListId);
// listItem.position start of index is 0 in BrAPI, but in DeltaBreed, it starts at 1. increment result data to account for this.
// The actual sort/filter performs the search on a formula column created on the prod server, so no need to worry about that in the request above.
li.getItem().putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_IMPORT_ENTRY_NUMBER, li.getListItem().getPosition() + 1);
});

if (germ == null) {
continue;
}

// We can't simply use germ.getGermplasmName here because the BrAPIGermplasmDAO code strips the key and gid via BrAPIGermplasmDAO.processGermplasmForDisplay()
// Rebuild the unique name so we can get the entry number via the order on the germplasmNamesFromBrapiList list which was derived from the list response.
String fullGermplasmName = Utilities.appendProgramKey(germ.getDefaultDisplayName(), program.getKey(), germ.getAccessionNumber());
List<BrAPIGermplasm> germplasm = listItemsWithFullItem.stream().map(BrAPIListItemWithFullItem::getItem).collect(Collectors.toList());

BrAPIGermplasm listEntry = cloneBrAPIGermplasm(germ);
BrAPIGermplasmListResponse germplasmSearchResponse = new BrAPIGermplasmListResponse();
BrAPIGermplasmListResponseResult germplasmListResponseResult = new BrAPIGermplasmListResponseResult();

int entryNumber = germplasmNamesFromBrapiList.indexOf(fullGermplasmName) + 1;

// Set entry number.
listEntry.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_IMPORT_ENTRY_NUMBER, entryNumber);
germ.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_IMPORT_ENTRY_NUMBER, entryNumber);
orderByEntryNumber.add(listEntry);
}
germplasmSearchResponse.setMetadata(listSearchResponse.getMetadata());
germplasmListResponseResult.setData(germplasm);
germplasmSearchResponse.setResult(germplasmListResponseResult);

if (germplasmQuery.getSortField() == null || germplasmQuery.getSortField().equals("importEntryNumber")) {
// This should order by entry number when germplasm list details page displays
germplasmSearchResponse.getResult().setData(orderByEntryNumber);
} else {
// In all other cases it will order by the other selected data
germplasmSearchResponse.getResult().setData(germplasm);
if (germplasm.isEmpty()) {
return germplasmSearchResponse;
}

return germplasmSearchResponse;
} else throw new ApiException();
}

// private BrAPIGermplasmListResponse orderByListImportEntryNumber() {
// for (String gid : gids) {
// BrAPIGermplasm germ = germplasmByGid.get(gid);
//
// if (germ == null) {
// continue;
// }
//
// // We can't simply use germ.getGermplasmName here because the BrAPIGermplasmDAO code strips the key and gid via BrAPIGermplasmDAO.processGermplasmForDisplay()
// // Rebuild the unique name so we can get the entry number via the order on the germplasmNamesFromBrapiList list which was derived from the list response.
// String fullGermplasmName = Utilities.appendProgramKey(germ.getDefaultDisplayName(), program.getKey(), germ.getAccessionNumber());
//
// BrAPIGermplasm listEntry = cloneBrAPIGermplasm(germ);
//
// int entryNumber = germplasmNamesFromBrapiList.indexOf(fullGermplasmName) + 1;
//
// // Set entry number.
// listEntry.putAdditionalInfoItem(BrAPIAdditionalInfoFields.GERMPLASM_IMPORT_ENTRY_NUMBER, entryNumber);
// orderByEntryNumber.add(listEntry);
// }
// }

private BrAPIGermplasm cloneBrAPIGermplasm(BrAPIGermplasm germplasm) {
// Serialize then deserialize to deep copy.
return (BrAPIGermplasm) gson.fromJson(gson.toJson(germplasm), BrAPIGermplasm.class);
}

public DownloadFile exportGermplasm(UUID programId, FileType fileExtension) throws IllegalArgumentException, ApiException, IOException, DoesNotExistException {
List<Column> columns = GermplasmFileColumns.getOrderedColumns();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.breedinginsight.services;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonObject;
import io.reactivex.functions.Function;
import io.reactivex.functions.Function3;
Expand Down Expand Up @@ -60,7 +61,7 @@ void setup() {
listDAO = mock(BrAPIListDAO.class);
programDAO = mock(ProgramDAO.class);
brAPIDAOUtil = mock(BrAPIDAOUtil.class);
germplasmDAO = new BrAPIGermplasmDAO(programDAO, mock(ImportDAO.class), brAPIDAOUtil, new BrAPIEndpointProvider(), 65000);
germplasmDAO = new BrAPIGermplasmDAO(programDAO, mock(ImportDAO.class), brAPIDAOUtil, new BrAPIEndpointProvider(), 65000, new ObjectMapper(), listDAO);
programService = mock(ProgramService.class);

Field externalReferenceSource = BrAPIGermplasmDAO.class.getDeclaredField("referenceSource");
Expand Down
Loading