From bec63f1a6e9d7e4a7a4b41834453b47871679e25 Mon Sep 17 00:00:00 2001 From: Gcolon021 <34667267+Gcolon021@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:19:32 -0400 Subject: [PATCH] Merge for AIM-AHEAD 2024-03-14-Release (#187) ## Features - **Search by CA ID** - Enabled search functionality by common area (CA) ID in addition to the existing uuid-based query system, enhancing the platform's search capabilities and covering more use cases. ## Bugs - **Visualization Fixes** - Resolved an issue where the Open Access StatViz did not display the "Other" category, ensuring complete data visualization. - Addressed a bug in the resources table by removing an obsolete stack column, improving data management and presentation consistency. ## Enhancements - **Key Length Handling in Visualization** - Improved the `limitKeySize` method in `VisualizationUtil` to ensure key uniqueness while handling keys longer than 45 characters, enhancing data integrity in visualizations. - Added `VisualizationUtilTests` to validate the functionality and adjustments made to the key shortening logic, ensuring robustness and accuracy. - Refined empty return conditions in `DataProcessingService` to better account for data scenarios where min and max values are 0, optimizing data processing logic. - **Persistence and Resource Management** - Added `persistence.xml` to the visualization resource to resolve startup errors related to persistence unit injection, ensuring the smooth operation of visualization resources. --- .../dbmi/avillach/data/entity/Resource.java | 34 ++++++- .../data/repository/ResourceRepository.java | 2 +- .../avillach/service/PicsureInfoService.java | 88 +++++++++---------- .../service/DataProcessingService.java | 4 +- 4 files changed, 79 insertions(+), 49 deletions(-) diff --git a/pic-sure-api-data/src/main/java/edu/harvard/dbmi/avillach/data/entity/Resource.java b/pic-sure-api-data/src/main/java/edu/harvard/dbmi/avillach/data/entity/Resource.java index 3faf9ddc..b2cb4367 100644 --- a/pic-sure-api-data/src/main/java/edu/harvard/dbmi/avillach/data/entity/Resource.java +++ b/pic-sure-api-data/src/main/java/edu/harvard/dbmi/avillach/data/entity/Resource.java @@ -1,12 +1,12 @@ package edu.harvard.dbmi.avillach.data.entity; import java.io.StringReader; +import java.util.Optional; import javax.json.Json; import javax.json.JsonObject; import javax.json.JsonReader; -import javax.persistence.Column; -import javax.persistence.Entity; +import javax.persistence.*; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -18,6 +18,9 @@ public class Resource extends BaseEntity{ @Column(length = 8192) private String description; private String targetURL; + + + @Convert(converter = ResourcePathConverter.class) private String resourceRSPath; @Column(length = 8192) @@ -102,4 +105,31 @@ public String toString() { .add("metadata", metadataObj) .build().toString(); } + + /** + * This resource path converter allows resource paths to contain a reference to a specific stack that is + * imputed at runtime based an an environment parameter. This allows multiple stacks to share the same database. + * + * The ___target_stack___ token in any resource path value will be replaced with the TARGET_STACK environment variable + */ + @Converter + public static class ResourcePathConverter implements AttributeConverter { + + public ResourcePathConverter() { + } + + private static final Optional targetStack = Optional.ofNullable(System.getProperty("TARGET_STACK", null)); + + @Override + public String convertToDatabaseColumn(String attribute) { + return attribute; + } + + @Override + public String convertToEntityAttribute(String dbData) { + return targetStack + .map(stack -> dbData.replace("___target_stack___", stack)) + .orElse(dbData); + } + } } diff --git a/pic-sure-api-data/src/main/java/edu/harvard/dbmi/avillach/data/repository/ResourceRepository.java b/pic-sure-api-data/src/main/java/edu/harvard/dbmi/avillach/data/repository/ResourceRepository.java index 8bb400f4..f377c9d6 100644 --- a/pic-sure-api-data/src/main/java/edu/harvard/dbmi/avillach/data/repository/ResourceRepository.java +++ b/pic-sure-api-data/src/main/java/edu/harvard/dbmi/avillach/data/repository/ResourceRepository.java @@ -15,5 +15,5 @@ protected ResourceRepository() { super(Resource.class); } - + } diff --git a/pic-sure-api-war/src/main/java/edu/harvard/dbmi/avillach/service/PicsureInfoService.java b/pic-sure-api-war/src/main/java/edu/harvard/dbmi/avillach/service/PicsureInfoService.java index 922746f8..a64cf005 100644 --- a/pic-sure-api-war/src/main/java/edu/harvard/dbmi/avillach/service/PicsureInfoService.java +++ b/pic-sure-api-war/src/main/java/edu/harvard/dbmi/avillach/service/PicsureInfoService.java @@ -21,55 +21,55 @@ public class PicsureInfoService { - private final Logger logger = LoggerFactory.getLogger(PicsureQueryService.class); + private final Logger logger = LoggerFactory.getLogger(PicsureQueryService.class); - private final static ObjectMapper mapper = new ObjectMapper(); + private final static ObjectMapper mapper = new ObjectMapper(); - @Inject - ResourceRepository resourceRepo; + @Inject + ResourceRepository resourceRepo; - @Inject - ResourceWebClient resourceWebClient; + @Inject + ResourceWebClient resourceWebClient; - /** - * Retrieve resource info for a specific resource. - * - * @param resourceId - Resource UUID - * @param credentialsQueryRequest - Contains resource specific credentials map - * @return a {@link edu.harvard.dbmi.avillach.domain.ResourceInfo ResourceInfo} - */ - public ResourceInfo info(UUID resourceId, QueryRequest credentialsQueryRequest, HttpHeaders headers) { - Resource resource = resourceRepo.getById(resourceId); - if (resource == null){ - throw new ProtocolException(ProtocolException.RESOURCE_NOT_FOUND + resourceId.toString()); - } - if (resource.getResourceRSPath() == null){ - throw new ApplicationException(ApplicationException.MISSING_RESOURCE_PATH); - } - if (credentialsQueryRequest == null){ - credentialsQueryRequest = new GeneralQueryRequest(); - } - if (credentialsQueryRequest.getResourceCredentials() == null){ - credentialsQueryRequest.setResourceCredentials(new HashMap()); - } + /** + * Retrieve resource info for a specific resource. + * + * @param resourceId - Resource UUID + * @param credentialsQueryRequest - Contains resource specific credentials map + * @return a {@link edu.harvard.dbmi.avillach.domain.ResourceInfo ResourceInfo} + */ + public ResourceInfo info(UUID resourceId, QueryRequest credentialsQueryRequest, HttpHeaders headers) { + Resource resource = resourceRepo.getById(resourceId); + if (resource == null) { + throw new ProtocolException(ProtocolException.RESOURCE_NOT_FOUND + resourceId.toString()); + } + if (resource.getResourceRSPath() == null) { + throw new ApplicationException(ApplicationException.MISSING_RESOURCE_PATH); + } + if (credentialsQueryRequest == null) { + credentialsQueryRequest = new GeneralQueryRequest(); + } + if (credentialsQueryRequest.getResourceCredentials() == null) { + credentialsQueryRequest.setResourceCredentials(new HashMap()); + } - logger.info("path=/info/{resourceId}, resourceId={}, requestSource={}, credentialsQueryRequest={}", - resourceId, - Utilities.getRequestSourceFromHeader(headers), - Utilities.convertQueryRequestToString(mapper, credentialsQueryRequest) - ); + logger.info( + "path=/info/{resourceId}, resourceId={}, requestSource={}, credentialsQueryRequest={}", resourceId, + Utilities.getRequestSourceFromHeader(headers), Utilities.convertQueryRequestToString(mapper, credentialsQueryRequest) + ); - credentialsQueryRequest.getResourceCredentials().put(ResourceWebClient.BEARER_TOKEN_KEY, resource.getToken()); - return resourceWebClient.info(resource.getResourceRSPath(), credentialsQueryRequest); - } + credentialsQueryRequest.getResourceCredentials().put(ResourceWebClient.BEARER_TOKEN_KEY, resource.getToken()); + return resourceWebClient.info(resource.getResourceRSPath(), credentialsQueryRequest); + } - /** - * Retrieve a list of all available resources. - * - * @return List containing limited metadata about all available resources and ids. - */ - public Map resources(HttpHeaders headers) { - logger.info("path=/info/resources, requestSource={}", Utilities.getRequestSourceFromHeader(headers)); - return resourceRepo.list().stream().collect(Collectors.toMap(Resource::getUuid, Resource::getName)); - } + /** + * Retrieve a list of all available resources. + * + * @return List containing limited metadata about all available resources and ids. + */ + public Map resources(HttpHeaders headers) { + logger.info("path=/info/resources, requestSource={}", Utilities.getRequestSourceFromHeader(headers)); + return resourceRepo.list().stream().filter(resource -> !resource.getHidden()) + .collect(Collectors.toMap(Resource::getUuid, Resource::getName)); + } } 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 1988aab4..845909e4 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 @@ -158,8 +158,8 @@ private static Map bucketData(Map originalMap) int numBins = calcNumBins(data); double min = data.keySet().stream().min(Double::compareTo).orElse(0.0); double max = data.keySet().stream().max(Double::compareTo).orElse(0.0); - - if ((min == 0.0 && max == 0.0) || numBins == 0) return new HashMap<>(); + // The min and max can both be 0, but we could still have a numBins of 1 if there are values in the data. + if (min == 0.0 && max == 0.0 && numBins == 0) return new HashMap<>(); int binSize = (int) Math.ceil((max - min) / numBins);