diff --git a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/pix/PixMergePatientFeed.java b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/pix/PixMergePatientFeed.java index dbea0cf5ec7..1b253a2a5f5 100644 --- a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/pix/PixMergePatientFeed.java +++ b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/pix/PixMergePatientFeed.java @@ -12,7 +12,17 @@ import java.util.Date; import java.util.List; - +import lombok.Builder; +import lombok.Getter; +import lombok.NonNull; +import lombok.Singular; +import lombok.ToString; +import net.ihe.gazelle.hl7v3.prpain201304UV02.PRPAIN201304UV02Type; +import net.ihe.gazelle.hl7v3.prpamt201303UV02.PRPAMT201303UV02Citizen; +import net.ihe.gazelle.hl7v3.prpamt201303UV02.PRPAMT201303UV02Employee; +import net.ihe.gazelle.hl7v3.prpamt201303UV02.PRPAMT201303UV02LanguageCommunication; +import net.ihe.gazelle.hl7v3.prpamt201303UV02.PRPAMT201303UV02Nation; +import net.ihe.gazelle.hl7v3.prpamt201303UV02.PRPAMT201303UV02Person; import org.hl7.fhir.r4.model.Address; import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.ContactPoint; @@ -28,18 +38,6 @@ import org.projecthusky.communication.utils.PixPdqV3Utils; import org.projecthusky.fhir.structures.gen.FhirCommon; -import lombok.Builder; -import lombok.Getter; -import lombok.NonNull; -import lombok.Singular; -import lombok.ToString; -import net.ihe.gazelle.hl7v3.prpain201304UV02.PRPAIN201304UV02Type; -import net.ihe.gazelle.hl7v3.prpamt201303UV02.PRPAMT201303UV02Citizen; -import net.ihe.gazelle.hl7v3.prpamt201303UV02.PRPAMT201303UV02Employee; -import net.ihe.gazelle.hl7v3.prpamt201303UV02.PRPAMT201303UV02LanguageCommunication; -import net.ihe.gazelle.hl7v3.prpamt201303UV02.PRPAMT201303UV02Nation; -import net.ihe.gazelle.hl7v3.prpamt201303UV02.PRPAMT201303UV02Person; - /** * This class is designed to collect the parameters of the merge patient service call at high level and transform them * into the request object, that is sent to the service. @@ -51,6 +49,8 @@ @ToString public class PixMergePatientFeed { + public static class PixMergePatientFeedBuilder {} + @NonNull private Destination destination; /** Use providingOrganization instead */ @@ -58,7 +58,7 @@ public class PixMergePatientFeed { private Organization scopingOrganization; private Organization providerOrganization; @NonNull - private String obsolatePatientID; + private String obsoletePatientID; @NonNull private String homeCommunityOID; @NonNull @@ -80,16 +80,15 @@ public class PixMergePatientFeed { private List languages; @Singular private List telecomContacts; + private CodeableConcept employeeOccupation; - - public static class PixMergePatientFeedBuilder {} public PixMergePatientRequest build() { - PixMergePatientRequest request = new PixMergePatientRequest(this.destination.getSenderApplicationOid(), null, - this.destination.getReceiverApplicationOid(), null); + PixMergePatientRequest request = new PixMergePatientRequest(destination.getSenderApplicationOid(), null, + destination.getReceiverApplicationOid(), null); addIdentifiers(request); addNonMedicalIdentifiers(request); - addObsolatePatientId(request); + addObsoletePatientId(request); addPatientName(request); addPatientBirthday(request); addPatientGender(request); @@ -105,8 +104,10 @@ public PixMergePatientRequest build() { return request; } - private void addObsolatePatientId(PixMergePatientRequest request) { - request.setObsoletePatientID(obsolatePatientID, homeCommunityOID, homeCommunityNamespace); + private void addAddresses(PixMergePatientRequest request) { + for (Address address : addresses) { + request.addPatientAddress(PixPdqV3Utils.createAd(address)); + } } private void addEmployeeOccupation(PixMergePatientRequest request) { @@ -114,46 +115,24 @@ private void addEmployeeOccupation(PixMergePatientRequest request) { PRPAMT201303UV02Person patientPerson = rootElement.getControlActProcess().getSubject().get(0).getRegistrationEvent() .getSubject1().getPatient().getPatientPerson(); - if (this.employeeOccupation != null) { + if (employeeOccupation != null) { var employee = new PRPAMT201303UV02Employee(); employee.setOccupationCode(PixPdqV3Utils.createCE(employeeOccupation.getText())); patientPerson.getAsEmployee().add(employee); } } - private void addProviderOrganization(PixMergePatientRequest request) { - if (providerOrganization == null && scopingOrganization != null) { - providerOrganization = scopingOrganization; - } - - if (providerOrganization != null) { - String organizationName = ""; - String telecomValue = "NOTPROVIDED"; - - if (providerOrganization.getName() != null) { - organizationName = providerOrganization.getName(); - } - - if (providerOrganization.getTelecom() != null && !providerOrganization.getTelecom().isEmpty()) { - var contactPoint = providerOrganization.getTelecomFirstRep(); - if (contactPoint != null) { - telecomValue = contactPoint.getValue(); + private void addIdentifiers(PixMergePatientRequest request) { + for (Identifier identifier : identifiers) { + if ((identifier.getSystem().length() > 8)) { + final String oid = FhirCommon.removeUrnOidPrefix(identifier.getSystem()); + if (homeCommunityOID != null && homeCommunityOID.equals(oid)) { + request.addPatientID(identifier.getValue(), homeCommunityOID, homeCommunityNamespace); + } else { + request.addPatientID(identifier.getValue(), oid, ""); } } - request.setProviderOrganization(providerOrganization.getIdentifier(), organizationName, telecomValue); - } - } - - private void addTelecomContacts(PixMergePatientRequest request) { - PRPAIN201304UV02Type rootElement = request.getRootElement(); - PRPAMT201303UV02Person patientPerson = rootElement.getControlActProcess().getSubject().get(0).getRegistrationEvent() - .getSubject1().getPatient().getPatientPerson(); - - for (ContactPoint contactPoint : this.telecomContacts) { - patientPerson.getTelecom().add(V3PixSourceMessageHelper.createTEL(ConverterUtil.getTelecomValue(contactPoint), - ConverterUtil.getTelecomAddressUse(contactPoint))); } - } private void addLanguages(PixMergePatientRequest request) { @@ -161,7 +140,7 @@ private void addLanguages(PixMergePatientRequest request) { PRPAMT201303UV02Person patientPerson = rootElement.getControlActProcess().getSubject().get(0).getRegistrationEvent() .getSubject1().getPatient().getPatientPerson(); - for (CodeableConcept language : this.languages) { + for (CodeableConcept language : languages) { var communication = new PRPAMT201303UV02LanguageCommunication(); communication.setLanguageCode( @@ -172,19 +151,13 @@ private void addLanguages(PixMergePatientRequest request) { } private void addMaritalStatus(PixMergePatientRequest request) { - if (this.maritalStatus != null) { + if (maritalStatus != null) { request.setPatientMaritalStatus(maritalStatus.getCodingFirstRep().getCode()); } } - private void addReligion(PixMergePatientRequest request) { - if (this.religion != null) { - request.setPatientReligiousAffiliation(religion.getText()); - } - } - private void addNation(PixMergePatientRequest request) { - if (this.nation != null) { + if (nation != null) { PRPAIN201304UV02Type rootElement = request.getRootElement(); PRPAMT201303UV02Person patientPerson = rootElement.getControlActProcess().getSubject().get(0) .getRegistrationEvent() @@ -199,62 +172,85 @@ private void addNation(PixMergePatientRequest request) { } - private void addAddresses(PixMergePatientRequest request) { - for (Address address : this.addresses) { - request.addPatientAddress(PixPdqV3Utils.createAd(address)); + private void addNonMedicalIdentifiers(PixMergePatientRequest request) { + for (Identifier identifier : nonMedicalIdentifiers) { + if ((identifier.getSystem().length() > 8)) { + final String oid = FhirCommon.removeUrnOidPrefix(identifier.getSystem()); + request.addPatientOtherID(identifier.getValue(), oid); + } } } - private void addPatientsMothersMaidenName(PixMergePatientRequest request) { - if (this.mothersMaidenName != null) { - request.setPatientMothersMaidenName(mothersMaidenName.getFamily(), mothersMaidenName.getGivenAsSingleString(), - null, - mothersMaidenName.getPrefixAsSingleString(), mothersMaidenName.getSuffixAsSingleString()); + private void addObsoletePatientId(PixMergePatientRequest request) { + request.setObsoletePatientID(obsoletePatientID, homeCommunityOID, homeCommunityNamespace); + } + + private void addPatientBirthday(PixMergePatientRequest request) { + if (birthday != null) { + DateType birthdate = new DateType(); + birthdate.setValue(birthday); + request.setPatientBirthTime(birthdate.getValueAsString().replace("-", "")); } } private void addPatientGender(PixMergePatientRequest request) { - if (this.gender != null) { + if (gender != null) { request.setPatientGender(ConverterUtil.convertAdministrativeGenderToSingleCharString(gender)); } } - private void addPatientBirthday(PixMergePatientRequest request) { - if (this.birthday != null) { - DateType birthdate = new DateType(); - birthdate.setValue(this.birthday); - request.setPatientBirthTime(birthdate.getValueAsString().replace("-", "")); + private void addPatientName(PixMergePatientRequest request) { + if (patientName != null) { + request.addPatientName(patientName.getFamily(), patientName.getGivenAsSingleString(), null, + patientName.getPrefixAsSingleString(), patientName.getSuffixAsSingleString()); } } - private void addPatientName(PixMergePatientRequest request) { - if (this.patientName != null) { - request.addPatientName(this.patientName.getFamily(), this.patientName.getGivenAsSingleString(), null, - this.patientName.getPrefixAsSingleString(), this.patientName.getSuffixAsSingleString()); + private void addPatientsMothersMaidenName(PixMergePatientRequest request) { + if (mothersMaidenName != null) { + request.setPatientMothersMaidenName(mothersMaidenName.getFamily(), mothersMaidenName.getGivenAsSingleString(), + null, + mothersMaidenName.getPrefixAsSingleString(), mothersMaidenName.getSuffixAsSingleString()); } } - private void addNonMedicalIdentifiers(PixMergePatientRequest request) { - for (Identifier identifier : this.nonMedicalIdentifiers) { - if ((identifier.getSystem().length() > 8)) { - final String oid = FhirCommon.removeUrnOidPrefix(identifier.getSystem()); - request.addPatientOtherID(identifier.getValue(), oid); - } + private void addProviderOrganization(PixMergePatientRequest request) { + if (providerOrganization == null && scopingOrganization != null) { + providerOrganization = scopingOrganization; } - } + if (providerOrganization != null) { + String organizationName = ""; + String telecomValue = "NOTPROVIDED"; - private void addIdentifiers(PixMergePatientRequest request) { - for (Identifier identifier : this.identifiers) { - if ((identifier.getSystem().length() > 8)) { - final String oid = FhirCommon.removeUrnOidPrefix(identifier.getSystem()); - if (this.homeCommunityOID != null && this.homeCommunityOID.equals(oid)) { - request.addPatientID(identifier.getValue(), this.homeCommunityOID, this.homeCommunityNamespace); - } else { - request.addPatientID(identifier.getValue(), oid, ""); + if (providerOrganization.getName() != null) { + organizationName = providerOrganization.getName(); + } + + if (providerOrganization.getTelecom() != null && !providerOrganization.getTelecom().isEmpty()) { + var contactPoint = providerOrganization.getTelecomFirstRep(); + if (contactPoint != null) { + telecomValue = contactPoint.getValue(); } } + request.setProviderOrganization(providerOrganization.getIdentifier(), organizationName, telecomValue); + } + } + + private void addReligion(PixMergePatientRequest request) { + if (religion != null) { + request.setPatientReligiousAffiliation(religion.getText()); } } + private void addTelecomContacts(PixMergePatientRequest request) { + PRPAIN201304UV02Type rootElement = request.getRootElement(); + PRPAMT201303UV02Person patientPerson = rootElement.getControlActProcess().getSubject().get(0).getRegistrationEvent() + .getSubject1().getPatient().getPatientPerson(); + + for (ContactPoint contactPoint : telecomContacts) { + patientPerson.getTelecom().add(V3PixSourceMessageHelper.createTEL(ConverterUtil.getTelecomValue(contactPoint), + ConverterUtil.getTelecomAddressUse(contactPoint))); + } + } } diff --git a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/xds/XdsDocumentSetRequest.java b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/xds/XdsDocumentSetRequest.java index cd128a19ff3..52ea924bb92 100644 --- a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/xds/XdsDocumentSetRequest.java +++ b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/xds/XdsDocumentSetRequest.java @@ -32,7 +32,7 @@ public class XdsDocumentSetRequest { @NonNull private Destination destination; - @NonNull + /** may be null for testing environments like the EPD Playground */ private SecurityHeaderElement xuaToken; @Singular private List documentRequests; diff --git a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/xds/XdsProvideAndRetrieveDocumentSetQuery.java b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/xds/XdsProvideAndRetrieveDocumentSetQuery.java index 5c2a921ca73..1efc2ad4dbd 100644 --- a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/xds/XdsProvideAndRetrieveDocumentSetQuery.java +++ b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/xds/XdsProvideAndRetrieveDocumentSetQuery.java @@ -29,7 +29,7 @@ public class XdsProvideAndRetrieveDocumentSetQuery { private List documentWithMetadata; @NotNull private SubmissionSetMetadata submissionSetMetadata; - @NotNull + /** may be null for testing environments like the EPD Playground */ private SecurityHeaderElement xuaToken; @NotNull private Destination destination; diff --git a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/xds/XdsRegistryStoredFindDocumentsQuery.java b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/xds/XdsRegistryStoredFindDocumentsQuery.java index f5f80143330..8eb115f4076 100644 --- a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/xds/XdsRegistryStoredFindDocumentsQuery.java +++ b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/requests/xds/XdsRegistryStoredFindDocumentsQuery.java @@ -54,7 +54,7 @@ public class XdsRegistryStoredFindDocumentsQuery { private Destination destination; @NonNull private Identificator patientID; - @NonNull + /** may be null for testing environments like the EPD Playground */ private SecurityHeaderElement xuaToken; @Singular("availabilityStatus") diff --git a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/responses/xua/XuaResponse.java b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/responses/xua/XuaResponse.java index 057c673079a..ae230fda39b 100644 --- a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/responses/xua/XuaResponse.java +++ b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/responses/xua/XuaResponse.java @@ -9,17 +9,77 @@ */ package org.projecthusky.communication.responses.xua; +import java.lang.reflect.Field; +import java.util.List; import javax.validation.constraints.NotNull; -import lombok.AllArgsConstructor; +import javax.xml.namespace.QName; import lombok.Getter; import lombok.ToString; -import org.projecthusky.xua.saml2.Assertion; +import lombok.extern.slf4j.Slf4j; +import org.opensaml.core.xml.XMLObject; +import org.opensaml.soap.wstrust.RequestSecurityTokenResponse; +import org.opensaml.soap.wstrust.RequestedSecurityToken; +import org.projecthusky.xua.communication.xua.XUserAssertionResponse; +import org.projecthusky.xua.communication.xua.impl.XUserAssertionResponseImpl; +import org.projecthusky.xua.saml2.impl.AssertionBuilderImpl; +import org.projecthusky.xua.saml2.impl.AssertionImpl; +/** + * Class holding the XUA assertion. + * + *

+ * Be aware: Most frameworks are using the org.opensaml implementation of the SAMLAssertion. + * For the Husky Framework, there is an own implementation of the Assertion, therefor, we will + * transform the standard Assertion into the husky assertion. + */ +@Slf4j @Getter -@AllArgsConstructor @ToString public class XuaResponse { @NotNull - private Assertion assertion; + private final org.projecthusky.xua.saml2.Assertion assertion; + + public XuaResponse(List xuaResponse) { + assertion = getXuaAssertionFromResponse(xuaResponse); + } + + /** + * Important - do NOT use new AssertionBuilderImpl().create(assertion) as it will break the DOM of + * the assertion object, e.g. the SignatureValue is removed! Therefor, we use reflection to avoid + * this problem. + */ + private org.projecthusky.xua.saml2.Assertion convertSamlToHuskyAssertion( + org.opensaml.saml.saml2.core.Assertion assertion) { + org.projecthusky.xua.saml2.Assertion huskyIdpAssertion = new AssertionBuilderImpl().create(); + setAssertion(huskyIdpAssertion, assertion); + return huskyIdpAssertion; + } + + private org.projecthusky.xua.saml2.Assertion getXuaAssertionFromResponse( + List response) { + RequestSecurityTokenResponse responseCollection = ((XUserAssertionResponseImpl) response.get(0)).getWrappedObject(); + + // copied from XUserAssertionResponseImpl, husky-xua-gen-impl + List requestedTokens = responseCollection.getUnknownXMLObjects(new QName( + "http://docs.oasis-open.org/ws-sx/ws-trust/200512", "RequestedSecurityToken")); + if (!requestedTokens.isEmpty()) { + RequestedSecurityToken token = (RequestedSecurityToken) requestedTokens.get(0); + org.opensaml.saml.saml2.core.Assertion openSamlAssertion = + (org.opensaml.saml.saml2.core.Assertion) token.getUnknownXMLObject(); + return convertSamlToHuskyAssertion(openSamlAssertion); + } + + throw new RuntimeException("Received XUA assertion does not contain any requestSecurityTokens."); + } + private void setAssertion(org.projecthusky.xua.saml2.Assertion huskyIdpAssertion, org.opensaml.saml.saml2.core.Assertion assertion) { + try { + Field field = AssertionImpl.class.getDeclaredField("assertion"); + field.setAccessible(true); + field.set(huskyIdpAssertion, assertion); + } catch (Exception ex) { + log.error("Converting opensaml assertion to husky assertion failed.", ex); + throw new RuntimeException(ex); + } + } } \ No newline at end of file diff --git a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/services/HuskyService.java b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/services/HuskyService.java index 2b5946a0564..1ebdddbafe9 100644 --- a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/services/HuskyService.java +++ b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/services/HuskyService.java @@ -9,13 +9,11 @@ */ package org.projecthusky.communication.services; -import java.io.IOException; - -import javax.xml.bind.DataBindingException; -import javax.xml.bind.JAXBException; -import javax.xml.parsers.ParserConfigurationException; - +import lombok.extern.slf4j.Slf4j; +import net.ihe.gazelle.hl7v3.mcciin000002UV01.MCCIIN000002UV01Type; +import net.ihe.gazelle.hl7v3.prpain201306UV02.PRPAIN201306UV02Type; import org.hl7.fhir.r4.model.Organization; +import org.openehealth.ipf.commons.audit.AuditContext; import org.openehealth.ipf.commons.ihe.hl7v3.core.responses.PixV3QueryResponse; import org.openehealth.ipf.commons.ihe.hpd.stub.dsmlv2.BatchResponse; import org.openehealth.ipf.commons.ihe.xds.core.requests.query.QueryReturnType; @@ -29,42 +27,35 @@ import org.projecthusky.common.model.Identificator; import org.projecthusky.common.model.Name; import org.projecthusky.common.model.Patient; -import org.projecthusky.communication.requests.xds.XdsDocumentWithMetadata; -import org.projecthusky.communication.requests.xds.XdsFindFoldersStoredQuery; +import org.projecthusky.communication.requests.hpd.HpdAddFeed; +import org.projecthusky.communication.requests.hpd.HpdBatchRequest; +import org.projecthusky.communication.requests.hpd.HpdDeleteFeed; +import org.projecthusky.communication.requests.hpd.HpdSearchQuery; import org.projecthusky.communication.requests.pdq.PdqSearchQuery; import org.projecthusky.communication.requests.pix.PixAddPatientFeed; import org.projecthusky.communication.requests.pix.PixMergePatientFeed; import org.projecthusky.communication.requests.pix.PixPatientIDQuery; import org.projecthusky.communication.requests.pix.PixUpdatePatientFeed; -import org.projecthusky.communication.requests.xds.XdsRegistryStoredFindDocumentsQuery; +import org.projecthusky.communication.requests.svs.SvsValueSetRequest; import org.projecthusky.communication.requests.xds.XdsDocumentSetRequest; +import org.projecthusky.communication.requests.xds.XdsDocumentWithMetadata; +import org.projecthusky.communication.requests.xds.XdsFindFoldersStoredQuery; import org.projecthusky.communication.requests.xds.XdsProvideAndRetrieveDocumentSetQuery; -import org.projecthusky.communication.requests.hpd.HpdAddFeed; -import org.projecthusky.communication.requests.hpd.HpdBatchRequest; -import org.projecthusky.communication.requests.hpd.HpdDeleteFeed; -import org.projecthusky.communication.requests.hpd.HpdSearchQuery; -import org.projecthusky.communication.requests.svs.SvsValueSetRequest; +import org.projecthusky.communication.requests.xds.XdsRegistryStoredFindDocumentsQuery; import org.projecthusky.communication.requests.xua.XuaRequest; -import org.projecthusky.communication.responses.pix.PixAddPatientResponse; import org.projecthusky.communication.responses.hpd.HpdResponse; -import org.projecthusky.communication.responses.pix.PixPatientIDResult; import org.projecthusky.communication.responses.pdq.PdqSearchQueryResponse; import org.projecthusky.communication.responses.pdq.PdqSearchResults; +import org.projecthusky.communication.responses.pix.PixAddPatientResponse; +import org.projecthusky.communication.responses.pix.PixPatientIDResult; import org.projecthusky.communication.responses.svs.SvsValueSetResponse; import org.projecthusky.communication.responses.xua.XuaResponse; import org.projecthusky.communication.utils.PdqUtils; import org.projecthusky.fhir.structures.gen.FhirPatient; -import org.projecthusky.valueset.exceptions.InitializationException; import org.projecthusky.xua.exceptions.ClientSendException; -import org.projecthusky.xua.exceptions.SerializeException; import org.springframework.stereotype.Component; import org.springframework.util.Assert; -import lombok.extern.slf4j.Slf4j; -import net.ihe.gazelle.hl7v3.mcciin000002UV01.MCCIIN000002UV01Type; -import net.ihe.gazelle.hl7v3.prpain201306UV02.PRPAIN201306UV02Type; -import org.xml.sax.SAXException; - /** * The main service class to use when working with the EPD web services. As it is marked as a @Component, it will be * immediately available in your application to reference.
It provides query building capabilities and executing @@ -121,16 +112,75 @@ public HuskyService(HuskyWebServiceClient wsClient) { //leverage constructor inj this.wsClient = wsClient; } + /** + * Gets the auditcontext used by the IPF Framework. + * + * @return {@link AuditContext} + */ + public AuditContext configAuditContext() { + return wsClient.getAuditContext(); + } + public void configAtna(AtnaConfig.AtnaConfigMode atna) { - this.wsClient.setAtnaConfigMode(atna); + wsClient.setAtnaConfigMode(atna); + } + + public void configMetadataExtractionMode(DocumentMetadataExtractionMode documentExtractionMode) { + wsClient.setDocumentMetadataExtractionMode(documentExtractionMode); } public void configSubmissionMode(SubmissionSetMetadataExtractionMode submissionSetExtractionMode) { - this.wsClient.setSubmissionSetMetadataExtractionMode(submissionSetExtractionMode); + wsClient.setSubmissionSetMetadataExtractionMode(submissionSetExtractionMode); } - public void configMetadataExtractionMode(DocumentMetadataExtractionMode documentExtractionMode) { - this.wsClient.setDocumentMetadataExtractionMode(documentExtractionMode); + /** + * This method will start building a {@link XdsDocumentSetRequest}, which allows the user to download the documents ofa + * Patient. + * + * @param destination {@link Destination} + * @return builder + */ + public XdsDocumentSetRequest.XdsDocumentSetRequestBuilder createDocumentSetRequest(Destination destination) { + return XdsDocumentSetRequest.builder().destination(destination); + } + + /** + * This method will start building a {@link XdsDocumentWithMetadata}, which will be used to build the + * {@link XdsProvideAndRetrieveDocumentSetQuery} + */ + public XdsDocumentWithMetadata.XdsDocumentWithMetadataBuilder createDocumentWithMetadata() { + return XdsDocumentWithMetadata.builder(); + } + + /** + * This method will start building a {@link XdsFindFoldersStoredQuery}, which allows the user to search the folders of a + * Patient. + */ + public XdsFindFoldersStoredQuery.XdsFindFoldersStoredQueryBuilder createFindFoldersStoredQuery() { + return XdsFindFoldersStoredQuery.builder(); + } + + /** This method will start building a {@link HpdAddFeed}, which is needed to create the HPD request */ + public HpdAddFeed createHpdAddFeed() { + return new HpdAddFeed(); + } + + /** This method will start building a {@link HpdBatchRequest}, which contain multiple HPD requests. + * The request also provides more options like how to process the request (sequential or in parallel), + * how to retrieve the response (sequential or unordered) and how to proceed in case of an error (resume or exit). + */ + public HpdBatchRequest.HpdBatchRequestBuilder createHpdBatchRequest() { + return HpdBatchRequest.builder(); + } + + /** This method will start building a {@link HpdDeleteFeed}, which is needed to create the HPD request */ + public HpdDeleteFeed createHpdDeleteFeed() { + return new HpdDeleteFeed(); + } + + /** This method will start building a {@link HpdSearchQuery}, which is needed to create the HPD request */ + public HpdSearchQuery.HpdSearchQueryBuilder createHpdSearchQuery() { + return HpdSearchQuery.builder(); } /** @@ -156,19 +206,12 @@ public PdqSearchQuery.PdqSearchQueryBuilder createPdqSearchQuery(Destination des return PdqSearchQuery.builder().destination(destination); } - /** - * Use this method to build a {@link PixPatientIDQuery}, where the user can ask for all IDs known of a patient. - */ - public PixPatientIDQuery.PixPatientIDQueryBuilder createPixPatientIDQuery(Destination destination) { - return PixPatientIDQuery.builder().destination(destination); - } - /** * This method will start building a {@link PixAddPatientFeed}, which allows the user to create a new Patient in the * system.
The properties of an {@link FhirPatient} are used as a template and expected to be filled. * - * @param destination - * @return PixAddPatientQueryBuilder + * @param destination {@link Destination} + * @return PixAddPatientQueryBuilder - to build the query * @see Registry Stored * Query @@ -178,12 +221,38 @@ public PixAddPatientFeed.PixAddPatientFeedBuilder createPixAddPatientFeed(Destin return PixAddPatientFeed.builder().destination(destination).providerOrganization(providerOrganization); } + /** + * Use this method to build a {@link PixMergePatientFeed}, with which the user can merge two know patient objects + * into one in case those two are the same person.
This case is mostly used to correct user errors when the same + * person is entered into a system multiple times and needs to be merged into one. + * + * @param destination {@link Destination} + * @param providerOrganization {@link Organization} + * @param obsoletePatientId - the ID of the patient that should be merged into the new one. + * @param homeCommunityOID - the OID of the home community + * @param homeCommunityNamespace - the namespace of the home community + * @return builder filled with default parameters + */ + public PixMergePatientFeed.PixMergePatientFeedBuilder createPixMergePatientFeed(Destination destination, + Organization providerOrganization, String obsoletePatientId, String homeCommunityOID, String homeCommunityNamespace) { + return PixMergePatientFeed.builder().destination(destination).providerOrganization(providerOrganization) + .obsoletePatientID(obsoletePatientId).homeCommunityOID(homeCommunityOID) + .homeCommunityNamespace(homeCommunityNamespace); + } + + /** + * Use this method to build a {@link PixPatientIDQuery}, where the user can ask for all IDs known of a patient. + */ + public PixPatientIDQuery.PixPatientIDQueryBuilder createPixPatientIDQuery(Destination destination) { + return PixPatientIDQuery.builder().destination(destination); + } + /** * This method will start building a {@link PixUpdatePatientFeed}, which allows the user to update an existing * patient in the system.
The properties of an {@link FhirPatient} are used, fill them accordingly. * - * @param destination - * @param providerOrganization + * @param destination {@link Destination} + * @param providerOrganization {@link Organization} * @return PixUpdatePatientFeedBuilder */ public PixUpdatePatientFeed.PixUpdatePatientFeedBuilder createPixUpdatePatientFeed(Destination destination, @@ -192,22 +261,11 @@ public PixUpdatePatientFeed.PixUpdatePatientFeedBuilder createPixUpdatePatientFe } /** - * Use this method to build a {@link PixMergePatientFeed}, with which the user can merge two know patient objects - * into one in case those two are the same person.
This case is mostly used to correct user errors when the same - * person is entered into a system multiple times and needs to be merged into one. - * - * @param destination - * @param providerOrganization - * @param obsolatePatientId - * @param homeCommunityOID - * @param homeCommunityNamespace - * @return + * This method will start building a {@link XdsProvideAndRetrieveDocumentSetQuery}, which will be sent to the webservice + * and allows the user to add or replace an existing document */ - public PixMergePatientFeed.PixMergePatientFeedBuilder createPixMergePatientFeed(Destination destination, - Organization providerOrganization, String obsolatePatientId, String homeCommunityOID, String homeCommunityNamespace) { - return PixMergePatientFeed.builder().destination(destination).providerOrganization(providerOrganization) - .obsolatePatientID(obsolatePatientId).homeCommunityOID(homeCommunityOID) - .homeCommunityNamespace(homeCommunityNamespace); + public XdsProvideAndRetrieveDocumentSetQuery.XdsProvideAndRetrieveDocumentSetQueryBuilder createProvideAndRetrieveDocumentSetQuery() { + return XdsProvideAndRetrieveDocumentSetQuery.builder(); } /** @@ -225,30 +283,10 @@ public PixMergePatientFeed.PixMergePatientFeedBuilder createPixMergePatientFeed( } /** - * This method will start building a {@link XdsDocumentSetRequest}, which allows the user to download the documents ofa - * Patient. - * - * @param destination - * @return - */ - public XdsDocumentSetRequest.XdsDocumentSetRequestBuilder createDocumentSetRequest(Destination destination) { - return XdsDocumentSetRequest.builder().destination(destination); - } - - /** - * This method will start building a {@link XdsDocumentWithMetadata}, which will be used to build the - * {@link XdsProvideAndRetrieveDocumentSetQuery} - */ - public XdsDocumentWithMetadata.XdsDocumentWithMetadataBuilder createDocumentWithMetadata() { - return XdsDocumentWithMetadata.builder(); - } - - /** - * This method will start building a {@link XdsProvideAndRetrieveDocumentSetQuery}, which will be sent to the webservice - * and allows the user to add or replace an existing document + * This method will start building a {@link SvsValueSetRequest}, which allows to download a value set */ - public XdsProvideAndRetrieveDocumentSetQuery.XdsProvideAndRetrieveDocumentSetQueryBuilder createProvideAndRetrieveDocumentSetQuery() { - return XdsProvideAndRetrieveDocumentSetQuery.builder(); + public SvsValueSetRequest.SvsValueSetRequestBuilder createValueSetRequest() { + return SvsValueSetRequest.builder(); } /** @@ -260,41 +298,31 @@ public XuaRequest.XuaRequestBuilder createXuaRequest() { } /** - * This method will start building a {@link XdsFindFoldersStoredQuery}, which allows the user to search the folders of a - * Patient. - */ - public XdsFindFoldersStoredQuery.XdsFindFoldersStoredQueryBuilder createFindFoldersStoredQuery() { - return XdsFindFoldersStoredQuery.builder(); - } - - /** - * This method will start building a {@link SvsValueSetRequest}, which allows to download a value set + * Creates {@link org.openehealth.ipf.commons.ihe.hpd.stub.dsmlv2.SearchRequest} which queries the Healthcare + * Provider Directory returning a {@link BatchResponse} containing informations regarding the: + * Individual Provider + * Organizational Provider + * Relationship + * + * Creates {@link org.openehealth.ipf.commons.ihe.hpd.stub.dsmlv2.AddRequest} which writes to the Healthcare + * Provider Directory a: Individual Provider, Organizational Provider or a Relationship returning a {@link BatchResponse} + * containing a response code for success and error + * + * Creates {@link org.openehealth.ipf.commons.ihe.hpd.stub.dsmlv2.DelRequest} which deletes from the Healthcare + * Provider Directory a: Individual Provider, Organizational Provider or a Relationship returning a {@link BatchResponse} + * containing a response code for success and error + * + * @param hpdBatchRequest contains a batch of {@link org.projecthusky.communication.requests.hpd.HpdRequest} + * + * @return {@link HpdResponse} + * @throws Exception thrown in the webservice call */ - public SvsValueSetRequest.SvsValueSetRequestBuilder createValueSetRequest() { - return SvsValueSetRequest.builder(); - } - - /** This method will start building a {@link HpdSearchQuery}, which is needed to create the HPD request */ - public HpdSearchQuery.HpdSearchQueryBuilder createHpdSearchQuery() { - return HpdSearchQuery.builder(); - } - - /** This method will start building a {@link HpdAddFeed}, which is needed to create the HPD request */ - public HpdAddFeed createHpdAddFeed() { - return new HpdAddFeed(); - } - - /** This method will start building a {@link HpdDeleteFeed}, which is needed to create the HPD request */ - public HpdDeleteFeed createHpdDeleteFeed() { - return new HpdDeleteFeed(); - } + public HpdResponse send(HpdBatchRequest hpdBatchRequest) throws Exception { + if (!hpdBatchRequest.isValid()) { + throw new IllegalArgumentException("Invalid request: mandatory constraints are not fulfilled!"); + } - /** This method will start building a {@link HpdBatchRequest}, which contain multiple HPD requests. - * The request also provides more options like how to process the request (sequential or in parallel), - * how to retrieve the response (sequential or unordered) and how to proceed in case of an error (resume or exit). - */ - public HpdBatchRequest.HpdBatchRequestBuilder createHpdBatchRequest() { - return HpdBatchRequest.builder(); + return wsClient.sendHpdBatchRequest(hpdBatchRequest); } /** @@ -302,19 +330,13 @@ public HpdBatchRequest.HpdBatchRequestBuilder createHpdBatchRequest() { * * @param patientSearchQuery A {@link PdqSearchQuery} previously built. * @return A {@link PdqSearchResults} object containing the matching {@link FhirPatient} objects in a list. - * @throws DataBindingException - * @throws JAXBException - * @throws ParserConfigurationException - * @throws SerializeException - * @throws IOException - * @throws RuntimeException - For errors/exceptions happening in the webservice there will be a - * RuntimeException wrapped SOAPException thrown. + * @throws Exception errors occurring in the webservice client + * @throws RuntimeException For errors/exceptions happening in the webservice there will be a RuntimeException wrapped SOAPException thrown. */ - public PdqSearchResults send(PdqSearchQuery patientSearchQuery) - throws DataBindingException, JAXBException, ParserConfigurationException, SerializeException, IOException { + public PdqSearchResults send(PdqSearchQuery patientSearchQuery) throws Exception { Assert.notNull(patientSearchQuery, "The search query can not be null."); log.debug("A Search Query is initiated for send: {}", patientSearchQuery); - PRPAIN201306UV02Type sendITI47Query = this.wsClient.sendPdqSearchQueryRequest(patientSearchQuery.build(), null, + PRPAIN201306UV02Type sendITI47Query = wsClient.sendPdqSearchQueryRequest(patientSearchQuery.build(), null, patientSearchQuery.getDestination().getUri(), null); PdqSearchQueryResponse response = new PdqSearchQueryResponse(sendITI47Query); PdqSearchResults results = new PdqSearchResults( @@ -327,60 +349,31 @@ public PdqSearchResults send(PdqSearchQuery patientSearchQuery) * Send your built {@link PixAddPatientFeed} through the Internet to the webservice and receive an answer, whether * the Patient was added or not. * - * @param addPatientFeed + * @param addPatientFeed {@link PixAddPatientFeed} * @return True if the patient was added without error. Errors are reported as exceptions. - * @throws JAXBException - * @throws SerializeException - * @throws ParserConfigurationException - * @throws IOException - * @throws RuntimeException - For errors/exceptions happening in the webservice there will be a - * RuntimeException wrapped SOAPException thrown. + * @throws Exception errors occurring in the webservice client + * @throws RuntimeException For errors/exceptions happening in the webservice there will be a RuntimeException wrapped SOAPException thrown. */ - public boolean send(PixAddPatientFeed addPatientFeed) - throws JAXBException, SerializeException, ParserConfigurationException, IOException { + public boolean send(PixAddPatientFeed addPatientFeed) throws Exception { Assert.notNull(addPatientFeed, "The patient creation query can not be null."); - MCCIIN000002UV01Type iti44QueryResponseType = this.wsClient.sendPixAddPatientRequest( + MCCIIN000002UV01Type iti44QueryResponseType = wsClient.sendPixAddPatientRequest( addPatientFeed.build().getRootElement(), null, addPatientFeed.getDestination().getUri(), "urn:hl7-org:v3:PRPA_IN201301UV02", null); PixAddPatientResponse response = new PixAddPatientResponse(iti44QueryResponseType); return !response.hasError(); //Inverting error flag to indicate success with true returned. } - /** - * Send your built {@link PixUpdatePatientFeed} through the Internet to the webservice and receive an answer (updated - * or error). - * - * @param updatePatientFeed - * @return True if the patient was updated without error. Errors are reported as exceptions. - * @throws JAXBException - * @throws SerializeException - * @throws ParserConfigurationException - * @throws IOException - */ - public boolean send(PixUpdatePatientFeed updatePatientFeed) - throws JAXBException, SerializeException, ParserConfigurationException, IOException { - Assert.notNull(updatePatientFeed, "The patient update query can not be null."); - MCCIIN000002UV01Type iti44QueryResponseType = this.wsClient.sendPixUpdatePatientRequest( - updatePatientFeed.build().getRootElement(), null, updatePatientFeed.getDestination().getUri(), - "urn:hl7-org:v3:PRPA_IN201302UV02", null); - PixAddPatientResponse response = new PixAddPatientResponse(iti44QueryResponseType); - return !response.hasError(); //Inverting error flag to indicate success with true returned. - } - /** * Send the built {@link PixMergePatientFeed} through the Internet to the webservice and receive an answer. * - * @param mergePatientFeed - * @return - * @throws JAXBException - * @throws SerializeException - * @throws ParserConfigurationException - * @throws IOException + * @param mergePatientFeed {@link PixMergePatientFeed} + * @return True if the patient was updated without error. Errors are reported as exceptions. + * @throws Exception errors occurring in the webservice client + * @throws RuntimeException For errors/exceptions happening in the webservice there will be a RuntimeException wrapped SOAPException thrown. */ - public boolean send(PixMergePatientFeed mergePatientFeed) - throws JAXBException, SerializeException, ParserConfigurationException, IOException { + public boolean send(PixMergePatientFeed mergePatientFeed) throws Exception { Assert.notNull(mergePatientFeed, "The patient merge query can not be null."); - MCCIIN000002UV01Type mergePatientXMLResponse = this.wsClient.sendITI44Query( + MCCIIN000002UV01Type mergePatientXMLResponse = wsClient.sendITI44Query( mergePatientFeed.build().getRootElement(), null, mergePatientFeed.getDestination().getUri(), "urn:hl7-org:v3:PRPA_IN201304UV02", null); PixAddPatientResponse response = new PixAddPatientResponse(mergePatientXMLResponse); @@ -390,58 +383,76 @@ public boolean send(PixMergePatientFeed mergePatientFeed) /** * Send the built {@link PixPatientIDQuery} through the Internet to the webservice and receive an answer. * - * @param searchPatientIDQuery - * @return - * @throws Exception + * @param searchPatientIDQuery {@link PixPatientIDQuery} + * @return {@link PixPatientIDResult} + * @throws Exception thrown in the webservice call */ public PixPatientIDResult send(PixPatientIDQuery searchPatientIDQuery) throws Exception { Assert.notNull(searchPatientIDQuery, "The patient ID search query can not be null."); - PixV3QueryResponse response = this.wsClient.sendQuery(searchPatientIDQuery.build(), null, + PixV3QueryResponse response = wsClient.sendQuery(searchPatientIDQuery.build(), null, searchPatientIDQuery.getDestination().getUri(), null); PixPatientIDResult.PixPatientIDResultBuilder result = PixPatientIDResult.builder(); for (String domainId : searchPatientIDQuery.getQueryDomainOids()) { result.patientID(PdqUtils.getPatientDomainId(response, domainId)); } + return result.build(); } /** - * Send your built {@link XdsDocumentSetRequest} through the Internet to the webservice and receive the documents of the - * Patient. + * Send your built {@link PixUpdatePatientFeed} through the Internet to the webservice and receive an answer (updated + * or error). * - * @param retrievedDocumentsRequest - * @return - * @throws SerializeException - * @throws ParserConfigurationException - * @throws IOException + * @param updatePatientFeed {@link PixUpdatePatientFeed} + * @return True if the patient was updated without error. Errors are reported as exceptions. + * @throws Exception errors occurring in the webservice client + * @throws RuntimeException For errors/exceptions happening in the webservice there will be a RuntimeException wrapped SOAPException thrown. */ - public RetrievedDocumentSet send(XdsDocumentSetRequest retrievedDocumentsRequest) - throws SerializeException, ParserConfigurationException, IOException { - Assert.notNull(retrievedDocumentsRequest, "The document set request query can not be null."); - return this.wsClient.send(retrievedDocumentsRequest, retrievedDocumentsRequest.getDestination().getUri(), null); + public boolean send(PixUpdatePatientFeed updatePatientFeed) throws Exception { + Assert.notNull(updatePatientFeed, "The patient update query can not be null."); + MCCIIN000002UV01Type iti44QueryResponseType = wsClient.sendPixUpdatePatientRequest( + updatePatientFeed.build().getRootElement(), null, updatePatientFeed.getDestination().getUri(), + "urn:hl7-org:v3:PRPA_IN201302UV02", null); + PixAddPatientResponse response = new PixAddPatientResponse(iti44QueryResponseType); + return !response.hasError(); //Inverting error flag to indicate success with true returned. } /** - * Send your built {@link XdsRegistryStoredFindDocumentsQuery} through the Internet to the webservice and receive the - * document handlers. + *

Downloads a value set as defined in the given configuration, + * or in raw dformat exactly as downloaded
+ * @param valueSetRequest request used to create the value set config + * @param isUseRaw flag that signals if the response is needed in raw dformat + * @return ValueSetResponse object that contains both formats of the response + * @throws Exception thrown in the webservice call + */ + public SvsValueSetResponse send(SvsValueSetRequest valueSetRequest, boolean isUseRaw) throws Exception { + return wsClient.downloadValueSet(valueSetRequest, isUseRaw); + } + + /** + * Send your built {@link XdsDocumentSetRequest} through the Internet to the webservice and receive the documents of the + * Patient. * - * @return {@link QueryResponse} - * @throws Exception + * @param retrievedDocumentsRequest {@link XdsDocumentSetRequest} + * @return {@link RetrievedDocumentSet} + * @throws Exception errors occurring in the webservice client + * @throws RuntimeException For errors/exceptions happening in the webservice there will be a RuntimeException wrapped SOAPException thrown. */ - public QueryResponse send(XdsRegistryStoredFindDocumentsQuery query) throws Exception { - Assert.notNull(query, "The find documents query can not be null."); - return this.wsClient.sendRegistryStoredFindDocumentsQuery(query, query.getDestination().getUri(), - QueryReturnType.LEAF_CLASS, null); + public RetrievedDocumentSet send(XdsDocumentSetRequest retrievedDocumentsRequest) + throws Exception { + Assert.notNull(retrievedDocumentsRequest, "The document set request query can not be null."); + return wsClient.send(retrievedDocumentsRequest, retrievedDocumentsRequest.getDestination().getUri(), null); } /** - * Use the {@link XuaRequest} which is sent to the webservice and returns details about the identity of the authenticated user + * Send your built {@link XdsFindFoldersStoredQuery} to the webservice to find folders (XDSFolder objects) in the + * registry for a given patientID with matching 'status' attribute * - * @return {@link XuaResponse} - * @throws ClientSendException + * @return {@link QueryResponse} + * @throws Exception thrown in the webservice call */ - public XuaResponse send(XuaRequest xuaRequest) throws ClientSendException { - return this.wsClient.send(xuaRequest); + public QueryResponse send(XdsFindFoldersStoredQuery findFoldersStoredQuery) throws Exception { + return wsClient.sendQueryFoldersRequest(findFoldersStoredQuery); } /** @@ -449,74 +460,33 @@ public XuaResponse send(XuaRequest xuaRequest) throws ClientSendException { * sent to the webservice and adds or replaces an existing document * * @return {@link Response} - * @throws SerializeException - * @throws ParserConfigurationException - * @throws IOException + * @throws Exception thrown in the webservice call */ - public Response send(XdsProvideAndRetrieveDocumentSetQuery documentSet) - throws SerializeException, ParserConfigurationException, IOException { - return this.wsClient.sendProvideAndRegisterDocumentSetRequest(documentSet); + public Response send(XdsProvideAndRetrieveDocumentSetQuery documentSet) throws Exception { + return wsClient.sendProvideAndRegisterDocumentSetRequest(documentSet); } /** - * Send your built {@link XdsFindFoldersStoredQuery} to the webservice to find folders (XDSFolder objects) in the - * registry for a given patientID with matching 'status' attribute + * Send your built {@link XdsRegistryStoredFindDocumentsQuery} through the Internet to the webservice and receive the + * document handlers. * * @return {@link QueryResponse} - * @throws SerializeException - * @throws ParserConfigurationException - * @throws IOException - */ - public QueryResponse send(XdsFindFoldersStoredQuery findFoldersStoredQuery) - throws SerializeException, ParserConfigurationException, IOException { - return this.wsClient.sendQueryFoldersRequest(findFoldersStoredQuery); - } - - /** - *
Downloads a value set as defined in the given configuration, - * or in raw dformat exactly as downloaded
- * @param valueSetRequest request used to create the value set config - * @param isUseRaw flag that signals if the response is needed in raw dformat - * @return ValueSetResponse object that contains both formats of the response - * @throws IOException Signals that an I/O exception has - * occurred. - * @throws SAXException - * @throws ParserConfigurationException - * @throws InitializationException + * @throws Exception errors occurring in the webservice client + * @throws RuntimeException For errors/exceptions happening in the webservice there will be a RuntimeException wrapped SOAPException thrown. */ - public SvsValueSetResponse send(SvsValueSetRequest valueSetRequest, boolean isUseRaw) - throws IOException, ParserConfigurationException, InitializationException, SAXException { - return this.wsClient.downloadValueSet(valueSetRequest, isUseRaw); + public QueryResponse send(XdsRegistryStoredFindDocumentsQuery query) throws Exception { + Assert.notNull(query, "The find documents query can not be null."); + return wsClient.sendRegistryStoredFindDocumentsQuery(query, query.getDestination().getUri(), + QueryReturnType.LEAF_CLASS, null); } /** - * Creates {@link org.openehealth.ipf.commons.ihe.hpd.stub.dsmlv2.SearchRequest} which queries the Healthcare - * Provider Directory returning a {@link BatchResponse} containing informations regarding the: - * Individual Provider - * Organizational Provider - * Relationship - * - * Creates {@link org.openehealth.ipf.commons.ihe.hpd.stub.dsmlv2.AddRequest} which writes to the Healthcare - * Provider Directory a: Individual Provider, Organizational Provider or a Relationship returning a {@link BatchResponse} - * containing a response code for success and error - * - * Creates {@link org.openehealth.ipf.commons.ihe.hpd.stub.dsmlv2.DelRequest} which deletes from the Healthcare - * Provider Directory a: Individual Provider, Organizational Provider or a Relationship returning a {@link BatchResponse} - * containing a response code for success and error - * - * @param hpdBatchRequest contains a batch of {@link org.projecthusky.communication.requests.hpd.HpdRequest} + * Use the {@link XuaRequest} which is sent to the webservice and returns details about the identity of the authenticated user * - * @return {@link HpdResponse} - * @throws SerializeException - * @throws JAXBException - * @throws ParserConfigurationException - * @throws IOException + * @return {@link XuaResponse} + * @throws ClientSendException thrown in the xua call */ - public HpdResponse send(HpdBatchRequest hpdBatchRequest) - throws SerializeException, JAXBException, ParserConfigurationException, IOException { - if (!hpdBatchRequest.isValid()) { - throw new IllegalArgumentException("Invalid request: mandatory constraints are not fulfilled!"); - } - return this.wsClient.sendHpdBatchRequest(hpdBatchRequest); + public XuaResponse send(XuaRequest xuaRequest) throws ClientSendException { + return wsClient.send(xuaRequest); } } \ No newline at end of file diff --git a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/services/HuskyWebServiceClient.java b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/services/HuskyWebServiceClient.java index 82c99b8c234..7bca2fbc025 100644 --- a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/services/HuskyWebServiceClient.java +++ b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/services/HuskyWebServiceClient.java @@ -71,15 +71,15 @@ import org.projecthusky.common.utils.xml.XmlMarshaller; import org.projecthusky.common.utils.xml.XmlUnmarshaller; import org.projecthusky.communication.DocumentRequest; -import org.projecthusky.communication.requests.hpd.HpdRequest; -import org.projecthusky.communication.requests.xds.XdsFindFoldersStoredQuery; -import org.projecthusky.communication.requests.xds.XdsProvideAndRetrieveDocumentSetQuery; -import org.projecthusky.communication.requests.xds.XdsRegistryStoredFindDocumentsQuery; -import org.projecthusky.communication.requests.xds.XdsDocumentSetRequest; import org.projecthusky.communication.requests.hpd.HpdBatchRequest; +import org.projecthusky.communication.requests.hpd.HpdRequest; import org.projecthusky.communication.requests.hpd.HpdSearchQuery; import org.projecthusky.communication.requests.pdq.PdqQuery; import org.projecthusky.communication.requests.svs.SvsValueSetRequest; +import org.projecthusky.communication.requests.xds.XdsDocumentSetRequest; +import org.projecthusky.communication.requests.xds.XdsFindFoldersStoredQuery; +import org.projecthusky.communication.requests.xds.XdsProvideAndRetrieveDocumentSetQuery; +import org.projecthusky.communication.requests.xds.XdsRegistryStoredFindDocumentsQuery; import org.projecthusky.communication.requests.xua.XuaRequest; import org.projecthusky.communication.responses.hpd.HpdFeedResponse; import org.projecthusky.communication.responses.hpd.HpdQueryResponse; @@ -118,441 +118,435 @@ @Component @Slf4j public class HuskyWebServiceClient { - private static final String LOG_SEND_REQUEST = "Sending request to '{}' endpoint"; - - @Getter - @Setter - /** The ATNA config mode (secure or unsecure) */ - private AtnaConfig.AtnaConfigMode atnaConfigMode = AtnaConfigMode.UNSECURE; - - @Getter - @Setter - /** - * Determines if XDS document metadata will be extracted automatically (e.g. - * from CDA documents - */ - private DocumentMetadataExtractionMode documentMetadataExtractionMode = DocumentMetadataExtractionMode.DEFAULT_EXTRACTION; - - @Getter - @Setter - private SubmissionSetMetadataExtractionMode submissionSetMetadataExtractionMode = SubmissionSetMetadataExtractionMode.DEFAULT_EXTRACTION; - - private final CamelContext camelContext; - private final AuditContext auditContext; - - public HuskyWebServiceClient(final CamelContext camelContext, final AuditContext auditContext) { - this.camelContext = camelContext; - this.auditContext = auditContext; - } - - protected void addWssHeader(SecurityHeaderElement securityHeaderElement, Exchange exchange) - throws SerializeException, ParserConfigurationException { - log.debug("Adding WSS Headers..."); - Element wssElement = new OpenSaml2SerializerImpl() - .serializeToXml((XMLObject) securityHeaderElement.getWrappedObject()); - - DocumentBuilder docBuilder = XmlFactories.newSafeDocumentBuilder(); - Document doc = docBuilder.newDocument(); - - Element wsseElement = doc.createElementNS( - "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", - "wsse:Security"); - - QName wsseQName = new QName( - "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", - "Security", "wsse"); - - Node replaceNode = wsseElement.getOwnerDocument().importNode(wssElement, true); - wsseElement.appendChild(replaceNode); - - Map soapHeaders = CastUtils - .cast((Map) exchange.getIn() - .getHeader(AbstractWsEndpoint.OUTGOING_SOAP_HEADERS)); - - if (soapHeaders == null) { - soapHeaders = new HashMap<>(); - } - - try { - Header newHeader = new Header(wsseQName, wsseElement); - newHeader.setDirection(Direction.DIRECTION_OUT); - soapHeaders.put(wsseQName, newHeader); - exchange.getIn().setHeader(AbstractWsEndpoint.OUTGOING_SOAP_HEADERS, soapHeaders); - } catch (Exception e) { - log.error("Exception caught while creating the WSS header", e); - } - - } - - protected void addHttpHeader(Exchange exchange, Map outgoingHttpHeaders) { - log.debug("Adding HTTP Headers..."); - Map outgoingHeaders = CastUtils.cast((Map) exchange.getIn() - .getHeader(AbstractWsEndpoint.OUTGOING_HTTP_HEADERS)); - - if (outgoingHeaders == null) { - outgoingHeaders = new HashMap<>(); - } - - for (Entry entry : outgoingHttpHeaders.entrySet()) { - if (entry != null && entry.getValue() != null && entry.getKey() != null) { - outgoingHeaders.put(entry.getKey(), entry.getValue()); - } - } - - exchange.getIn().setHeader(AbstractWsEndpoint.OUTGOING_HTTP_HEADERS, outgoingHeaders); - } - - public Exchange send(String endpoint, Object body, SecurityHeaderElement securityHeaderElement, - String messageId, Map outgoingHttpHeaders) - throws SerializeException, ParserConfigurationException, IOException { - log.debug("Sending message..."); - Exchange exchange = new DefaultExchange(camelContext); - exchange.getIn().setBody(body); - - if (securityHeaderElement != null) { - addWssHeader(securityHeaderElement, exchange); - } - - if (outgoingHttpHeaders != null && !outgoingHttpHeaders.isEmpty()) { - addHttpHeader(exchange, outgoingHttpHeaders); - } - - try (ProducerTemplate template = camelContext.createProducerTemplate()) { - Exchange result = template.send(endpoint, exchange); - if (result.getException() != null) { - throw new RuntimeException(result.getException()); - } - return result; - } - } - - public PRPAIN201306UV02Type sendPdqSearchQueryRequest(PdqQuery request, - SecurityHeaderElement security, URI pdqDest, String messageId) throws JAXBException, - DataBindingException, ParserConfigurationException, SerializeException, IOException { - - String endpoint = HuskyUtils.createEndpoint( - PDQV3.Interactions.ITI_47.getWsTransactionConfiguration().getName(), // - pdqDest, // - pdqDest.toString().contains(HuskyUtils.HTTPS_LITERAL), // - this.atnaConfigMode.equals(AtnaConfigMode.SECURE)); - - String message = XmlMarshaller.marshall(request.getRootElement()); - - Map outgoingHeaders = new HashMap<>(); - outgoingHeaders.put("Accept", "application/soap+xml"); - outgoingHeaders.put("Content-Type", - "application/soap+xml; charset=UTF-8; action=\"urn:hl7-org:v3:PRPA_IN201305UV02\""); - - Exchange exchange = this.send(endpoint, message, security, messageId, outgoingHeaders); - - String xml = exchange.getMessage().getBody(String.class); - - return XmlUnmarshaller.unmarshallStringAsType(xml, PRPAIN201306UV02Type.class); - } - - public MCCIIN000002UV01Type sendPixAddPatientRequest(PRPAIN201301UV02Type request, - SecurityHeaderElement assertion, URI pdqDest, String action, String messageId) - throws JAXBException, SerializeException, ParserConfigurationException, IOException { - Marshaller marshaller = createMarshaller( - JAXBContext.newInstance(PRPAIN201301UV02Type.class)); - - StringWriter stringWriter = new StringWriter(); - marshaller.marshal(request, stringWriter); - - String xml = sendITI44Query(stringWriter.toString(), assertion, pdqDest, action, messageId); - - Unmarshaller unmarshaller = JAXBContext.newInstance(MCCIIN000002UV01Type.class) - .createUnmarshaller(); - return (MCCIIN000002UV01Type) unmarshaller - .unmarshal(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); - } - - public MCCIIN000002UV01Type sendPixUpdatePatientRequest(PRPAIN201302UV02Type request, - SecurityHeaderElement assertion, URI pdqDest, String action, String messageId) - throws JAXBException, SerializeException, ParserConfigurationException, IOException { - Marshaller marshaller = createMarshaller( - JAXBContext.newInstance(PRPAIN201302UV02Type.class)); - - StringWriter stringWriter = new StringWriter(); - marshaller.marshal(request, stringWriter); - - String xml = sendITI44Query(stringWriter.toString(), assertion, pdqDest, action, messageId); - - Unmarshaller unmarshaller = JAXBContext.newInstance(MCCIIN000002UV01Type.class) - .createUnmarshaller(); - return (MCCIIN000002UV01Type) unmarshaller - .unmarshal(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); - } - - public MCCIIN000002UV01Type sendITI44Query(PRPAIN201304UV02Type request, - SecurityHeaderElement assertion, URI pdqDest, String action, String messageId) - throws JAXBException, SerializeException, ParserConfigurationException, IOException { - - Marshaller marshaller = createMarshaller( - JAXBContext.newInstance(PRPAIN201304UV02Type.class)); - - StringWriter stringWriter = new StringWriter(); - marshaller.marshal(request, stringWriter); - - String xml = sendITI44Query(stringWriter.toString(), assertion, pdqDest, action, messageId); - - Unmarshaller unmarshaller = JAXBContext.newInstance(MCCIIN000002UV01Type.class) - .createUnmarshaller(); - return (MCCIIN000002UV01Type) unmarshaller - .unmarshal(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); - } - - private String sendITI44Query(String request, SecurityHeaderElement assertion, URI pdqDest, - String action, String messageId) - throws SerializeException, ParserConfigurationException, IOException { - String endpoint = HuskyUtils.createEndpoint( - PIXV3.Interactions.ITI_44_PIX.getWsTransactionConfiguration().getName(), // - pdqDest, // - pdqDest.toString().contains(HuskyUtils.HTTPS_LITERAL), // - this.atnaConfigMode.equals(AtnaConfigMode.SECURE)); - - log.info("Sending request to '{}' endpoint", endpoint); - - Map outgoingHeaders = new HashMap<>(); - outgoingHeaders.put("Accept", "application/soap+xml"); - outgoingHeaders.put("Content-Type", - String.format("application/soap+xml; charset=UTF-8; action=\"%s\"", action)); - - Exchange exchange = send(endpoint, request, assertion, messageId, outgoingHeaders); - - return exchange.getMessage().getBody(String.class); - } - - public PixV3QueryResponse sendQuery(PixV3QueryRequest request, SecurityHeaderElement assertion, - URI pdqDest, String messageId) throws Exception { - String endpoint = HuskyUtils.createEndpoint( - PIXV3.Interactions.ITI_45.getWsTransactionConfiguration().getName(), // - pdqDest, // - pdqDest.toString().contains(HuskyUtils.HTTPS_LITERAL), // - this.atnaConfigMode.equals(AtnaConfigMode.SECURE)); - - Map outgoingHeaders = new HashMap<>(); - outgoingHeaders.put("Accept", "application/soap+xml"); - outgoingHeaders.put("Content-Type", - "application/soap+xml; charset=UTF-8; action=\"urn:hl7-org:v3:PRPA_IN201309UV02\""); - - Exchange exchange = send(endpoint, request, assertion, messageId, outgoingHeaders); - - return exchange.getMessage().getBody(PixV3QueryResponse.class); - } - - public QueryResponse sendRegistryStoredFindDocumentsQuery(XdsRegistryStoredFindDocumentsQuery query, URI destination, - QueryReturnType returnType, String messageId) throws SerializeException, ParserConfigurationException, IOException { - QueryRegistry queryRegistry = new QueryRegistry(query.getIpfQuery()); - queryRegistry.setReturnType(returnType); - - // String endpoint = createEndpoint(destination.toString(), XDS_ITI18); - final String strippedUrl = destination.toString().replace(HuskyUtils.HTTPS_LITERAL, "") - .replace(HuskyUtils.HTTP_LITERAL, ""); - String endpoint = HuskyUtils.createEndpoint( - XDS.Interactions.ITI_18.getWsTransactionConfiguration().getName(), // - strippedUrl, // - destination.toString().contains(HuskyUtils.HTTPS_LITERAL), // - this.atnaConfigMode.equals(AtnaConfigMode.SECURE)); - Exchange exchange = send(endpoint, queryRegistry, query.getXuaToken(), messageId, null); - - return exchange.getMessage().getBody(QueryResponse.class); - } - - public RetrievedDocumentSet send(XdsDocumentSetRequest request, URI destination, String messageId) - throws SerializeException, ParserConfigurationException, IOException { - RetrieveDocumentSet retrieveDocumentSet = new RetrieveDocumentSet(); - - for (final DocumentRequest element : request.getDocumentRequests()) { - if (element != null) { - retrieveDocumentSet.addReferenceTo(element.getIpfDocumentEntry()); - } - } - - String endpoint = HuskyUtils.createEndpoint( - XDS.Interactions.ITI_43.getWsTransactionConfiguration().getName(), // - destination, // - this.atnaConfigMode.equals(AtnaConfigMode.SECURE)); - Exchange exchange = send(endpoint, retrieveDocumentSet, request.getXuaToken(), messageId, null); - - return exchange.getMessage().getBody(RetrievedDocumentSet.class); - } - - /** - * It implements the following IHE transaction: [ITI-40] Provide Identity - * Assertions - */ - public XuaResponse send(XuaRequest xuaRequest) throws ClientSendException { - SimpleXuaClient xuaClient = new SimpleXuaClient(createXuaClientConfig(xuaRequest)); - - List xuaResponses = xuaClient.send(xuaRequest.getIdpAssertion(), - xuaRequest.build()); - - // TODO: Fix implementation of the AssertionBuilderImpl to retrieve the - // Assertion with the signature in place - return new XuaResponse(xuaResponses.get(0).getAssertion()); - } - - /** - * It implements the following IHE transaction: [ITI-41] Provide and - * Register Document Set – b - *

- * Using this method, both extraction modes can be set explicitly, e.g. if - * the default option is not suitable for all kinds of request. - */ - public Response sendProvideAndRegisterDocumentSetRequest( - XdsProvideAndRetrieveDocumentSetQuery documentSet, - SubmissionSetMetadataExtractionMode extractionMode, - DocumentMetadataExtractionMode documentMetadataExtractionMode) - throws SerializeException, ParserConfigurationException, IOException { - ProvideAndRegisterDocumentSet txnData = createProvideAndRegisterDocumentSet(documentSet); - - documentSet.getDocumentWithMetadata().forEach(docMetadata -> XDSUtils - .addDocument(docMetadata, txnData, documentMetadataExtractionMode)); - - XDSUtils.setDefaultKeystoreTruststore(documentSet.getDestination()); - - if (extractionMode == SubmissionSetMetadataExtractionMode.DEFAULT_EXTRACTION) { - log.debug("extract submission set metadata"); - XDSUtils.generateDefaultSubmissionSetAttributes(txnData); - XDSUtils.linkDocumentEntryWithSubmissionSet(txnData); - } - - if (documentSet.getAssociation() != null) { - txnData.getAssociations().add(documentSet.getAssociation()); - log.debug("set association data"); - if (txnData.getDocuments() != null && !txnData.getDocuments().isEmpty() - && txnData.getDocuments().get(0) != null) { - documentSet.getAssociation().setSourceUuid( - txnData.getDocuments().get(0).getDocumentEntry().getEntryUuid()); - } else if (txnData.getFolders() != null && !txnData.getFolders().isEmpty() - && txnData.getFolders().get(0) != null) { - documentSet.getAssociation() - .setSourceUuid(txnData.getFolders().get(0).getEntryUuid()); - } - } - - log.debug("prepare submit of document"); - String endpoint = HuskyUtils.createEndpoint( - XDS.Interactions.ITI_41.getWsTransactionConfiguration().getName(), // - documentSet.getDestination().getUri(), // - this.atnaConfigMode.equals(AtnaConfigMode.SECURE)); - - Exchange exchange = send(endpoint, txnData, documentSet.getXuaToken(), null, null); - - return exchange.getMessage().getBody(Response.class); - } - - public Response sendProvideAndRegisterDocumentSetRequest( - XdsProvideAndRetrieveDocumentSetQuery documentSet) - throws SerializeException, ParserConfigurationException, IOException { - return sendProvideAndRegisterDocumentSetRequest(documentSet, - submissionSetMetadataExtractionMode, documentMetadataExtractionMode); - } - - /** It implements the following IHE transaction: [ITI-18] Find folders */ - public QueryResponse sendQueryFoldersRequest(XdsFindFoldersStoredQuery findFoldersStoredQuery) - throws SerializeException, ParserConfigurationException, IOException { - return this.sendRegistryStoredFindDocumentsQuery(findFoldersStoredQuery, findFoldersStoredQuery.getDestination().getUri(), - QueryReturnType.LEAF_CLASS, null); - } - - /** - * It implements the following IHE transaction: [ITI-48] Retrieve value set - * and value set raw - */ - public SvsValueSetResponse downloadValueSet(SvsValueSetRequest valueSetRequest, - boolean isUseRaw) throws IOException, ParserConfigurationException, - InitializationException, SAXException { - ValueSetConfig valueSetConfig = valueSetRequest.build(); - ValueSetManager valueSetManager = new ValueSetManager(); - return isUseRaw - ? SvsValueSetResponse.builder() - .valueSetRaw(valueSetManager.downloadValueSetRaw(valueSetConfig)).build() - : SvsValueSetResponse.builder() - .valueSet(valueSetManager.downloadValueSet(valueSetConfig)).build(); - } - - /** - * It implements the following IHE transactions: [ITI-58] Provider - * Information Query - Search Request [ITI-59] Provider Information Feed - - * Add Request [ITI-59] Provider Information Feed - Delete Request - */ - public HpdResponse sendHpdBatchRequest(HpdBatchRequest hpdBatchRequest) - throws SerializeException, ParserConfigurationException, IOException { - BatchRequest request = new BatchRequest(); - - HPD.ReadInteractions.ITI_58.getWsTransactionConfiguration().getName(); - - String protocolPrefix = hpdBatchRequest.getHpdRequests().stream() - .map(hpdRequest -> hpdRequest instanceof HpdSearchQuery - ? HPD.ReadInteractions.ITI_58.getWsTransactionConfiguration().getName() - : HPD.FeedInteractions.ITI_59.getWsTransactionConfiguration().getName()) - .findFirst().orElseThrow(); - - hpdBatchRequest.getHpdRequests().forEach(hpdRequest -> { - DsmlMessage dsmlMessage = hpdRequest.build(); - request.getBatchRequests().add(dsmlMessage); - }); - - String endpoint = HuskyUtils.createEndpoint(protocolPrefix, // - hpdBatchRequest.getDestination().getUri(), // - this.atnaConfigMode.equals(AtnaConfigMode.SECURE)); - Exchange exchange = send(endpoint, request, null, null, null); - BatchResponse batchResponse = exchange.getMessage().getBody(BatchResponse.class); - - handleErrorResponse(batchResponse); - - return (HPD.ReadInteractions.ITI_58.getWsTransactionConfiguration().getName() - .equals(protocolPrefix)) ? // - new HpdQueryResponse().build(batchResponse) : // - ((HPD.FeedInteractions.ITI_59.getWsTransactionConfiguration().getName() - .equals(protocolPrefix)) ? // - new HpdFeedResponse().build(batchResponse) : // - null); - } - - /** - * Method that can be used for sending an individual request e.g. - * {@link org.projecthusky.communication.requests.hpd.HpdAddFeed} - */ - public HpdResponse sendHpdRequest(HpdRequest hpdRequest) - throws SerializeException, ParserConfigurationException, IOException { - HpdBatchRequest hpdBatchRequest = HpdBatchRequest.builder().hpdRequest(hpdRequest).build(); - return sendHpdBatchRequest(hpdBatchRequest); - } - - private static Marshaller createMarshaller(JAXBContext newInstance) throws JAXBException { - Marshaller marshaller = newInstance.createMarshaller(); - marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE); - marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); - marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF8"); - return marshaller; - } - - private XuaClientConfig createXuaClientConfig(XuaRequest xuaRequest) { - return new XuaClientConfigBuilderImpl().clientKeyStore(xuaRequest.getClientKeyStore()) - .clientKeyStorePassword(xuaRequest.getClientKeyStorePass()) - .clientKeyStoreType(xuaRequest.getClientKeyStoreType()) - .url(xuaRequest.getRepositoryUri()).create(); - } - - private ProvideAndRegisterDocumentSet createProvideAndRegisterDocumentSet( - XdsProvideAndRetrieveDocumentSetQuery documentSet) { - ProvideAndRegisterDocumentSet txnData = new ProvideAndRegisterDocumentSet(); - txnData.setSubmissionSet(new SubmissionSet()); - documentSet.getSubmissionSetMetadata().toOhtSubmissionSetType(txnData.getSubmissionSet()); - return txnData; - } - - private void handleErrorResponse(BatchResponse response) { - ErrorResponse errorResponse = HpdUtils.getValidResponse(response, ErrorResponse.class); - Optional.ofNullable(errorResponse).ifPresent(err -> { - String errorMessage = "Request failed with the following message: " + err.getMessage(); - if (err.getType() != null && err.getType().value() != null) { - errorMessage += " and error type " + err.getType().value(); - } - throw new IllegalArgumentException(errorMessage); - }); - } + private static Marshaller createMarshaller(JAXBContext newInstance) throws JAXBException { + Marshaller marshaller = newInstance.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE); + marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); + marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF8"); + return marshaller; + } + + /** The ATNA config mode (secure or unsecure) */ + @Getter + @Setter + private AtnaConfig.AtnaConfigMode atnaConfigMode = AtnaConfigMode.UNSECURE; + + /** + * Determines if XDS document metadata will be extracted automatically (e.g. + * from CDA documents + */ + @Getter + @Setter + private DocumentMetadataExtractionMode documentMetadataExtractionMode = DocumentMetadataExtractionMode.DEFAULT_EXTRACTION; + + @Getter + @Setter + private SubmissionSetMetadataExtractionMode submissionSetMetadataExtractionMode = SubmissionSetMetadataExtractionMode.DEFAULT_EXTRACTION; + + @Getter + private final AuditContext auditContext; + private final CamelContext camelContext; + + public HuskyWebServiceClient(final CamelContext camelContext, AuditContext auditContext) { + this.camelContext = camelContext; + this.auditContext = auditContext; + } + + /** + * It implements the following IHE transaction: [ITI-48] Retrieve value set + * and value set raw + */ + public SvsValueSetResponse downloadValueSet(SvsValueSetRequest valueSetRequest, + boolean isUseRaw) throws IOException, ParserConfigurationException, + InitializationException, SAXException { + ValueSetConfig valueSetConfig = valueSetRequest.build(); + ValueSetManager valueSetManager = new ValueSetManager(); + return isUseRaw + ? SvsValueSetResponse.builder() + .valueSetRaw(valueSetManager.downloadValueSetRaw(valueSetConfig)).build() + : SvsValueSetResponse.builder() + .valueSet(valueSetManager.downloadValueSet(valueSetConfig)).build(); + } + + public Exchange send(String endpoint, Object body, SecurityHeaderElement securityHeaderElement, + String messageId, Map outgoingHttpHeaders) + throws SerializeException, ParserConfigurationException, IOException { + log.debug("Sending message..."); + Exchange exchange = new DefaultExchange(camelContext); + exchange.getIn().setBody(body); + + if (securityHeaderElement != null) { + addWssHeader(securityHeaderElement, exchange); + } + + if (outgoingHttpHeaders != null && !outgoingHttpHeaders.isEmpty()) { + addHttpHeader(exchange, outgoingHttpHeaders); + } + + try (ProducerTemplate template = camelContext.createProducerTemplate()) { + Exchange result = template.send(endpoint, exchange); + if (result.getException() != null) { + throw new RuntimeException(result.getException()); + } + return result; + } + } + + public RetrievedDocumentSet send(XdsDocumentSetRequest request, URI destination, String messageId) + throws SerializeException, ParserConfigurationException, IOException { + RetrieveDocumentSet retrieveDocumentSet = new RetrieveDocumentSet(); + + for (final DocumentRequest element : request.getDocumentRequests()) { + if (element != null) { + retrieveDocumentSet.addReferenceTo(element.getIpfDocumentEntry()); + } + } + + String endpoint = HuskyUtils.createEndpoint( + XDS.Interactions.ITI_43.getWsTransactionConfiguration().getName(), // + destination, // + AtnaConfigMode.SECURE.equals(atnaConfigMode)); + Exchange exchange = send(endpoint, retrieveDocumentSet, request.getXuaToken(), messageId, null); + + return exchange.getMessage().getBody(RetrievedDocumentSet.class); + } + + /** + * It implements the following IHE transaction: [ITI-40] Provide Identity + * Assertions + */ + public XuaResponse send(XuaRequest xuaRequest) throws ClientSendException { + SimpleXuaClient xuaClient = new SimpleXuaClient(createXuaClientConfig(xuaRequest)); + + List xuaResponses = xuaClient.send(xuaRequest.getIdpAssertion(), + xuaRequest.build()); + + return new XuaResponse(xuaResponses); + } + + /** + * It implements the following IHE transactions: [ITI-58] Provider + * Information Query - Search Request [ITI-59] Provider Information Feed - + * Add Request [ITI-59] Provider Information Feed - Delete Request + */ + public HpdResponse sendHpdBatchRequest(HpdBatchRequest hpdBatchRequest) + throws SerializeException, ParserConfigurationException, IOException { + BatchRequest request = new BatchRequest(); + + HPD.ReadInteractions.ITI_58.getWsTransactionConfiguration().getName(); + + String protocolPrefix = hpdBatchRequest.getHpdRequests().stream() + .map(hpdRequest -> hpdRequest instanceof HpdSearchQuery + ? HPD.ReadInteractions.ITI_58.getWsTransactionConfiguration().getName() + : HPD.FeedInteractions.ITI_59.getWsTransactionConfiguration().getName()) + .findFirst().orElseThrow(); + + hpdBatchRequest.getHpdRequests().forEach(hpdRequest -> { + DsmlMessage dsmlMessage = hpdRequest.build(); + request.getBatchRequests().add(dsmlMessage); + }); + + String endpoint = HuskyUtils.createEndpoint(protocolPrefix, // + hpdBatchRequest.getDestination().getUri(), // + AtnaConfigMode.SECURE.equals(atnaConfigMode)); + Exchange exchange = send(endpoint, request, null, null, null); + BatchResponse batchResponse = exchange.getMessage().getBody(BatchResponse.class); + + handleErrorResponse(batchResponse); + + return (HPD.ReadInteractions.ITI_58.getWsTransactionConfiguration().getName() + .equals(protocolPrefix)) ? // + new HpdQueryResponse().build(batchResponse) : // + ((HPD.FeedInteractions.ITI_59.getWsTransactionConfiguration().getName() + .equals(protocolPrefix)) ? // + new HpdFeedResponse().build(batchResponse) : // + null); + } + + /** + * Method that can be used for sending an individual request e.g. + * {@link org.projecthusky.communication.requests.hpd.HpdAddFeed} + */ + public HpdResponse sendHpdRequest(HpdRequest hpdRequest) + throws SerializeException, ParserConfigurationException, IOException { + HpdBatchRequest hpdBatchRequest = HpdBatchRequest.builder().hpdRequest(hpdRequest).build(); + return sendHpdBatchRequest(hpdBatchRequest); + } + + public MCCIIN000002UV01Type sendITI44Query(PRPAIN201304UV02Type request, + SecurityHeaderElement assertion, URI pdqDest, String action, String messageId) + throws JAXBException, SerializeException, ParserConfigurationException, IOException { + + Marshaller marshaller = createMarshaller( + JAXBContext.newInstance(PRPAIN201304UV02Type.class)); + + StringWriter stringWriter = new StringWriter(); + marshaller.marshal(request, stringWriter); + + String xml = sendITI44Query(stringWriter.toString(), assertion, pdqDest, action, messageId); + + Unmarshaller unmarshaller = JAXBContext.newInstance(MCCIIN000002UV01Type.class) + .createUnmarshaller(); + return (MCCIIN000002UV01Type) unmarshaller + .unmarshal(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); + } + + public PRPAIN201306UV02Type sendPdqSearchQueryRequest(PdqQuery request, + SecurityHeaderElement security, URI pdqDest, String messageId) throws JAXBException, + DataBindingException, ParserConfigurationException, SerializeException, IOException { + + String endpoint = HuskyUtils.createEndpoint( + PDQV3.Interactions.ITI_47.getWsTransactionConfiguration().getName(), // + pdqDest, // + pdqDest.toString().contains(HuskyUtils.HTTPS_LITERAL), // + AtnaConfigMode.SECURE.equals(atnaConfigMode)); + + String message = XmlMarshaller.marshall(request.getRootElement()); + + Map outgoingHeaders = new HashMap<>(); + outgoingHeaders.put("Accept", "application/soap+xml"); + outgoingHeaders.put("Content-Type", + "application/soap+xml; charset=UTF-8; action=\"urn:hl7-org:v3:PRPA_IN201305UV02\""); + + Exchange exchange = this.send(endpoint, message, security, messageId, outgoingHeaders); + + String xml = exchange.getMessage().getBody(String.class); + + return XmlUnmarshaller.unmarshallStringAsType(xml, PRPAIN201306UV02Type.class); + } + + public MCCIIN000002UV01Type sendPixAddPatientRequest(PRPAIN201301UV02Type request, + SecurityHeaderElement assertion, URI pdqDest, String action, String messageId) + throws JAXBException, SerializeException, ParserConfigurationException, IOException { + Marshaller marshaller = createMarshaller( + JAXBContext.newInstance(PRPAIN201301UV02Type.class)); + + StringWriter stringWriter = new StringWriter(); + marshaller.marshal(request, stringWriter); + + String xml = sendITI44Query(stringWriter.toString(), assertion, pdqDest, action, messageId); + + Unmarshaller unmarshaller = JAXBContext.newInstance(MCCIIN000002UV01Type.class) + .createUnmarshaller(); + return (MCCIIN000002UV01Type) unmarshaller + .unmarshal(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); + } + + public MCCIIN000002UV01Type sendPixUpdatePatientRequest(PRPAIN201302UV02Type request, + SecurityHeaderElement assertion, URI pdqDest, String action, String messageId) + throws JAXBException, SerializeException, ParserConfigurationException, IOException { + Marshaller marshaller = createMarshaller( + JAXBContext.newInstance(PRPAIN201302UV02Type.class)); + + StringWriter stringWriter = new StringWriter(); + marshaller.marshal(request, stringWriter); + + String xml = sendITI44Query(stringWriter.toString(), assertion, pdqDest, action, messageId); + + Unmarshaller unmarshaller = JAXBContext.newInstance(MCCIIN000002UV01Type.class) + .createUnmarshaller(); + return (MCCIIN000002UV01Type) unmarshaller + .unmarshal(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); + } + + public Response sendProvideAndRegisterDocumentSetRequest( + XdsProvideAndRetrieveDocumentSetQuery documentSet) + throws SerializeException, ParserConfigurationException, IOException { + return sendProvideAndRegisterDocumentSetRequest(documentSet, + submissionSetMetadataExtractionMode, documentMetadataExtractionMode); + } + + /** + * It implements the following IHE transaction: [ITI-41] Provide and + * Register Document Set – b + *

+ * Using this method, both extraction modes can be set explicitly, e.g. if + * the default option is not suitable for all kinds of request. + */ + public Response sendProvideAndRegisterDocumentSetRequest( + XdsProvideAndRetrieveDocumentSetQuery documentSet, + SubmissionSetMetadataExtractionMode extractionMode, + DocumentMetadataExtractionMode documentMetadataExtractionMode) + throws SerializeException, ParserConfigurationException, IOException { + ProvideAndRegisterDocumentSet txnData = createProvideAndRegisterDocumentSet(documentSet); + + documentSet.getDocumentWithMetadata().forEach(docMetadata -> XDSUtils + .addDocument(docMetadata, txnData, documentMetadataExtractionMode)); + + if (extractionMode == SubmissionSetMetadataExtractionMode.DEFAULT_EXTRACTION) { + log.debug("extract submission set metadata"); + XDSUtils.generateDefaultSubmissionSetAttributes(txnData); + XDSUtils.linkDocumentEntryWithSubmissionSet(txnData); + } + + if (documentSet.getAssociation() != null) { + txnData.getAssociations().add(documentSet.getAssociation()); + log.debug("set association data"); + if (txnData.getDocuments() != null && !txnData.getDocuments().isEmpty() + && txnData.getDocuments().get(0) != null) { + documentSet.getAssociation().setSourceUuid( + txnData.getDocuments().get(0).getDocumentEntry().getEntryUuid()); + } else if (txnData.getFolders() != null && !txnData.getFolders().isEmpty() + && txnData.getFolders().get(0) != null) { + documentSet.getAssociation() + .setSourceUuid(txnData.getFolders().get(0).getEntryUuid()); + } + } + + log.debug("prepare submit of document"); + String endpoint = HuskyUtils.createEndpoint( + XDS.Interactions.ITI_41.getWsTransactionConfiguration().getName(), // + documentSet.getDestination().getUri(), // + AtnaConfigMode.SECURE.equals(atnaConfigMode)); + + Exchange exchange = send(endpoint, txnData, documentSet.getXuaToken(), null, null); + return exchange.getMessage().getBody(Response.class); + } + + public PixV3QueryResponse sendQuery(PixV3QueryRequest request, SecurityHeaderElement assertion, + URI pdqDest, String messageId) throws Exception { + String endpoint = HuskyUtils.createEndpoint( + PIXV3.Interactions.ITI_45.getWsTransactionConfiguration().getName(), // + pdqDest, // + pdqDest.toString().contains(HuskyUtils.HTTPS_LITERAL), // + AtnaConfigMode.SECURE.equals(atnaConfigMode)); + + Map outgoingHeaders = new HashMap<>(); + outgoingHeaders.put("Accept", "application/soap+xml"); + outgoingHeaders.put("Content-Type", + "application/soap+xml; charset=UTF-8; action=\"urn:hl7-org:v3:PRPA_IN201309UV02\""); + + Exchange exchange = send(endpoint, request, assertion, messageId, outgoingHeaders); + + return exchange.getMessage().getBody(PixV3QueryResponse.class); + } + + /** It implements the following IHE transaction: [ITI-18] Find folders */ + public QueryResponse sendQueryFoldersRequest(XdsFindFoldersStoredQuery findFoldersStoredQuery) + throws SerializeException, ParserConfigurationException, IOException { + return sendRegistryStoredFindDocumentsQuery(findFoldersStoredQuery, findFoldersStoredQuery.getDestination().getUri(), + QueryReturnType.LEAF_CLASS, null); + } + + public QueryResponse sendRegistryStoredFindDocumentsQuery(XdsRegistryStoredFindDocumentsQuery query, URI destination, + QueryReturnType returnType, String messageId) throws SerializeException, ParserConfigurationException, IOException { + QueryRegistry queryRegistry = new QueryRegistry(query.getIpfQuery()); + queryRegistry.setReturnType(returnType); + + // String endpoint = createEndpoint(destination.toString(), XDS_ITI18); + final String strippedUrl = destination.toString().replace(HuskyUtils.HTTPS_LITERAL, "") + .replace(HuskyUtils.HTTP_LITERAL, ""); + String endpoint = HuskyUtils.createEndpoint( + XDS.Interactions.ITI_18.getWsTransactionConfiguration().getName(), // + strippedUrl, // + destination.toString().contains(HuskyUtils.HTTPS_LITERAL), // + AtnaConfigMode.SECURE.equals(atnaConfigMode)); + Exchange exchange = send(endpoint, queryRegistry, query.getXuaToken(), messageId, null); + + return exchange.getMessage().getBody(QueryResponse.class); + } + + protected void addHttpHeader(Exchange exchange, Map outgoingHttpHeaders) { + log.debug("Adding HTTP Headers..."); + Map outgoingHeaders = CastUtils.cast((Map) exchange.getIn() + .getHeader(AbstractWsEndpoint.OUTGOING_HTTP_HEADERS)); + + if (outgoingHeaders == null) { + outgoingHeaders = new HashMap<>(); + } + + for (Entry entry : outgoingHttpHeaders.entrySet()) { + if (entry != null && entry.getValue() != null && entry.getKey() != null) { + outgoingHeaders.put(entry.getKey(), entry.getValue()); + } + } + + exchange.getIn().setHeader(AbstractWsEndpoint.OUTGOING_HTTP_HEADERS, outgoingHeaders); + } + + protected void addWssHeader(SecurityHeaderElement securityHeaderElement, Exchange exchange) + throws SerializeException, ParserConfigurationException { + log.debug("Adding WSS Headers..."); + Element wssElement = new OpenSaml2SerializerImpl() + .serializeToXml((XMLObject) securityHeaderElement.getWrappedObject()); + + DocumentBuilder docBuilder = XmlFactories.newSafeDocumentBuilder(); + Document doc = docBuilder.newDocument(); + + Element wsseElement = doc.createElementNS( + "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", + "wsse:Security"); + + QName wsseQName = new QName( + "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", + "Security", "wsse"); + + Node replaceNode = wsseElement.getOwnerDocument().importNode(wssElement, true); + wsseElement.appendChild(replaceNode); + + Map soapHeaders = CastUtils + .cast((Map) exchange.getIn() + .getHeader(AbstractWsEndpoint.OUTGOING_SOAP_HEADERS)); + + if (soapHeaders == null) { + soapHeaders = new HashMap<>(); + } + + try { + Header newHeader = new Header(wsseQName, wsseElement); + newHeader.setDirection(Direction.DIRECTION_OUT); + soapHeaders.put(wsseQName, newHeader); + exchange.getIn().setHeader(AbstractWsEndpoint.OUTGOING_SOAP_HEADERS, soapHeaders); + } catch (Exception e) { + log.error("Exception caught while creating the WSS header", e); + } + + } + + private ProvideAndRegisterDocumentSet createProvideAndRegisterDocumentSet( + XdsProvideAndRetrieveDocumentSetQuery documentSet) { + ProvideAndRegisterDocumentSet txnData = new ProvideAndRegisterDocumentSet(); + txnData.setSubmissionSet(new SubmissionSet()); + documentSet.getSubmissionSetMetadata().toOhtSubmissionSetType(txnData.getSubmissionSet()); + return txnData; + } + + private XuaClientConfig createXuaClientConfig(XuaRequest xuaRequest) { + return new XuaClientConfigBuilderImpl().clientKeyStore(xuaRequest.getClientKeyStore()) + .clientKeyStorePassword(xuaRequest.getClientKeyStorePass()) + .clientKeyStoreType(xuaRequest.getClientKeyStoreType()) + .url(xuaRequest.getRepositoryUri()).create(); + } + + private void handleErrorResponse(BatchResponse response) { + ErrorResponse errorResponse = HpdUtils.getValidResponse(response, ErrorResponse.class); + Optional.ofNullable(errorResponse).ifPresent(err -> { + String errorMessage = "Request failed with the following message: " + err.getMessage(); + if (err.getType() != null && err.getType().value() != null) { + errorMessage += " and error type " + err.getType().value(); + } + throw new IllegalArgumentException(errorMessage); + }); + } + + private String sendITI44Query(String request, SecurityHeaderElement assertion, URI pdqDest, + String action, String messageId) + throws SerializeException, ParserConfigurationException, IOException { + String endpoint = HuskyUtils.createEndpoint( + PIXV3.Interactions.ITI_44_PIX.getWsTransactionConfiguration().getName(), // + pdqDest, // + pdqDest.toString().contains(HuskyUtils.HTTPS_LITERAL), // + AtnaConfigMode.SECURE.equals(atnaConfigMode)); + + log.info("Sending request to '{}' endpoint", endpoint); + + Map outgoingHeaders = new HashMap<>(); + outgoingHeaders.put("Accept", "application/soap+xml"); + outgoingHeaders.put("Content-Type", + String.format("application/soap+xml; charset=UTF-8; action=\"%s\"", action)); + + Exchange exchange = send(endpoint, request, assertion, messageId, outgoingHeaders); + + return exchange.getMessage().getBody(String.class); + } } \ No newline at end of file diff --git a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/utils/XDSUtils.java b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/utils/XDSUtils.java index 109e21edc81..cc494b0879f 100644 --- a/husky-communication/husky-service/src/main/java/org/projecthusky/communication/utils/XDSUtils.java +++ b/husky-communication/husky-service/src/main/java/org/projecthusky/communication/utils/XDSUtils.java @@ -17,7 +17,6 @@ import org.openehealth.ipf.commons.ihe.xds.core.metadata.Timestamp; import org.openehealth.ipf.commons.ihe.xds.core.metadata.Timestamp.Precision; import org.openehealth.ipf.commons.ihe.xds.core.requests.ProvideAndRegisterDocumentSet; -import org.projecthusky.common.communication.Destination; import org.projecthusky.common.communication.DocumentMetadata; import org.projecthusky.common.communication.DocumentMetadata.DocumentMetadataExtractionMode; import org.projecthusky.common.enums.DocumentDescriptor; @@ -52,6 +51,80 @@ public static void addDocument(XdsDocumentWithMetadata documentWithMetadata, Pro } } + public static void generateDefaultSubmissionSetAttributes(ProvideAndRegisterDocumentSet txnData) { + if (txnData.getSubmissionSet() == null) { + txnData.setSubmissionSet(new SubmissionSet()); + } + + // Create SubmissionSet + final var subSet = txnData.getSubmissionSet(); + + if (txnData.getDocuments() != null && !txnData.getDocuments().isEmpty()) { + setSubSetDetailsFromDocument(subSet, txnData); + } else if (txnData.getFolders() != null && !txnData.getFolders().isEmpty()) { + setSubSetDetailsFromFolder(subSet, txnData); + } + } + + public static void linkDocumentEntryWithSubmissionSet(ProvideAndRegisterDocumentSet txnData) { + for (Document document : txnData.getDocuments()) { + // link document entry to submission set + var association = new Association(); + association.setAssociationType(AssociationType.HAS_MEMBER); + association.setSourceUuid(txnData.getSubmissionSet().getEntryUuid()); + association.setTargetUuid(document.getDocumentEntry().getEntryUuid()); + association.setLabel(AssociationLabel.ORIGINAL); + association.assignEntryUuid(); + + txnData.getAssociations().add(association); + } + + for (Folder folder : txnData.getFolders()) { + // link folder to submission set + var association = new Association(AssociationType.HAS_MEMBER, + txnData.getSubmissionSet().getEntryUuid(), txnData.getSubmissionSet().getEntryUuid(), + folder.getEntryUuid()); + association.assignEntryUuid(); + + txnData.getAssociations().add(association); + } + } + + protected static String getSourceId(Identifiable patientId) { + if (patientId != null) { + return patientId.getAssigningAuthority().getUniversalId(); + } + return EhcVersions.getCurrentVersion().getOid(); + } + + protected static void setGeneralSubSetDetails(SubmissionSet subSet, Identifiable patientId) { + // set submission time + if (subSet.getSubmissionTime() == null) { + subSet.setSubmissionTime(new Timestamp(ZonedDateTime.now(), Precision.SECOND)); + } + + if (subSet.getEntryUuid() == null) { + subSet.setEntryUuid(UUID.randomUUID().toString()); + } + + if ((subSet.getUniqueId() == null) || (subSet.getSourceId() == null)) { + + if (subSet.getUniqueId() == null) { + subSet.assignUniqueId(); + } + + // set submission set source id + if (subSet.getSourceId() == null) { + subSet.setSourceId(getSourceId(patientId)); + } + } + + // Use the PatientId of the first Document for the Submission set ID + if (subSet.getPatientId() == null) { + subSet.setPatientId(patientId); + } + } + private static void addXdsDocument(Document doc, ProvideAndRegisterDocumentSet txnData, DocumentMetadata documentMetadata, DocumentMetadataExtractionMode extractionMode) { if (documentMetadata != null) { @@ -118,22 +191,6 @@ private static void generateDefaultDocEntryAttributes(DocumentMetadata docMetada } } - public static void generateDefaultSubmissionSetAttributes(ProvideAndRegisterDocumentSet txnData) { - - if (txnData.getSubmissionSet() == null) { - txnData.setSubmissionSet(new SubmissionSet()); - } - - // Create SubmissionSet - final var subSet = txnData.getSubmissionSet(); - - if (txnData.getDocuments() != null && !txnData.getDocuments().isEmpty()) { - setSubSetDetailsFromDocument(subSet, txnData); - } else if (txnData.getFolders() != null && !txnData.getFolders().isEmpty()) { - setSubSetDetailsFromFolder(subSet, txnData); - } - } - private static void setSubSetDetailsFromDocument(SubmissionSet subSet, ProvideAndRegisterDocumentSet txnData) { log.info("count of documents {}", txnData.getDocuments().size()); for (Document document : txnData.getDocuments()) { @@ -167,84 +224,4 @@ private static void setSubSetDetailsFromFolder(SubmissionSet subSet, ProvideAndR setGeneralSubSetDetails(subSet, folder.getPatientId()); } } - - protected static void setGeneralSubSetDetails(SubmissionSet subSet, Identifiable patientId) { - // set submission time - if (subSet.getSubmissionTime() == null) { - subSet.setSubmissionTime(new Timestamp(ZonedDateTime.now(), Precision.SECOND)); - } - - if (subSet.getEntryUuid() == null) { - subSet.setEntryUuid(UUID.randomUUID().toString()); - } - - if ((subSet.getUniqueId() == null) || (subSet.getSourceId() == null)) { - - if (subSet.getUniqueId() == null) { - subSet.assignUniqueId(); - } - - // set submission set source id - if (subSet.getSourceId() == null) { - subSet.setSourceId(getSourceId(patientId)); - } - } - - // Use the PatientId of the first Document for the Submission set ID - if (subSet.getPatientId() == null) { - subSet.setPatientId(patientId); - } - } - - protected static String getSourceId(Identifiable patientId) { - if (patientId != null) { - return patientId.getAssigningAuthority().getUniversalId(); - } else { - return EhcVersions.getCurrentVersion().getOid(); - } - } - - public static void setDefaultKeystoreTruststore(Destination dest) { - if (dest.getKeyStore() == null) { - System.clearProperty("javax.net.ssl.keyStore"); - System.clearProperty("javax.net.ssl.keyStorePassword"); - System.clearProperty("javax.net.ssl.keyStoreType"); - System.clearProperty("javax.net.ssl.trustStore"); - System.clearProperty("javax.net.ssl.trustStorePassword"); - System.clearProperty("javax.net.ssl.trustStoreType"); - } else { - System.setProperty("javax.net.ssl.keyStore", dest.getKeyStore()); - System.setProperty("javax.net.ssl.keyStorePassword", dest.getKeyStorePassword()); - System.setProperty("javax.net.ssl.keyStoreType", dest.getKeyStoreType()); - System.setProperty("javax.net.ssl.trustStore", dest.getTrustStore()); - System.setProperty("javax.net.ssl.trustStorePassword", dest.getTrustStorePassword()); - System.setProperty("javax.net.ssl.trustStoreType", dest.getTrustStoreType()); - } - } - - public static void linkDocumentEntryWithSubmissionSet(ProvideAndRegisterDocumentSet txnData) { - - for (Document document : txnData.getDocuments()) { - // link document entry to submission set - var association = new Association(); - - association.setAssociationType(AssociationType.HAS_MEMBER); - association.setSourceUuid(txnData.getSubmissionSet().getEntryUuid()); - association.setTargetUuid(document.getDocumentEntry().getEntryUuid()); - association.setLabel(AssociationLabel.ORIGINAL); - association.assignEntryUuid(); - - txnData.getAssociations().add(association); - } - - for (Folder folder : txnData.getFolders()) { - // link folder to submission set - var association = new Association(AssociationType.HAS_MEMBER, - txnData.getSubmissionSet().getEntryUuid(), txnData.getSubmissionSet().getEntryUuid(), - folder.getEntryUuid()); - association.assignEntryUuid(); - - txnData.getAssociations().add(association); - } - } } \ No newline at end of file