Skip to content

Commit

Permalink
Call the history API for inbound orders (#746)
Browse files Browse the repository at this point in the history
* Changed OrderSender.sendOrder to return the sent submissionId (as optional)

* Added sentSubmissionId to PartnerMetadata record, and renamed uniqueId to receivedSubmissionId. Also, overloaded record constructor to only take receivedSubmissionId

* Updated tests

* Added missed import and fixed more tests

* Fixed test

* Fixed e2e test

* Refactored to split RS endpoint logic to its own ReportStreamEndpointClient class

* Added custom exception for ReportStreamEndpointClient

* Refactored for separation of concerns and clarity

* Further refactoring in preparation to call the history API

* Added implementation for http get method

* Added call to history API to update receiver metadata

* Added missing application context registration for ReportStreamEndpointClient

* Removed unused line

* Import missing class

* Added some comments

* Added methods to partially update PartnerMetadata and making sure to read existing metadata before updating

* Added tests for PartnerMetadataOrchestrator

* Some code cleaning

* Fixed test

* Added tests for PartnerMetadata changes

* Added tests for requestHistoryEndpoint + some cleanup

* Cleaned up naming and add logging

* Implemented updateMetadataForReceivedOrder and getMetadata

* Refactored PartnerMetadata.withSentSubmissionFields to split into separate methods for each parameter

* Changed logic to make sure to save sentSubmissionId into metadata file even if not able to retrieve receiver

* Fixed tests

* Added tests for updateMetadataForReceivedOrder + validation logic

* Added test to cover logic for missing receiver in getMetadata

* Added todo comment

* Added logging

* Refactored string comparison

* Made improvements based on Jeff's feedback

* Simplified logic by using try/catch instead of checking for expected format

* Added null check

* Simplified logic by catching exception instead of checking for expected format

* Return if sentSubmissionId is null given we can't update the metadata

* Fixed wrong commit

* Fixed failing tests

* Update etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/metadata/PartnerMetadataOrchestrator.java

Co-authored-by: halprin <[email protected]>

* Fixed exception

* test case for single param constructor

* single param contructor for PartnerMetadataException

* super with sigle param

* Added missing mock return value for requestHistoryEndpoint

* Fixed failing test

* Refactored to pass order hash as a parameter

* PartnerMetadataOrchestrator unit test for updateMetadataForSentOrder when sentSubmissionId is null

---------

Co-authored-by: halprin <[email protected]>
Co-authored-by: jorge Lopez <[email protected]>
  • Loading branch information
3 people authored Jan 4, 2024
1 parent e485ad4 commit a9944e3
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ class MetadataTest extends Specification {
def labOrderJsonFileString = Files.readString(Path.of("../examples/fhir/MN NBS FHIR Order Message.json"))

when:

def orderResponse = orderClient.submit(labOrderJsonFileString, submissionId, true)

then:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ public class PartnerMetadataException extends Exception {
public PartnerMetadataException(String message, Throwable cause) {
super(message, cause);
}

public PartnerMetadataException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package gov.hhs.cdc.trustedintermediary.etor.metadata;

import gov.hhs.cdc.trustedintermediary.etor.RSEndpointClient;
import gov.hhs.cdc.trustedintermediary.etor.orders.Order;
import gov.hhs.cdc.trustedintermediary.external.reportstream.ReportStreamEndpointClientException;
import gov.hhs.cdc.trustedintermediary.wrappers.Logger;
import gov.hhs.cdc.trustedintermediary.wrappers.formatter.Formatter;
import gov.hhs.cdc.trustedintermediary.wrappers.formatter.FormatterProcessingException;
import gov.hhs.cdc.trustedintermediary.wrappers.formatter.TypeReference;
Expand All @@ -24,26 +24,46 @@ public class PartnerMetadataOrchestrator {
@Inject PartnerMetadataStorage partnerMetadataStorage;
@Inject RSEndpointClient rsclient;
@Inject Formatter formatter;
@Inject Logger logger;

public static PartnerMetadataOrchestrator getInstance() {
return INSTANCE;
}

private PartnerMetadataOrchestrator() {}

public void updateMetadataForReceivedOrder(String receivedSubmissionId, Order<?> order)
public void updateMetadataForReceivedOrder(String receivedSubmissionId, String orderHash)
throws PartnerMetadataException {
// will call the RS history API given the submissionId, currently blocked by:
// https://github.com/CDCgov/prime-reportstream/issues/12624
// from the response, extract the "sender" and "timestamp" (timeReceived)
// we will calculate the hash.
// then we call the metadata storage to save this stuff.

String sender = "unknown";
Instant timeReceived = Instant.now();
String hash = String.valueOf(order.hashCode());
// currently blocked by: https://github.com/CDCgov/prime-reportstream/issues/12624
// once we get the right receivedSubmissionId from RS, this method should work
logger.logInfo(
"Looking up sender name and timeReceived from RS history API for receivedSubmissionId: {}",
receivedSubmissionId);

String sender;
Instant timeReceived;
try {
String bearerToken = rsclient.getRsToken();
String responseBody =
rsclient.requestHistoryEndpoint(receivedSubmissionId, bearerToken);
Map<String, Object> responseObject =
formatter.convertJsonToObject(responseBody, new TypeReference<>() {});

sender = responseObject.get("sender").toString();
String timestamp = responseObject.get("timestamp").toString();
timeReceived = Instant.parse(timestamp);

} catch (Exception e) {
throw new PartnerMetadataException(
"Unable to retrieve metadata from RS history API", e);
}

logger.logInfo(
"Updating metadata with sender: {}, timeReceived: {} and hash",
sender,
timeReceived);
PartnerMetadata partnerMetadata =
new PartnerMetadata(receivedSubmissionId, sender, timeReceived, hash);
new PartnerMetadata(receivedSubmissionId, sender, timeReceived, orderHash);
partnerMetadataStorage.saveMetadata(partnerMetadata);
}

Expand All @@ -54,13 +74,24 @@ public void updateMetadataForSentOrder(String receivedSubmissionId, String sentS
return;
}

PartnerMetadata partnerMetadata =
partnerMetadataStorage.readMetadata(receivedSubmissionId).orElseThrow();
Optional<PartnerMetadata> optionalPartnerMetadata =
partnerMetadataStorage.readMetadata(receivedSubmissionId);
if (optionalPartnerMetadata.isEmpty()) {
logger.logWarning(
"Metadata not found for receivedSubmissionId: {}", receivedSubmissionId);
return;
}

PartnerMetadata partnerMetadata = optionalPartnerMetadata.get();
if (!sentSubmissionId.equals(partnerMetadata.sentSubmissionId())) {
logger.logInfo("Updating metadata with sentSubmissionId: {}", sentSubmissionId);
partnerMetadata = partnerMetadata.withSentSubmissionId(sentSubmissionId);
partnerMetadataStorage.saveMetadata(partnerMetadata);
}

logger.logInfo(
"Looking up receiver name from RS history API for sentSubmissionId: {}",
sentSubmissionId);
String receiver;
try {
String bearerToken = rsclient.getRsToken();
Expand All @@ -71,19 +102,28 @@ public void updateMetadataForSentOrder(String receivedSubmissionId, String sentS
"Unable to retrieve metadata from RS history API", e);
}

logger.logInfo("Updating metadata with receiver: {}", receiver);
partnerMetadata = partnerMetadata.withReceiver(receiver);
partnerMetadataStorage.saveMetadata(partnerMetadata);
}

public Optional<PartnerMetadata> getMetadata(String receivedSubmissionId)
throws PartnerMetadataException {
// call the metadata storage to get the metadata.
// check if the receiver is filled out, and if it isn't, call the RS history API to get the
// receiver.
// if had to call the history API, extract the receiver and call the metadata storage to
// save the metadata with the receiver added.
// return the metadata.
return partnerMetadataStorage.readMetadata(receivedSubmissionId);
Optional<PartnerMetadata> optionalPartnerMetadata =
partnerMetadataStorage.readMetadata(receivedSubmissionId);
if (optionalPartnerMetadata.isEmpty()) {
logger.logInfo("Metadata not found for receivedSubmissionId: {}", receivedSubmissionId);
return Optional.empty();
}

PartnerMetadata partnerMetadata = optionalPartnerMetadata.get();
if (partnerMetadata.receiver() == null && partnerMetadata.sentSubmissionId() != null) {
logger.logInfo("Receiver name not found in metadata, looking up from RS history API");
updateMetadataForSentOrder(receivedSubmissionId, partnerMetadata.sentSubmissionId());
return partnerMetadataStorage.readMetadata(receivedSubmissionId);
}

return Optional.of(partnerMetadata);
}

String getReceiverName(String responseBody) throws FormatterProcessingException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ private void savePartnerMetadataForReceivedOrder(
}

try {
partnerMetadataOrchestrator.updateMetadataForReceivedOrder(receivedSubmissionId, order);
String orderHash = String.valueOf(order.hashCode());
partnerMetadataOrchestrator.updateMetadataForReceivedOrder(
receivedSubmissionId, orderHash);
} catch (PartnerMetadataException e) {
logger.logError(
"Unable to save metadata for receivedSubmissionId " + receivedSubmissionId, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public String requestWatersEndpoint(String body, String bearerToken)
public String requestHistoryEndpoint(String submissionId, String bearerToken) {
return """
{
"timestamp" : "2020-01-01T00:00:00.000Z",
"sender" : "flexion.simulated-hospital",
"destinations": [{
"organization_id": "flexion",
"service": "simulated-lab"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ package gov.hhs.cdc.trustedintermediary.etor.metadata
import spock.lang.Specification

class PartnerMetadataExceptionTest extends Specification {
def "constructor works"() {

def "two param constructor works"() {
given:
def message = "something blew up!"
def cause = new NullPointerException()
Expand All @@ -17,4 +16,15 @@ class PartnerMetadataExceptionTest extends Specification {
exception.getMessage() == message
exception.getCause() == cause
}

def "single param constructor works"() {
given:
def message = "something blew up!"

when:
def exception = new PartnerMetadataException(message)

then:
exception.getMessage() == message
}
}
Loading

0 comments on commit a9944e3

Please sign in to comment.