Skip to content

Commit

Permalink
More fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
forus committed Jan 19, 2025
1 parent 31c3842 commit 670ffff
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@
import org.cbioportal.persistence.MolecularProfileRepository;
import org.cbioportal.persistence.SampleListRepository;
import org.cbioportal.persistence.StudyRepository;
import org.cbioportal.service.impl.vs.VirtualStudyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

@Component
public class CacheMapBuilder {
Expand All @@ -28,6 +31,11 @@ public class CacheMapBuilder {
@Autowired
private StudyRepository studyRepository;

@Autowired
private VirtualStudyService virtualStudyService;

@Value("${vs_mode:false}") Boolean vsMode;

@Autowired
private MolecularProfileRepository molecularProfileRepository;

Expand Down Expand Up @@ -65,13 +73,16 @@ public Map<String, SampleList> buildSampleListMap() {
}

public Map<String, CancerStudy> buildCancerStudyMap() {
Map<String, CancerStudy> cancerStudyMap = studyRepository.getAllStudies(
null,
"SUMMARY",
REPOSITORY_RESULT_LIMIT,
REPOSITORY_RESULT_OFFSET,
null,
"ASC").stream()
Map<String, CancerStudy> cancerStudyMap = Stream.concat(
studyRepository.getAllStudies(
null,
"SUMMARY",
REPOSITORY_RESULT_LIMIT,
REPOSITORY_RESULT_OFFSET,
null,
"ASC").stream(),
vsMode ? virtualStudyService.findVirtualStudies(null).stream() : Stream.empty()
)
.collect(Collectors.toMap(CancerStudy::getCancerStudyIdentifier, Function.identity()));
LOG.debug(" cancer study map size: " + cancerStudyMap.size());
return cancerStudyMap;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.cbioportal.service.impl.vs;

import org.cbioportal.service.CancerTypeService;
import org.cbioportal.service.ReadPermissionService;
import org.cbioportal.service.StudyService;
import org.cbioportal.service.util.SessionServiceRequestHandler;
Expand Down Expand Up @@ -36,7 +37,7 @@ public Executor asyncExecutor() {

@Primary
@Bean
public StudyService studyService(StudyService studyService, Executor asyncExecutor) {
return new VSAwareStudyServiceImpl(studyService, sessionServiceRequestHandler, readPermissionService, asyncExecutor);
public StudyService studyService(StudyService studyService, VirtualStudyService virtualStudyService, Executor asyncExecutor) {
return new VSAwareStudyServiceImpl(studyService, virtualStudyService, readPermissionService, asyncExecutor);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import org.cbioportal.model.CancerStudy;
import org.cbioportal.model.CancerStudyTags;
import org.cbioportal.model.meta.BaseMeta;
import org.cbioportal.service.CancerTypeService;
import org.cbioportal.service.ReadPermissionService;
import org.cbioportal.service.StudyService;
import org.cbioportal.service.exception.CancerTypeNotFoundException;
import org.cbioportal.service.exception.StudyNotFoundException;
import org.cbioportal.service.util.SessionServiceRequestHandler;
import org.cbioportal.utils.security.AccessLevel;
Expand All @@ -25,14 +27,13 @@ public class VSAwareStudyServiceImpl implements StudyService {

private final StudyService studyService;

private final SessionServiceRequestHandler sessionServiceRequestHandler;

private final ReadPermissionService readPermissionService;
private final Executor asyncExecutor;
private final VirtualStudyService virtualStudyService;

public VSAwareStudyServiceImpl(StudyService studyService, SessionServiceRequestHandler sessionServiceRequestHandler, ReadPermissionService readPermissionService, Executor asyncExecutor) {
public VSAwareStudyServiceImpl(StudyService studyService, VirtualStudyService virtualStudyService, ReadPermissionService readPermissionService, Executor asyncExecutor) {
this.studyService = studyService;
this.sessionServiceRequestHandler = sessionServiceRequestHandler;
this.virtualStudyService = virtualStudyService;
this.readPermissionService = readPermissionService;
this.asyncExecutor = asyncExecutor;
}
Expand All @@ -59,27 +60,20 @@ public List<CancerStudy> getAllStudies(String keyword, String projection, Intege
readPermissionService.setReadPermission(result, authentication);
return result;
}

//TODO these should not fail the whole request if one of them fails
@Async
private CompletableFuture<List<CancerStudy>> getVirtualStudiesAsync(String keyword) {
return CompletableFuture.supplyAsync(() -> sessionServiceRequestHandler.getVirtualStudiesAccessibleToUser("*").stream()
.map(VSAwareStudyServiceImpl::toCancerStudy).filter(cs -> shouldSelect(cs, keyword)).toList(), asyncExecutor);
return CompletableFuture.supplyAsync(() -> virtualStudyService.findVirtualStudies(keyword), asyncExecutor);
//TODO return empty list if the request fails
//.exceptionally(e -> List.of());
}

@Async
private CompletableFuture<List<CancerStudy>> getMaterialisedStudiesAsync(String keyword, String projection, Authentication authentication, AccessLevel accessLevel) {
return CompletableFuture.supplyAsync(() -> studyService.getAllStudies(keyword, projection, null, null, null, null, authentication, accessLevel), asyncExecutor);
}

private static CancerStudy toCancerStudy(VirtualStudy vs) {
VirtualStudyData vsd = vs.getData();
CancerStudy cs = new CancerStudy();
cs.setCancerStudyIdentifier(vs.getId());
cs.setName(vsd.getName());
cs.setDescription(vsd.getDescription());
cs.setPmid(vsd.getPmid());
return cs;
}


private static Comparator<CancerStudy> buildComparator(String sortBy, String direction) {
Function<CancerStudy, Comparable> getValue;
Expand All @@ -98,10 +92,7 @@ private static Comparator<CancerStudy> buildComparator(String sortBy, String dir
throw new IllegalArgumentException("Invalid direction value: " + direction);
}

private static boolean shouldSelect(CancerStudy cs, String keyword) {
//TODO improve the search. The keyword can be also sent to mongo to search for virtual studies
return cs.getName().toLowerCase().contains(keyword.toLowerCase());
}


@Override
public BaseMeta getMetaStudies(String keyword) {
Expand All @@ -119,7 +110,7 @@ public CancerStudy getStudy(String studyId) throws StudyNotFoundException {

@Async
private CompletableFuture<Optional<CancerStudy>> getVirtualStudyAsync(String studyId) {
return CompletableFuture.supplyAsync(() -> Optional.ofNullable(sessionServiceRequestHandler.getVirtualStudyById(studyId)).map(VSAwareStudyServiceImpl::toCancerStudy), asyncExecutor);
return CompletableFuture.supplyAsync(() -> virtualStudyService.findVirtualStudy(studyId), asyncExecutor);
}

@Async
Expand Down Expand Up @@ -153,8 +144,10 @@ private static <T> CompletableFuture<Optional<T>> firstPresent(
public List<CancerStudy> fetchStudies(List<String> studyIds, String projection) {
List<CancerStudy> materialisedStudies = studyService.fetchStudies(studyIds, projection);
List<String> notFoundStudyIds = materialisedStudies.stream().map(CancerStudy::getCancerStudyIdentifier).filter(studyId -> !studyIds.contains(studyId)).toList();
//TODO implement using completable futures. It must be better for IO bound operations
List<CancerStudy> virtualStudies = notFoundStudyIds.parallelStream().map(sessionServiceRequestHandler::getVirtualStudyById).map(VSAwareStudyServiceImpl::toCancerStudy).toList();
//TODO implement using completable futures. It must be better for IO bound operations. Fetch all instead of one by one
List<CancerStudy> virtualStudies = notFoundStudyIds.parallelStream().map(virtualStudyService::findVirtualStudy)
.flatMap(Optional::stream)
.toList();
return Stream.concat(materialisedStudies.stream(), virtualStudies.stream()).toList();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.cbioportal.service.impl.vs;

import org.cbioportal.model.CancerStudy;
import org.cbioportal.service.CancerTypeService;
import org.cbioportal.service.exception.CancerTypeNotFoundException;
import org.cbioportal.service.util.SessionServiceRequestHandler;
import org.cbioportal.web.parameter.VirtualStudy;
import org.cbioportal.web.parameter.VirtualStudyData;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class VirtualStudyService {

private final CancerTypeService cancerTypeService;
private final SessionServiceRequestHandler sessionServiceRequestHandler;

public VirtualStudyService(SessionServiceRequestHandler sessionServiceRequestHandler, CancerTypeService cancerTypeService) {
this.sessionServiceRequestHandler = sessionServiceRequestHandler;
this.cancerTypeService = cancerTypeService;
}

public List<CancerStudy> findVirtualStudies(String keyword) {
return sessionServiceRequestHandler.getVirtualStudiesAccessibleToUser("*").stream()
.map(this::toCancerStudy).filter(cs -> shouldSelect(cs, keyword)).toList();
}

public Optional<CancerStudy> findVirtualStudy(String id) {
return Optional.ofNullable(sessionServiceRequestHandler.getVirtualStudyById(id)).map(this::toCancerStudy);
}

private CancerStudy toCancerStudy(VirtualStudy vs) {
VirtualStudyData vsd = vs.getData();
CancerStudy cs = new CancerStudy();
cs.setCancerStudyIdentifier(vs.getId());
cs.setName(vsd.getName());
//TODO fetch mixed cancer type in the constructor once. To fail initialization if the type is not found
String typeOfCancerId = vsd.getTypeOfCancerId() == null ? "mixed" : vsd.getTypeOfCancerId();
try {
cs.setTypeOfCancer(cancerTypeService.getCancerType(typeOfCancerId));
cs.setTypeOfCancerId(typeOfCancerId);
} catch (CancerTypeNotFoundException e) {
throw new RuntimeException(e);
}
cs.setDescription(vsd.getDescription());
cs.setPmid(vsd.getPmid());
//TODO run filters on the dynamic virtual study
cs.setAllSampleCount(vsd.getStudies().stream().map(s -> s.getSamples().size()).reduce(0, Integer::sum));
//TODO we can implement this field for published virtual studies to predefine rights on groups even before the study is created
cs.setGroups("PUBLIC");
return cs;
}

private static boolean shouldSelect(CancerStudy cs, String keyword) {
//TODO improve the search. The keyword can be also sent to mongo to search for virtual studies
if (keyword == null) {
return true;
}
return cs.getName().toLowerCase().contains(keyword.toLowerCase());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public ResponseEntity<Void> unPublishVirtualStudy(
* @param pmid - if specified (not null) update PubMed ID of published virtual study
*/
private void publishVirtualStudy(String id, String typeOfCancerId, String pmid) {
//TODO add to cahce map when vs_mode is true
VirtualStudy virtualStudyDataToPublish = sessionServiceRequestHandler.getVirtualStudyById(id);
VirtualStudyData virtualStudyData = virtualStudyDataToPublish.getData();
updateStudyMetadataFieldsIfSpecified(virtualStudyData, typeOfCancerId, pmid);
Expand All @@ -105,6 +106,7 @@ private void publishVirtualStudy(String id, String typeOfCancerId, String pmid)
* @param id - id of public virtual study to un-publish
*/
private void unPublishVirtualStudy(String id) {
//TODO remove from cahce map when vs_mode is true
VirtualStudy virtualStudyToUnPublish = sessionServiceRequestHandler.getVirtualStudyById(id);
if (virtualStudyToUnPublish == null) {
throw new NoSuchElementException("The virtual study with id=" + id + " has not been found in the public list.");
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/seed_mini.sql
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ INSERT INTO "type_of_cancer" ("TYPE_OF_CANCER_ID","NAME","DEDICATED_COLOR","SHOR
INSERT INTO "type_of_cancer" ("TYPE_OF_CANCER_ID","NAME","DEDICATED_COLOR","SHORT_NAME","PARENT") VALUES ('blca','Bladder Urothelial Carcinoma','Yellow','Bladder','tissue');
INSERT INTO "type_of_cancer" ("TYPE_OF_CANCER_ID","NAME","DEDICATED_COLOR","SHORT_NAME","PARENT") VALUES ('bpdcn','Blastic Plasmacytoid Dendritic Cell Neoplasm','LightSalmon','BPDCN','tissue');
INSERT INTO "type_of_cancer" ("TYPE_OF_CANCER_ID","NAME","DEDICATED_COLOR","SHORT_NAME","PARENT") VALUES ('brca','Breast Invasive Carcinoma','HotPink','Breast','tissue');
INSERT INTO "type_of_cancer" ("TYPE_OF_CANCER_ID","NAME","DEDICATED_COLOR","SHORT_NAME","PARENT") VALUES ('mixed','Mixed Cancer Types','Yellow','Mixed','tissue');

-- reference_genome
INSERT INTO `reference_genome` VALUES (1,'human','hg19','GRCh37',2897310462,'http://hgdownload.cse.ucsc.edu/goldenPath/hg19/bigZips','2009-02-01');
Expand Down

0 comments on commit 670ffff

Please sign in to comment.