Skip to content

Commit

Permalink
Story 676/consolidated orders (#799)
Browse files Browse the repository at this point in the history
* WIP Adding consolidated endpoint

* Update the consolidated metadata API to return whether the data is stale or not

* Adding unit tests

* Renaming endpoint

* Remove TODO, we have decided to retrieve all of the metadata when getting by sender

* Removed 💩 emoji stale status for consolidated metadata endpoint

* Update unit test for orchestrating the collection of our consolidated metadata

* added readMetadata for sender throough metadata_directory

* Adding test for FilePartnerMetadataStorage

* Fixing merge issue

* Update JavaDocs for readMetadataForSender

* Write an unhappy path unit test for the consolidated endpoint handler

* Have our PostgresDao test return multiple PartnerMetadata

* Test multiple metadatas in our FileMetadataStorage test

---------

Co-authored-by: halprin <[email protected]>
  • Loading branch information
jcrichlake and halprin authored Jan 25, 2024
1 parent e8941a2 commit 94dda8c
Show file tree
Hide file tree
Showing 12 changed files with 318 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public class EtorDomainRegistration implements DomainConnector {
static final String METADATA_API_ENDPOINT = "/v1/etor/metadata/{id}";
static final String RESULTS_API_ENDPOINT = "/v1/etor/results";

static final String CONSOLIDATED_SUMMARY_API_ENDPOINT = "/v1/etor/metadata/summary/{sender}";

@Inject PatientDemographicsController patientDemographicsController;
@Inject OrderController orderController;
@Inject ConvertAndSendDemographicsUsecase convertAndSendDemographicsUsecase;
Expand All @@ -82,7 +84,9 @@ public class EtorDomainRegistration implements DomainConnector {
new HttpEndpoint("POST", DEMOGRAPHICS_API_ENDPOINT, true),
this::handleDemographics,
new HttpEndpoint("POST", ORDERS_API_ENDPOINT, true), this::handleOrders,
new HttpEndpoint("GET", METADATA_API_ENDPOINT, true), this::handleMetadata);
new HttpEndpoint("GET", METADATA_API_ENDPOINT, true), this::handleMetadata,
new HttpEndpoint("GET", CONSOLIDATED_SUMMARY_API_ENDPOINT, true),
this::handleConsolidatedSummary);

@Override
public Map<HttpEndpoint, Function<DomainRequest, DomainResponse>> domainRegistration() {
Expand Down Expand Up @@ -227,6 +231,23 @@ DomainResponse handleMetadata(DomainRequest request) {
}
}

DomainResponse handleConsolidatedSummary(DomainRequest request) {

Map<String, Map<String, Object>> metadata;
try {
String senderName = request.getPathParams().get("sender");

metadata = partnerMetadataOrchestrator.getConsolidatedMetadata(senderName);

} catch (Exception e) {
var errorString = "Unable to retrieve consolidated orders";
logger.logError(errorString, e);
return domainResponseHelper.constructErrorResponse(500, errorString);
}

return domainResponseHelper.constructOkResponse(metadata);
}

public DomainResponse handleResults(DomainRequest request) {

// Get the result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
import gov.hhs.cdc.trustedintermediary.wrappers.formatter.TypeReference;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.inject.Inject;

/**
Expand Down Expand Up @@ -118,9 +120,7 @@ public Optional<PartnerMetadata> getMetadata(String receivedSubmissionId)

PartnerMetadata partnerMetadata = optionalPartnerMetadata.get();
var sentSubmissionId = partnerMetadata.sentSubmissionId();
if ((partnerMetadata.receiver() == null
|| partnerMetadata.deliveryStatus() == PartnerMetadataStatus.PENDING)
&& sentSubmissionId != null) {
if (metadataIsStale(partnerMetadata) && sentSubmissionId != null) {
logger.logInfo(
"Receiver name not found in metadata or delivery status still pending, looking up {} from RS history API",
sentSubmissionId);
Expand Down Expand Up @@ -186,6 +186,29 @@ public void setMetadataStatusToFailed(String submissionId, String errorMessage)
partnerMetadataStorage.saveMetadata(partnerMetadata);
}

public Map<String, Map<String, Object>> getConsolidatedMetadata(String senderName)
throws PartnerMetadataException {

var metadataSet = partnerMetadataStorage.readMetadataForSender(senderName);

return metadataSet.stream()
.collect(
Collectors.toMap(
PartnerMetadata::receivedSubmissionId,
metadata -> {
var status = String.valueOf(metadata.deliveryStatus());
var stale = metadataIsStale(metadata);
var failureReason = metadata.failureReason();

Map<String, Object> innerMap = new HashMap<>();
innerMap.put("status", status);
innerMap.put("stale", stale);
innerMap.put("failureReason", failureReason);

return innerMap;
}));
}

String[] getDataFromReportStream(String responseBody) throws FormatterProcessingException {
// the expected json structure for the response is:
// {
Expand Down Expand Up @@ -258,4 +281,9 @@ PartnerMetadataStatus ourStatusFromReportStreamStatus(String rsStatus) {
default -> PartnerMetadataStatus.PENDING;
};
}

private boolean metadataIsStale(PartnerMetadata partnerMetadata) {
return partnerMetadata.receiver() == null
|| partnerMetadata.deliveryStatus() == PartnerMetadataStatus.PENDING;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gov.hhs.cdc.trustedintermediary.etor.metadata.partner;

import java.util.Optional;
import java.util.Set;

/** Interface to store and retrieve our partner-facing metadata. */
public interface PartnerMetadataStorage {
Expand All @@ -21,4 +22,12 @@ Optional<PartnerMetadata> readMetadata(String receivedSubmissionId)
* @param metadata The metadata to save.
*/
void saveMetadata(PartnerMetadata metadata) throws PartnerMetadataException;

/**
* This method will return a set of partner metadata for the given sender.
*
* @param sender the name of the sender to search for
* @return a set of {@link PartnerMetadata}s.
*/
Set<PartnerMetadata> readMetadataForSender(String sender) throws PartnerMetadataException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import gov.hhs.cdc.trustedintermediary.wrappers.formatter.FormatterProcessingException;
import gov.hhs.cdc.trustedintermediary.wrappers.formatter.TypeReference;
import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;

/** Implements the {@link PartnerMetadataStorage} using files stored in an Azure Storage Account. */
Expand Down Expand Up @@ -65,6 +66,12 @@ public void saveMetadata(final PartnerMetadata metadata) throws PartnerMetadataE
}
}

@Override
public Set<PartnerMetadata> readMetadataForSender(String sender)
throws PartnerMetadataException {
return null;
}

public static String getMetadataFileName(String uniqueId) {
return uniqueId + ".json";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import gov.hhs.cdc.trustedintermediary.wrappers.Logger;
import java.sql.SQLException;
import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;

/** Implements the {@link PartnerMetadataStorage} using a database. */
Expand Down Expand Up @@ -51,4 +52,16 @@ public void saveMetadata(final PartnerMetadata metadata) throws PartnerMetadataE
throw new PartnerMetadataException("Error saving metadata", e);
}
}

@Override
public Set<PartnerMetadata> readMetadataForSender(String sender)
throws PartnerMetadataException {
Set<PartnerMetadata> consolidatedMetadata;
try {
consolidatedMetadata = dao.fetchMetadataForSender(sender);
} catch (SQLException e) {
throw new PartnerMetadataException("Error retrieving consolidated metadata", e);
}
return consolidatedMetadata;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package gov.hhs.cdc.trustedintermediary.external.database;

import gov.hhs.cdc.trustedintermediary.etor.metadata.partner.PartnerMetadata;
import gov.hhs.cdc.trustedintermediary.etor.metadata.partner.PartnerMetadataStatus;
import java.sql.SQLException;
import java.time.Instant;
import java.util.Set;

/** Interface for accessing the database for metadata */
public interface DbDao {
Expand All @@ -17,5 +19,7 @@ void upsertMetadata(
String failureReason)
throws SQLException;

Set<PartnerMetadata> fetchMetadataForSender(String sender) throws SQLException;

Object fetchMetadata(String uniqueId) throws SQLException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
import java.sql.Timestamp;
import java.sql.Types;
import java.time.Instant;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import javax.inject.Inject;

/** Class for accessing and managing data for the postgres Database */
Expand Down Expand Up @@ -113,6 +115,26 @@ ON CONFLICT (received_message_id) DO UPDATE SET receiver = EXCLUDED.receiver, se
}
}

@Override
public synchronized Set<PartnerMetadata> fetchMetadataForSender(String sender)
throws SQLException {

try (Connection conn = connect();
PreparedStatement statement =
conn.prepareStatement("SELECT * FROM metadata WHERE sender = ?")) {
statement.setString(1, sender);
ResultSet resultSet = statement.executeQuery();

Set<PartnerMetadata> metadataSet = new HashSet<>();

while (resultSet.next()) {
metadataSet.add(partnerMetadataFromResultSet(resultSet));
}

return metadataSet;
}
}

@Override
public synchronized PartnerMetadata fetchMetadata(String submissionId) throws SQLException {
try (Connection conn = connect();
Expand All @@ -129,21 +151,25 @@ public synchronized PartnerMetadata fetchMetadata(String submissionId) throws SQ
return null;
}

Instant timeReceived = null;
Timestamp timestamp = result.getTimestamp("time_received");
if (timestamp != null) {
timeReceived = timestamp.toInstant();
}
return partnerMetadataFromResultSet(result);
}
}

return new PartnerMetadata(
result.getString("received_message_id"),
result.getString("sent_message_id"),
result.getString("sender"),
result.getString("receiver"),
timeReceived,
result.getString("hash_of_order"),
PartnerMetadataStatus.valueOf(result.getString("delivery_status")),
result.getString("failure_reason"));
private PartnerMetadata partnerMetadataFromResultSet(ResultSet resultSet) throws SQLException {
Instant timeReceived = null;
Timestamp timestamp = resultSet.getTimestamp("time_received");
if (timestamp != null) {
timeReceived = timestamp.toInstant();
}

return new PartnerMetadata(
resultSet.getString("received_message_id"),
resultSet.getString("sent_message_id"),
resultSet.getString("sender"),
resultSet.getString("receiver"),
timeReceived,
resultSet.getString("hash_of_order"),
PartnerMetadataStatus.valueOf(resultSet.getString("delivery_status")),
resultSet.getString("failure_reason"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.Inject;

Expand Down Expand Up @@ -94,6 +96,40 @@ public void saveMetadata(final PartnerMetadata metadata) throws PartnerMetadataE
}
}

@Override
public Set<PartnerMetadata> readMetadataForSender(String sender)
throws PartnerMetadataException {

Set<PartnerMetadata> partnerMetadata = null;

try (Stream<Path> fileList = Files.list(METADATA_DIRECTORY)) {
partnerMetadata =
fileList.map(
fileName -> {
try {
return Files.readString(fileName);
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.map(
metadataContent -> {
try {
return formatter.convertJsonToObject(
metadataContent,
new TypeReference<PartnerMetadata>() {});
} catch (FormatterProcessingException e) {
throw new RuntimeException(e);
}
})
.filter(metadata -> metadata.sender().equals(sender))
.collect(Collectors.toSet());
} catch (Exception e) {
throw new PartnerMetadataException("Failed reading metadata for sender: " + sender, e);
}
return partnerMetadata;
}

private Path getFilePath(String metadataId) {
return METADATA_DIRECTORY.resolve(metadataId + ".json");
}
Expand Down
Loading

0 comments on commit 94dda8c

Please sign in to comment.