Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Navitabs
rootDokumentdelingsservice (DDS)
firsttabDokumentdelingsservice (DDS)
includeroottrue


1       Introduction

1.1          Purpose

DDS Registry allows document source systems to register metadata concerning documents according to the Integrating the Healthcare Enterprise (IHE) Cross-Enterprise Document Sharing (XDS.b) transactions ITI-42 and ITI-61.

...

The document metadata to be registered must adhere to a certain metadata definition, that is, be based on defined value sets, formats, encoding systems and so forth. The DDS Registry may be used with one of many metadata definitions, but currently, it is used with the one defined in [Metadata Profile].

Table of Contents

1.2          Reading Guide

This document is intended for developers and architects that will be using DDS Registry for registering document metadata. Comprehension of this document is facilitated considerably, when the reader is familiar with IHE ITI-42 and ITI-61, described in [ITI TF-2b].

...

It has been prioritized to keep the code examples short, possibly at the expense of ordinary division of responsibilities.

1.3          Document History

Version

Date

Responsible

Description

0.7

11.1.2013

Systematic

Initial version

0.9

27.2.2013

Systematic

Prepared for testing in the demo project.

0.9a

19.04.2013

Systematic

Version for Release Candidate 1

1.0

19.06.2013

Systematic

Quality assured.

1.1

28.11.2014

Systematic

National Patient Index (NPI) replaced by  Document Sharing Service (DDS)

1.2

05.05.2015

Systematic

Code references has been updated due to name change from NPI to DDS

1.3

26.01.2016

Systematic

Added reference to Danish metadata profile.

1.4          Definitions and References

Definition

Description

DDS

Document Sharing Service

IHE

Integrating the Healthcare Enterprise

NSI

National eHealth Authority

NSP

National Service Platform (within health care)

SOR

Health Service Organization Register

STS

Security Token Service

XDS.b

Cross-Enterprise Document Sharing

Reference

Description

DGWS 1.0

Den Gode Webservice 1.0

DGWS 1.0.1

Den Gode Webservice 1.0.1

ITI TF-2b

IHE IT Infrastructure Technical Framework, Volume 2b (linked from http://ihe.net/Technical_Frameworks/#IT and accessible as http://ihe.net/uploadedFiles/Documents/ITI/IHE_ITI_TF_Vol2b.pdf)

Metadata Profile

XDS Metadata for Document Sharing. Danish Profile.

National eHealth Authority, Draft profile for Trial Use, version 0.90b January 30, 2015

http://svn.medcom.dk/svn/drafts/Standarder/IHE/DK_profil_metadata/Metadata-v090.docx

DDS Registry Querying User’s Guide

DDS Registry Querying User’s Guide (SSE/11734/PHB/0037)

DDS Registry Querying Interface

DDS Registry Querying Interface Description (SSE/11734/IFS/0016)

DDS Registry Registering Interface

DDS Registry Registering Interface Description (SSE/11734/IFS/0015)

2       Usage of DDS Registry

DDS Registry provides operations for registration of document metadata in document sharing service through a web service interface, described in [DDS Registry Registering Interface].

...

The headers are added as implicit headers, i.e. by being described in the WSDL’s bindings without being added to the message structure of RegisterDocumentSet-b and RegisterOnDemandDocumentEntry.

2.1          Preparation for Invoking of the DDS Registry

Before invoking of the DDS Registry, it is the source system’s responsibility:

...

Note that the Central Business Register (CVR) number of the organization using the source system must be present in DDS Registry’s whitelist. Addition to the whitelist must be agreed with the DDS Registry system owner.

2.2          Invoking the DDS Registry

2.2.1      Invoking DocumentRegistry_RegisterDocumentSet-b

On invoking of the operation DocumentRegistry_RegisterDocumentSet-b on DDS Registry, the following must be completed:

  1. A SubmitObjectsRequest (i.e. payload of DocumentRegistry_RegistryStoredQuery) is created
  2. Security header must be populated with the ID card from STS
  3. Medcom-header is created, including:
    1. A unique message ID must be assigned
    2. The Medcom-header’s flowID element must be assigned a unique session ID

2.2.2      Invoking DocumentRegistry_RegisterOnDemandDocumentEntry

On invoking of the operation DocumentRegistry_RegisterOnDemandDocumentEntry on DDS Registry, the same steps as on invoking of DocumentRegistry_RegisterDocumentSet-b are completed.

3       Examples of DDS Registry Invocation

This section provides an example on how this service can be invoked. At present, no .NET-example code for calls to DDS Registry exists, but WSDL’s are available, from which a Web service consumer can be created using Visual Studio’s Web service wizard combined with Seal.NET (see below).

3.1     Source System Obtains DGWS ID Card from STS

Below is outlined how a Java-based source system can use Seal.Java to obtain a STS-signed ID card.

...

Code Block
DGWSHeaderWrapper signedHeaders = getValidDGWSHeaders(flowId);

3.2          Source System Creates SubmitObjectsRequest

A helper class SubmitObjectsRequestHelper, described in section 3.4, is used below to create SubmitObjectsRequest. The SubmitObjectsRequest contains metadata for an on-demand document that the source system can make available.

Note that the provided code that shows the principles for registration do not necessarily entail registration of all required metadata-information. Which metadata that may or must figure in registration must be agreed upon between the document source and NSI. The provided code is just an example of one of the ways in which the IHE standard makes it possible to register metadata.

3.2.1      Creation of SubmitObjectsRequest

Code Block
SubmitObjectsRequestHelper requestHelper = new SubmitObjectsRequestHelper();
SubmitObjectsRequest request = requestHelper.create();

3.2.2      Creation and addition of XDSDocumentEntry for on-demand document

Code Block
// Unique identification of the document that must be replaced by an actual value
String documentId = "urn:myorg:mydoc:doc:12345";
String repositoryUniqueId = "1.3.6.1.4.1.21367.2010.1.2.300.1";


ExtrinsicObjectType metadata = requestHelper.addOnDemandDocumentMetadataEntry(
          request
          documentId,
          repositoryUniqueId);

...

Code Block
String authorInstitution = "OUH Fælles Akut Amb (Svendborg)^^^^^& 1.2.208.176.1&ISO^^^^486651000016002";
String patientId = "1122334455^^^&2.16.840.1.113883.3.4208.100.2&ISO";
requestHelper.addDocumentMetadataAttributes(metadata, authorInstitution, patientId);

// Add additional metadata-information in the same manner


3.2.3      Creation and addition of XDSSubmissionSet

As part of the SubmitObjectsRequest, a description of the complete addition in the form of an XDSSubmissionSet must be provided. This is created and added with:

...

Code Block
requestHelper.addAssociation(request, metadata, submissionSet);


3.2.4      Possible creation and addition of replacement-associations

If the (new) document metadata described above replaces pre-existing document metadata, then an association as shown below must be added to the SubmitObjectsRequest:

...

Pre-existing document metadata-objects for a particular document ID can be found by use of search in the response from a DDS Registry query. DDS Registry querying is described in [DDS Registry Querying Interface] and [DDS Registry Querying User’s Guide].

3.3          Source System Calls RegisterOnDemandDocumentEntry

Below the ID card that has been obtained as described in section 3.1 is used to call DDS Registry’s operation RegisterOnDemandDocumentEntry. Those metadata, that are registered, are created as described in section 3.2.

...

Code Block
collapsetrue
SubmitObjectsRequestHelper requestHelper = new SubmitObjectsRequestHelper();
SubmitObjectsRequest request = requestHelper.create();
… // request-structure is populated as described above

String flowId = XMLUtil.createNonce(); // A unique flow ID that figures in the ID card is created                                                               
									   // using SEAL
DGWSHeaderWrapper signedHeaders = getValidDGWSHeaders(flowId); // see above

RegistryResponseType response =
  port.documentRegistryRegisterOnDemandDocumentEntry(
                   request,
                    signedHeaders.getSecurityHeader(),
                    new Holder<Header>(signedHeaders.getMedcomHeader()));

3.4          Helper Class for Creation of SubmitObjectsRequest

Code Block
languagejava
linenumberstrue
collapsetrue
package dk.nsi.ddsregistry.ws;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import oasis.names.tc.ebxml_regrep.xsd.lcm._3.ObjectFactory;
import oasis.names.tc.ebxml_regrep.xsd.lcm._3.SubmitObjectsRequest;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.AssociationType1;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.ClassificationType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.ExternalIdentifierType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.ExtrinsicObjectType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.LocalizedStringType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.RegistryPackageType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.SlotType1;

public class SubmitObjectsRequestHelper {

     public SubmitObjectsRequest create() {
          ObjectFactory objFactory = new ObjectFactory();
          return objFactory.createSubmitObjectsRequest();
     }

     public ExtrinsicObjectType addOnDemandDocumentMetadataEntry(
              SubmitObjectsRequest request,
              String documentId,
              String repositoryUniqueId) {
          ExtrinsicObjectType onDemandDocumentMetadata =
                   createOnDemandDocumentMetadataEntry(
                                   UUID.randomUUID().toString(),
                                   repositoryUniqueId);
          oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory objFactory =
                   new oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory();
          if (request.getRegistryObjectList() == null) {
              request.setRegistryObjectList(objFactory.createRegistryObjectListType());
          }
          request.getRegistryObjectList().getIdentifiable().add(
                   objFactory.createExtrinsicObject(onDemandDocumentMetadata));


          ExternalIdentifierType uniqueIdIdentifier =
                   createUniqueIdExternalIdentifierType(documentId, onDemandDocumentMetadata);
          onDemandDocumentMetadata.getExternalIdentifier().add(uniqueIdIdentifier);

          return onDemandDocumentMetadata;
     }


     public void addDocumentMetadataAttributes(ExtrinsicObjectType documentMetadataEntry,
              String authorInstitution, String patientId) {
          oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory objFactory =
                   new oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory();
          ClassificationType classification = objFactory .createClassificationType();
          classification.setId(UUID.randomUUID().toString());
          classification.setClassificationScheme("urn:uuid:93606bcf-9494-43ec-9b4e-a7748d1a838d");
          classification.setClassifiedObject(documentMetadataEntry.getId());
          SlotType1 authorInstitutionSlot = objFactory.createSlotType1();
          authorInstitutionSlot.setName("authorInstitution");
          authorInstitutionSlot.setValueList(objFactory.createValueListType());
          authorInstitutionSlot.getValueList().getValue().add(authorInstitution);
          classification.getSlot().add(authorInstitutionSlot);
          documentMetadataEntry.getClassification().add(classification);


          ExternalIdentifierType patientIdIdentifier = objFactory.createExternalIdentifierType();
          patientIdIdentifier.setId(UUID.randomUUID().toString());
          patientIdIdentifier.setIdentificationScheme("urn:uuid:58a6f841-87b3-4a3e-92fd-a8ffeff98427");
          patientIdIdentifier.setRegistryObject(documentMetadataEntry.getId());
          patientIdIdentifier.setValue(patientId);
          documentMetadataEntry.getExternalIdentifier().add(patientIdIdentifier);
     }


     public RegistryPackageType addSubmissionSet(SubmitObjectsRequest request) {
          oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory objFactory =
                   new oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory();
          RegistryPackageType submissionSetEntry = objFactory.createRegistryPackageType();
          submissionSetEntry.setId(UUID.randomUUID().toString());
          submissionSetEntry.setObjectType("urn:oasis:names:tc:ebxml-regrep:ObjectType:RegistryObject:RegistryPackage");
          request.getRegistryObjectList().getIdentifiable().add(objFactory.createRegistryPackage(submissionSetEntry));


          // Classify registry package as XDSSubmissionSet (outside the RegistryPackage)
          ClassificationType classification = objFactory.createClassificationType();
          classification.setClassificationNode("urn:uuid:a54d6aa5-d40d-43f9-88c5-b4633d873bdd"); // XDSSubmissionSet node value
          classification.setId(UUID.randomUUID().toString());
          classification.setObjectType("urn:oasis:names:tc:ebxml-regrep:ObjectType:RegistryObject:Classification");
          classification.setClassifiedObject(submissionSetEntry.getId());
          request.getRegistryObjectList().getIdentifiable().add(objFactory.createClassification(classification));


          return submissionSetEntry;
     }


     public void addSubmissionSetAttributes(RegistryPackageType submissionSetEntry, String patientId) {
          oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory objFactory =
                   new oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory();
          ExternalIdentifierType patientIdIdentifier = objFactory.createExternalIdentifierType();
          patientIdIdentifier.setId(UUID.randomUUID().toString());
          patientIdIdentifier.setObjectType("urn:oasis:names:tc:ebxml-regrep:ObjectType:RegistryObject:ExternalIdentifier");
          patientIdIdentifier.setIdentificationScheme("urn:uuid:6b5aea1a-874d-4603-a4bc-96a0a7b38446");
          patientIdIdentifier.setRegistryObject(submissionSetEntry.getId());
          patientIdIdentifier.setValue(patientId);
          submissionSetEntry.getExternalIdentifier().add(patientIdIdentifier);
     }


     public AssociationType1 addAssociation(SubmitObjectsRequest request,
              ExtrinsicObjectType documentMetadataEntry,
              RegistryPackageType submissionSetEntry) {
          oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory objFactory =
                   new oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory();
          AssociationType1 association = objFactory.createAssociationType1();
          association.setId(UUID.randomUUID().toString());
          association.setAssociationType("urn:oasis:names:tc:ebxml-regrep:AssociationType:HasMember");
          association.setObjectType("urn:oasis:names:tc:ebxml-regrep:ObjectType:RegistryObject:Association");
          association.setSourceObject(submissionSetEntry.getId());
          association.setTargetObject(documentMetadataEntry.getId());
          request.getRegistryObjectList().getIdentifiable().add(objFactory.createAssociation(association));
          return association;
     }


     public List<AssociationType1> addAssociationsForReplacements(
              SubmitObjectsRequest request,
              ExtrinsicObjectType documentMetadataEntry,
              List<String> extrinsicObjectIdsReplaced) {
          List<AssociationType1> result = new ArrayList<AssociationType1>();
          oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory objFactory =
                   new oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory();
          for (String extrinsicObjectId : extrinsicObjectIdsReplaced) {
              AssociationType1 association = objFactory.createAssociationType1();
              association.setId(UUID.randomUUID().toString());
              association.setAssociationType("urn:ihe:iti:2007:AssociationType:RPLC");
              association.setObjectType("urn:oasis:names:tc:ebxml-regrep:ObjectType:RegistryObject:Association");
              association.setSourceObject(documentMetadataEntry.getId());
              association.setTargetObject(extrinsicObjectId);
              request.getRegistryObjectList().getIdentifiable().add(objFactory.createAssociation(association));
              result.add(association);
          }
          return result;
     }

     private ExternalIdentifierType createUniqueIdExternalIdentifierType(
              String documentId, ExtrinsicObjectType metadataObjId) {
          oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory objFactory =
                   new oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory();
          ExternalIdentifierType uniqueIdIdentifier = objFactory.createExternalIdentifierType();
          uniqueIdIdentifier.setId(UUID.randomUUID().toString());
          uniqueIdIdentifier.setIdentificationScheme(XDSConstantsHelper.XDS_EXTERNAL_IDENTIFIER_UNIQUE_ID_IDENTIFICATION_SCHEME);
          uniqueIdIdentifier.setRegistryObject(metadataObjId.getId());
          uniqueIdIdentifier.setName(objFactory.createInternationalStringType());
          LocalizedStringType name = objFactory.createLocalizedStringType();
          name.setValue("XDSDocumentEntry.uniqueId");
          uniqueIdIdentifier.getName().getLocalizedString().add(name);
          uniqueIdIdentifier.setValue(documentId);
          return uniqueIdIdentifier;
     }


     private ExtrinsicObjectType createOnDemandDocumentMetadataEntry(
              String documentId,
              String repositoryUniqueId) {
          return createDocumentMetadataEntry(
                   documentId,
                   XDSConstantsHelper.XDS_ONDEMANDDOCUMENT_OBJ_TYPE,
                   repositoryUniqueId);
     }

     private ExtrinsicObjectType createStableDocumentMetadataEntry(
              String documentId,
              String repositoryUniqueId) {
          return createDocumentMetadataEntry(
                   documentId,
                   XDSConstantsHelper.XDS_STABLEDOCUMENT_OBJ_TYPE,
                   repositoryUniqueId);
     }


     private ExtrinsicObjectType createDocumentMetadataEntry(
              String documentId,
              String documentObjType,
              String repositoryUniqueId) {
          oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory objFactory =
                   new oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory();
          ExtrinsicObjectType extrinsicObjectType = objFactory.createExtrinsicObjectType();
          extrinsicObjectType.setId(documentId);
          extrinsicObjectTfype.setMimeType("text/xml");
          extrinsicObjectType.setObjectType(documentObjType);


          SlotType1 repositoryUniqueIdSlot = objFactory.createSlotType1();
          repositoryUniqueIdSlot.setName("repositoryUniqueId");
          repositoryUniqueIdSlot.setValueList(objFactory.createValueListType());
          repositoryUniqueIdSlot.getValueList().getValue().add(repositoryUniqueId);
          extrinsicObjectType.getSlot().add(repositoryUniqueIdSlot );
          return extrinsicObjectType;
     }
}


3.5          Client Generation from WSDL

A Web service client can be generated based on the DDS Registry WSDL-file, see [DDS Registry Registering Interface]. It is not given that the Web service client’s proxy classes can be generated based on a deployed service (using ?wsdl-extension on the service), as such calls are not necessarily supported.