From 6ce44fe7a5aaf1d1b6fa55da83be917185400dc5 Mon Sep 17 00:00:00 2001 From: humsika Date: Fri, 11 Sep 2026 12:06:33 -0400 Subject: [PATCH 1/2] BI-2921: Removed remaining ProgramCache operations from BrAPIStudyDAO. --- .../brapi/v2/dao/BrAPICachedDAO.java | 15 ---- .../brapi/v2/dao/BrAPIStudyDAO.java | 87 ++++--------------- .../brapi/v2/services/BrAPITrialService.java | 2 - .../ExperimentControllerIntegrationTest.java | 3 + .../brapi/v2/dao/BrAPIStudyDAOUnitTest.java | 38 +++++--- 5 files changed, 43 insertions(+), 102 deletions(-) delete mode 100644 src/main/java/org/breedinginsight/brapi/v2/dao/BrAPICachedDAO.java diff --git a/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPICachedDAO.java b/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPICachedDAO.java deleted file mode 100644 index 2d623b02b..000000000 --- a/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPICachedDAO.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.breedinginsight.brapi.v2.dao; - -import org.breedinginsight.daos.cache.ProgramCache; - -import java.util.UUID; - -public abstract class BrAPICachedDAO { - - protected ProgramCache programCache; - - public void repopulateCache(UUID programId) { - this.programCache.invalidate(programId); - this.programCache.populate(programId); - } -} diff --git a/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAO.java b/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAO.java index 2f2b808e0..69339e9a2 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAO.java +++ b/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAO.java @@ -19,7 +19,6 @@ import com.google.gson.JsonObject; import io.micronaut.context.annotation.Property; import io.micronaut.http.server.exceptions.InternalServerException; -import io.micronaut.scheduling.annotation.Scheduled; import lombok.extern.slf4j.Slf4j; import org.brapi.client.v2.model.exceptions.ApiException; import org.brapi.client.v2.model.queryParams.core.StudyQueryParams; @@ -32,7 +31,6 @@ import org.breedinginsight.brapps.importer.model.ImportUpload; import org.breedinginsight.brapps.importer.services.ExternalReferenceSource; import org.breedinginsight.daos.ProgramDAO; -import org.breedinginsight.daos.cache.ProgramCacheProvider; import org.breedinginsight.model.Program; import org.breedinginsight.services.brapi.BrAPIEndpointProvider; import org.breedinginsight.utilities.BrAPIDAOUtil; @@ -42,16 +40,14 @@ import javax.inject.Singleton; import javax.validation.constraints.NotNull; import java.util.*; -import java.util.concurrent.Callable; import java.util.stream.Collectors; @Slf4j @Singleton -public class BrAPIStudyDAO extends BrAPICachedDAO { +public class BrAPIStudyDAO { @Property(name = "brapi.server.reference-source") private String referenceSource; - @Property(name = "micronaut.bi.api.run-scheduled-tasks") - private boolean runScheduledTasks; + @Property(name = "brapi.cache.fetch-page-size") private int brapiMaxPageSize; @@ -61,52 +57,15 @@ public class BrAPIStudyDAO extends BrAPICachedDAO { private final BrAPIEndpointProvider brAPIEndpointProvider; @Inject - public BrAPIStudyDAO(ProgramDAO programDAO, ImportDAO importDAO, BrAPIDAOUtil brAPIDAOUtil, BrAPIEndpointProvider brAPIEndpointProvider, ProgramCacheProvider programCacheProvider) { + public BrAPIStudyDAO( + ProgramDAO programDAO, + ImportDAO importDAO, + BrAPIDAOUtil brAPIDAOUtil, + BrAPIEndpointProvider brAPIEndpointProvider) { // NEW this.programDAO = programDAO; this.importDAO = importDAO; this.brAPIDAOUtil = brAPIDAOUtil; this.brAPIEndpointProvider = brAPIEndpointProvider; - this.programCache = programCacheProvider.getProgramCache(this::fetchProgramStudy, BrAPIStudy.class); - } - - @Scheduled(initialDelay = "${startup.delay.study}") - public void setup() { - if(!runScheduledTasks) { - return; - } - // Populate study cache for all programs on startup - log.debug("populating study cache"); - List programs = programDAO.getActive(); - if(programs != null) { - programCache.populate(programs.stream().map(Program::getId).collect(Collectors.toList())); - } - } - - - /** - * Fetch formatted study for this program - * @param programId - * @return Map - Key = string representing study UUID, value = formatted BrAPIStudy - * @throws ApiException - */ - private Map fetchProgramStudy(UUID programId) throws ApiException { - StudiesApi api = brAPIEndpointProvider.get(programDAO.getCoreClient(programId), StudiesApi.class); - // Get the program key - List programs = programDAO.get(programId); - if (programs.size() != 1) { - throw new InternalServerException("Program was not found for given key"); - } - Program program = programs.get(0); - - // Set query params and make call - BrAPIStudySearchRequest studySearch = new BrAPIStudySearchRequest(); - studySearch.externalReferenceIDs(List.of(programId.toString())); - studySearch.externalReferenceSources(List.of(Utilities.generateReferenceSource(referenceSource, ExternalReferenceSource.PROGRAMS))); - return processStudyForDisplay(brAPIDAOUtil.search( - api::searchStudiesPost, - api::searchStudiesSearchResultsDbIdGet, - studySearch - ), program.getKey()); } /** @@ -201,39 +160,23 @@ public List getStudiesByExperimentIds(@NotNull Collection expe public List createBrAPIStudies(List brAPIStudyList, UUID programId, ImportUpload upload) throws ApiException { StudiesApi api = brAPIEndpointProvider.get(programDAO.getCoreClient(programId), StudiesApi.class); - List createdStudies = new ArrayList<>(); + try { if (!brAPIStudyList.isEmpty()) { - Callable> postCallback = () -> { - List postedStudies = brAPIDAOUtil - .post(brAPIStudyList, upload, api::studiesPost, importDAO::update); - return environmentById(postedStudies); - }; - createdStudies.addAll(programCache.post(programId, postCallback)); + //Create studies directly through BrAPI. + List postedStudies = brAPIDAOUtil.post(brAPIStudyList, upload, api::studiesPost, importDAO::update); + + // Return the BrAPI response without updating Redis. + return postedStudies; } - return createdStudies; + // Preserve the existing empty-input behavior. + return new ArrayList<>(); } catch (Exception e) { throw new InternalServerException("Unknown error has occurred: " + e.getMessage(), e); } } - /** - * @return Map - Key = BI external reference ID, Value = BrAPIStudy - * */ - private Map environmentById(List studies) { - Map environmentById = new HashMap<>(); - for (BrAPIStudy environment: studies) { - BrAPIExternalReference xref = environment - .getExternalReferences() - .stream() - .filter(reference -> String.format("%s/%s", referenceSource, ExternalReferenceSource.STUDIES.getName()).equals(reference.getReferenceSource())) - .findFirst().orElseThrow(() -> new IllegalStateException("No BI external reference found")); - environmentById.put(xref.getReferenceID(), environment); - } - return environmentById; - } - public List getStudiesByStudyDbId(Collection studyDbIds, Program program) throws ApiException { if(studyDbIds.isEmpty()) { return Collections.emptyList(); diff --git a/src/main/java/org/breedinginsight/brapi/v2/services/BrAPITrialService.java b/src/main/java/org/breedinginsight/brapi/v2/services/BrAPITrialService.java index e698df2e6..f6a78c695 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/services/BrAPITrialService.java +++ b/src/main/java/org/breedinginsight/brapi/v2/services/BrAPITrialService.java @@ -814,8 +814,6 @@ public int deleteExperiment(Program program, UUID experimentId, boolean hard) th for (BrAPIListSummary list : lists) { listDAO.deleteBrAPIList(list.getListDbId(), program.getId(), hard); } - // TODO: if performance is poor, implement more precise invalidation, possibly using hierarchical cache keys. - studyDAO.repopulateCache(program.getId()); } // Successful or not, return the number of observations in this experiment. diff --git a/src/test/java/org/breedinginsight/api/v1/controller/ExperimentControllerIntegrationTest.java b/src/test/java/org/breedinginsight/api/v1/controller/ExperimentControllerIntegrationTest.java index 36055121a..f1b5e9ce8 100644 --- a/src/test/java/org/breedinginsight/api/v1/controller/ExperimentControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/api/v1/controller/ExperimentControllerIntegrationTest.java @@ -16,6 +16,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.brapi.v2.model.BrAPIExternalReference; +import org.brapi.v2.model.core.BrAPIStudy; import org.brapi.v2.model.core.BrAPITrial; import org.brapi.v2.model.germ.BrAPIGermplasm; import org.breedinginsight.BrAPITest; @@ -218,6 +219,8 @@ void setup() throws Exception { envIds.clear(); brAPIStudyDAO.getStudies(program.getId()) + .stream() + .sorted(Comparator.comparing(BrAPIStudy::getStudyName)) .forEach(study -> envIds.add(study.getStudyDbId())); } diff --git a/src/test/java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAOUnitTest.java b/src/test/java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAOUnitTest.java index 3dda7b8e3..95cf4a73a 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAOUnitTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAOUnitTest.java @@ -16,6 +16,7 @@ */ package org.breedinginsight.brapi.v2.dao; +import io.reactivex.functions.Consumer; import io.reactivex.functions.Function; import io.reactivex.functions.Function3; import lombok.SneakyThrows; @@ -26,11 +27,9 @@ import org.brapi.v2.model.core.BrAPIStudy; import org.brapi.v2.model.core.request.BrAPIStudySearchRequest; import org.breedinginsight.brapps.importer.daos.ImportDAO; +import org.breedinginsight.brapps.importer.model.ImportUpload; import org.breedinginsight.brapps.importer.services.ExternalReferenceSource; import org.breedinginsight.daos.ProgramDAO; -import org.breedinginsight.daos.cache.FetchFunction; -import org.breedinginsight.daos.cache.ProgramCache; -import org.breedinginsight.daos.cache.ProgramCacheProvider; import org.breedinginsight.model.Program; import org.breedinginsight.services.brapi.BrAPIEndpointProvider; import org.breedinginsight.utilities.BrAPIDAOUtil; @@ -56,7 +55,6 @@ public class BrAPIStudyDAOUnitTest { private BrAPIStudyDAO studyDAO; private ProgramDAO programDAO; private BrAPIDAOUtil brAPIDAOUtil; - private ProgramCache programCache; private Program program; private UUID programId; private UUID environmentId; @@ -76,11 +74,7 @@ void setup() { programDAO = mock(ProgramDAO.class); brAPIDAOUtil = mock(BrAPIDAOUtil.class); - ProgramCacheProvider programCacheProvider = mock(ProgramCacheProvider.class); - programCache = mock(ProgramCache.class); - when(programCacheProvider.getProgramCache(any(FetchFunction.class), eq(BrAPIStudy.class))) - .thenReturn(programCache); when(programDAO.get(programId)).thenReturn(List.of(program)); when(programDAO.getCoreClient(programId)).thenReturn(mock(BrAPIClient.class)); when(programDAO.getProgramBrAPI(program)).thenReturn(brapiProgram); @@ -89,8 +83,7 @@ void setup() { programDAO, mock(ImportDAO.class), brAPIDAOUtil, - new BrAPIEndpointProvider(), - programCacheProvider + new BrAPIEndpointProvider() ); Field referenceSource = BrAPIStudyDAO.class.getDeclaredField("referenceSource"); @@ -119,7 +112,6 @@ void getStudiesUsesDirectBrAPIGetInsteadOfProgramCache() { assertEquals("brapi-program-1", queryParamsCaptor.getValue().programDbId()); assertEquals(0, queryParamsCaptor.getValue().page()); assertEquals(1000, queryParamsCaptor.getValue().pageSize()); - verify(programCache, never()).get(any(UUID.class)); } @Test @@ -143,8 +135,6 @@ void getStudiesByStudyDbIdUsesDirectBrAPISearch() { assertEquals(List.of("brapi-program-1"), requestCaptor.getValue().getProgramDbIds()); assertEquals(List.of(studyDbId), requestCaptor.getValue().getStudyDbIds()); - - verify(programCache, never()).get(any(UUID.class)); } @Test @@ -158,6 +148,28 @@ void getStudyByDbIdReturnsEmptyWhenBrAPIDoesNotFindStudy() { assertTrue(result.isEmpty()); } + @Test + @SneakyThrows + void createBrAPIStudiesReturnsDirectBrAPIPostResponse() { + + BrAPIStudy requestedStudy = new BrAPIStudy().studyName("Env1 [TEST-1]"); + List requestedStudies = List.of(requestedStudy); + + BrAPIStudy createdStudy = new BrAPIStudy().studyDbId("study-db-id").studyName("Env1 [TEST-1]"); + ImportUpload upload = mock(ImportUpload.class); + + doReturn(List.of(createdStudy)) + .when(brAPIDAOUtil) + .post(eq(requestedStudies),eq(upload),any(Function.class),any(Consumer.class)); + + List result = studyDAO.createBrAPIStudies(requestedStudies,programId,upload); + + assertEquals(1, result.size()); + assertEquals("study-db-id",result.get(0).getStudyDbId()); + + verify(brAPIDAOUtil).post(eq(requestedStudies),eq(upload),any(Function.class),any(Consumer.class)); + } + private BrAPIStudy study(UUID environmentId, String studyName) { BrAPIExternalReference studyReference = new BrAPIExternalReference() .referenceSource(Utilities.generateReferenceSource(REFERENCE_SOURCE, ExternalReferenceSource.STUDIES)) From 5bef696149260d51886ba733df4035dae30f3708 Mon Sep 17 00:00:00 2001 From: humsika Date: Sun, 13 Sep 2026 23:00:44 -0400 Subject: [PATCH 2/2] BI-2921: Formatted the file. --- .../java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAO.java b/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAO.java index 69339e9a2..079bf11a1 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAO.java +++ b/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIStudyDAO.java @@ -61,7 +61,7 @@ public BrAPIStudyDAO( ProgramDAO programDAO, ImportDAO importDAO, BrAPIDAOUtil brAPIDAOUtil, - BrAPIEndpointProvider brAPIEndpointProvider) { // NEW + BrAPIEndpointProvider brAPIEndpointProvider) { this.programDAO = programDAO; this.importDAO = importDAO; this.brAPIDAOUtil = brAPIDAOUtil;