Skip to main content

Admit Discharge Transfer (ADT) Query Patient (XML)

In this scenario a client application queries a remote Master Patient Index (MPI) asynchronously using an XML version of an ADT HL7v2 message.

ADT Admit Patient – XML format – Asynchronous

client application queries a remote Master Patient Index (MPI) asynchronously using an XML version of an ADT HL7v2 message

Overview

In this scenario a client application queries a remote Master Patient Index (MPI) asynchronously using an XML version of an ADT HL7v2 message. From a business perspective this is typically used by a departmental system to retrieve demographics from the hospital PAS.

The following describes the logic required to invoke the ITK urn:nhs-itk:services:201005:getPatientDetailsByNHSNumber-v1-0 service.

From a black-box perspective this asynchronous interaction is still fairly straightforward, though obviously more complicated than the synchronous interactions. The service requestor sends the appropriate ITK request message and receives a synchronous acknowledgement. Any exceptions encountered in accepting the request will be returned as synchronous Simple Object Access Protocol (SOAP) Faults.Sometime later, the query response is returned by the service provider (PAS) asynchronously to a callback handler specified by the service requestor. Any exceptions encountered in processing the request will be returned as asynchronous SOAP Faults.

Sender view

The Sender builds a SimpleMessage using a String containing the XML ADT message. Configuration of the service tells the R.I. that this message is XML and does not requires base64 encoding.

Receiver view

The Receiver consumers the SOAP message. This validates the SOAP headers and then extracts the payload. The SOAP payload is then split further into Distribution Envelope and business payload. The Distribution Envelope is validated and extracted into MessageProperties. The R.I. then looks up the service properties from the configuration and – in this case – as the payload is simple XML it is passed onto the Application Message Handler.

Request message

Copy
[code lang=”xml”]

<soap:Envelope xmlns:itk="urn:nhs-itk:ns:201005" … >

<soap:Header></soap:Header>

<soap:Body>

<itk:DistributionEnvelope>

<itk:header service="urn:nhs-itk:services:201005:queryPatientDemographics-v1-0" …>

<itk:manifest count="1">

<itk:manifestitem mimetype="text/xml" base64="false" compressed="false" id="… "

</itk:manifest>

</itk:header>

<itk:payloads count="1">

<itk:payload id="uuid_E808A967-49B2-498B-AD75-1D7A0F1262D7">

<hl7v2:QBP_Q21 xmlns:hl7v2="urn:hl7-org:v2xml"><hl7v2:MSH><hl7v2:MSH.1>|</hl7v2:MSH>

[/code]

HTML

Response message

Copy
[code lang=”xml”]

<itk:DistributionEnvelope xmlns:itk="urn:nhs-itk:ns:201005"
<itk:header service="urn:nhs-itk:services:201005:queryPatientDemographics-v1-0Response"
<itk:manifest count="1">

<itk:manifestitem mimetype="text/xml" base64="false"
</itk:manifest>

</itk:header>

<itk:payloads count="1">

<itk:payload id="uuid_E808A967-49B2-498B-AD75-1D7A0F1262D7">

<hl7v2:RSP_K21 xmlns:hl7v2="urn:hl7-org:v2xml">

<hl7v2:MSH>

<hl7v2:MSH.1>|</hl7v2:MSH.1>

[/code]

HTML

How it all happens - step 1

The sending application builds a SimpleMessage and populates the business payload with the ADT message. The application then sets a number of message properties before creating a message sender and sending the message.

In this case the application uses the sendAsync call of the ITK API because the call is to be asynchronous. Normally this will be known at design time, but as the example shows this decision can be made at run-time provided the application is sophisticated enough to handle the two paradigms.

See the full source code for the sample ADT Servlet.

Copy
[code lang=”java”]

// Create the message

ITKMessage msg = new SimpleMessage();

msg.setBusinessPayload(docText);


// Set the message properties

mp.setServiceId("urn:nhs-itk:services:201005:queryPatientDemographics-v1-0");


// Create the sender

ITKMessageSender sender = new ITKMessageSenderImpl();


// Send this message Asynchronously – return is void.

sender.sendAsync(msg);

[/code]

Java

Step 2

The first layer of the ITK Reference Implementation (R.I.) is the sendAsync method of the ITKMessageSenderImpl. This component is responsible for checking service properties, establishing the physical transport route and adding the ITK Distribution Envelope, as described in earlier scenarios.

For a simple asynchronous message the service configuration is of particular interest. ADT messages can be sent synchronously or asynchronously, but in the later case the return endpoint needs to be defined. The R.I. does this through the directory.properties configuration file, which manages all configurable aspects of message routing.

The config on the right is taken from the Samples Project and shows where callback calls are routed to.

See the full source code for the ITKMessageSenderImpl.

Copy
[code lang=”java”]

public void sendAsync(ITKMessage request) throws ITKMessagingException {

String serviceId = request.getMessageProperties().getServiceId();

// Get the ITKService from the DirectoryOfService

ITKService service = dos.getService(serviceId);

// validate the service configuration is valid for an async call


ITKTransportRoute route = getRoute(request);

ITKSender sender = getSender(route);

ITKMessage message = buildMessage(request, route, service);

sender.sendAysnc(route, message);

[/code]

[code lang=”java”]

urn\:nhs-itk\:services\:201005\:queryPatientDemographics-v1-0.urn\:nhs-uk\:addressing\:ods\:TESTORGS\:ADTLOCAL.channelid=ADTLOCAL

# Configure callback for async calls

ADTLOCAL.ReplyTo=https://developer.nhs.uk:8080/itk-samples/adt/callback

ADTLOCAL.ExceptionTo=https://developer.nhs.uk:8080/itk-samples/adt/callback

[/code]

Java

Step 3

The next layer of the ITK Reference Implementation (R.I.) is the sendAsync method of the ITKSenderWSImpl.

This component is responsible for managing the WebServices layer – building the SOAP wrappers, physically sending the message, then interpreting the response.

The sendAsync code tells the SOAP handler (WSSOAPMessageImpl) that the message is an Async request which, together with the configuration properties, enables the R.I. to build the correct SOAP Headers.

See the full source code for the ITKSenderWSImpl.

Copy
[code lang=”java”]

public void sendAysnc(ITKTransportRoute dest, ITKMessage req)
// Add the soap wrappers

WSSOAPMessageImpl message

= new WSSOAPMessageImpl(dest, req, WSSOAPMessageImpl.ASYNCREQ);

[/code]

[code lang=”xml”]

<soap:Header>

<wsa:MessageID>D16AF8FB- … -0A7858587D49</wsa:MessageID>

<wsa:Action>urn:nhs … :queryPatientDemographics-v1-0</wsa:Action>

<wsa:To>https://developer.nhs.uk:8080/itk-samples/adt/emulator</wsa:To>

<wsa:From> … </wsa:From>

<wsa:ReplyTo>

<wsa:Address>https://developer.nhs.uk:8080/itk-samples/adt/callback

</wsa:Address>

</wsa:ReplyTo>

<wsa:FaultTo>

<wsa:Address>https://developer.nhs.uk:8080/itk-samples/adt/callback

</wsa:Address>

</wsa:FaultTo>


</soap:Header>

[/code]

Java

Step 4

The Reference Implementation provides the AbstractSimpleMessageServlet as an abstract implementation of an ITK receiving application. This is realised by an application provider producing an extension of this class providing concete implementations of the abstract methods.

This abstract class extracts the incoming transport properties from the SOAP headers and attaches them to the ITKMessage which is built to represent the inbound message, providing a mechanism for the reply to parameters to live with the message.

Importantly the replyTo parameter is used by the R.I. to determine whether to invoke the application handler synchronously or asynchronously.

See the full source code for the AbstractSimpleMessageServlet.

Copy
[code lang=”java”]

// 2) PROCESS THE SOAP HEADERS

//Extract the transport properties

itkTransportProperties = ITKTransportPropertiesImpl.buildFromSoap(doc);


//Attach the associated transport properties so that they

// are available for asynchronous invocations

itkMessageProperties.setInboundTransportProperties(itkTransportProperties);


//Determine which method to call on application

if (StringUtils.hasValue(itkTransportProperties.getTransportReplyTo())) {

//ReplyTo is present – must want asynchronous response

this.messageConsumer.onMessage(requestMsg);

} else {

//ReplyTo is not present assume synchronous application

response = this.messageConsumer.onSyncMessage(requestMsg);

}

[/code]

Java

Step 5

In the Async ADT Query in the Samples project the SimpleApplicationEmulator is used to illustrate this. This emulator creates the response message using the message properties from the request, thereby telling the R.I. that this is a response to that message.

In this scenario the onMessage method of the application handler wass called which provides no response. Once control is received from the handler the R.I. will simply return an HTTP 202 acknowledgement on the open channel.

See the full source code for the SimpleApplicationEmulator.

Copy
[code lang=”java”]

private ITKMessage turnaroundViaFile(String responseProfileId,

ITKMessage request) throws ITKMessagingException {



//Create a response using the message properties from the request

SimpleMessage msg = new SimpleMessage(request.getMessageProperties(),

this.auditIdentity, responseProfileId, true);


// Read the response from a pre-defined file

String responseString;

try {

responseString = readFile(fileName);

} catch (IOException e) {


}

msg.setBusinessPayload(responseString);

return msg;

[/code]

Java

Step 6

The response message is sent through the normal send API. However. because the ITKMessage was built from the incoming message properties (including the ReplyTo), the message already knows the route back to the callback endpoint and therefore skips the routing lookup.

The ITKMessageSenderImpl allows for this pre-determination of route.

See the full source code for the ITKMessageSenderImpl.

Copy
[code lang=”java”]

private ITKTransportRoute getRoute(ITKMessage request)


String serviceId = request.getMessageProperties().getServiceId();



// Has the transport route already been resolved?

ITKTransportRoute route = request.getPreresolvedRoute();


// If the route has not been pre-resolved look it up

if (route == null) {

route = dos.resolveDestination(serviceId, toAddress);

} else {

Logger.debug("Pre-resolved transport route on object "
}

[/code]

Java

Step 7

The Reference Implementation provides the AbstractCallbackListenerServlet as an abstract implementation of an ITK callback application. This is realised by an application provider producing an extension of this class which acts as a factory providing an instance of the callback handler ITKCallbackHandler.

The abstract class extracts the incoming transport properties from the SOAP headers and attaches them to the ITKMessage which is built to represent the inbound message. The message is passed to the processITKMessage layer which hands off processing to the appropriate application handler.

See the full source code for the AbstractCallbackListenerServlet.

Copy
[code lang=”java”]

public interface ITKCallbackHandler {



public abstract void onMessage(ITKMessage response);



public abstract void onAck(ITKAckDetails ack);



public abstract void onNack(ITKAckDetails ack);



}

[/code]

Java

Step 8

Finally, the application call handler processes the message as per the local requirements of the system

The sample callback hander simply prints a message.

Copy
[code lang=”java”]

public class SimpleMessageCallbackHandler

extends AbstractCallbackListenerServlet

implements ITKCallbackHandler {



public void onMessage(ITKMessage request) {

Logger.trace("This is my example callback handler:onMessage()");

}



[/code]

Java

Last edited: 2 May 2019 10:11 am