Skip to content

Commit 4d0eb94

Browse files
committed
Use VirtualStudy service from public VS controller
Submitting dynamic virtual studies without explicitly defined sample IDs previously resulted in a NullPointerException. This behavior was incorrect, as dynamic studies are designed to derive their sample IDs dynamically from filters, not require them upfront. The issue revealed that the public VS controller was not using the appropriate VirtualStudy service. This change aligns the controller with the correct service to handle public dynamic virtual studies safely.
1 parent ac89a94 commit 4d0eb94

3 files changed

Lines changed: 120 additions & 118 deletions

File tree

src/main/java/org/cbioportal/legacy/service/VirtualStudyService.java

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,42 @@
22

33
import java.util.List;
44
import java.util.Map;
5+
import java.util.NoSuchElementException;
56
import java.util.Optional;
67
import java.util.Set;
78
import java.util.stream.Collectors;
9+
import org.cbioportal.legacy.service.exception.CancerTypeNotFoundException;
10+
import org.cbioportal.legacy.service.exception.DuplicateVirtualStudyException;
11+
import org.cbioportal.legacy.service.exception.StudyNotFoundException;
812
import org.cbioportal.legacy.service.util.SessionServiceRequestHandler;
913
import org.cbioportal.legacy.web.parameter.SampleIdentifier;
1014
import org.cbioportal.legacy.web.parameter.VirtualStudy;
1115
import org.cbioportal.legacy.web.parameter.VirtualStudyData;
1216
import org.cbioportal.legacy.web.parameter.VirtualStudySamples;
1317
import org.cbioportal.legacy.web.util.StudyViewFilterApplier;
18+
import org.slf4j.Logger;
19+
import org.slf4j.LoggerFactory;
1420
import org.springframework.stereotype.Service;
1521

1622
@Service
1723
public class VirtualStudyService {
24+
private static final Logger LOG = LoggerFactory.getLogger(VirtualStudyService.class);
25+
26+
public static final String ALL_USERS = "*";
1827
private final SessionServiceRequestHandler sessionServiceRequestHandler;
1928
private final StudyViewFilterApplier studyViewFilterApplier;
29+
private final CancerTypeService cancerTypeService;
30+
private final StudyService studyService;
2031

2132
public VirtualStudyService(
2233
SessionServiceRequestHandler sessionServiceRequestHandler,
23-
StudyViewFilterApplier studyViewFilterApplier) {
34+
StudyViewFilterApplier studyViewFilterApplier,
35+
CancerTypeService cancerTypeService,
36+
StudyService studyService) {
2437
this.sessionServiceRequestHandler = sessionServiceRequestHandler;
2538
this.studyViewFilterApplier = studyViewFilterApplier;
39+
this.cancerTypeService = cancerTypeService;
40+
this.studyService = studyService;
2641
}
2742

2843
public VirtualStudy getVirtualStudy(String id) {
@@ -59,6 +74,10 @@ public List<VirtualStudy> getUserVirtualStudies(String user) {
5974
return virtualStudies;
6075
}
6176

77+
public List<VirtualStudy> getPublicVirtualStudies() {
78+
return getUserVirtualStudies(ALL_USERS);
79+
}
80+
6281
/**
6382
* This method populates the `virtualStudyData` object with a new set of sample IDs retrieved as
6483
* the result of executing a query based on virtual study view filters. It first applies the
@@ -107,4 +126,91 @@ private Map<String, Set<String>> groupSampleIdsByStudyId(
107126
SampleIdentifier::getStudyId,
108127
Collectors.mapping(SampleIdentifier::getSampleId, Collectors.toSet())));
109128
}
129+
130+
/**
131+
* Publishes virtual study optionally updating metadata fields
132+
*
133+
* @param id - id of public virtual study to publish
134+
* @param typeOfCancerId - if specified (not null) update type of cancer of published virtual
135+
* study
136+
* @param pmid - if specified (not null) update PubMed ID of published virtual study
137+
* @param virtualStudyData - if specified (not null) create new virtual study with this data,
138+
* otherwise updates virtual study with the given id
139+
*/
140+
public void publishVirtualStudy(
141+
String id, String typeOfCancerId, String pmid, VirtualStudyData virtualStudyData) {
142+
if (virtualStudyData == null) {
143+
VirtualStudy virtualStudyDataToPublish = sessionServiceRequestHandler.getVirtualStudyById(id);
144+
VirtualStudyData storedVirtualStudyData = virtualStudyDataToPublish.getData();
145+
updateStudyMetadataFieldsIfSpecified(storedVirtualStudyData, typeOfCancerId, pmid);
146+
storedVirtualStudyData.setUsers(Set.of(ALL_USERS));
147+
sessionServiceRequestHandler.updateVirtualStudy(virtualStudyDataToPublish);
148+
} else {
149+
updateStudyMetadataFieldsIfSpecified(virtualStudyData, typeOfCancerId, pmid);
150+
virtualStudyData.setUsers(Set.of(ALL_USERS));
151+
try {
152+
studyService.getStudy(id);
153+
throw new DuplicateVirtualStudyException(
154+
"The study with id="
155+
+ id
156+
+ " already exists. Use a different id for the virtual study.");
157+
} catch (StudyNotFoundException e) {
158+
LOG.debug(
159+
"The study with id={} does not exist, proceeding to create a new virtual study.", id);
160+
}
161+
sessionServiceRequestHandler.createVirtualStudy(id, virtualStudyData);
162+
}
163+
}
164+
165+
/**
166+
* Un-publish virtual study
167+
*
168+
* @param id - id of public virtual study to un-publish
169+
*/
170+
public void unPublishVirtualStudy(String id) {
171+
VirtualStudy virtualStudyToUnPublish = sessionServiceRequestHandler.getVirtualStudyById(id);
172+
if (virtualStudyToUnPublish == null) {
173+
throw new NoSuchElementException(
174+
"The virtual study with id=" + id + " has not been found in the public list.");
175+
}
176+
VirtualStudyData virtualStudyData = virtualStudyToUnPublish.getData();
177+
checkIfVSWasPublished(id, virtualStudyData);
178+
virtualStudyData.setUsers(Set.of(virtualStudyData.getOwner()));
179+
sessionServiceRequestHandler.updateVirtualStudy(virtualStudyToUnPublish);
180+
}
181+
182+
/**
183+
* Drops public virtual study, removing it from the public list
184+
*
185+
* @param id - id of public virtual study to drop
186+
*/
187+
public void dropPublicVirtualStudyById(String id) {
188+
VirtualStudy virtualStudyToUnPublish = sessionServiceRequestHandler.getVirtualStudyById(id);
189+
checkIfVSWasPublished(id, virtualStudyToUnPublish.getData());
190+
sessionServiceRequestHandler.dropVirtualStudy(id);
191+
}
192+
193+
private static void checkIfVSWasPublished(String id, VirtualStudyData virtualStudyData) {
194+
Set<String> users = virtualStudyData.getUsers();
195+
if (users == null || users.isEmpty() || !users.contains(ALL_USERS)) {
196+
throw new NoSuchElementException(
197+
"The virtual study with id=" + id + " has not been found in the public list.");
198+
}
199+
}
200+
201+
private void updateStudyMetadataFieldsIfSpecified(
202+
VirtualStudyData virtualStudyData, String typeOfCancerId, String pmid) {
203+
if (typeOfCancerId != null) {
204+
try {
205+
cancerTypeService.getCancerType(typeOfCancerId);
206+
virtualStudyData.setTypeOfCancerId(typeOfCancerId);
207+
} catch (CancerTypeNotFoundException e) {
208+
LOG.error("No cancer type with id={} were found.", typeOfCancerId);
209+
throw new IllegalArgumentException("The cancer type is not valid: " + typeOfCancerId);
210+
}
211+
}
212+
if (pmid != null) {
213+
virtualStudyData.setPmid(pmid);
214+
}
215+
}
110216
}

src/main/java/org/cbioportal/legacy/web/PublicVirtualStudiesController.java

Lines changed: 12 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,9 @@
44
import io.swagger.v3.oas.annotations.media.Schema;
55
import io.swagger.v3.oas.annotations.responses.ApiResponse;
66
import java.util.List;
7-
import java.util.NoSuchElementException;
8-
import java.util.Set;
9-
import org.cbioportal.legacy.service.CancerTypeService;
10-
import org.cbioportal.legacy.service.StudyService;
7+
import org.cbioportal.legacy.service.VirtualStudyService;
118
import org.cbioportal.legacy.service.exception.AccessForbiddenException;
12-
import org.cbioportal.legacy.service.exception.CancerTypeNotFoundException;
139
import org.cbioportal.legacy.service.exception.DuplicateVirtualStudyException;
14-
import org.cbioportal.legacy.service.exception.StudyNotFoundException;
15-
import org.cbioportal.legacy.service.util.SessionServiceRequestHandler;
1610
import org.cbioportal.legacy.web.parameter.VirtualStudy;
1711
import org.cbioportal.legacy.web.parameter.VirtualStudyData;
1812
import org.slf4j.Logger;
@@ -36,25 +30,15 @@
3630
public class PublicVirtualStudiesController {
3731

3832
private static final Logger LOG = LoggerFactory.getLogger(PublicVirtualStudiesController.class);
39-
40-
public static final String ALL_USERS = "*";
41-
4233
private final String requiredPublisherApiKey;
4334

44-
private final SessionServiceRequestHandler sessionServiceRequestHandler;
45-
46-
private final CancerTypeService cancerTypeService;
47-
private final StudyService studyService;
35+
private final VirtualStudyService virtualStudyService;
4836

4937
public PublicVirtualStudiesController(
5038
@Value("${session.endpoint.publisher-api-key:}") String requiredPublisherApiKey,
51-
SessionServiceRequestHandler sessionServiceRequestHandler,
52-
CancerTypeService cancerTypeService,
53-
StudyService studyService) {
39+
VirtualStudyService virtualStudyService) {
5440
this.requiredPublisherApiKey = requiredPublisherApiKey;
55-
this.sessionServiceRequestHandler = sessionServiceRequestHandler;
56-
this.cancerTypeService = cancerTypeService;
57-
this.studyService = studyService;
41+
this.virtualStudyService = virtualStudyService;
5842
}
5943

6044
@GetMapping
@@ -63,8 +47,7 @@ public PublicVirtualStudiesController(
6347
description = "OK",
6448
content = @Content(schema = @Schema(implementation = VirtualStudy.class)))
6549
public ResponseEntity<List<VirtualStudy>> getPublicVirtualStudies() {
66-
List<VirtualStudy> virtualStudies =
67-
sessionServiceRequestHandler.getVirtualStudiesAccessibleToUser(ALL_USERS);
50+
List<VirtualStudy> virtualStudies = virtualStudyService.getPublicVirtualStudies();
6851
return new ResponseEntity<>(virtualStudies, HttpStatus.OK);
6952
}
7053

@@ -80,7 +63,7 @@ public ResponseEntity<Void> publishVirtualStudy(
8063
@RequestParam(required = false) String pmid,
8164
@RequestBody(required = false) VirtualStudyData virtualStudyData) {
8265
ensureProvidedPublisherApiKeyCorrect(providedPublisherApiKey);
83-
publishVirtualStudy(id, typeOfCancerId, pmid, virtualStudyData);
66+
virtualStudyService.publishVirtualStudy(id, typeOfCancerId, pmid, virtualStudyData);
8467
return ResponseEntity.ok().build();
8568
}
8669

@@ -92,45 +75,17 @@ public ResponseEntity<Void> unPublishVirtualStudy(
9275
@RequestHeader(value = "X-PUBLISHER-API-KEY") String providedPublisherApiKey) {
9376
ensureProvidedPublisherApiKeyCorrect(providedPublisherApiKey);
9477
if (softDelete) {
95-
unPublishVirtualStudy(id);
78+
virtualStudyService.unPublishVirtualStudy(id);
9679
} else {
97-
dropPublicVirtualStudyById(id);
80+
virtualStudyService.dropPublicVirtualStudyById(id);
9881
}
9982
return ResponseEntity.ok().build();
10083
}
10184

102-
/**
103-
* Publishes virtual study optionally updating metadata fields
104-
*
105-
* @param id - id of public virtual study to publish
106-
* @param typeOfCancerId - if specified (not null) update type of cancer of published virtual
107-
* study
108-
* @param pmid - if specified (not null) update PubMed ID of published virtual study
109-
* @param virtualStudyData - if specified (not null) create new virtual study with this data,
110-
* otherwise updates virtual study with the given id
111-
*/
112-
private void publishVirtualStudy(
113-
String id, String typeOfCancerId, String pmid, VirtualStudyData virtualStudyData) {
114-
if (virtualStudyData == null) {
115-
VirtualStudy virtualStudyDataToPublish = sessionServiceRequestHandler.getVirtualStudyById(id);
116-
VirtualStudyData storedVirtualStudyData = virtualStudyDataToPublish.getData();
117-
updateStudyMetadataFieldsIfSpecified(storedVirtualStudyData, typeOfCancerId, pmid);
118-
storedVirtualStudyData.setUsers(Set.of(ALL_USERS));
119-
sessionServiceRequestHandler.updateVirtualStudy(virtualStudyDataToPublish);
120-
} else {
121-
updateStudyMetadataFieldsIfSpecified(virtualStudyData, typeOfCancerId, pmid);
122-
virtualStudyData.setUsers(Set.of(ALL_USERS));
123-
try {
124-
studyService.studyExists(id);
125-
throw new DuplicateVirtualStudyException(
126-
"The study with id="
127-
+ id
128-
+ " already exists. Use a different id for the virtual study.");
129-
} catch (StudyNotFoundException e) {
130-
LOG.debug(
131-
"The study with id={} does not exist, proceeding to create a new virtual study.", id);
132-
}
133-
sessionServiceRequestHandler.createVirtualStudy(id, virtualStudyData);
85+
private void ensureProvidedPublisherApiKeyCorrect(String providedPublisherApiKey) {
86+
if (requiredPublisherApiKey.isBlank()
87+
|| !requiredPublisherApiKey.equals(providedPublisherApiKey)) {
88+
throw new AccessForbiddenException("The provided publisher API key is not correct.");
13489
}
13590
}
13691

@@ -140,63 +95,4 @@ public ResponseEntity<String> handleDuplicateVirtualStudyException(
14095
LOG.error("Duplicate virtual study error: {}", e.getMessage());
14196
return ResponseEntity.status(HttpStatus.CONFLICT).body(e.getMessage());
14297
}
143-
144-
/**
145-
* Un-publish virtual study
146-
*
147-
* @param id - id of public virtual study to un-publish
148-
*/
149-
private void unPublishVirtualStudy(String id) {
150-
VirtualStudy virtualStudyToUnPublish = sessionServiceRequestHandler.getVirtualStudyById(id);
151-
if (virtualStudyToUnPublish == null) {
152-
throw new NoSuchElementException(
153-
"The virtual study with id=" + id + " has not been found in the public list.");
154-
}
155-
VirtualStudyData virtualStudyData = virtualStudyToUnPublish.getData();
156-
checkIfVSWasPublished(id, virtualStudyData);
157-
virtualStudyData.setUsers(Set.of(virtualStudyData.getOwner()));
158-
sessionServiceRequestHandler.updateVirtualStudy(virtualStudyToUnPublish);
159-
}
160-
161-
/**
162-
* Drops public virtual study, removing it from the public list
163-
*
164-
* @param id - id of public virtual study to drop
165-
*/
166-
private void dropPublicVirtualStudyById(String id) {
167-
VirtualStudy virtualStudyToUnPublish = sessionServiceRequestHandler.getVirtualStudyById(id);
168-
checkIfVSWasPublished(id, virtualStudyToUnPublish.getData());
169-
sessionServiceRequestHandler.dropVirtualStudy(id);
170-
}
171-
172-
private static void checkIfVSWasPublished(String id, VirtualStudyData virtualStudyData) {
173-
Set<String> users = virtualStudyData.getUsers();
174-
if (users == null || users.isEmpty() || !users.contains(ALL_USERS)) {
175-
throw new NoSuchElementException(
176-
"The virtual study with id=" + id + " has not been found in the public list.");
177-
}
178-
}
179-
180-
private void ensureProvidedPublisherApiKeyCorrect(String providedPublisherApiKey) {
181-
if (requiredPublisherApiKey.isBlank()
182-
|| !requiredPublisherApiKey.equals(providedPublisherApiKey)) {
183-
throw new AccessForbiddenException("The provided publisher API key is not correct.");
184-
}
185-
}
186-
187-
private void updateStudyMetadataFieldsIfSpecified(
188-
VirtualStudyData virtualStudyData, String typeOfCancerId, String pmid) {
189-
if (typeOfCancerId != null) {
190-
try {
191-
cancerTypeService.getCancerType(typeOfCancerId);
192-
virtualStudyData.setTypeOfCancerId(typeOfCancerId);
193-
} catch (CancerTypeNotFoundException e) {
194-
LOG.error("No cancer type with id={} were found.", typeOfCancerId);
195-
throw new IllegalArgumentException("The cancer type is not valid: " + typeOfCancerId);
196-
}
197-
}
198-
if (pmid != null) {
199-
virtualStudyData.setPmid(pmid);
200-
}
201-
}
20298
}

src/main/java/org/cbioportal/legacy/web/SessionServiceController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.cbioportal.legacy.web;
22

3-
import static org.cbioportal.legacy.web.PublicVirtualStudiesController.ALL_USERS;
3+
import static org.cbioportal.legacy.service.VirtualStudyService.ALL_USERS;
44

55
import com.fasterxml.jackson.annotation.JsonInclude.Include;
66
import com.fasterxml.jackson.core.JsonProcessingException;

0 commit comments

Comments
 (0)