Skip to content
Merged
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 @@ -298,4 +298,43 @@ public HttpResponse deleteExperimentalCollaborator(
}

}

/**
* Deletes an experiment.
* @param programId The UUID of the program
* @param experimentId The UUID of the experiment
* @param hard Specifies hard or soft delete
* @return A Http Response
*/
@Delete("/${micronaut.bi.api.version}/programs/{programId}/experiments/{experimentId}{?hard}")
@ProgramSecured(roles = {ProgramSecuredRole.PROGRAM_ADMIN, ProgramSecuredRole.SYSTEM_ADMIN})
@Produces(MediaType.APPLICATION_JSON)
public HttpResponse deleteExperiment(
@PathVariable("programId") UUID programId,
@PathVariable("experimentId") UUID experimentId,
@QueryValue(defaultValue = "false") Boolean hard
) throws ApiException {
try {
Optional<Program> program = programService.getById(programId);
if(program.isEmpty()) {
return HttpResponse.notFound();
}
int observationCount = experimentService.deleteExperiment(program.get(), experimentId, hard);
if (observationCount > 0 && hard) {
// 409 Conflict. https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/409
return HttpResponse.status(HttpStatus.CONFLICT);
}
// 204 No Content indicates successful delete. https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204
return HttpResponse.noContent();
} catch (ApiException e) {
log.error("Error deleting experiment.\n\tprogramId: " + programId + "\n\texperimentId: " + experimentId + "\n\thard: " + hard);
if (e.getCode() == 404) {
return HttpResponse.notFound();
} else {
return HttpResponse.serverError();
}
}
}


}
15 changes: 15 additions & 0 deletions src/main/java/org/breedinginsight/brapi/v2/dao/BrAPICachedDAO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.breedinginsight.brapi.v2.dao;

import org.breedinginsight.daos.cache.ProgramCache;

import java.util.UUID;

public abstract class BrAPICachedDAO<T> {

protected ProgramCache<T> programCache;

public void repopulateCache(UUID programId) {
this.programCache.invalidate(programId);
this.programCache.populate(programId);
}
}
17 changes: 3 additions & 14 deletions src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIListDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,8 @@
package org.breedinginsight.brapi.v2.dao;

import io.micronaut.http.HttpResponse;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.exceptions.HttpStatusException;
import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.brapi.client.v2.ApiResponse;
import org.brapi.client.v2.model.exceptions.ApiException;
Expand All @@ -38,27 +35,19 @@
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.breedinginsight.api.model.v1.response.DataResponse;
import org.breedinginsight.api.model.v1.response.Response;
import org.breedinginsight.brapi.v1.controller.BrapiVersion;
import org.breedinginsight.brapps.importer.daos.ImportDAO;
import org.breedinginsight.brapps.importer.model.ImportUpload;
import org.breedinginsight.daos.ProgramDAO;
import org.breedinginsight.model.ProgramBrAPIEndpoints;
import org.breedinginsight.services.ProgramService;
import org.breedinginsight.services.brapi.BrAPIEndpointProvider;
import org.breedinginsight.services.exceptions.DoesNotExistException;
import org.breedinginsight.utilities.BrAPIDAOUtil;
import org.breedinginsight.utilities.Utilities;

import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Slf4j
public class BrAPIListDAO {
Expand All @@ -79,7 +68,7 @@ public BrAPIListDAO(ProgramDAO programDAO,
this.brAPIEndpointProvider = brAPIEndpointProvider;
}

public List<BrAPIListSummary> getListByName(List<String> listNames, UUID programId) throws ApiException {
public List<BrAPIListSummary> getListsByName(List<String> listNames, UUID programId) throws ApiException {
if(listNames.isEmpty()) {
return Collections.emptyList();
}
Expand All @@ -100,7 +89,7 @@ public BrAPIListsSingleResponse getListById(String listId, UUID programId) throw
return response.getBody();
}

public List<BrAPIListSummary> getListBySearch(@NotNull BrAPIListSearchRequest searchRequest, UUID programId) throws ApiException {
public List<BrAPIListSummary> getListsBySearch(@NotNull BrAPIListSearchRequest searchRequest, UUID programId) throws ApiException {
ListsApi api = brAPIEndpointProvider.get(programDAO.getCoreClient(programId), ListsApi.class);
List<BrAPIListSummary> programLists = brAPIDAOUtil.search(api::searchListsPost, api::searchListsSearchResultsDbIdGet, searchRequest);
if (searchRequest.getExternalReferenceSources() != null && searchRequest.getExternalReferenceIDs() != null) {
Expand All @@ -112,7 +101,7 @@ public List<BrAPIListSummary> getListBySearch(@NotNull BrAPIListSearchRequest se

}

public List<BrAPIListSummary> getListByTypeAndExternalRef(@NotNull BrAPIListTypes listType, UUID programId, String externalReferenceSource, UUID externalReferenceId) throws ApiException {
public List<BrAPIListSummary> getListsByTypeAndExternalRef(@NotNull BrAPIListTypes listType, UUID programId, String externalReferenceSource, UUID externalReferenceId) throws ApiException {
BrAPIListSearchRequest searchRequest = new BrAPIListSearchRequest()
.externalReferenceIDs(List.of(externalReferenceId.toString()))
.externalReferenceSources(List.of(externalReferenceSource))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,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.ProgramCache;
import org.breedinginsight.daos.cache.ProgramCacheProvider;
import org.breedinginsight.model.Program;
import org.breedinginsight.services.brapi.BrAPIEndpointProvider;
Expand All @@ -54,7 +53,7 @@

@Singleton
@Slf4j
public class BrAPIObservationDAO {
public class BrAPIObservationDAO extends BrAPICachedDAO<BrAPIObservation> {

private ProgramDAO programDAO;
private ImportDAO importDAO;
Expand All @@ -63,7 +62,6 @@ public class BrAPIObservationDAO {
private final BrAPIEndpointProvider brAPIEndpointProvider;
private final String referenceSource;
private boolean runScheduledTasks;
private final ProgramCache<BrAPIObservation> programObservationCache;

@Inject
public BrAPIObservationDAO(ProgramDAO programDAO,
Expand All @@ -81,7 +79,7 @@ public BrAPIObservationDAO(ProgramDAO programDAO,
this.brAPIEndpointProvider = brAPIEndpointProvider;
this.referenceSource = referenceSource;
this.runScheduledTasks = runScheduledTasks;
this.programObservationCache = programCacheProvider.getProgramCache(this::fetchProgramObservations, BrAPIObservation.class);
this.programCache = programCacheProvider.getProgramCache(this::fetchProgramObservations, BrAPIObservation.class);
}

@Scheduled(initialDelay = "3s")
Expand All @@ -93,7 +91,7 @@ public void setup() {
log.debug("populating observation cache");
List<Program> programs = programDAO.getActive();
if (programs != null) {
programObservationCache.populate(programs.stream().map(Program::getId).collect(Collectors.toList()));
programCache.populate(programs.stream().map(Program::getId).collect(Collectors.toList()));
}
}

Expand Down Expand Up @@ -163,7 +161,7 @@ private void processObservations(String programKey, List<BrAPIObservation> obser
* Get all observations for a program from the cache.
*/
private Map<String, BrAPIObservation> getProgramObservations(UUID programId) throws ApiException {
return programObservationCache.get(programId);
return programCache.get(programId);
}

// Note: not using cache, because unique studyName (with "[ProgramKey-ExtraInfo]") is not stored directly on Observation.
Expand Down Expand Up @@ -259,7 +257,7 @@ public List<BrAPIObservation> createBrAPIObservations(List<BrAPIObservation> brA
List<BrAPIObservation> postResponse = brAPIDAOUtil.post(brAPIObservationList, upload, api::observationsPost, importDAO::update);
return processObservationsForCache(postResponse, program.getKey());
};
return programObservationCache.post(programId, postFunction);
return programCache.post(programId, postFunction);
}
return new ArrayList<>();
} catch (Exception e) {
Expand Down Expand Up @@ -287,7 +285,7 @@ public BrAPIObservation updateBrAPIObservation(String dbId, BrAPIObservation obs
}
return processObservationsForCache(List.of(updatedObservation), program.getKey());
};
return programObservationCache.post(programId, postFunction).get(0);
return programCache.post(programId, postFunction).get(0);
} catch (ApiException e) {
log.error(Utilities.generateApiExceptionLogMessage(e));
throw new InternalServerException("Unknown error has occurred: " + e.getMessage(), e);
Expand Down Expand Up @@ -343,7 +341,7 @@ public List<BrAPIObservation> updateBrAPIObservation(Map<String, BrAPIObservatio
}
}
Map<String, BrAPIObservation> processedObservations = processObservationsForCache(updatedObservations, program.getKey());
return programObservationCache.postThese(programId,processedObservations);
return programCache.postThese(programId,processedObservations);
} catch (ApiException e) {
log.error("Error updating observation: " + Utilities.generateApiExceptionLogMessage(e), e);
throw e;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,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.ProgramCache;
import org.breedinginsight.daos.cache.ProgramCacheProvider;
import org.breedinginsight.model.Program;
import org.breedinginsight.services.ProgramService;
Expand All @@ -61,7 +60,7 @@

@Slf4j
@Singleton
public class BrAPIObservationUnitDAO {
public class BrAPIObservationUnitDAO extends BrAPICachedDAO<BrAPIObservationUnit> {
private final ProgramDAO programDAO;
private final ImportDAO importDAO;
private final BrAPIDAOUtil brAPIDAOUtil;
Expand All @@ -75,8 +74,6 @@ public class BrAPIObservationUnitDAO {
private final Gson gson = new JSON().getGson();
private final Type treatmentlistType = new TypeToken<ArrayList<BrAPIObservationTreatment>>(){}.getType();

private final ProgramCache<BrAPIObservationUnit> programObservationUnitCache;

@Inject
public BrAPIObservationUnitDAO(ProgramDAO programDAO,
ImportDAO importDAO,
Expand All @@ -95,7 +92,7 @@ public BrAPIObservationUnitDAO(ProgramDAO programDAO,
this.runScheduledTasks = runScheduledTasks;
this.programService = programService;
this.germplasmService = germplasmService;
this.programObservationUnitCache = programCacheProvider.getProgramCache(this::fetchProgramObservationUnits, BrAPIObservationUnit.class);
this.programCache = programCacheProvider.getProgramCache(this::fetchProgramObservationUnits, BrAPIObservationUnit.class);
}

@Scheduled(initialDelay = "3s")
Expand All @@ -107,7 +104,7 @@ public void setup() {
log.debug("populating observation unit cache");
List<Program> programs = programDAO.getActive();
if(programs != null) {
programObservationUnitCache.populate(programs.stream().map(Program::getId).collect(Collectors.toList()));
programCache.populate(programs.stream().map(Program::getId).collect(Collectors.toList()));
}
}

Expand Down Expand Up @@ -157,7 +154,7 @@ private Map<String, BrAPIObservationUnit> processObservationUnitsForCache(List<B
* Get all observation units for a program from the cache.
*/
private Map<String, BrAPIObservationUnit> getProgramObservationUnits(UUID programId) throws ApiException {
return programObservationUnitCache.get(programId);
return programCache.get(programId);
}

public List<BrAPIObservationUnit> getObservationUnitByName(List<String> observationUnitNames, Program program) throws ApiException {
Expand All @@ -183,7 +180,7 @@ public List<BrAPIObservationUnit> createBrAPIObservationUnits(List<BrAPIObservat
List<BrAPIObservationUnit> ous = brAPIDAOUtil.post(brAPIObservationUnitList, upload, api::observationunitsPost, importDAO::update);
return processObservationUnitsForCache(ous, program, false);
};
return programObservationUnitCache.post(programId, postFunction);
return programCache.post(programId, postFunction);
}
return new ArrayList<>();
} catch (Exception e) {
Expand All @@ -205,7 +202,7 @@ public List<BrAPIObservationUnit> createBrAPIObservationUnits(List<BrAPIObservat
List<BrAPIObservationUnit> ous = brAPIDAOUtil.post(brAPIObservationUnitList, api::observationunitsPost);
return processObservationUnitsForCache(ous, program, false);
};
return programObservationUnitCache.post(programId, postFunction);
return programCache.post(programId, postFunction);
}
return new ArrayList<>();
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,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.ProgramCache;
import org.breedinginsight.daos.cache.ProgramCacheProvider;
import org.breedinginsight.model.Program;
import org.breedinginsight.services.brapi.BrAPIEndpointProvider;
Expand All @@ -46,7 +45,7 @@

@Slf4j
@Singleton
public class BrAPIStudyDAO {
public class BrAPIStudyDAO extends BrAPICachedDAO<BrAPIStudy> {
@Property(name = "brapi.server.reference-source")
private String referenceSource;
@Property(name = "micronaut.bi.api.run-scheduled-tasks")
Expand All @@ -56,16 +55,14 @@ public class BrAPIStudyDAO {
private ImportDAO importDAO;
private final BrAPIDAOUtil brAPIDAOUtil;
private final BrAPIEndpointProvider brAPIEndpointProvider;
private final ProgramCache<BrAPIStudy> programStudyCache;


@Inject
public BrAPIStudyDAO(ProgramDAO programDAO, ImportDAO importDAO, BrAPIDAOUtil brAPIDAOUtil, BrAPIEndpointProvider brAPIEndpointProvider, ProgramCacheProvider programCacheProvider) {
this.programDAO = programDAO;
this.importDAO = importDAO;
this.brAPIDAOUtil = brAPIDAOUtil;
this.brAPIEndpointProvider = brAPIEndpointProvider;
this.programStudyCache = programCacheProvider.getProgramCache(this::fetchProgramStudy, BrAPIStudy.class);
this.programCache = programCacheProvider.getProgramCache(this::fetchProgramStudy, BrAPIStudy.class);
}

@Scheduled(initialDelay = "2s")
Expand All @@ -77,7 +74,7 @@ public void setup() {
log.debug("populating study cache");
List<Program> programs = programDAO.getActive();
if(programs != null) {
programStudyCache.populate(programs.stream().map(Program::getId).collect(Collectors.toList()));
programCache.populate(programs.stream().map(Program::getId).collect(Collectors.toList()));
}
}

Expand Down Expand Up @@ -115,7 +112,7 @@ private Map<String, BrAPIStudy> fetchProgramStudy(UUID programId) throws ApiExce
* @throws ApiException
*/
public List<BrAPIStudy> getStudies(UUID programId) throws ApiException {
return new ArrayList<>(programStudyCache.get(programId).values());
return new ArrayList<>(programCache.get(programId).values());
}

public Optional<BrAPIStudy> getStudyByName(String studyName, Program program) throws ApiException {
Expand Down Expand Up @@ -153,7 +150,7 @@ public List<BrAPIStudy> getStudiesByExperimentID(@NotNull UUID experimentId, Pro
}

public List<BrAPIStudy> getStudiesByEnvironmentIds(@NotNull Collection<UUID> environmentIds, Program program) throws ApiException {
return programStudyCache.get(program.getId())
return programCache.get(program.getId())
.entrySet()
.stream()
.filter(entry -> environmentIds.contains(UUID.fromString(entry.getKey())))
Expand Down Expand Up @@ -193,7 +190,7 @@ public List<BrAPIStudy> createBrAPIStudies(List<BrAPIStudy> brAPIStudyList, UUID
.post(brAPIStudyList, upload, api::studiesPost, importDAO::update);
return environmentById(postedStudies);
};
createdStudies.addAll(programStudyCache.post(programId, postCallback));
createdStudies.addAll(programCache.post(programId, postCallback));
}

return createdStudies;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,8 @@ List<BrAPITrial> createBrAPITrials(List<BrAPITrial> brAPITrialList, UUID program
List<BrAPITrial> getTrialsByDbIds(Collection<String> trialDbIds, Program program) throws ApiException;

List<BrAPITrial> getTrialsByExperimentIds(Collection<UUID> experimentIds, Program program) throws ApiException;

void deleteBrAPITrial(Program program, BrAPITrial trial, boolean hard) throws ApiException;

void repopulateCache(UUID programId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import io.micronaut.http.server.exceptions.InternalServerException;
import io.micronaut.scheduling.annotation.Scheduled;
import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;
import okhttp3.Request;
import org.brapi.client.v2.model.exceptions.ApiException;
import org.brapi.client.v2.modules.core.TrialsApi;
import org.brapi.v2.model.BrAPIExternalReference;
Expand Down Expand Up @@ -277,4 +279,25 @@ public List<BrAPITrial> getTrialsByExperimentIds(Collection<UUID> experimentIds,
trialSearch
), program.getKey());
}

@Override
public void deleteBrAPITrial(Program program, BrAPITrial trial, boolean hard) throws ApiException {
// TODO: Switch to using the TrialsApi from the BrAPI client library once the delete endpoints are merged into it.
var programBrAPIBaseUrl = brAPIDAOUtil.getProgramBrAPIBaseUrl(program.getId());
var requestUrl = HttpUrl.parse(programBrAPIBaseUrl + "/trials/" + trial.getTrialDbId()).newBuilder();
requestUrl.addQueryParameter("hardDelete", Boolean.toString(hard));
HttpUrl url = requestUrl.build();
var brapiRequest = new Request.Builder().url(url)
.method("DELETE", null)
.addHeader("Content-Type", "application/json")
.build();

brAPIDAOUtil.makeCall(brapiRequest);
}

@Override
public void repopulateCache(UUID programId) {
this.programExperimentCache.invalidate(programId);
this.programExperimentCache.populate(programId);
}
}
Loading