Skip to content

Commit

Permalink
ARC-1487: Added option to replace documents (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasrichner-oviva committed Mar 22, 2024
1 parent d1209ad commit 9e865c4
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,30 @@
import com.oviva.epa.client.model.WriteDocumentResponse;
import de.gematik.epa.ihe.model.document.Document;
import de.gematik.epa.ihe.model.simple.AuthorInstitution;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.List;
import java.util.UUID;

public interface KonnektorService {
@NonNull
List<AuthorInstitution> getAuthorInstitutions();

@NonNull
List<Card> getCardsInfo();

PinStatus verifySmcPin(String cardHandle);
@NonNull
PinStatus verifySmcPin(@NonNull String cardHandle);

WriteDocumentResponse writeDocument(RecordIdentifier recordIdentifier, Document document);
@NonNull
WriteDocumentResponse writeDocument(
@NonNull RecordIdentifier recordIdentifier, @NonNull Document document);

String getHomeCommunityID(String kvnr);
@NonNull
WriteDocumentResponse replaceDocument(
@NonNull RecordIdentifier recordIdentifier,
@NonNull Document document,
@NonNull UUID documentToReplaceId);

@NonNull
String getHomeCommunityID(@NonNull String kvnr);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.oviva.epa.client;

import com.oviva.epa.client.internal.ExceptionMappedKonnektorService;
import com.oviva.epa.client.internal.KonnektorServiceImpl;
import com.oviva.epa.client.internal.svc.model.KonnektorContext;
import com.oviva.epa.client.konn.KonnektorConnection;
Expand Down Expand Up @@ -62,6 +63,7 @@ public KonnektorService build() {
}

var ctx = new KonnektorContext(mandantId, clientSystemId, workplaceId, userId);
return new KonnektorServiceImpl(connection, ctx);
var svc = new KonnektorServiceImpl(connection, ctx);
return new ExceptionMappedKonnektorService(svc);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.oviva.epa.client.internal;

import com.oviva.epa.client.KonnektorService;
import com.oviva.epa.client.model.*;
import de.gematik.epa.ihe.model.document.Document;
import de.gematik.epa.ihe.model.simple.AuthorInstitution;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.List;
import java.util.UUID;
import telematik.ws.conn.exception.FaultMessageException;

/**
* Simple decorator for a KonnektorService to wrap underlying {@link
* telematik.ws.conn.exception.FaultMessageException} into {@link KonnektorException}
*/
public class ExceptionMappedKonnektorService implements KonnektorService {

private final KonnektorService delegate;

public ExceptionMappedKonnektorService(KonnektorService delegate) {
this.delegate = delegate;
}

@NonNull
@Override
public List<AuthorInstitution> getAuthorInstitutions() {
return wrap(delegate::getAuthorInstitutions);
}

@NonNull
@Override
public List<Card> getCardsInfo() {
return wrap(delegate::getCardsInfo);
}

@Override
public @NonNull PinStatus verifySmcPin(@NonNull String cardHandle) {
return wrap(() -> delegate.verifySmcPin(cardHandle));
}

@Override
public @NonNull WriteDocumentResponse writeDocument(
@NonNull RecordIdentifier recordIdentifier, @NonNull Document document) {
return wrap(() -> delegate.writeDocument(recordIdentifier, document));
}

@Override
public @NonNull WriteDocumentResponse replaceDocument(
@NonNull RecordIdentifier recordIdentifier,
@NonNull Document document,
@NonNull UUID documentToReplaceId) {
return wrap(() -> delegate.replaceDocument(recordIdentifier, document, documentToReplaceId));
}

@Override
public @NonNull String getHomeCommunityID(@NonNull String kvnr) {
return wrap(() -> delegate.getHomeCommunityID(kvnr));
}

private static <T> T wrap(WebServiceExecutor<T> requestor) {
try {
return requestor.execute();
} catch (FaultMessageException e) {
throw new KonnektorException("request failed: " + e.getMessage(), e);
}
}

interface WebServiceExecutor<T> {
T execute() throws FaultMessageException;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@
import com.oviva.epa.client.model.*;
import de.gematik.epa.LibIheXdsMain;
import de.gematik.epa.ihe.model.document.Document;
import de.gematik.epa.ihe.model.document.DocumentMetadata;
import de.gematik.epa.ihe.model.document.ReplaceDocument;
import de.gematik.epa.ihe.model.request.DocumentReplaceRequest;
import de.gematik.epa.ihe.model.request.DocumentSubmissionRequest;
import de.gematik.epa.ihe.model.simple.AuthorInstitution;
import de.gematik.epa.ihe.model.simple.SubmissionSetMetadata;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.*;
import oasis.names.tc.ebxml_regrep.xsd.rs._3.RegistryErrorList;
import oasis.names.tc.ebxml_regrep.xsd.rs._3.RegistryResponseType;
import telematik.ws.conn.cardservicecommon.xsd.v2_0.CardTypeType;
import telematik.ws.conn.exception.FaultMessageException;

public class KonnektorServiceImpl implements KonnektorService {

Expand Down Expand Up @@ -54,11 +58,13 @@ public KonnektorServiceImpl(KonnektorConnection connection, KonnektorContext kon
new SmbInformationServiceClient(eventServiceClient, certificateServiceClient);
}

@NonNull
@Override
public List<AuthorInstitution> getAuthorInstitutions() {
return smbInformationServiceClient.getAuthorInstitutions();
}

@NonNull
@Override
public List<Card> getCardsInfo() {
// don't be fooled by the name, this returns a list of cards...
Expand All @@ -76,25 +82,58 @@ private Card.CardType mapCardType(CardTypeType t) {
}

@Override
public PinStatus verifySmcPin(String cardHandle) {
public @NonNull PinStatus verifySmcPin(@NonNull String cardHandle) {
var response = cardServiceClient.getPinStatusResponse(cardHandle, "PIN.SMC");
return PinStatus.valueOf(response.getPinStatus().name());
}

@Override
public WriteDocumentResponse writeDocument(RecordIdentifier recordIdentifier, Document document) {
public @NonNull WriteDocumentResponse writeDocument(
@NonNull RecordIdentifier recordIdentifier, @NonNull Document document) {

var phrRecordIdentifier =
new com.oviva.epa.client.internal.svc.phr.model.RecordIdentifier(
recordIdentifier.kvnr(), recordIdentifier.homeCommunityId());

var metadata = getSubmissionSetMetadata(document.documentMetadata());
var docSubmissionRequest =
new DocumentSubmissionRequest(
new RecordIdentifierAdapter(phrRecordIdentifier),
List.of(document),
getSubmissionSetMetadata(document));
new RecordIdentifierAdapter(phrRecordIdentifier), List.of(document), metadata);

var provideAndRegisterRequest =
LibIheXdsMain.convertDocumentSubmissionRequest(docSubmissionRequest);
var req = LibIheXdsMain.convertDocumentSubmissionRequest(docSubmissionRequest);

var res =
phrServiceClient.documentRepositoryProvideAndRegisterDocumentSetB(phrRecordIdentifier, req);

validateResponse(res);

return new WriteDocumentResponse(res.getRequestId());
}

@Override
public @NonNull WriteDocumentResponse replaceDocument(
@NonNull RecordIdentifier recordIdentifier,
@NonNull Document document,
@NonNull UUID documentToReplaceId) {

var phrRecordIdentifier =
new com.oviva.epa.client.internal.svc.phr.model.RecordIdentifier(
recordIdentifier.kvnr(), recordIdentifier.homeCommunityId());

var metadata = getSubmissionSetMetadata(document.documentMetadata());

var replaceDocument =
new ReplaceDocument(
document.documentData(),
document.documentMetadata(),
// this ID must be a valid object ID in IHE
uuidToUrn(documentToReplaceId).orElse(null));

var req =
new DocumentReplaceRequest(
new RecordIdentifierAdapter(phrRecordIdentifier), List.of(replaceDocument), metadata);

var provideAndRegisterRequest = LibIheXdsMain.convertDocumentReplaceRequest(req);

var res =
phrServiceClient.documentRepositoryProvideAndRegisterDocumentSetB(
Expand Down Expand Up @@ -129,17 +168,30 @@ private void validateResponse(RegistryResponseType res) {
}

@Override
public String getHomeCommunityID(String kvnr) {
return phrManagementServiceClient.getHomeCommunityID(kvnr);
public @NonNull String getHomeCommunityID(@NonNull String kvnr) {
try {
return phrManagementServiceClient.getHomeCommunityID(kvnr);
} catch (FaultMessageException e) {
throw new KonnektorException(e.getMessage(), e);
}
}

private SubmissionSetMetadata getSubmissionSetMetadata(Document document) {
private SubmissionSetMetadata getSubmissionSetMetadata(DocumentMetadata metadata) {

var author =
document.documentMetadata().author().stream()
metadata.author().stream()
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("no author"));

return new SubmissionSetMetadata(List.of(author), null, LocalDateTime.now(), null, null, null);
}

/**
* Convert the UUID to a valid object identity in the context of IHE <a
* href="https://wiki.ihe.net/index.php/Creating_Unique_IDs_-_OID_and_UUID">Creating Unique IDs -
* OID and UUID</a>
*/
private Optional<String> uuidToUrn(@Nullable UUID id) {
return Optional.ofNullable(id).map("urn:uuid:%s"::formatted);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ void testGetCardsInfo() throws Exception {
@Test
void writeDocument() {

String documentId = UUID.randomUUID().toString();
var documentId = UUID.randomUUID();

// when

Expand All @@ -98,6 +98,35 @@ void writeDocument() {
assertDoesNotThrow(() -> konnektorService.writeDocument(recordIdentifier, document));
}

@Test
void replaceDocument() {

var documentId = UUID.randomUUID();

// when

// 1) get home community
var hcid = konnektorService.getHomeCommunityID(KVNR);
var recordIdentifier = new RecordIdentifier(KVNR, hcid);

// 2) read author/telematik ID from SMC-B
var authorInstitution =
konnektorService.getAuthorInstitutions().stream()
.findFirst()
.orElseThrow(() -> new IllegalStateException("no SMC-B found"));

var document = buildDocumentPayload(documentId, authorInstitution, EXPORT_XML.getBytes());

// 3) write the FHIR/MIO document
assertDoesNotThrow(() -> konnektorService.writeDocument(recordIdentifier, document));

// 4) replace the document
var newDocumentId = UUID.randomUUID();
var newDocument = buildDocumentPayload(newDocumentId, authorInstitution, EXPORT_XML.getBytes());
assertDoesNotThrow(
() -> konnektorService.replaceDocument(recordIdentifier, newDocument, documentId));
}

/** establish a connection to the TI Konnektor */
private KonnektorService buildService() throws Exception {

Expand Down Expand Up @@ -125,10 +154,12 @@ private KonnektorService buildService() throws Exception {
}

private Document buildDocumentPayload(
String id, AuthorInstitution authorInstitution, byte[] contents) {
var entryUUID = UUID.randomUUID().toString();
UUID id, AuthorInstitution authorInstitution, byte[] contents) {
var repositoryUniqueId = UUID.randomUUID().toString();

// IMPORTANT: Without the urn prefix we can't replace it later
var documentUuid = "urn:uuid:" + id;

return new Document(
contents,
new DocumentMetadata(
Expand All @@ -151,7 +182,7 @@ private Document buildDocumentPayload(
ClassCode.DURCHFUEHRUNGSPROTOKOLL.getValue(),
"DiGA MIO-Beispiel eines Dokument von Referenzimplementierung geschickt (Simple Roundtrip)",
LocalDateTime.now().minusHours(3),
entryUUID,
documentUuid,
List.of(EventCode.PATIENTEN_MITGEBRACHT.getValue()),
FormatCode.DIGA.getValue(),
"",
Expand All @@ -166,7 +197,7 @@ private Document buildDocumentPayload(
contents.length,
"Gesundheitsmonitoring",
TypeCode.PATIENTENEIGENE_DOKUMENTE.getValue(),
id,
documentUuid,
"monitoring.xml",
repositoryUniqueId,
"",
Expand Down

0 comments on commit 9e865c4

Please sign in to comment.