Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pom.xml.versionsBackup
target/
lexer/target
service/target
service/unittests.txt
model/target
application-*.properties

Expand Down
34 changes: 27 additions & 7 deletions model/swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ info:

tags:
- name: 1. all products
description: search any classe of product and resolve product's identifiers
description: search any classes of product and resolve product's identifiers
- name: 2. product references
description: explore the product hierarchy
- name: 3. by product classes
Expand Down Expand Up @@ -233,7 +233,27 @@ paths:
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/Sort"
- $ref: "#/components/parameters/SearchAfter"


/products/{identifier}/tools:
get:
tags:
- 1. all products
summary: |
for the given product, returns deep links to all tools that support the display of that product
operationId: product-cross-links
responses:
"200":
$ref: "#/components/responses/Singular"
"400":
$ref: "#/components/responses/Error"
"404":
$ref: "#/components/responses/Error"
"500":
$ref: "#/components/responses/Error"
"501":
$ref: "#/components/responses/Error"
parameters:
- $ref: "#/components/parameters/Identifier"

/properties:
get:
Expand Down Expand Up @@ -462,9 +482,9 @@ components:
description: |
syntax: fields=field1,field2,...

behavior: this parameter and the headder Accept: type determine what content is packaged for the result. While the types application/csv, application/kvp+json, and text/csv return only the fields requesteted, all of the other types have a minimal set of fields that must be returned. Duplicating a minimally required field in this parameter has not effect. The types vnd.nasa.pds.pds4+json and vnd.nasa.pds.pds4+xml have a complete set of fields that must be returned; meaning this parameter does not impact their content. When fields is not used, then the minimal set of fields, or all when minimal is an empty set, is returned.
behavior: this parameter and the header Accept: type determine what content is packaged for the result. While the types application/csv, application/kvp+json, and text/csv return only the fields requested, all of the other types have a minimal set of fields that must be returned. Duplicating a minimally required field in this parameter has not effect. The types vnd.nasa.pds.pds4+json and vnd.nasa.pds.pds4+xml have a complete set of fields that must be returned; meaning this parameter does not impact their content. When fields is not used, then the minimal set of fields, or all when minimal is an empty set, is returned.

notes: the blob fields are blocked unless specifically requrested and only for the */csv and application/kvp+csv types.
notes: the blob fields are blocked unless specifically requested and only for the */csv and application/kvp+csv types.
required: false
schema:
type: array
Expand Down Expand Up @@ -498,11 +518,11 @@ components:
description: |
syntax: lidvid or lid

behavior (lid): returns one or more items whose lid matches this lid exactly. If the endpoint ends with the identifier or /latest then a signle result is returned and it is the highest version. If the endpoint ends with /all then all versions of the lid are returned.
behavior (lid): returns one or more items whose lid matches this lid exactly. If the endpoint ends with the identifier or /latest then a single result is returned and it is the highest version. If the endpoint ends with /all then all versions of the lid are returned.

behavior (lidvid): returns one and only one item whose lidvid matches this lidvid exactly.

note: the current lid/lidvid resolution will match all the lids that start with lid. In other words, it acts like a glob of foobar*. It behavesn this way from first character to the last
note: the current lid/lidvid resolution will match all the lids that start with lid. In other words, it acts like a glob of foobar*. It behaves this way from first character to the last

note: simple sorting of the lidvid is being done to select the latest from the end of the list. However, the versions 1.0, 2.0, and 13.0 will sort to 1.0, 13.0, and 2.0 so the end of the list may not be the latest.
required: true
Expand Down Expand Up @@ -846,7 +866,7 @@ components:
$ref: '#/components/schemas/metadata'
properties:
type: object
description: propertie's values extracted from pds4 model, as a dictionnary, syntax for property name is {namespace}:{property}[{namespace}:{property}]*
description: properties' values extracted from pds4 model, as a dictionary, syntax for property name is {namespace}:{property}[{namespace}:{property}]*
additionalProperties:
$ref: '#/components/schemas/propertyArrayValues'
xml:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.lang.reflect.InvocationTargetException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
Expand All @@ -15,6 +16,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.context.request.RequestContextHolder;
Expand All @@ -32,10 +34,11 @@
import gov.nasa.pds.api.registry.model.api_responses.RawMultipleProductResponse;
import gov.nasa.pds.api.registry.model.api_responses.WyriwygBusinessObject;
import gov.nasa.pds.api.registry.model.identifiers.PdsProductIdentifier;
import gov.nasa.pds.api.registry.model.tools.CrossLinksLoader;
import gov.nasa.pds.api.registry.model.tools.CrossLinks;
import gov.nasa.pds.api.registry.search.RegistrySearchRequestBuilder;



@Controller
public class ProductsController implements ProductsApi {

Expand All @@ -46,6 +49,8 @@ public class ProductsController implements ProductsApi {
private final ObjectMapper objectMapper;
private OpenSearchClient openSearchClient;
private SearchRequest presetSearchRequest;
private CrossLinksLoader crossLinksLoader;
private CrossLinks crossLinks;

// TODO move that at a better place, it is not specific to this controller
private static Map<String, Class<? extends ProductBusinessLogic>> formatters =
Expand Down Expand Up @@ -84,6 +89,11 @@ public ProductsController(ConnectionContext connectionContext,
this.connectionContext = connectionContext;
this.openSearchClient = this.connectionContext.getOpenSearchClient();

/**
* Initialize CrossLinksLoader for it to load the cross-links configuration on-load
*/
this.crossLinksLoader = new CrossLinksLoader();
this.crossLinks = this.crossLinksLoader.loadConfiguration();
}

private ResponseEntity<Object> formatSingleProduct(HashMap<String, Object> product,
Expand Down Expand Up @@ -186,7 +196,6 @@ public ResponseEntity<Object> selectByLidvid(String identifier, List<String> fie

}


@Override
public ResponseEntity<Object> selectByLidvidLatest(String identifier, List<String> fields)
throws UnhandledException, NotFoundException, AcceptFormatNotSupportedException {
Expand All @@ -204,6 +213,31 @@ public ResponseEntity<Object> selectByLidvidLatest(String identifier, List<Strin

}

@Override
public ResponseEntity<Object> productCrossLinks(String identifier)
throws UnhandledException, NotFoundException, AcceptFormatNotSupportedException {

// Get product metadata that we're cross-linking between services
HashMap<String, Object> product = new HashMap<>();

List<String> fields = new ArrayList<>();

try {
PdsProductIdentifier pdsIdentifier = PdsProductIdentifier.fromString(identifier);

if (pdsIdentifier.isLidvid()) {
product = this.getLidVid(pdsIdentifier, fields);
} else {
product = this.getLatestLidVid(pdsIdentifier, fields);
}
} catch (IOException | OpenSearchException e) {
throw new UnhandledException(e);
}

// Return all the crossLinks for it
return new ResponseEntity<Object>(this.crossLinks.getLinks(product), new HttpHeaders(), HttpStatus.OK);
}

@Override
public ResponseEntity<Object> selectByLidvidAll(String identifier, List<String> fields,
Integer limit, List<String> sort, List<String> searchAfter) throws UnhandledException,
Expand Down Expand Up @@ -271,6 +305,7 @@ private HashMap<String, Object> getLidVid(PdsProductIdentifier identifier, List<
// https://stackoverflow.com/questions/2390662/java-how-do-i-get-a-class-literal-from-a-generic-type
SearchResponse<HashMap> searchResponse =
this.openSearchClient.search(searchRequest, HashMap.class);

if (searchResponse.hits().total().value() == 0) {
throw new NotFoundException("No product found with identifier " + identifier.toString());
}
Expand Down Expand Up @@ -331,6 +366,4 @@ private RawMultipleProductResponse getAllLidVid(PdsProductIdentifier identifier,

}



}
Original file line number Diff line number Diff line change
Expand Up @@ -112,20 +112,20 @@ public List<String> getRef_lid_target() {
return ref_lid_target;
}

private static String getFirstElmentOrNull(List<String> l) {
private static String getFirstElementOrNull(List<String> l) {
return l != null ? l.get(0) : null;
}

public String getPDS4FileRef() {
return EntityProduct.getFirstElmentOrNull(this.pds4FileReference);
return EntityProduct.getFirstElementOrNull(this.pds4FileReference);
}

public String getStartDateTime() {
return EntityProduct.getFirstElmentOrNull(this.start_date_time);
return EntityProduct.getFirstElementOrNull(this.start_date_time);
}

public String getStopDateTime() {
return EntityProduct.getFirstElmentOrNull(this.stop_date_time);
return EntityProduct.getFirstElementOrNull(this.stop_date_time);
}

public List<String> getModificationDate() {
Expand Down
Loading