Black Box View
Overview
In this scenario a client application sends a CDA document to a CDA document repository.
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 Infrastruture 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)Receiveribeformessage. 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 example)
The Request message is a CDA document wrapped up as an ITK payload within the distribution envelope, within the SOAP wrappers.
<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>
Response Message (Get example)
The Infrastructure Ack. is simple message containing the id of the payload being acknowledged..
<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>
Step 1 (Sending Application)
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.
The full source code for the Hello World CDA example can be seen here.
// 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);
Step 2 (Receiving R.I.)
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 concete 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.
The full source code for the AbstractRoutedMessageServlet can be seen here.
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());
Step 3 (Receiver Application)
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.
The full source code for the Document Repository sample can be seen here.
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());
Step 4 (Receiver R.I.)
The Receiver R.I. simply sends back an Infrastructure Ack as previously described.
Step 5 (Callback R.I.)
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).
The full source code for the AbstractCallbackListenerServlet can be seen here.
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); }
Step 6 (Web App)
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.
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"); ... }
Step 7 (Web App)
The rendered CDA document is now displayed...