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..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 @@ -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; @@ -22,8 +19,10 @@ 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; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import gov.nasa.pds.api.base.ProductsApi; @@ -40,7 +39,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 +608,36 @@ 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 { + 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 new ResponseEntity<>(Arrays.stream(PdsProductClasses.values()).map(PdsProductClasses::getSwaggerName).toList(), HttpStatusCode.valueOf(200)); + } } 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/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); } 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); + } + } +}