From d82cf687f78865bc9a0f309d7e40f53c948c20ba Mon Sep 17 00:00:00 2001 From: Thomas Papke <web@thopap.de> Date: Mon, 18 Oct 2021 20:56:53 +0200 Subject: [PATCH] #365 XDS ExtraMetadata slots might get duplicated if SubmitObjectsRequest's are unmarshalled and marshalled on the same instance * Fix extra metadata slot duplication --- .../ihe/xds/core/XdsJaxbDataBinding.java | 2 + .../transform/ebxml/Ebrs30MarshalingTest.java | 60 +++-- ...mitObjectsRequest_ebrs3_extra_metadata.xml | 244 ++++++++++++++++++ 3 files changed, 286 insertions(+), 20 deletions(-) create mode 100644 commons/ihe/xds/src/test/resources/SubmitObjectsRequest_ebrs3_extra_metadata.xml diff --git a/commons/ihe/xds/src/main/java/org/openehealth/ipf/commons/ihe/xds/core/XdsJaxbDataBinding.java b/commons/ihe/xds/src/main/java/org/openehealth/ipf/commons/ihe/xds/core/XdsJaxbDataBinding.java index 14df8e3513..d168ffbadf 100644 --- a/commons/ihe/xds/src/main/java/org/openehealth/ipf/commons/ihe/xds/core/XdsJaxbDataBinding.java +++ b/commons/ihe/xds/src/main/java/org/openehealth/ipf/commons/ihe/xds/core/XdsJaxbDataBinding.java @@ -122,6 +122,8 @@ public void beforeMarshal(Object source) { private static void injectExtraMetadata(List<SlotType1> slots, ExtraMetadataHolder holder) { if (holder.getExtraMetadata() != null) { + slots.removeIf(slot -> isExtraMetadataSlotName(slot.getName()) + && holder.getExtraMetadata().containsKey(slot.getName())); holder.getExtraMetadata().entrySet().stream() .filter(entry -> isExtraMetadataSlotName(entry.getKey())) .forEach(entry -> { diff --git a/commons/ihe/xds/src/test/java/org/openehealth/ipf/commons/ihe/xds/core/transform/ebxml/Ebrs30MarshalingTest.java b/commons/ihe/xds/src/test/java/org/openehealth/ipf/commons/ihe/xds/core/transform/ebxml/Ebrs30MarshalingTest.java index 8a1fcda49d..c114475dde 100644 --- a/commons/ihe/xds/src/test/java/org/openehealth/ipf/commons/ihe/xds/core/transform/ebxml/Ebrs30MarshalingTest.java +++ b/commons/ihe/xds/src/test/java/org/openehealth/ipf/commons/ihe/xds/core/transform/ebxml/Ebrs30MarshalingTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.openehealth.ipf.commons.ihe.xds.core.XdsJaxbDataBinding; import org.openehealth.ipf.commons.ihe.xds.core.ebxml.EbXMLExtrinsicObject; import org.openehealth.ipf.commons.ihe.xds.core.ebxml.EbXMLObjectLibrary; import org.openehealth.ipf.commons.ihe.xds.core.ebxml.ebxml30.EbXMLAdhocQueryRequest30; @@ -29,21 +30,26 @@ import org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.lcm.SubmitObjectsRequest; import org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.query.AdhocQueryRequest; import org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.rim.ExtrinsicObjectType; -import org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.rim.IdentifiableType; +import org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.rim.ObjectFactory; import org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.rim.RegistryObjectListType; import org.openehealth.ipf.commons.ihe.xds.core.transform.requests.QueryParameter; import org.openehealth.ipf.commons.ihe.xds.core.transform.requests.RegisterDocumentSetTransformer; import org.openehealth.ipf.commons.ihe.xds.core.transform.requests.query.QuerySlotHelper; import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; -import javax.xml.namespace.QName; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.StringReader; +import java.io.StringWriter; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * Tests for marshaling objects created with our ebxml 2.1 classes. @@ -54,14 +60,13 @@ public class Ebrs30MarshalingTest { private EbXMLExtrinsicObject docEntry; private EbXMLFactory30 factory; private EbXMLObjectLibrary objectLibrary; - - private static final QName EXTRINSIC_OBJECT_QNAME = - new QName("urn:oasis:names:tc:ebxml-regrep:xsd:rim:3.0", "ExtrinsicObject", "rim"); + private JAXBContext context; @BeforeEach - public void setUp() { + public void setUp() throws JAXBException { factory = new EbXMLFactory30(); objectLibrary = factory.createObjectLibrary(); + context = JAXBContext.newInstance("org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.rs"); request = new SubmitObjectsRequest(); var objListElement = new RegistryObjectListType(); @@ -70,12 +75,7 @@ public void setUp() { docEntry = factory.createExtrinsic("Document01", objectLibrary); docEntry.setObjectType(DocumentEntryType.STABLE.getUuid()); - objList.add(getJaxbElement(EXTRINSIC_OBJECT_QNAME, ((EbXMLExtrinsicObject30)docEntry).getInternal())); - } - - @SuppressWarnings("unchecked") - private static JAXBElement<IdentifiableType> getJaxbElement(QName qname, IdentifiableType object) { - return new JAXBElement<>(qname, (Class)object.getClass(), object); + objList.add(new ObjectFactory().createExtrinsicObject(((EbXMLExtrinsicObject30)docEntry).getInternal())); } @Test @@ -131,8 +131,7 @@ public void testAddSlot() throws Exception { @Test public void testFromRealEbXML() throws Exception { var file = new File(getClass().getClassLoader().getResource("SubmitObjectsRequest_ebrs30.xml").toURI()); - - var context = JAXBContext.newInstance("org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.rs"); + var unmarshaller = context.createUnmarshaller(); var unmarshalled = unmarshaller.unmarshal(file); @@ -158,8 +157,6 @@ public void testFromRealEbXML() throws Exception { @Test public void testPatientIdSlotRegexp() throws Exception { var file = new File(getClass().getClassLoader().getResource("iti18request.xml").toURI()); - - var context = JAXBContext.newInstance("org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.rs"); var unmarshaller = context.createUnmarshaller(); var unmarshalled = unmarshaller.unmarshal(file); @@ -174,7 +171,6 @@ public void testPatientIdSlotRegexp() throws Exception { public void testPatientIdMPQSlotRegexp() throws Exception { var file = new File(getClass().getClassLoader().getResource("iti51request.xml").toURI()); - var context = JAXBContext.newInstance("org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.rs"); var unmarshaller = context.createUnmarshaller(); var unmarshalled = unmarshaller.unmarshal(file); @@ -184,9 +180,33 @@ public void testPatientIdMPQSlotRegexp() throws Exception { var patientIdList = slotHelper.toStringList(QueryParameter.DOC_ENTRY_PATIENT_ID); assertEquals(2, patientIdList.size()); } + + @Test + public void verifyExtraMetadataWithJaxbBinding() throws Exception { + var file = new File( + getClass().getClassLoader().getResource("SubmitObjectsRequest_ebrs3_extra_metadata.xml").toURI()); + var unmarshaller = context.createUnmarshaller(); + unmarshaller.setListener(new XdsJaxbDataBinding().getUnmarshallerListener()); + + var unmarshalled = unmarshaller.unmarshal(file); + var original = (SubmitObjectsRequest) unmarshalled; + int numberOfSlotsInFirstDoc = new EbXMLSubmitObjectsRequest30(original).getExtrinsicObjects().get(0).getSlots() + .size(); + + var marshaller = context.createMarshaller(); + marshaller.setListener(new XdsJaxbDataBinding().getMarshallerListener()); + StringWriter writer = new StringWriter(); + marshaller.marshal(original, writer); + + var unmarshalledSecond = (SubmitObjectsRequest) unmarshaller.unmarshal(new StringReader(writer.toString())); + int numberOfSlotsInSecondDoc = new EbXMLSubmitObjectsRequest30(unmarshalledSecond).getExtrinsicObjects().get(0) + .getSlots().size(); + + assertEquals(numberOfSlotsInFirstDoc, numberOfSlotsInSecondDoc, + "Number of slots after Marshalling and Unmarsshalling does not match"); + } private SubmitObjectsRequest send() throws JAXBException { - var context = JAXBContext.newInstance("org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.rs"); var marshaller = context.createMarshaller(); var unmarshaller = context.createUnmarshaller(); var outputStream = new ByteArrayOutputStream(); diff --git a/commons/ihe/xds/src/test/resources/SubmitObjectsRequest_ebrs3_extra_metadata.xml b/commons/ihe/xds/src/test/resources/SubmitObjectsRequest_ebrs3_extra_metadata.xml new file mode 100644 index 0000000000..8e8dbd46a1 --- /dev/null +++ b/commons/ihe/xds/src/test/resources/SubmitObjectsRequest_ebrs3_extra_metadata.xml @@ -0,0 +1,244 @@ +<lcm:SubmitObjectsRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:oasis:names:tc:ebxml-regrep:xsd:lcm:3.0 ../schema/ebRS/lcm.xsd" + xmlns:lcm="urn:oasis:names:tc:ebxml-regrep:xsd:lcm:3.0" xmlns:rim="urn:oasis:names:tc:ebxml-regrep:xsd:rim:3.0" + xmlns:rs="urn:oasis:names:tc:ebxml-regrep:xsd:rs:3.0"> + <rim:RegistryObjectList> + <rim:ExtrinsicObject id="Document01" mimeType="text/xml" + objectType="urn:uuid:7edca82f-054d-47f2-a032-9b2a5b5186c1"> + <rim:Slot name="creationTime"> + <rim:ValueList> + <rim:Value>20051224</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Slot name="languageCode"> + <rim:ValueList> + <rim:Value>en-us</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Slot name="serviceStartTime"> + <rim:ValueList> + <rim:Value>200412230800</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Slot name="serviceStopTime"> + <rim:ValueList> + <rim:Value>200412230801</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Slot name="sourcePatientId"> + <rim:ValueList> + <rim:Value>ST-1000^^^&1.3.6.1.4.1.21367.2003.3.9&ISO</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Slot name="sourcePatientInfo"> + <rim:ValueList> + <rim:Value>PID-3|ST-1000^^^&1.3.6.1.4.1.21367.2003.3.9&ISO</rim:Value> + <rim:Value>PID-5|Doe^John^^^</rim:Value> + <rim:Value>PID-7|19560527</rim:Value> + <rim:Value>PID-8|M</rim:Value> + <rim:Value>PID-11|100 Main St^^Metropolis^Il^44130^USA</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Slot name="urn:my:company:slot"> + <rim:ValueList> + <rim:Value>somevalue</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Name> + <rim:LocalizedString value="Physical"/> + </rim:Name> + <rim:Description/> + <rim:Classification id="cl01" + classificationScheme="urn:uuid:93606bcf-9494-43ec-9b4e-a7748d1a838d" + classifiedObject="Document01"> + <rim:Slot name="authorPerson"> + <rim:ValueList> + <rim:Value>Gerald Smitty</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Slot name="authorInstitution"> + <rim:ValueList> + <rim:Value>Cleveland Clinic</rim:Value> + <rim:Value>Parma Community</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Slot name="authorRole"> + <rim:ValueList> + <rim:Value>Attending</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Slot name="authorSpeciality"> + <rim:ValueList> + <rim:Value>Orthopedic</rim:Value> + </rim:ValueList> + </rim:Slot> + </rim:Classification> + <rim:Classification id="cl02" + classificationScheme="urn:uuid:41a5887f-8865-4c09-adf7-e362475b143a" + classifiedObject="Document01" nodeRepresentation="History and Physical"> + <rim:Slot name="codingScheme"> + <rim:ValueList> + <rim:Value>Connect-a-thon classCodes</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Name> + <rim:LocalizedString value="History and Physical"/> + </rim:Name> + </rim:Classification> + <rim:Classification id="cl03" + classificationScheme="urn:uuid:f4f85eac-e6cb-4883-b524-f2705394840f" + classifiedObject="Document01" nodeRepresentation="1.3.6.1.4.1.21367.2006.7.101"> + <rim:Slot name="codingScheme"> + <rim:ValueList> + <rim:Value>Connect-a-thon confidentialityCodes</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Name> + <rim:LocalizedString value="Clinical-Staff"/> + </rim:Name> + </rim:Classification> + <rim:Classification id="cl04" + classificationScheme="urn:uuid:a09d5840-386c-46f2-b5ad-9c3699a4309d" + classifiedObject="Document01" nodeRepresentation="CDAR2/IHE 1.0"> + <rim:Slot name="codingScheme"> + <rim:ValueList> + <rim:Value>Connect-a-thon formatCodes</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Name> + <rim:LocalizedString value="CDAR2/IHE 1.0"/> + </rim:Name> + </rim:Classification> + <rim:Classification id="cl05" + classificationScheme="urn:uuid:f33fb8ac-18af-42cc-ae0e-ed0b0bdb91e1" + classifiedObject="Document01" nodeRepresentation="Outpatient"> + <rim:Slot name="codingScheme"> + <rim:ValueList> + <rim:Value>Connect-a-thon healthcareFacilityTypeCodes</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Name> + <rim:LocalizedString value="Outpatient"/> + </rim:Name> + </rim:Classification> + <rim:Classification id="cl06" + classificationScheme="urn:uuid:cccf5598-8b07-4b77-a05e-ae952c785ead" + classifiedObject="Document01" nodeRepresentation="General Medicine"> + <rim:Slot name="codingScheme"> + <rim:ValueList> + <rim:Value>Connect-a-thon practiceSettingCodes</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Name> + <rim:LocalizedString value="General Medicine"/> + </rim:Name> + </rim:Classification> + <rim:Classification id="cl07" + classificationScheme="urn:uuid:f0306f51-975f-434e-a61c-c59651d33983" + classifiedObject="Document01" nodeRepresentation="34108-1"> + <rim:Slot name="codingScheme"> + <rim:ValueList> + <rim:Value>LOINC</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Name> + <rim:LocalizedString value="Outpatient Evaluation And Management"/> + </rim:Name> + </rim:Classification> + <rim:ExternalIdentifier id="ei01" registryObject="Document01" + identificationScheme="urn:uuid:58a6f841-87b3-4a3e-92fd- a8ffeff98427" + value="SELF-5^^^&1.3.6.1.4.1.21367.2005.3.7&ISO"> + <rim:Name> + <rim:LocalizedString value="XDSDocumentEntry.patientId"/> + </rim:Name> + </rim:ExternalIdentifier> + <rim:ExternalIdentifier id="ei02" registryObject="Document01" + identificationScheme="urn:uuid:2e82c1f6-a085-4c72-9da3-8640a32e42ab" + value="1.3.6.1.4.1.21367.2005.3.9999.32"> + <rim:Name> + <rim:LocalizedString value="XDSDocumentEntry.uniqueId"/> + </rim:Name> + </rim:ExternalIdentifier> + </rim:ExtrinsicObject> + <rim:RegistryPackage id="SubmissionSet01"> + <rim:Slot name="submissionTime"> + <rim:ValueList> + <rim:Value>20041225235050</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Name> + <rim:LocalizedString value="Physical"/> + </rim:Name> + <rim:Description> + <rim:LocalizedString value="Annual physical"/> + </rim:Description> + <rim:Classification id="cl08" + classificationScheme="urn:uuid:a7058bb9-b4e4-4307-ba5b-e3f0ab85e12d" + classifiedObject="SubmissionSet01"> + <rim:Slot name="authorPerson"> + <rim:ValueList> + <rim:Value>Sherry Dopplemeyer</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Slot name="authorInstitution"> + <rim:ValueList> + <rim:Value>Cleveland Clinic</rim:Value> + <rim:Value>Berea Community</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Slot name="authorRole"> + <rim:ValueList> + <rim:Value>Primary Surgon</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Slot name="authorSpeciality"> + <rim:ValueList> + <rim:Value>Orthopedic</rim:Value> + </rim:ValueList> + </rim:Slot> + </rim:Classification> + <rim:Classification id="cl09" + classificationScheme="urn:uuid:aa543740-bdda-424e-8c96- df4873be8500" + classifiedObject="SubmissionSet01" nodeRepresentation="History and Physical"> + <rim:Slot name="codingScheme"> + <rim:ValueList> + <rim:Value>Connect-a-thon contentTypeCodes</rim:Value> + </rim:ValueList> + </rim:Slot> + <rim:Name> + <rim:LocalizedString value="History and Physical"/> + </rim:Name> + </rim:Classification> + <rim:ExternalIdentifier id="ei03" registryObject="SubmissionSet01" + identificationScheme="urn:uuid:96fdda7c-d067-4183-912e- bf5ee74998a8" + value="1.3.6.1.4.1.21367.2005.3.9999.33"> + <rim:Name> + <rim:LocalizedString value="XDSSubmissionSet.uniqueId"/> + </rim:Name> + </rim:ExternalIdentifier> + <rim:ExternalIdentifier id="ei04" registryObject="SubmissionSet01" + identificationScheme="urn:uuid:554ac39e-e3fe-47fe-b233-965d2a147832" value="3670984664"> + <rim:Name> + <rim:LocalizedString value="XDSSubmissionSet.sourceId"/> + </rim:Name> + </rim:ExternalIdentifier> + <rim:ExternalIdentifier id="ei05" registryObject="SubmissionSet01" + identificationScheme="urn:uuid:6b5aea1a-874d-4603-a4bc- 96a0a7b38446" + value="SELF-5^^^&1.3.6.1.4.1.21367.2005.3.7&ISO"> + <rim:Name> + <rim:LocalizedString value="XDSSubmissionSet.patientId"/> + </rim:Name> + </rim:ExternalIdentifier> + </rim:RegistryPackage> + <rim:Classification id="cl10" classifiedObject="SubmissionSet01" + classificationNode="urn:uuid:a54d6aa5-d40d-43f9-88c5-b4633d873bdd"/> + <rim:Association id="as01" associationType="urn:oasis:names:tc:ebxml-regrep:AssociationType:HasMember" sourceObject="SubmissionSet01" targetObject="Document01"> + <rim:Slot name="SubmissionSetStatus"> + <rim:ValueList> + <rim:Value>Original</rim:Value> + </rim:ValueList> + </rim:Slot> + </rim:Association> + <rim:Association id="as02" associationType="urn:ihe:iti:2010:AssociationType:IsSnapshotOf" sourceObject="Document01" targetObject="urn:uuid:e0985823-dc50-45a5-a6c8-a11a829893bd" /> + </rim:RegistryObjectList> +</lcm:SubmitObjectsRequest>