diff --git a/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/main/java/edu/harvard/hms/dbmi/avillach/AggregateDataSharingResourceRS.java b/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/main/java/edu/harvard/hms/dbmi/avillach/AggregateDataSharingResourceRS.java index d7cd47db..a5203d93 100644 --- a/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/main/java/edu/harvard/hms/dbmi/avillach/AggregateDataSharingResourceRS.java +++ b/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/main/java/edu/harvard/hms/dbmi/avillach/AggregateDataSharingResourceRS.java @@ -242,7 +242,7 @@ public Response querySync(QueryRequest queryRequest) { return Response.status(Response.Status.BAD_REQUEST).build(); } - HttpResponse response = getHttpResponse(queryRequest, resourceUUID); + HttpResponse response = getHttpResponse(queryRequest, resourceUUID, "/query/sync"); HttpEntity entity = response.getEntity(); String entityString = EntityUtils.toString(entity, "UTF-8"); @@ -267,10 +267,13 @@ public Response querySync(QueryRequest queryRequest) { } } - private HttpResponse getHttpResponse(QueryRequest queryRequest, UUID resourceUUID) throws JsonProcessingException { + private HttpResponse getHttpResponse(QueryRequest queryRequest, UUID resourceUUID, String pathName) throws JsonProcessingException { String targetPicsureUrl = properties.getTargetPicsureUrl(); String queryString = objectMapper.writeValueAsString(queryRequest); - String pathName = "/query/sync"; + return doHttpRequest(resourceUUID, targetPicsureUrl, queryString, pathName); + } + + private HttpResponse doHttpRequest(UUID resourceUUID, String targetPicsureUrl, String queryString, String pathName) { String composedURL = composeURL(targetPicsureUrl, pathName); logger.debug("Aggregate Data Sharing Resource, sending query: " + queryString + ", to: " + composedURL); HttpResponse response = retrievePostResponse(composedURL, headers, queryString); @@ -297,7 +300,7 @@ private HttpResponse getHttpResponse(QueryRequest queryRequest, UUID resourceUUI * @return String The response that will be returned * @throws JsonProcessingException If there is an error processing the response */ - private String getExpectedResponse(String expectedResultType, String entityString, String responseString, QueryRequest queryRequest) throws IOException { + private String getExpectedResponse(String expectedResultType, String entityString, String responseString, QueryRequest queryRequest) throws IOException, JsonProcessingException { String crossCountResponse; switch (expectedResultType) { case "COUNT": @@ -333,7 +336,7 @@ private String getExpectedResponse(String expectedResultType, String entityStrin private String getCrossCountForQuery(QueryRequest queryRequest) throws IOException { logger.debug("Calling Aggregate Data Sharing Resource getCrossCountForQuery()"); - HttpResponse response = getHttpResponse(changeQueryToOpenCrossCount(queryRequest), queryRequest.getResourceUUID()); + HttpResponse response = getHttpResponse(changeQueryToOpenCrossCount(queryRequest), queryRequest.getResourceUUID(), "/query/sync"); HttpEntity entity = response.getEntity(); return EntityUtils.toString(entity, "UTF-8"); } @@ -508,15 +511,32 @@ private int generateVarianceWithCrossCounts(Map crossCounts) { return generateRequestVariance(crossCountsString.toString()); } - protected String processContinuousCrossCounts(String entityString, String crossCountResponse) throws JsonProcessingException { + protected String processContinuousCrossCounts(String continuousCrossCountResponse, String crossCountResponse) throws IOException { logger.info("Processing continuous cross counts"); - logger.info("Entity string: {}", entityString); + logger.info("Cross count response: {} ", crossCountResponse); + logger.info("Continuous count response: {}", continuousCrossCountResponse); + + // convert continuousCrossCountResponse to a map + Map> continuousCrossCounts = objectMapper.convertValue(continuousCrossCountResponse, new TypeReference<>() {}); + + // I want to call the binning endpoint from the visualization service + QueryRequest queryRequest = new QueryRequest(); + queryRequest.setResourceUUID(properties.getVisualizationResourceId()); + queryRequest.setQuery(continuousCrossCounts); + + // call the binning endpoint + HttpResponse httpResponse = getHttpResponse(queryRequest, properties.getVisualizationResourceId(), "/format/continuous"); - if (entityString == null || crossCountResponse == null) { + HttpEntity entity = httpResponse.getEntity(); + String responseString = EntityUtils.toString(entity, "UTF-8"); + + logger.info("Response from binning endpoint: {}", responseString); + + if (continuousCrossCountResponse == null || crossCountResponse == null) { return null; } - return entityString; + return continuousCrossCountResponse; } /** @@ -555,19 +575,11 @@ protected String processCategoricalCrossCounts(String categoricalEntityString, S } } - // If we don't need to obfuscate we can just return the entity string. if (!mustObfuscate) { return categoricalEntityString; } - Map> categoricalCrossCount; - try { - categoricalCrossCount = objectMapper.readValue(categoricalEntityString, new TypeReference<>(){}); - } catch (Exception e) { - logger.error("Error processing categorical cross counts: {}", e.getMessage()); - throw new JsonProcessingException(e.getMessage()) {}; - } - + Map> categoricalCrossCount = objectMapper.readValue(categoricalEntityString, new TypeReference<>(){}); if (categoricalCrossCount == null) { return categoricalEntityString; } diff --git a/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/main/java/edu/harvard/hms/dbmi/avillach/ApplicationProperties.java b/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/main/java/edu/harvard/hms/dbmi/avillach/ApplicationProperties.java index 2df1b343..176d8e17 100644 --- a/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/main/java/edu/harvard/hms/dbmi/avillach/ApplicationProperties.java +++ b/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/main/java/edu/harvard/hms/dbmi/avillach/ApplicationProperties.java @@ -26,6 +26,7 @@ public class ApplicationProperties implements Serializable { private int targetPicsureObfuscationThreshold; private int targetPicsureObfuscationVariance; private String targetPicsureObfuscationSalt; + private UUID visualizationResourceId; public static final int DEFAULT_OBFUSCATION_THRESHOLD = 10; public static final int DEFAULT_OBFUSCATION_VARIANCE = 3; @@ -60,6 +61,10 @@ public String getTargetPicsureObfuscationSalt() { return targetPicsureObfuscationSalt; } + public UUID getVisualizationResourceId() { + return visualizationResourceId; + } + public void init(String contextPath) { logger.info("initializing aggregate Resource properties"); @@ -89,6 +94,11 @@ public void init(String contextPath) { throw new PicsureQueryException("target.picsure.token property must be set."); } + visualizationResourceId = UUID.fromString(properties.getProperty("visualization.resource.id")); + logger.debug("visualizationResourceId: " + visualizationResourceId); + if (visualizationResourceId == null) + throw new PicsureQueryException("visualization.resource.id property must be set."); + targetPicsureObfuscationThreshold = Optional.ofNullable(properties.getProperty("target.picsure.obfuscation_threshold")) .map(Integer::parseInt) .orElse(DEFAULT_OBFUSCATION_THRESHOLD); diff --git a/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/test/java/edu/harvard/hms/dbmi/avillach/AggregateDataSharingResourceRSAcceptanceTests.java b/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/test/java/edu/harvard/hms/dbmi/avillach/AggregateDataSharingResourceRSAcceptanceTests.java index cd3c8176..ae72bbc0 100644 --- a/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/test/java/edu/harvard/hms/dbmi/avillach/AggregateDataSharingResourceRSAcceptanceTests.java +++ b/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/test/java/edu/harvard/hms/dbmi/avillach/AggregateDataSharingResourceRSAcceptanceTests.java @@ -266,7 +266,7 @@ public void testMinimumThreshold() throws IOException { } @Test - public void testProcessContinuousCrossCounts() throws JsonProcessingException { + public void testProcessContinuousCrossCounts() throws IOException { assertNull(objectUnderTest.processContinuousCrossCounts(null, null)); } diff --git a/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/VisualizationResource.java b/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/VisualizationResource.java index be2bee46..d16c0af9 100644 --- a/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/VisualizationResource.java +++ b/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/VisualizationResource.java @@ -57,7 +57,7 @@ public class VisualizationResource implements IResourceRS { public ResourceInfo info(QueryRequest infoRequest) { ResourceInfo info = new ResourceInfo(); info.setName("Pic-Sure Visualization Resource"); -// info.setId(properties.getVisualizationResourceId()); + info.setId(properties.getVisualizationResourceId()); QueryFormat queryFormat = new QueryFormat(); queryFormat.setName("Pic-Sure Query Format"); info.getQueryFormats().add(queryFormat); @@ -101,4 +101,10 @@ public Response queryFormat(QueryRequest resultRequest) { return Response.serverError().entity("An error occurred formatting the query for display: " + e.getLocalizedMessage()).build(); } } + + @POST + @Path("/format/continuous") + public Response generateContinuousBin(QueryRequest continuousData) { + return visualizationService.generateContinuousBin(continuousData); + } } \ No newline at end of file diff --git a/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/model/CategoricalData.java b/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/model/CategoricalData.java index e13f2479..eebcd199 100644 --- a/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/model/CategoricalData.java +++ b/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/model/CategoricalData.java @@ -9,8 +9,6 @@ @EqualsAndHashCode(callSuper = false) public class CategoricalData extends edu.harvard.hms.dbmi.avillach.resource.visualization.model.VisualizationData { Map categoricalMap; - Map categoricalObfuscatedMap; - public CategoricalData(String title, Map categoricalMap) { super(); @@ -24,14 +22,15 @@ public CategoricalData(String title, Map categoricalMap, String this.categoricalMap = categoricalMap; this.setXAxisName(xAxisLabel); this.setYAxisName(yAxisLabel); + this.isObfuscated = false; } - public CategoricalData(String title, Map categoricalMap, Map categoricalObfuscatedMap, String xAxisLabel, String yAxisLabel) { + public CategoricalData(String title, Map categoricalMap, String xAxisLabel, String yAxisLabel, boolean isObfuscated) { super(); this.setTitle(title); this.categoricalMap = categoricalMap; - this.categoricalObfuscatedMap = categoricalObfuscatedMap; this.setXAxisName(xAxisLabel); this.setYAxisName(yAxisLabel); + this.isObfuscated = isObfuscated; } } diff --git a/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/model/VisualizationData.java b/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/model/VisualizationData.java index 5c64b0e5..69ec1039 100644 --- a/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/model/VisualizationData.java +++ b/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/model/VisualizationData.java @@ -17,6 +17,7 @@ public class VisualizationData { private String yAxisName; Integer chartWidth; Integer chartHeight; + boolean isObfuscated; public int getChartHeight() { if (this.chartHeight == null) { diff --git a/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/service/DataProcessingService.java b/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/service/DataProcessingService.java index f8167582..40204d29 100644 --- a/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/service/DataProcessingService.java +++ b/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/service/DataProcessingService.java @@ -48,25 +48,14 @@ public DataProcessingService() { * @return List - result of query */ public List getCategoricalData(Map> crossCountsMap) { - List categoricalDataList = new ArrayList<>(); - - for (Map.Entry> entry : crossCountsMap.entrySet()) { - if (skipKey(entry)) continue; - Map axisMap = processResults(entry.getValue()); + return handleGetCategoricalData(crossCountsMap, false); + } - String title = getChartTitle(entry.getKey()); - categoricalDataList.add(new CategoricalData( - title, - new LinkedHashMap<>(axisMap), - createXAxisLabel(title), - "Number of Participants" - )); - } - logger.debug("Finished Categorical Data with " + categoricalDataList.size() + " results"); - return categoricalDataList; + public List getCategoricalData(Map> crossCountsMap, boolean isObfuscated) { + return handleGetCategoricalData(crossCountsMap, isObfuscated); } - public List getCategoricalData(Map> crossCountsMap, Map> obfuscationMap) { + private List handleGetCategoricalData(Map> crossCountsMap, boolean isObfuscated) { List categoricalDataList = new ArrayList<>(); for (Map.Entry> entry : crossCountsMap.entrySet()) { @@ -77,9 +66,9 @@ public List getCategoricalData(Map categoricalDataList.add(new CategoricalData( title, new LinkedHashMap<>(axisMap), - obfuscationMap.get(entry.getKey()), createXAxisLabel(title), - "Number of Participants" + "Number of Participants", + isObfuscated )); } logger.debug("Finished Categorical Data with " + categoricalDataList.size() + " results"); diff --git a/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/service/VisualizationService.java b/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/service/VisualizationService.java index 1626151c..60f49ca8 100644 --- a/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/service/VisualizationService.java +++ b/pic-sure-resources/pic-sure-visualization-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/visualization/service/VisualizationService.java @@ -1,8 +1,10 @@ package edu.harvard.hms.dbmi.avillach.resource.visualization.service; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import edu.harvard.dbmi.avillach.domain.QueryRequest; import edu.harvard.hms.dbmi.avillach.resource.visualization.ApplicationProperties; +import edu.harvard.hms.dbmi.avillach.resource.visualization.model.ContinuousData; import edu.harvard.hms.dbmi.avillach.resource.visualization.model.ProcessedCrossCountsResponse; import edu.harvard.hms.dbmi.avillach.resource.visualization.model.domain.Query; import edu.harvard.hms.dbmi.avillach.resource.visualization.model.domain.ResultType; @@ -13,6 +15,7 @@ import javax.inject.Inject; import javax.ws.rs.core.Response; import java.util.HashMap; +import java.util.List; import java.util.Map; @Stateless @@ -87,10 +90,10 @@ private Response getOpenProcessedCrossCountResponse(Map> obfuscationMap = generateObfuscationMap(categroyCrossCountsMap); + boolean isCategoricalObfuscated = isObfuscated(categroyCrossCountsMap); Map> cleanedCategoricalData = cleanCategoricalData(categroyCrossCountsMap); - ProcessedCrossCountsResponse response = buildOpenProcessedCrossCountsResponse(cleanedCategoricalData, obfuscationMap); + ProcessedCrossCountsResponse response = buildOpenProcessedCrossCountsResponse(cleanedCategoricalData, isCategoricalObfuscated); return Response.ok(response).build(); } @@ -128,7 +131,6 @@ private Map> generateObfuscationMap(Map> generateObfuscationMap(Map> categroyCrossCountsMap) { + boolean isObfuscated = false; + for (Map.Entry> e : categroyCrossCountsMap.entrySet()) { + Map value = e.getValue(); + + for (Map.Entry entry : value.entrySet()) { + String subValue = entry.getValue(); + if (subValue.contains(threshold) || subValue.contains(variance)) { + isObfuscated = true; + break; + } + } + } + + return isObfuscated; + } + private ProcessedCrossCountsResponse buildOpenProcessedCrossCountsResponse(Map> categroyCrossCountsMap, - Map> categoryCrossCountsObfuscationMap) { + boolean isObfuscated) { ProcessedCrossCountsResponse response = new ProcessedCrossCountsResponse(); - response.getCategoricalData().addAll(dataProcessingServices.getCategoricalData(categroyCrossCountsMap, categoryCrossCountsObfuscationMap)); + response.getCategoricalData().addAll(dataProcessingServices.getCategoricalData(categroyCrossCountsMap, isObfuscated)); return response; } @@ -185,4 +204,9 @@ private Map> getOpenCrossCounts(QueryRequest query, return crossCountsMap; } + public Response generateContinuousBin(QueryRequest continuousData) { + Map> continuousDataMap = mapper.convertValue(continuousData.getQuery(), new TypeReference<>() {}); + List continuousData1 = dataProcessingServices.getContinuousData(continuousDataMap); + return Response.ok(continuousData1).build(); + } }