Skip to content

Commit

Permalink
Merge pull request #738 from CDCgov/story-672-history_api_skeleton
Browse files Browse the repository at this point in the history
672: Parter Metadata Orchestrator Skeleton
  • Loading branch information
halprin authored Dec 20, 2023
2 parents 66cdde6 + baccd59 commit 16d0cb7
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import gov.hhs.cdc.trustedintermediary.etor.demographics.PatientDemographicsResponse;
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadata;
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataException;
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataOrchestrator;
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataStorage;
import gov.hhs.cdc.trustedintermediary.etor.orders.Order;
import gov.hhs.cdc.trustedintermediary.etor.orders.OrderController;
Expand Down Expand Up @@ -53,7 +54,7 @@ public class EtorDomainRegistration implements DomainConnector {
@Inject SendOrderUseCase sendOrderUseCase;
@Inject Logger logger;
@Inject DomainResponseHelper domainResponseHelper;
@Inject PartnerMetadataStorage partnerMetadataStorage;
@Inject PartnerMetadataOrchestrator partnerMetadataOrchestrator;

private final Map<HttpEndpoint, Function<DomainRequest, DomainResponse>> endpoints =
Map.of(
Expand All @@ -72,6 +73,8 @@ public Map<HttpEndpoint, Function<DomainRequest, DomainResponse>> domainRegistra
ApplicationContext.register(OrderConverter.class, HapiOrderConverter.getInstance());
ApplicationContext.register(OrderController.class, OrderController.getInstance());
ApplicationContext.register(SendOrderUseCase.class, SendOrderUseCase.getInstance());
ApplicationContext.register(
PartnerMetadataOrchestrator.class, PartnerMetadataOrchestrator.getInstance());

if (ApplicationContext.getEnvironment().equalsIgnoreCase("local")) {
ApplicationContext.register(OrderSender.class, LocalFileOrderSender.getInstance());
Expand Down Expand Up @@ -147,7 +150,8 @@ DomainResponse handleOrders(DomainRequest request) {
DomainResponse handleMetadata(DomainRequest request) {
try {
String metadataId = request.getPathParams().get("id");
Optional<PartnerMetadata> metadata = partnerMetadataStorage.readMetadata(metadataId);
Optional<PartnerMetadata> metadata =
partnerMetadataOrchestrator.getMetadata(metadataId);

if (metadata.isEmpty()) {
return domainResponseHelper.constructErrorResponse(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package gov.hhs.cdc.trustedintermediary.etor.metadata;

import gov.hhs.cdc.trustedintermediary.etor.orders.Order;
import java.time.Instant;
import java.util.Optional;
import javax.inject.Inject;

/**
* The PartnerMetadataOrchestrator class is responsible for updating and retrieving partner-facing
* metadata. It interacts with the metadata storage and the history API to create, update, and store
* metadata.
*/
public class PartnerMetadataOrchestrator {

private static final PartnerMetadataOrchestrator INSTANCE = new PartnerMetadataOrchestrator();

@Inject PartnerMetadataStorage partnerMetadataStorage;

public static PartnerMetadataOrchestrator getInstance() {
return INSTANCE;
}

private PartnerMetadataOrchestrator() {}

public void updateMetadataForReceivedOrder(String submissionId, Order<?> order)
throws PartnerMetadataException {
// will call the RS history API given the submissionId (albeit, right now this won't work
// given the way RS works).
// from the history API response, extract the sender (organization + sender client), and
// time received.
// we will calculate the hash.
// then we call the metadata storage to save this stuff.

PartnerMetadata partnerMetadata =
new PartnerMetadata(
submissionId, "senderName", "receiverName", Instant.now(), "abcd");
partnerMetadataStorage.saveMetadata(partnerMetadata);
}

public void updateMetadataForSentOrder(
String receivedSubmissionId, String sentSubmissionId, Order<?> order)
throws PartnerMetadataException {
// call the metadata storage and add the sent order's submission ID to the existing metadata
// entry
// PartnerMetadata may need to be updated to store both the received order's submission ID
// _and_ the sent order's submission ID.
}

public Optional<PartnerMetadata> getMetadata(String submissionId)
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(submissionId);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package gov.hhs.cdc.trustedintermediary.etor.orders;

import gov.hhs.cdc.trustedintermediary.etor.metadata.EtorMetadataStep;
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadata;
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataException;
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataStorage;
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataOrchestrator;
import gov.hhs.cdc.trustedintermediary.wrappers.Logger;
import gov.hhs.cdc.trustedintermediary.wrappers.MetricMetadata;
import java.time.Instant;
import javax.inject.Inject;

/** The overall logic to receive, convert to OML, and subsequently send a lab order. */
Expand All @@ -15,7 +13,7 @@ public class SendOrderUseCase {
@Inject OrderConverter converter;
@Inject OrderSender sender;
@Inject MetricMetadata metadata;
@Inject PartnerMetadataStorage partnerMetadataStorage;
@Inject PartnerMetadataOrchestrator partnerMetadataOrchestrator;
@Inject Logger logger;

private SendOrderUseCase() {}
Expand All @@ -27,28 +25,48 @@ public static SendOrderUseCase getInstance() {
public void convertAndSend(final Order<?> order, String submissionId)
throws UnableToSendOrderException {

try {
savePartnerMetadata(submissionId);
} catch (PartnerMetadataException e) {
logger.logError("Unable to save metadata for submissionId " + submissionId, e);
}
savePartnerMetadataForReceivedOrder(submissionId, order);

var omlOrder = converter.convertMetadataToOmlOrder(order);
metadata.put(order.getFhirResourceId(), EtorMetadataStep.ORDER_CONVERTED_TO_OML);
omlOrder = converter.addContactSectionToPatientResource(omlOrder);
metadata.put(order.getFhirResourceId(), EtorMetadataStep.CONTACT_SECTION_ADDED_TO_PATIENT);
sender.sendOrder(omlOrder);

saveSentOrderSubmissionId(
submissionId,
"TBD, need to be filled in from the sender.sendOrder(omlOrder) call",
order);
}

private void savePartnerMetadata(String submissionId) throws PartnerMetadataException {
private void savePartnerMetadataForReceivedOrder(String submissionId, final Order<?> order) {
if (submissionId == null) {
return;
}

// TODO: still need to get metadata from the order: sender, receiver, timeReceived, hash
PartnerMetadata partnerMetadata =
new PartnerMetadata(
submissionId, "senderName", "receiverName", Instant.now(), "abcd");
partnerMetadataStorage.saveMetadata(partnerMetadata);
try {
partnerMetadataOrchestrator.updateMetadataForReceivedOrder(submissionId, order);
} catch (PartnerMetadataException e) {
logger.logError("Unable to save metadata for submissionId " + submissionId, e);
}
}

private void saveSentOrderSubmissionId(
String receivedSubmissionId, String sentSubmissionId, final Order<?> order) {
if (sentSubmissionId == null || receivedSubmissionId == null) {
return;
}

try {
partnerMetadataOrchestrator.updateMetadataForSentOrder(
receivedSubmissionId, sentSubmissionId, order);
} catch (PartnerMetadataException e) {
logger.logError(
"Unable to update metadata for received submissionId "
+ receivedSubmissionId
+ " and sent submissionId "
+ sentSubmissionId,
e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import gov.hhs.cdc.trustedintermediary.etor.demographics.PatientDemographicsCont
import gov.hhs.cdc.trustedintermediary.etor.demographics.PatientDemographicsResponse
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadata
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataException
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataStorage
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataOrchestrator
import gov.hhs.cdc.trustedintermediary.etor.orders.Order
import gov.hhs.cdc.trustedintermediary.etor.orders.OrderController
import gov.hhs.cdc.trustedintermediary.etor.orders.OrderResponse
Expand All @@ -23,7 +23,6 @@ import gov.hhs.cdc.trustedintermediary.external.jackson.Jackson
import gov.hhs.cdc.trustedintermediary.wrappers.FhirParseException
import gov.hhs.cdc.trustedintermediary.wrappers.Logger
import gov.hhs.cdc.trustedintermediary.wrappers.formatter.Formatter
import gov.hhs.cdc.trustedintermediary.wrappers.formatter.FormatterProcessingException
import java.time.Instant
import spock.lang.Specification

Expand Down Expand Up @@ -321,9 +320,9 @@ class EtorDomainRegistrationTest extends Specification {
def request = new DomainRequest()
request.setPathParams(["id": "metadataId"])

def mockPartnerMetadataStorage = Mock(PartnerMetadataStorage)
mockPartnerMetadataStorage.readMetadata(_ as String) >> Optional.ofNullable(new PartnerMetadata("metadataId", "sender", "receiver", Instant.parse("2023-12-04T18:51:48.941875Z"), "abcd"))
TestApplicationContext.register(PartnerMetadataStorage, mockPartnerMetadataStorage)
def mockPartnerMetadataOrchestrator = Mock(PartnerMetadataOrchestrator)
mockPartnerMetadataOrchestrator.getMetadata(_ as String) >> Optional.ofNullable(new PartnerMetadata("metadataId", "sender", "receiver", Instant.parse("2023-12-04T18:51:48.941875Z"), "abcd"))
TestApplicationContext.register(PartnerMetadataOrchestrator, mockPartnerMetadataOrchestrator)

def mockResponseHelper = Mock(DomainResponseHelper)
mockResponseHelper.constructOkResponse(_ as PartnerMetadata) >> new DomainResponse(expectedStatusCode)
Expand All @@ -350,9 +349,9 @@ class EtorDomainRegistrationTest extends Specification {
def request = new DomainRequest()
request.setPathParams(["id": "metadataId"])

def mockPartnerMetadataStorage = Mock(PartnerMetadataStorage)
mockPartnerMetadataStorage.readMetadata(_ as String) >> Optional.empty()
TestApplicationContext.register(PartnerMetadataStorage, mockPartnerMetadataStorage)
def mockPartnerMetadataOrchestrator = Mock(PartnerMetadataOrchestrator)
mockPartnerMetadataOrchestrator.getMetadata(_ as String) >> Optional.empty()
TestApplicationContext.register(PartnerMetadataOrchestrator, mockPartnerMetadataOrchestrator)

def mockResponseHelper = Mock(DomainResponseHelper)
mockResponseHelper.constructErrorResponse(expectedStatusCode, _ as String) >> new DomainResponse(expectedStatusCode)
Expand All @@ -378,9 +377,9 @@ class EtorDomainRegistrationTest extends Specification {
def request = new DomainRequest()
request.setPathParams(["id": "metadataId"])

def mockPartnerMetadataStorage = Mock(PartnerMetadataStorage)
mockPartnerMetadataStorage.readMetadata(_ as String) >> { throw new PartnerMetadataException("DogCow", new Exception()) }
TestApplicationContext.register(PartnerMetadataStorage, mockPartnerMetadataStorage)
def mockPartnerMetadataOrchestrator = Mock(PartnerMetadataOrchestrator)
mockPartnerMetadataOrchestrator.getMetadata(_ as String) >> { throw new PartnerMetadataException("DogCow", new Exception()) }
TestApplicationContext.register(PartnerMetadataOrchestrator, mockPartnerMetadataOrchestrator)

def mockResponseHelper = Mock(DomainResponseHelper)
mockResponseHelper.constructErrorResponse(expectedStatusCode, _ as String) >> new DomainResponse(expectedStatusCode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package gov.hhs.cdc.trustedintermediary.etor.orders
import gov.hhs.cdc.trustedintermediary.OrderMock
import gov.hhs.cdc.trustedintermediary.context.TestApplicationContext
import gov.hhs.cdc.trustedintermediary.etor.metadata.EtorMetadataStep
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataStorage
import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataOrchestrator
import gov.hhs.cdc.trustedintermediary.wrappers.MetricMetadata
import spock.lang.Specification

Expand All @@ -14,7 +14,7 @@ class SendOrderUsecaseTest extends Specification {
TestApplicationContext.init()
TestApplicationContext.register(SendOrderUseCase, SendOrderUseCase.getInstance())
TestApplicationContext.register(MetricMetadata, Mock(MetricMetadata))
TestApplicationContext.register(PartnerMetadataStorage, Mock(PartnerMetadataStorage))
TestApplicationContext.register(PartnerMetadataOrchestrator, Mock(PartnerMetadataOrchestrator))
}

def "send sends successfully"() {
Expand Down

0 comments on commit 16d0cb7

Please sign in to comment.