Skip to main content

Routed clinical document architecture (CDA) document – repository example

In this scenario a client application sends a CDA document to a CDA document repository.

Overview

Some services used within the ITK are generically used across many ITK instantiations. These services are termed Core Services and are defined in the ITK Core Pack.

This scenario illustrates the use of a Core Service – “SendCDADocument-v2-0” – to send a CDA document to a CDA document repository. Core services supports effective multi-hop routing by providing an acknowledgement framework. This framework requires the end-point application to send an infrastructure Acknowledgment to the Sender on successful receipt at the infrastructure level. Similarly the end-point and all intermediary hop in the routing chain should send a NACK to the Sender in the event of a failure to process at the infrastructure level.

This does not provide true reliability, but does provide delivery assurance in the majority of cases leaving only exceptions to be investigated (as deemed necessary by the sending organisation).

Sender view

From the Sender perspective this is initially no different to sending a simple asynchronous message. The CDA message is formed and sent using the sendAsync API call. There the sending responsibilities end. However, as CDA is sent using one of the ITK Core services the sender is required to provide the capability to handle the Infrastructure and Business Acks which may be returned.

This scenario explores the Infrastructure Acks further in the step-by-step section below.

ITK Router view

The ITK Router is not within the scope of the Reference Implementation, but in short this has a simple role.

The Router sends a SimpleMessageResponse back to the preceding hop to acknowledge receipt and closes that synchronous channel. The Router will then identify the next end-point from the ITK Address on the incoming Distribution Envelope, and forward the message on to the next hop – which may or may not be the final destination.

The router has one further responsibility which is to route a NACK back to the originator in the event of failure to process (or forward) the message.

Receiver view

The Receiver consumes the CDA Message and sends a simple acknowledgement of receipt to the sender( as a SimpleMessageResponse).

As with the intermediary ITK Routers, the end receiver is also responsible for routing an ACK or NACK (as an InfrastructureAcknowledgement).

This validates the SOAP headers and then extracts the payload. The SOAP payload is then split further to the originator as defined in the Distribution Envelope.

The Infrastructure Acknowledgement is a routed message (defined in the core ITK specification) and this message may go through any number of intermediary ITK Routers before resolving to the originating end-point.

Request message

Get Request Message example

The Request message is a CDA document wrapped up as an ITK payload within the distribution envelope, within the SOAP wrappers.

[code lang=”xml”]
<soap:Envelope xmlns:itk="urn:nhs-itk:ns:201005" …
<soap:Header>
<wsa:MessageID>B8652870- …
…
</soap:Header>
<soap:Body>
<itk:DistributionEnvelope …
<itk:header service="urn:nhs-itk…
…
</itk:header>
<itk:payloads count="1">
<itk:payload id="uuid_NJ1">
<ClinicalDocument classCode="DOCCLIN" moodCode="EVN"
…
</ClinicalDocument>[/code]

Response message

Get Response Message example

The Infrastructure Ack. is simple message containing the id of the payload being acknowledged.

[code lang=”xml”]
<soap:Envelope xmlns:itk="urn:nhs-itk:ns:201005" …
<soap:Header>
<wsa:MessageID>B8652870- …
</soap:Header>
<soap:Body>
<itk:DistributionEnvelope …
<itk:header service="urn:nhs-itk … </itk:header>
<itk:payloads count="1">
<itk:payload id="uuid_6931E0D7-DD26-4BE1-918E-CC7897AD4552">
<itk:InfrastructureResponse result="OK"
serviceRef="urn:nhs-itk:services:201005:SendCDADocument-v2-0"
timestamp="2013-02-04T13:41:28+0000" trackingIdRef="6931E0D7-DD26-4BE1-918E-CC7897AD4552">
<itk:reportingIdentity>
<itk:id uri="urn:nhs-uk:identity:cfh:ri:application"/>
</itk:reportingIdentity>
</itk:InfrastructureResponse>
</itk:payload>
[/code]

How it all happens - step 1

The sending application builds a SimpleMessage and populates the business payload with the CDA Document in serialized form. The application then sets a number of message properties before creating a message sender and sending the message using the sendAsync call.

See the full source code for the Hello World CDA example

[code lang=”java”]
// Create the message
ITKMessage msg = new SimpleMessage();
msg.setBusinessPayload(docText);
…
// Set the message properties
mp.setServiceId("urn:nhs-itk:services:201005:SendCDADocument-v2-0");
…
// Create the sender
ITKMessageSender sender = new ITKMessageSenderImpl();
…
// Send this message Asynchronously – return is void.
sender.sendAsync(msg);
[/code]

Step 2

The Reference Implementation provides the AbstractRoutedMessageServlet as an abstract implementation of an ITK receiving application for Routed Messages. This is realised by an application provider producing an extension of this class providing concrete implementations of the abstract methods.

On top of the basic responsibilities of the AbstractSimpleMessageServlet discussed previously, this component is also responsible for sending an Infrastructure Acknowledgement.

This component creates the ITK Message representing the on-the-wire request and forwards that message to the configured application handler.

Once control is returned from the application handler then the Infrastructure Acknowledgement is generated and routed back to the originating sender.

See the full source code for the AbstractRoutedMessageServlet.

[code lang=”java”]
protected void doPost(HttpServletRequest req, HttpServletResponse resp)byte[] requestMsgBytes = ServletUtils.readRequestContent(req);
…
String requestString = new String(requestMsgBytes);
ITKMessage requestMsg = this.createRequestMessage(requestString);
ITKMessage responseMsg = this.processMessage(requestMsg);

//Now create and Send InfrastructureAck
this.sendInfrastructureAck(requestMsg.getMessageProperties());
[/code]

Step 3

The receiving application in this example scenario simply stores the incoming CDA document in a data store.

Being a sample application that is simply represented by an in memory HashMap keyed by the document id.

See the full source code for the Document Repository sample.

[code lang=”java”]
public void onMessage(ITKMessage request) {
Logger.trace("This is CDA Repository receiving a message:onMessage()");
String docId = request.getMessageProperties().getBusinessPayloadId();
if (docId.substring(0,5).equals("uuid_")){
docId = docId.substring(5);
}
DocStore.putDocument(docId, request.getBusinessPayload());
[/code]

Step 4

The Receiver R.I. simply sends back an Infrastructure Ack as previously described.

[code lang=”java”]
[/code]


Step 5

The AbstractCallbackListenerServlet described in the earlier scenarios is aware of Infrastructure Acks. The component will build an ITK Message to contain the Ack, call the configured application handler and then acknowledge receipt of the Ack to the caller (HTTP 202).

See the full source code for the AbstractCallbackListenerServlet.

[code lang=”java”]
if (businessPayloadName.equalsIgnoreCase("InfrastructureResponse")){
Logger.trace("Processing InfrastructureResponse");

// For an Infrastructure Acknowledgement, check if it is a ACK or a NACK,
// extract the pertinent details and pass
// as an ITKAckDetails object to the application defined handlers

String result = distributionEnvelope.getDocumentElement().getAttribute("result");
if (result.equals("OK")){
// Pass to APP for correlation etc.
//TODO – Build the Acknowledgement
this.callbackHandler.onAck(null);
} else {
//TODO – Build the Acknowledgement
this.callbackHandler.onNack(null);
}
[/code]

Step 6

The Repository example comes complete with a sample “Get Document” Web Application. This prompts for a document Id, then looks up that id in the in-memory data store used by the repository in Step 3.

Provided a document is found, it is rendered using the default XSLT template for generic rendering of CDA document and displayed to the user.

In only a few steps a simple CDA document has been created, sent over the wire to a CDA repository where it is available for query and retrieval.

See the full source code for the CDA Viewer.

[code lang=”java”]
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String docId= request.getParameter("docid");
String document = DocStore.getDocument(docId);
if (null!=document){
String htmlResponse = TransformManager.doTransform("CDA_NPfIT_Document_Renderer.xsl", document);
response.setContentType("text/html");
response.getWriter().write(htmlResponse);
} else {
Logger.trace("Document not found");
…
}
[/code]

Step 7

The rendered CDA document is now displayed…

Rendered CDA document

Last edited: 14 January 2022 10:52 am