From 58d3c684c012b513f3f6b5d37607b7543e9a87c6 Mon Sep 17 00:00:00 2001 From: edunn Date: Wed, 24 Jul 2024 11:12:31 -0700 Subject: [PATCH 1/4] add TODOs for controller common code refactor --- .../controllers/ProductsController.java | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java b/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java index 0c31e496..b3e28f85 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java @@ -2,12 +2,9 @@ import java.lang.reflect.InvocationTargetException; import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.Objects; +import java.util.*; +import gov.nasa.pds.api.base.ClassesApi; import gov.nasa.pds.api.registry.model.exceptions.*; import gov.nasa.pds.api.registry.model.identifiers.PdsLid; import gov.nasa.pds.api.registry.model.identifiers.PdsLidVid; @@ -24,6 +21,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import gov.nasa.pds.api.base.ProductsApi; @@ -40,7 +38,16 @@ @Controller -public class ProductsController implements ProductsApi { +// TODO: Refactor common controller code out of ProductsController and split the additional API implementations out into +// corresponding controllers +public class ProductsController implements ProductsApi, ClassesApi { + + @Override + // TODO: Remove this when the common controller code is refactored out - it is only necessary because additional + // interfaces have been implemented as a stopgap + public Optional getRequest() { + return ProductsApi.super.getRequest(); + } private static final Logger log = LoggerFactory.getLogger(ProductsController.class); @@ -600,4 +607,15 @@ public ResponseEntity productMemberOfOf( } } + @Override + // TODO: Relocate this to ClassesController once common controller code has been extracted/refactored + public ResponseEntity classList(String propertyClass, List fields, List keywords, Integer limit, String q, List sort, List searchAfter) throws Exception { + return ClassesApi.super.classList(propertyClass, fields, keywords, limit, q, sort, searchAfter); + } + + @Override + // TODO: Relocate this to ClassesController once common controller code has been extracted/refactored + public ResponseEntity> classes() throws Exception { + return ClassesApi.super.classes(); + } } From 924cffc1af982087c9e769fd5af946f21e936912 Mon Sep 17 00:00:00 2001 From: edunn Date: Tue, 23 Jul 2024 16:32:01 -0700 Subject: [PATCH 2/4] implement swagger-name conversions in PdsProductClasses --- .../model/identifiers/PdsProductClasses.java | 45 ++++++++++++++++++- .../registry/model/PdsProductClassesTest.java | 16 +++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 service/src/test/java/gov/nasa/pds/api/registry/model/PdsProductClassesTest.java diff --git a/service/src/main/java/gov/nasa/pds/api/registry/model/identifiers/PdsProductClasses.java b/service/src/main/java/gov/nasa/pds/api/registry/model/identifiers/PdsProductClasses.java index b33fed06..fbbda05f 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/model/identifiers/PdsProductClasses.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/model/identifiers/PdsProductClasses.java @@ -1,5 +1,8 @@ package gov.nasa.pds.api.registry.model.identifiers; +import java.util.Arrays; +import java.util.List; + /** * An enumeration of the valid product_class values from the PDS4 Data Dictionary * ... @@ -52,12 +55,52 @@ public String getValue() { } /** - * @return The database property/field these string values appear in. Provided for convenience. + * @return the database property/field these string values appear in. Provided for convenience. */ public static String getPropertyName() { return "product_class"; } + public static List getValidSwaggerNames() { + return Arrays.stream(PdsProductClasses.values()).map(PdsProductClasses::getSwaggerName).toList(); + } + + /** + * @return the shorthand name used for convenience in API routes, ex. "Product_Bundle" -> "bundle" + */ + public String getSwaggerName() { + List chunks = Arrays.asList(this.value.split("_")); + + if (chunks.size() < 2 || !chunks.get(0).equals("Product")) { + throw new IllegalArgumentException("Could not generate swagger name for PDSProductClasses value '" + this.value + "'"); + } + + List relevantChunks = chunks.subList(1, chunks.size()); + + return String.join("-", relevantChunks).toLowerCase(); + } + + /** + * @return the PdsProductClass which is equivalent to a given swagger-formatted product class name + */ + public static PdsProductClasses fromSwaggerName(String swaggerName) { + List matches = Arrays.stream(PdsProductClasses.values()) + .filter(value -> value.getSwaggerName().equals(swaggerName)) + .toList(); + + if (matches.isEmpty()) { + throw new IllegalArgumentException("No PdsProductClass matches swagger name '" + swaggerName + "'" + + "'. Valid names are: " + String.join(", ", getValidSwaggerNames())); + } + + if (matches.size() > 1) { +// This should never be possible and indicates an error in the enum value definitions + throw new IllegalArgumentException("Multiple PdsProductClass matches swagger name '" + swaggerName + "'"); + } + + return matches.get(0); + } + public Boolean isBundle() { return this == Product_Bundle; } diff --git a/service/src/test/java/gov/nasa/pds/api/registry/model/PdsProductClassesTest.java b/service/src/test/java/gov/nasa/pds/api/registry/model/PdsProductClassesTest.java new file mode 100644 index 00000000..055f6b04 --- /dev/null +++ b/service/src/test/java/gov/nasa/pds/api/registry/model/PdsProductClassesTest.java @@ -0,0 +1,16 @@ +package gov.nasa.pds.api.registry.model; + +import gov.nasa.pds.api.registry.model.identifiers.PdsProductClasses; +import org.junit.Assert; +import org.junit.Test; + +public class PdsProductClassesTest { + @Test + public void testSwaggerConversions() { + for (PdsProductClasses canonicalClass : PdsProductClasses.values()) { + String swaggerName = canonicalClass.getSwaggerName(); + PdsProductClasses parsedClass = PdsProductClasses.fromSwaggerName(swaggerName); + Assert.assertEquals(canonicalClass, parsedClass); + } + } +} From 1a36e9ae82c2be4b3f705ccaef7156af466a3208 Mon Sep 17 00:00:00 2001 From: edunn Date: Wed, 24 Jul 2024 11:43:15 -0700 Subject: [PATCH 3/4] implement RegistrySearchRequestBuilder.matchProductClass() --- .../pds/api/registry/search/RegistrySearchRequestBuilder.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/service/src/main/java/gov/nasa/pds/api/registry/search/RegistrySearchRequestBuilder.java b/service/src/main/java/gov/nasa/pds/api/registry/search/RegistrySearchRequestBuilder.java index c7c5cca6..66e3e065 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/search/RegistrySearchRequestBuilder.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/search/RegistrySearchRequestBuilder.java @@ -169,6 +169,10 @@ public RegistrySearchRequestBuilder matchLid(PdsProductIdentifier identifier) { return this.matchField("lid", identifier.getLid()); } + public RegistrySearchRequestBuilder matchProductClass(PdsProductClasses productClass) { + return this.matchField(PdsProductClasses.getPropertyName(), productClass.getValue()); + } + public RegistrySearchRequestBuilder matchMembersOfBundle(PdsLidVid identifier) { return this.matchField("ops:Provenance/ops:parent_bundle_identifier", identifier); } From 1475d1fb4a57ac5bcb446bd91670b603a2507c5e Mon Sep 17 00:00:00 2001 From: edunn Date: Wed, 24 Jul 2024 11:46:16 -0700 Subject: [PATCH 4/4] implement /classes and /classes/{class} API routes --- .../controllers/ProductsController.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java b/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java index b3e28f85..2dba1106 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java @@ -19,6 +19,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.context.request.NativeWebRequest; @@ -610,12 +611,33 @@ public ResponseEntity productMemberOfOf( @Override // TODO: Relocate this to ClassesController once common controller code has been extracted/refactored public ResponseEntity classList(String propertyClass, List fields, List keywords, Integer limit, String q, List sort, List searchAfter) throws Exception { - return ClassesApi.super.classList(propertyClass, fields, keywords, limit, q, sort, searchAfter); + PdsProductClasses pdsProductClass; + try { + pdsProductClass = PdsProductClasses.fromSwaggerName(propertyClass); + } catch (IllegalArgumentException err) { + throw new BadRequestException(err.getMessage()); + } + + SearchRequest searchRequest = new RegistrySearchRequestBuilder(this.connectionContext) + .matchProductClass(pdsProductClass) + .constrainByQueryString(q) + .addKeywordsParam(keywords) + .fieldsFromStrings(fields) + .paginate(limit, sort, searchAfter) + .onlyLatest() + .build(); + + SearchResponse searchResponse = + this.openSearchClient.search(searchRequest, HashMap.class); + + RawMultipleProductResponse products = new RawMultipleProductResponse(searchResponse); + + return formatMultipleProducts(products, fields); } @Override // TODO: Relocate this to ClassesController once common controller code has been extracted/refactored public ResponseEntity> classes() throws Exception { - return ClassesApi.super.classes(); + return new ResponseEntity<>(Arrays.stream(PdsProductClasses.values()).map(PdsProductClasses::getSwaggerName).toList(), HttpStatusCode.valueOf(200)); } }