IHE support
Concepts
The IPF provides support for several IHE profiles. The basic idea is to offer a Camel component for each IHE transaction. These components ensure that the technical requirements of the profile are met by applications built on top of the IPF IHE support.
Quick reference
All IPF IHE components are named according to the profile and transaction that they implement. Each profile corresponds to a Maven artifact in the group org.openehealth.ipf.platform-camel, whereby each artifact contains a set of components, as listed below:
Artifact platform-camel-xds
| IHE Transaction ID | Description | IPF IHE component |
|---|---|---|
| ITI-14 | XDS.a Register Document Set | xds-iti14 |
| ITI-15 | XDS.a Provide & Register Document Set | xds-iti15 |
| ITI-16 | XDS.a Query Registry | xds-iti16 |
| ITI-17 | XDS.a Retrieve Document | xds-iti17 |
| ITI-18 | XDS.a+b Registry Stored Query | xds-iti18 |
| ITI-41 | XDS.b Provide & Register Document Set | xds-iti41 |
| ITI-42 | XDS.b Register Document Set | xds-iti42 |
| ITI-43 | XDS.b Retrieve Document Set | xds-iti43 |
Artifact platform-camel-pixpdq
| IHE Transaction ID | Description | IPF IHE component |
|---|---|---|
| ITI-8 | Patient Identity Feed (PIX Feed) | pix-iti8 xds-iti8 |
| ITI-9 | PIX Query | pix-iti9 |
| ITI-10 | PIX Update Notification | pix-iti10 |
| ITI-21 | Patient Demographics Query (PDQ) | pdq-iti21 |
| ITI-22 | Patient Demographics and Visit Query (PDQ) | pdq-iti22 |
Artifact platform-camel-pixpdqv3 (since IPF 2.1)
| IHE Transaction ID | Description | IPF IHE component |
|---|---|---|
| ITI-44 | Patient Identity Feed (PIX Feed) v3 | pixv3-iti44 xds-iti44 |
| ITI-45 | PIX Query v3 | pixv3-iti45 |
| ITI-46 | PIX Update Notification v3 | pixv3-iti46 |
| ITI-47 | Patient Demographics Query (PDQ) v3 | pdqv3-iti47 |
Artifact platform-camel-xcpd (since IPF 2.1/2.2)
| IHE Transaction ID | Description | IPF IHE component |
|---|---|---|
| ITI-55 | Cross-Gateway Patient Discovery | xcpd-iti55 |
| ITI-56 | Cross-Gateway Patient Location Query | xcpd-iti56 |
Moreover, there are packages which serve for translation of request and response messages of selected ITI transactions between HL7 v3 and HL7 v2:
XDS.b
The IHE XDS.b profile mandates the use of the web service technology. The IPF provides these web services in conformance with the specification, together with their WSDL documents. The XDS.b actors (Registry, Repository, Source and Consumer) are not directly implemented by the IPF. Instead, the transactions required by the actors are offered via components that create endpoints for both the client and server sides. An application assembles these components to build the actors:

Note that registries are also required to support the PIX feed transaction, which is covered in the corresponding section.
XDS standard conformance
The IPF implementation of the XDS profiles conforms to Version 6.0 (August 2009) of the IHE infrastructure technical framework with the addition of the final texts of the change proposals up to CP 426.
Because the XDS components do not represent a full implementation of the XDS actors, they cannot fulfill all parts of the specification. E.g. they cannot check whether a patient ID is known to the registry. Such checks need to be performed within the route implementation. The following list should give a brief overview of the parts of the requirements that have been met by the IPF implementation:
- protocol specific requirements: most notably those listed in Appendix V of the ITI Technical Framework Volume 2x (Web Services for IHE Transactions). This includes WS-Addressing, SOAP 1.2/1.1 and mustUnderstand attributes in SOAP headers.
- meta class model requirements: as listed in chapter 4 of the ITI Technical Framework Volume 3 (Cross-Transaction Specifications). This also includes transformations between ebXML classes and meta model classes where applicable.
- stored query classes: as an extension to the meta model, simplified classes have been defined for each stored query type specified in section 3.18 of the ITI Technical Framework Volume 2a (Registry Stored Query).
XDS.b configuration
To use of the IPF XDS.b components in an application, you have to add the dependencies of the profile component to your pom.xml:
<dependency> <groupId>org.openehealth.ipf.platform-camel</groupId> <artifactId>platform-camel-ihe-xds</artifactId> <version>${ipf-version}</version> </dependency>
The web service implementation within the IPF component is based on Apache CXF. The necessary dependencies are transitively included via the above dependency. CXF itself can be used in various ways. For the purpose of this documentation we will use Spring configuration via imports and deploy the components into Apache Tomcat. The following snippet is an example for an application context that imports all relevant CXF and IPF beans:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camel="http://camel.apache.org/schema/spring" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd "> <!-- Importing the CXF configuration --> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/> <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-addr.xml"/> <camel:camelContext id="camelContext"> <camel:jmxAgent id="agent" disabled="true"/> <camel:routeBuilder ref="routeBuilder"/> </camel:camelContext> <bean id="routeBuilder" depends-on="routeModelExtender" class="org.openehealth.ipf.platform.camel.ihe.xds.iti18.GroovyRouteBuilder"> </bean> <bean id="coreModelExtension" class="org.openehealth.ipf.platform.camel.core.extend.CoreModelExtension"> </bean> <bean id="xdsModelExtension" class="org.openehealth.ipf.platform.camel.ihe.xds.core.extend.XDSModelExtension"> </bean> <bean id="routeModelExtender" class="org.openehealth.ipf.platform.camel.core.extend.DefaultModelExtender"> <property name="routeModelExtensions"> <list> <ref bean="coreModelExtension" /> <ref bean="xdsModelExtension" /> </list> </property> </bean> </beans>
Deployment within Tomcat is done by defining a web.xml that references the above application context as well as instantiating a CXF-related servlet. A simple setup could look like this:
<?xml version="1.0"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name>Test IPF IHE Web-App</display-name> <context-param> <!-- configures the classpath of the Spring application context --> <param-name>contextConfigLocation</param-name> <param-value>classpath:path/to/your/context.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet </servlet-class> </servlet> <servlet-mapping> <!-- configures the address of the servlet path under which our web services are published --> <servlet-name>CXFServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> </web-app>
Exposing an XDS.b service
Similar to other Camel components, the XDS.b components are used within your routes:
from('xds-iti18:myIti18Service')
...
This statement creates a web service that implements the ITI-18 transaction and publishes it under the service name myIti18Service. The full path of the service URL is made up by the web container and the servlet configuration. With the above configuration, the service will be published under http://HOSTNAME:PORT/WEBAPP/services/myIti18Service, where HOSTNAME is the name of the machine that the service is running on, PORT represents the TPC/IP port configured within the web container (e.g. in Tomcat you can configure this in server.xml, default value is 8080), and WEBAPP is a name that depends on your web application deployment (in Tomcat this is simply the name of the directory of the web application). More information about how to setup a simple web application with Apache Tomcat can be found here.
Secure transport can be used with the XDS.b services by configuring your container. There is no additional configuration required for IPF XDS components. Details on how to configure Apache Tomcat with SSL support can be found here.
Making calls to an XDS.b service
You access an XDS.b service within a route similar to other Camel endpoints:
...
.to('xds-iti18://localhost:8080/myWebApp/services/myIti18Service')
The whole endpoint URI resembles the service URL as it was described in the previous section. The only difference is that the protocol name is changed from http to xds-iti18.
Per default, all requests will be sent using SOAP 1.2, as prescribed by the specification. To switch to SOAP 1.1, URL parameter soap11=true can be used. Note that because of a bug in CXF, XDS.b consumer components will produce SOAP 1.2 responses independently from the actual SOAP version used in requests. This will be corrected as soon as the new CXF version will be available for the IPF. (Note 2010-02-10: parameter "soap11" is not supported any more)
Secure transport via HTTPS can be configured by adding the URL parameter secure=true. The following sample shows a call to a registry over HTTPS:
...
.to('xds-iti18://localhost:8080/myWebApp/services/myIti18Service?secure=true')
In addition, the HTTP client used by CXF must be configured as well. This is done within the application context according to the CXF documentation:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camel="http://camel.apache.org/schema/spring" xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:sec="http://cxf.apache.org/configuration/security" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd "> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <http:conduit name="*.http-conduit"> <http:tlsClientParameters disableCNCheck="true"> <sec:keyManagers keyPassword="changeit"> <sec:keyStore type="JKS" password="changeit" file="keystore" /> </sec:keyManagers> <sec:trustManagers> <sec:keyStore type="JKS" password="changeit" file="keystore" /> </sec:trustManagers> <sec:cipherSuitesFilter> <!-- these filters ensure that a ciphersuite with export-suitable or null encryption is used, but exclude anonymous Diffie-Hellman key change as this is vulnerable to man-in-the-middle attacks --> <sec:include>.*_EXPORT_.*</sec:include> <sec:include>.*_EXPORT1024_.*</sec:include> <sec:include>.*_WITH_DES_.*</sec:include> <sec:include>.*_WITH_NULL_.*</sec:include> <sec:exclude>.*_DH_anon_.*</sec:exclude> </sec:cipherSuitesFilter> </http:tlsClientParameters> </http:conduit> ...
Message types
Messages sent between XDS.b actors use a payload defined by ebXML 3.0. The profile specifies how messages are created to represent requests and responses as well as document entries, submission sets and folders. Besides the support of raw ebXML 3.0 messages, the IPF offers a model to abstract from the underlying details of transforming and validating ebXML 3.0 messages. A very technical view is shown on the diagram below (click to enlarge):
Raw ebXML 3.0 support
The body of input and output messages depends on the transaction:
| Transaction | Input message body | Output message body |
|---|---|---|
| ITI-18 | org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.query.AdhocQueryRequest | org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.query.AdhocQueryResponse |
| ITI-41 | org.openehealth.ipf.commons.ihe.xds.core.ebxml.ebxml30.ProvideAndRegisterDocumentSetRequestType | org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.rs.RegistryResponseType |
| ITI-42 | org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.lcm.SubmitObjectsRequest | org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.rs.RegistryResponseType |
| ITI-43 | org.openehealth.ipf.commons.ihe.xds.core.ebxml.ebxml30.RetrieveDocumentSetRequestType | org.openehealth.ipf.commons.ihe.xds.core.ebxml.ebxml30.RetrieveDocumentSetResponseType |
The IPF also provides the necessary ebRS 3.0 classes that are referenced within these types. All ebRS 3.0 related classes can be found in the sub-packages of org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.
Simplified model classes
ebXML 3.0 message bodies can be converted to a simplified model. The following table shows the types that can be used for each transaction:
| Transaction | Input message body | Output message body |
|---|---|---|
| ITI-18 | org.openehealth.ipf.commons.ihe.xds.core.requests.QueryRegistry | org.openehealth.ipf.commons.ihe.xds.core.responses.QueryResponse |
| ITI-41 | org.openehealth.ipf.commons.ihe.xds.core.requests.ProvideAndRegisterDocumentSet | org.openehealth.ipf.commons.ihe.xds.core.responses.Response |
| ITI-42 | org.openehealth.ipf.commons.ihe.xds.core.requests.RegisterDocumentSet | org.openehealth.ipf.commons.ihe.xds.core.responses.Response |
| ITI-43 | org.openehealth.ipf.commons.ihe.xds.core.requests.RetrieveDocumentSet | org.openehealth.ipf.commons.ihe.xds.core.responses.RetrievedDocumentSet |
These model classes can be used via type converters, as shown in the following Groovy route:
import static org.openehealth.ipf.commons.ihe.xds.core.responses.Status.* import org.apache.camel.spring.SpringRouteBuilder import org.openehealth.ipf.commons.ihe.xds.core.requests.QueryRegistry import org.openehealth.ipf.commons.ihe.xds.core.requests.query.FindDocumentsQuery import org.openehealth.ipf.commons.ihe.xds.core.responses.QueryResponse import org.openehealth.ipf.commons.ihe.xds.core.metadata.ObjectReference import org.openehealth.ipf.platform.camel.core.util.Exchanges public class RouteBuilder extends SpringRouteBuilder { @Override public void configure() throws Exception { from('xds-iti18:myIti18Service') .convertBodyTo(QueryRegistry.class) .choice() // Return an object reference for a find documents query .when { it.in.body.query instanceof FindDocumentsQuery } .transform { def response = new QueryResponse(SUCCESS) response.references.add(new ObjectReference('document01')) response } // Any other query else is a failure .otherwise() .transform { new QueryResponse(FAILURE) } } }
This route only accepts the stored query FindDocuments. If it receives such a query, it returns a single reference to a document (document01). Any other query returns a failure response. Of course this route does not fulfill the functional requirements of the ITI-18 transaction (e.g. all stored query types must be supported by a registry). However, it shows how a registry can be implemented without directly using the ebXML 3.0 classes.
| convertBodyTo Note that convertBodyTo(QueryRegistry.class) is not strictly required. If it is not used, the conversion must be done when accessing the body. In this case the when statement needs to use it.in.getBody(QueryRegistry.class).query. This will leave the body unchanged. However, keep in mind that converting the ebXML object every time you need to access the body can be time consuming. |
Large document content
The transactions ITI-41 and ITI-43 have to send document content as part of their request or response messages. In practice such messages can become quite large. To allow for memory-efficient streaming of the document content, the aforementioned components rely on CXF's support for binary data. CXF streams the content on disk and then provides a DataHandler to access the file. Therefore, it is not necessary to use IPF's large binary support (LBS).
Validation
The XDS.b components provide functionality for transaction-specific validation of ebXML 3.0 messages. This validation uses the validate DSL extension of the IPF. The following code snippet shows an example of a validation in
from('xds-iti18:myIti18Service')
.validate().iti18Request()
... // Process the message and create a response.
.validate().iti18Response()
The corresponding DSL extensions for validation need to be included into the model extender. Make sure that the following beans are defined within your application context:
... <bean id="coreModelExtension" class="org.openehealth.ipf.platform.camel.core.extend.CoreModelExtension" /> <bean id="xdsModelExtension" class="org.openehealth.ipf.platform.camel.ihe.xds.core.extend.XDSModelExtension" /> <bean id="routeModelExtender" class="org.openehealth.ipf.platform.camel.core.extend.DefaultModelExtender"> <property name="routeModelExtensions"> <list> <ref bean="coreModelExtension" /> <ref bean="xdsModelExtension" /> <!-- ... other model extension bean if necessary ... --> </list> </property> </bean> ...
XDS.a
Support for XDS.a is similar to that of XDS.b. Most transactions presume web service-based endpoints; only ITI-17 directly uses HTTP for the download of documents. With the exception of ITI-18, which is the same in both XDS.a and XDS.b, XDS.a transaction numbers differ from those in XDS.b and use SOAP 1.1 and SwA (SOAP with Attachments) instead of SOAP 1.2 and MTOM respectively. The following image gives a quick overview of the actors and transactions involved in the XDS.a profile:

Note that the Registry actor has to support the PIX feed transaction, which is covered in the corresponding section.
Configuring, exposing and accessing of the XDS.a components are to be performed in the same way as in the case of XDS.b. As already mentioned above, the only significant difference is that the ITI-17 transaction is not implemented as a SOAP-based web service. Therefore, it requires a few additional steps that are mentioned in the next sections.
XDS standard conformance
The IPF implementation of the XDS profiles conforms to Version 6.0 (August 2009) of the IHE infrastructure technical framework with the addition of the final texts of the change proposals up to CP 426.
ITI-17 configuration
To offer the ITI-17 transaction for a repository implementation you have to add an additional servlet to your web.xml:
<?xml version="1.0"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name>Test IPF IHE Web-App</display-name> <context-param> <!-- configures the classpath of the Spring application context --> <param-name>contextConfigLocation</param-name> <param-value>classpath:org/openehealth/ipf/platform/camel/ihe/xdsb/example/context.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <!-- Servlet used for all CXF web services --> <servlet-name>CXFServlet</servlet-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet </servlet-class> </servlet> <servlet> <!-- Servlet used only for ITI-17 --> <servlet-name>Iti17Servlet</servlet-name> <servlet-class> org.openehealth.ipf.platform.camel.ihe.xds.iti17.servlet.Iti17Servlet </servlet-class> </servlet> <servlet-mapping> <!-- configures the address of the servlet path under which our web services are published --> <servlet-name>CXFServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <servlet-mapping> <!-- configures the address of the servlet path under which the ITI-17 transaction is published --> <servlet-name>Iti17Servlet</servlet-name> <url-pattern>/iti17/*</url-pattern> </servlet-mapping> </web-app>
Exposing the ITI-17 transaction
The ITI-17 transaction is exposed via
from('xds-iti17:myIti17Service')
...
The URL that this transaction is accessible under is determined by the ITI-17 servlet configuration in your web.xml. For the above sample web.xml, the URL results in http://HOSTNAME:PORT/WEBAPP/iti17/myIti17Service. Note that the servlet path (iti17) is different to that of other transactions (services) that use the CXFServlet.
Making calls to the ITI-17 transaction
Calling the ITI-17 transaction from a document consumer can be achieved via:
...
.to('xds-iti17://localhost:8080/myWebApp/iti17/myIti17Service')
Again, note the difference in the URL. The ITI-17 servlet is accessed through a different path than the CXFServlet.
Message types
Messages sent between XDS.a actors use ebXML 2.1 (ebXML 3.0 for ITI-18) as payload format. The profile specifies how messages are created to represent requests and responses as well as document entries, submission sets and folders. Besides the support for raw ebXML messages, the IPF offers a model to abstract from the underlying details of transforming and validating ebXML messages. A very technical view is shown on the diagram below (click to enlarge):
Raw ebXML 2.1/3.0 support
The body of input and output messages depend on the transaction:
| Transaction | Input message body | Output message body |
|---|---|---|
| ITI-14 | org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs21.rs.SubmitObjectsRequest | org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs21.rs.RegistryResponse |
| ITI-15 | org.openehealth.ipf.commons.ihe.xds.core.ebxml.ebxml21.ProvideAndRegisterDocumentSetRequestType | org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs21.rs.RegistryResponse |
| ITI-16 | org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs21.query.AdhocQueryRequest | org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs21.rs.RegistryResponse |
| ITI-17 | String (document URL part) | InputStream |
| ITI-18 | org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.query.AdhocQueryRequest | org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.query.AdhocQueryResponse |
The IPF also provides the necessary ebRS 2.1 and 3.0 classes that are referenced within these types. All ebRS-related classes can be found in the sub-packages of org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30 and org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs21.
The input of the ITI-17 transaction is the part of the document URL that is appended to the URL of the service. The exact structure depends on the implementation of the Repository actor. It can be a path, a query, or a combination of both:
| Document URL | ITI-17 input message body |
|---|---|
http://HOSTNAME:PORT/WEBAPP/iti17/myIti17Service/my/path/to/document |
/my/path/to/document |
http://HOSTNAME:PORT/WEBAPP/iti17/myIti17Service?docId=123 |
?docId=123 |
http://HOSTNAME:PORT/WEBAPP/iti17/myIti17Service/my/path?docId=321 |
/my/path?docId=321 |
Simplified model classes
ebXML message bodies can be converted to a simplified model. The following table shows the types that can be used for each transaction:
| Transaction | Message input body type | Message output body type |
|---|---|---|
| ITI-14 | org.openehealth.ipf.commons.ihe.xds.core.requests.RegisterDocumentSet | org.openehealth.ipf.commons.ihe.xds.core.responses.Response |
| ITI-15 | org.openehealth.ipf.commons.ihe.xds.core.requests.ProvideAndRegisterDocumentSet | org.openehealth.ipf.commons.ihe.xds.core.responses.Response |
| ITI-16 | org.openehealth.ipf.commons.ihe.xds.core.requests.QueryRegistry | org.openehealth.ipf.commons.ihe.xds.core.responses.QueryResponse |
| ITI-18 | org.openehealth.ipf.commons.ihe.xds.core.requests.QueryRegistry | org.openehealth.ipf.commons.ihe.xds.core.responses.QueryResponse |
For an example of how to use these classes, refer to the corresponding XDS.b section.
Large document content
XDS.a uses SOAP with Attachments (SwA) instead of MTOM, which is used in XDS.b. The implementation of SwA within CXF has to be checked for efficient support for large documents. This is currently an open issue. However, it only applies to the ITI-15 transaction that performs the "upload" of documents. The ITI-17 transaction is a simple HTTP GET download that results in an InputStream contained in the exchange. This allows efficient streaming of the document.
Validation
Apart from ITI-17, XDS.a messages are validated similar to XDS.b messages. For ITI-17 there is no validation support.
PIX + PDQ
The IPF provides components for PIX and PDQ transactions that use HL7 v.2 as data format and MLLP as transport protocol. The following picture shows the relevant actors and transactions:

In fact, these components represent extensions of the standard camel-mina component. Exactly as for XDS.a+b, the application's pom.xml must state the corresponding dependency:
<dependency> <groupId>org.openehealth.ipf.platform-camel</groupId> <artifactId>platform-camel-ihe-pixpdq</artifactId> <version>${ipf-version}</version> </dependency>
This will automatically (transitively) involve, in particular, camel-mina, camel-hl7, HAPI and IPF HL7 processing support.
Starting from version 2.1-m2, the IPF provides client-side and server-side support for HL7 interactive message continuation, unsolicited message fragmentation as well as segment fragmentation.
Making and accepting calls via PIX/PDQ endpoints
The URL format is the same for consumers and producers:
from('pix-iti8://0.0.0.0:8888?param1=value1¶m2=value2')
...
...
.to('pix-iti8://hostname.org:9090?param3=value3¶m4=value4')
Only parameters are optional, all other URL parts are obligatory.
URL Parameters
There are two groups of URL parameters in the PIX/PDQ components: the ones inherited from the basis Camel components and the additional ones.
Parameters inherited from camel-mina and camel-hl7
Some parameters defined in camel-mina have obtained constant values in the PIX/PDQ components. It means that these parameters are actually not configurable by the user any more; values provided via endpoint URLs are silently ignored. These parameters are the following:
| Parameter name | Type | Constant value in PIX/PDQ components |
|---|---|---|
| sync | boolean | true |
| lazySessionCreation | boolean | true |
| transferExchange | boolean | false |
| encoding | String | corresponds to the charset name configured for the HL7 codec factory, as described below |
All other URL parameters defined in camel-mina remain fully functional and configurable by the user.
Moreover, camel-hl7 defines a parameter named codec, which contains the name of a Spring bean that corresponds to an HL7 codec factory. PIX/PDQ components set "#hl7codec" as a default value for this parameter. The user still has to define the corresponding bean, though:
<bean id="hl7codec" class="org.apache.camel.component.hl7.HL7MLLPCodec"> <property name="charset" value="iso-8859-1"/> </bean>
The character set name set up for the HL7 codec factory will be automatically
- propagated to the Camel component (see parameter encoding in the table above),
- stored in the Exchange.CHARSET_NAME property of each Camel exchange, and
- used in all data transformation activities.
SSL-related URL parameters
Security aspects of MLLP-based transactions are controlled by the following URL parameters:
| Parameter name | Type | Default value | Short description |
|---|---|---|---|
| secure | boolean | false | whether SSL should be supported by the given endpoint |
| mutualTLS | boolean | false | whether client authentication for mutual TLS is required on the given endpoint |
| sslContext | String | - | Spring bean name of a user-defined SSL context, if any, optionally with leading '#'. If not set, a default SSL contents will be used |
| sslProtocols | String | system defaults | comma-separated list of SSL protocols which should be supported by the given endpoint |
| sslCiphers | String | system defaults | comma-separated list of SSL cipher suites which should be supported by the given endpoint |
URL parameters for HL7v2 continuation and fragmentation
HL7v2 continuation and fragmentation features can be configured by means of the following URL parameters:
| Parameter name | Type | Default value | Short description |
|---|---|---|---|
| supportInteractiveContinuation | boolean | false | whether interactive message continuation should be supported by the given endpoint |
| interactiveContinuationDefaultThreshold | int | -1 | default threshold (maximal count of data records per message) for interactive message continuation. Relevant on consumer side only and will be used only if RCP-2-2 of the request does not equal to 'I' or RCP-2-1 does not contain a parseable value. Values smaller than 1 lead to no continuation |
| interactiveContinuationStorage | String | - | Spring bean name of a storage for interactive continuation chains. If not set, a default in-memory storage will be used |
| supportUnsolicitedFragmentation | boolean | false | whether unsolicited message fragmentation should be supported by the given endpoint |
| unsolicitedFragmentationThreshold | int | -1 | threshold (maximal count of segments per message) for unsolicited message fragmentation. Relevant on producer side only. Values smaller than 3 lead to no fragmentation. |
| supportSegmentFragmentation | boolean | false | whether segment fragmentation should be supported by the given endpoint |
| segmentFragmentationThreshold | int | -1 | threshold (maximal count of characters per segment) for segment fragmentation. Values smaller than 5 lead to no segment fragmentation. |
Other URL parameters
| Parameter name | Type | Default value | Short description |
|---|---|---|---|
| audit | boolean | true | whether ATNA audit should be performed on the corresponding endpoint |
| allowIncompleteAudit | boolean | false | whether incomplete ATNA audit resords are allowed to be sent to the audot repository as well |
| interceptorBeans | String | - | user-defined MLLP interceptors — a comma-separated list of Spring bean names representing instances of org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.MllpCustomInterceptor |
Handling of data types and exceptions
Incoming messages (i.e. requests on the consumer side and responses on the producer side) are automatically unmarshalled into IPF MessageAdapter's.
Outgoing messages on the producer side (i.e. requests) are expected to belong to one of the following types in order to be able to be successfully marshalled and sent:
- IPF MessageAdapter
- "raw" HAPI message
- String
- byte[]
- NIO ByteBuffer
- InputStream
- File
- org.apache.camel.component.file.GenericFile<File>
For outgoing messages on the consumer side (i.e. responses), the same set of data types as for the producer side requests is supported. In addition, the message body can contain an Exception instance, which will be transformed into a NAK response. Any exceptions thrown in the route will lead to NAK responses as well.
When neither the data type of the response message is supported nor an exception has been thrown in the route, the message header org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpComponent.ACK_TYPE_CODE_HEADER will be taken into consideration. When the value of this header belongs to the enumeration type org.openehealth.ipf.modules.hl7.AckTypeCode, an acknowledgement will be automatically generated and sent back to the requestor — a positive one for AckTypeCode.AA, a negative one (NAK) for AckTypeCode.AE and AckTypeCode.AR.
When even this header is not set or when its value is not of desired type, the route fails.
Validation
Same as for XDS.a+b messages, the IPF provides a validation mechanism for PIX/PDQ requests and responses. To use it, corresponding DSL extensions should be activated in the application's Spring descriptor as shown below:
... <bean id="mllpModelExtension" class="org.openehealth.ipf.platform.camel.ihe.mllp.core.extend.MllpModelExtension"/> <bean id="routeModelExtender" class="org.openehealth.ipf.platform.camel.core.extend.DefaultModelExtender"> <property name="routeModelExtensions"> <list> <ref bean="coreModelExtension" /> <ref bean="mllpModelExtension" /> </list> </property> </bean> ...
After that, the validation can be performed using the validate DSL extension, e.g. for PIX Feed (ITI-8):
from('xds-iti8://0.0.0.0:9999?audit=false')
.onException(ValidationException.class)
.maximumRedeliveries(0)
.end()
.validate().iti8Request()
.process {
// generate a response
Exchanges.resultMessage(it).body = ...
}
.validate().iti8Response()
Continuation and fragmentation support
Implemented features correspond to Sections 2.10.2.1 (Segment fragmentation/continuation using the ADD segment), 2.10.2.2 (Segment fragmentation/continuation using the DSC segment), and 5.6.3 (Interactive continuation of response messages) of the HL7 v2.5 specification, and are being referred to as "segment fragmentation", "unsolicited (message) fragmentation" and "interactive (message) continuation", respectively.
Segment fragmentation
Segment fragmentation is supported on both producer and consumer sides, for both incoming and outgoing messages. This support can be activated by setting the URL parameter supportSegmentFragmentation of the corresponding endpoint to true. For outgoing messages, the additional parameter segmentFragmentationThreshold should be set to an integer value greater on equal to 5 — it denotes the maximal allowed length of segments in outgoing messages, without consideration of segment separators '\r'. For example, when this threshold equals to 10, the message
MSH|^~\\&|MESA_PD_CONSUMER|MESA_DEPARTMENT|MESA_PD_SUPPLIER|PIM|20081031112704||QBP^Q22|324406609|P|2.5|||ER QPD|IHE PDQ Query|1402274727|@PID.3.1^12345678~@PID.3.2.1^BLABLA~'@PID.3.4.2^1.2.3.4~@PID.3.4.3^KRYSO||||| RCP|I|10^RD|||||
will be sent as
MSH|^~\&|M ADD|ESA_PD ADD|_CONSU ADD|MER|ME ADD|SA_DEP ADD|ARTMEN ADD|T|MESA ADD|_PD_SU ADD|PPLIER ADD||PIM|2 ADD|008103 ADD|111270 ADD|4||QBP ADD|^Q22|3 ADD|244066 ADD|09|P|2 ADD|.5|||E ADD|R QPD|IHE PD ADD|Q Quer ADD|y|1402 .....
Note that segment fragmentation across messages (described in Section 2.10.2.3 of the HL7 v2.5 specification) is not supported yet.
Unsolicited message fragmentation
This feature can be activated by setting the URL parameter of the corresponding endpoint supportUnsolicitedFragmentation to true.
On producer side, this will lead to automatical fragmentation of outgoing request messages based on the value of the URL parameter unsolicitedFragmentationThreshold, which denotes maximal count of segments allowed in an outgoing message. This value should be greater than 2 in order to "let in" at least one segment in addition to MSH and DSC. The producer will perform all necessary actions of the corresponding message exchange pattern to transport these fragments to the receiver, as depicted on the following interaction diagram (click to enlarge):
An IPF PIX/PDQ consumer with enabled segment fragmentation support is able to automatically collect pieces of fragmented requests and put them into the route as a single cumulative request message (click to enlarge):
Segment MSH of the resulting request message is the one of the very first fragment, therefore the corresponding response will contain its control ID (MSH-10) in its MSA-2.
On both producer and consumer sides, all unsolicited fragments or fragment requests (messages with filled MSH-14 and DSC-1, respectively), which cannot be attributed to any active conversation, will be unchanged passed through to the route. Unsolicited fragmentation is not possible, when the request message to be fragmented does already contain non-empty values in the fields MSH-14 and/or DSC-1.
Interactive continuation
Interactive continuation is like unsolicited fragmentation, but relates to response messages instead of request ones and uses data records count instead of segments count as the message splitting criterion (HL7 specification declares some other counts — e.g. those of lines, characters, or pages — to be usable as splitting criteria as well, but they are not supported by the IPF). What a "data record" does actually mean thereby, is transaction-dependent — for example, in PDQ (ITI-21), each data record corresponds to a QUERY_RESPONSE group which consists of segments PID, PD1, NK1, and QRI (data record definitions for ITI-21 and ITI-22 are available in the IPF out-of-the-box).
Support for interactive continuation can be enabled for an endpoint by setting its URL parameter supportInteractiveContinuation to true.
In this case, a consumer will apply transaction-specific rules to split the messages into fragments, using threshold value from the field RCP-2-1, provided that RCP-2-2 is equal to "RD". If the mentioned threshold field is not filled in the expected way, the value of the URL parameter interactiveContinuationDefaultThreshold will be used. When this parameter is not configured as well or its value is less than 1, no message splitting will be performed.
Interaction steps performed by the consumer are shown on the diagram below (click to enlarge):
Each fragment can be requested more than once, in arbitrary order. Fragments are stored internally, whereby the user has the possibility to provide a custom storage bean via the interactiveContinuationStorage URL parameter of the consumer endpoint. This bean must implement the interface org.openehealth.ipf.platform.camel.ihe.mllp.core.ContinuationStorage, refer to javadocs for details. Per default, an in-memory storage will be used.
Obsolete fragment chains can be removed from the storage either by means of a corresponding cancel message QCN^J01 sent by the client (as usual, such messages are automatically served by the IPF), by timestamp-based purging, or by some proprietary mechanisms of the storage, if available.
When an IPF PIX/PDQ producer with enabled interactive continuation support recognizes, that the response message it just received is actually the first fragment of an interactive chain, it automatically adds its segment DSC to the initial request message and sends the latter again, as prescribed by the HL7 specification, requesting the next fragment in that way. This step will be repeated for all subsequent fragments until the last fragment of the chain has arrived. After that, the producer joins all collected data records together (using the same transaction-specific rules as the consumer used) and delivers the cumulative response to the caller (i.e. to the Camel route containing the corresponding .to(...) statement). The diagram below shows these interaction steps (click to enlarge):
Same as in case of unsolicited message fragmentation, all unexpected fragments will be passed through to the route without changes. This rule applies to cancel messages which relate to non-existent interactive chains (represented by their query tags) as well.
Combination of fragmentation/continuation features
Segment fragmentation can be harmlessly combined with both unsolicited message fragmentation and interactive message continuation. Note that in case of outgoing request messages, unsolicited message fragmentation is performed before segment fragmentation, therefore the resulting count of segments can be actually greater than the value of the unsolicitedFragmentationThreshold parameter.
On the other hand, simultaneous activation of unsolicited message fragmentation and interactive message continuation can be problematic, because each of them makes use of the same fields in the segment DSC. For example, when a request message was sent using unsolicited fragmentation, and the response represents an interactive continuation fragment, it will be impossible to send the request for the second response fragment using unsolicited fragmentation, because DSC-1 will contain a non-empty value.
Purging obsolete fragments from storages
Both interactive message continuation and unsolicited message fragmentation implementations use storages for fragments. In the case of interactive message continuation, the user has the possibility to provide a custom bean, while for unsolicited message fragmentation an in-memory storage is implicitly created.
Under some circumstances these storages can contain garbage — for example, obsolete interactive continuation chains, whose requestors do not trouble themselves to send cancel messages; or accumulators of unsolicitedly fragmented messages, whose senders unexpectedly abandoned to provide subsequent fragments.
Therefore the route developer should consider to prevent the storages' obstruction. For this purpose, each of the IPF's own in-memory storages provides method purge(long ttl), that takes the desired time-to-live (in ms) as parameter and should be called on regular basis — e.g. from a timer-based Camel endpoint.
To access the storage beans, the following approach can be applied:
import org.apache.camel.CamelContext; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpEndpoint; import org.openehealth.ipf.commons.core.purgeable.PurgeableCollection; CamelContext context; MllpEndpoint endpoint = context.getEndpoint("pdq-iti21://...", MllpEndpoint.class); PurgeableCollection unsolicitedFragmentationStorage = endpoint.getUnsolicitedFragmentationStorage(); unsolicitedFragmentationStorage.purge(1000L * 60L * 10L); // 10 minutes Object continuationStorage = endpoint.getContinuationStorage(); if (continuationStorage instanceof PurgeableCollection) { ((PurgeableCollection) continuationStorage).purge(1000L * 60L * 10L); }
PIXv3 + PDQv3
Starting from version 2.1, IPF provides basic support for IHE transactions with numbers 44-47. They are in fact counterparts for PIX/PDQ transactions discussed in the previous section, but use HL7 v3 instead of v2 as data format and Web Services instead of MLLP as transport protocol.

Standard conformance
Normative description for PIXv3/PDQv3 transaction can be found in the corresponding IHE Supplement for Trial Implementation.
Note that ATNA logging is not defined there yet, therefore the IPF does not log any interaction events related to PIXv3/PDQv3.
Configuration
pom.xml must contain the following dependency:
<dependency> <groupId>org.openehealth.ipf.platform-camel</groupId> <artifactId>platform-camel-ihe-pixpdqv3</artifactId> <version>${ipf-version}</version> </dependency>
PIXv3/PDQv3 transactions use the same Web Service machinery as XDS.b transactions, therefore they must be configured in the same way. Sections "Exposing a service" and "Call a service" apply respectively, too.
There are two variants of ITI-44 endpoints — one for the PIX Identifier Cross-Reference Manager (Section 3.44.4.1.3.1 of the aforementioned IHE Supplement) and another one for the XDS.b Document Registry (Section 3.44.4.1.4.1). This leads to the existence of two pretty similar components in the IPF, namely pixv3-iti44 and xds-iti44, which differ in naming conventions and namespaces in WSDL documents.
Because of unsupported ATNA auditing, the only available URL parameter is secure.
Message types
Currently, PIXv3/PDQv3 components do not use any special data model and expect both request and response to be String representations of XML payload. Web Service metadata (WSDL documens) reflects this peculiarity by declaring all message parts to be xsd:anyType.
IPF's DSL extensions for XML processing can be efficiently used to handle and prepare request and response messages.
Validation
Validation of PIXv3/PDQv3 request and response messages is based on XSD with preliminary support for Schematron. Same as for other transactions, there are corresponding DSL extensions pre-defined, which can be activated for any given IPF application using the following Spring configuration:
... <bean id="pixpdqv3ModelExtension" class="org.openehealth.ipf.platform.camel.ihe.pixpdqv3.extend.PixPdqV3ModelExtension"/> <bean id="routeModelExtender" class="org.openehealth.ipf.platform.camel.core.extend.DefaultModelExtender"> <property name="routeModelExtensions"> <list> <ref bean="pixpdqv3ModelExtension" /> <!-- references to other extension beans --> </list> </property> </bean> ...
After that, requests and responses can be validated as outlined in the example route below:
from("pixv3-iti44:iti44service") .onException(Exception.class) .maximumRedeliveries(0) .end() .validate().iti44Request() .unmarshal().gnode() .process { // prepare response as String // <MCCI_IN000002UV01 xmlns="urn:hl7-org:v3" ...> // <id root="PID-3-4-2" extension="PID-3-1" /> // ... // </MCCI_IN000002UV01> } .validate().iti44Response()
Translation between HL7 v2 and HL7 v3 message models
| Preliminary contents Informations provided in this chapter relate to an early-access functionality, which may be changed out of all recognition in the near future. |
IPF 2.1+ contains utilities for translation between HL7 v2 and HL7 v3, thus giving the possibility to implement HL7 v3 transactions on top ot their HL7 v2 counterparts and to avoid redundancy in that way. Currently supported transaction pairs are PIX Feed (ITI-8/ITI-44), PIX Query (ITI-9/ITI-45), PIX Update Notification (ITI-10/ITI-46), and PDQ (ITI-21/ITI-47).
Configuration and Use
This section describes configuration steps the user has to perform in order to use the HL7 translators, and provides instructions how to perform the translation. The next section contains an example of a bridge route.
Step 1
First of all, the corresponding Maven artefact must be referenced as a dependency in the application's pom.xml, as described above. (Translation utilities per se belong to the artefact commons-ihe-pixpdqv3, which will be loaded transitively from platform-camel-ihe-pixpdqv3.)
Step 2
For translation of PIX Feed and PDQ messages, the IPF Mapping Service must be activated and configured to use the mappings provided by the IPF (these mappings can be accessed as classpath resources). Here is a snippet of Spring-based configuration:
<bean id="mappingService" class="org.openehealth.ipf.commons.map.BidiMappingService"> <property name="mappingScripts"> <list> <!-- for PIX Feed message translation --> <value>classpath:META-INF/map/pixfeed-translation.map</value> <!-- for PDQ message translation --> <value>classpath:META-INF/map/pdq-translation.map</value> <!-- other mappings --> <value>...</value> </list> </property> </bean> <bean id="hapiModelExtension" class="org.openehealth.ipf.modules.hl7.extend.HapiModelExtension"> <property name="mappingService" ref="mappingService" /> </bean> <bean id="mappingModelExtension" class="org.openehealth.ipf.commons.map.extend.MappingExtension"> <property name="mappingService" ref="mappingService" /> </bean> <bean id="pixpdqv3ModelExtension" class="org.openehealth.ipf.platform.camel.ihe.pixpdqv3.extend.PixPdqV3ModelExtension" /> <bean id="coreModelExtension" class="org.openehealth.ipf.platform.camel.core.extend.CoreModelExtension" /> <bean id="routeModelExtender" class="org.openehealth.ipf.platform.camel.core.extend.DefaultModelExtender"> <property name="routeModelExtensions"> <list> <ref bean="coreModelExtension" /> <ref bean="hapiModelExtension" /> <ref bean="mappingModelExtension" /> <ref bean="pixpdqv3ModelExtension" /> <ref bean="..." /> </list> </property> </bean>
Step 3
The third configuration step is to instantiate translator beans.
Package org.openehealth.ipf.commons.ihe.pixpdqv3.translation contains the following set of classes:
- PixFeedRequest3to2Translator — translates PIX Feed requests from v3 to v2.
- PixFeedAck2to3Translator — translates PIX Feed acknowledgements (responses) from v2 to v3.
- PixQueryRequest3to2Translator — translates PIX Query requests from v3 to v2.
- PixQueryResponse2to3Translator — translates PIX Query responses from v2 to v3.
- PixUpdateNotification2to3Translator — translates PIX Update Notifications from v2 to v3.
- PixUpdateNotificationAck3to2Translator — translates PIX Update Notification acknowledgements from v3 to v2.
- PdqRequest3to2Translator — translates Patient Demographic Queries from v3 to v2.
- PdqResponse2to3Translator — translates Patient Demographic Responses from v2 to v3.
Each translator has a set of configurable properties. Their descriptions can be currently taken from javadoc of the corresponding classes. Note also that there are reasonable default values, therefore the explicite configuration (see <property> items in the example below) can be harmlessly omitted in many cases.
An example for PIX Feed:
<bean name="pixFeedRequestTranslator" class="org.openehealth.ipf.commons.ihe.pixpdqv3.translation.PixFeedRequest3to2Translator"> <property name="useSenderDeviceName" value="true" /> <property name="useReceiverDeviceName" value="true" /> <property name="copyEmailAs" value="PID-13-1" /> <property name="copyAccountNumberAs" value="PID-18" /> <property name="accountNumberRoot" value="1.2.3" /> <property name="copyNationalIdentifierAs" value="PID-19" /> <property name="nationalIdentifierRoot" value="2.16.840.1.113883.4.1" /> <property name="birthNameCopyTo" value="PID-5" /> <property name="useOtherIds" value="true" /> </bean> <bean name="pixFeedAckTranslator" class="org.openehealth.ipf.commons.ihe.pixpdqv3.translation.PixFeedAck2to3Translator"> <property name="ackCodeFirstCharacter" value="C" /> </bean>
Step 4
Package platform-camel-ihe-pixpdqv3, being the basis for the PIXv3 and PDQv3 transactions' impementation, provides DSL extensions which can be used to embed HL7 translation functionality into a Camel route. Spring configuration performed on Step 2 already contains all necessary statements to activate these extensions — consider the bean pixpdqv3ModelExtension.
Using DSL Extensions
The DSL extension .translateHL7v3toHL7v2(translator) is responsible for the translation of messages from HL7 v3 to HL7 v2. Its parameter translator is the corresponding translator bean, e.g. it could be the bean pixFeedRequestTranslator defined on Step 3. Moreover, this DSL extensions saves the original HL7 v3 request internally, because some parts of it will have to be yielded unmodified into the HL7 v3 response message.
Translation of response messages from HL7 v2 to HL7 v3 is the task of the DSL extension .translateHL7v2toHL7v3(translator). The parameter translator denotes a response translator bean, e.g. pixFeedAckTranslator defined on Step 3.
When the translation of a response message was not preceded by the translation of the corresponding request message and therefore the request could not been saved automagically by means of IPF's internal machinery, the user has to provide the request manually (as a String containing XML document or a MessageAdapter instance depending on the transaction under consideration) in the property org.openehealth.ipf.platform.camel.ihe.pixpdqv3.extend.HL7V3_ORIGINAL_REQUEST_PROPERTY of the Camel exchange.
Example
Here is a sample Camel route that impements bridges PIX Feed v3 requests (ITI-44) to an HL7 v2-based Patient Identifier Cross-Reference Manager (ITI-8), and does the same in reverse direction for acknowledgements.
class BridgeRouteBuilder extends SpringRouteBuilder { // injected by Spring def pixFeedRequestTranslator def pixFeedAckTranslator def pixManagerUri void configure() throws Exception { from('pixv3-iti44:iti44service') .onException(Exception.class) .maximumRedeliveries(0) // some reasonable exception handling .end() .translateHL7v3toHL7v2(pixFeedRequestTranslator) .to("pix-iti8://${pixManagerUri}") .translateHL7v2toHL7v3(pixFeedAckTranslator) } }
This is, probably, the shortest possible HL7v3 PIX Manager implementation
.
XCPD
Preliminary contents |
Normative references for the implementation of this profile in the IPF are IHE Supplement XCPD, IHE Supplement Asynchronous Web Services Exchange (both dated August 2009) and CP-420.
The two actors of XCPD are Initiating Gateway and Responding Gateway:

As opposed to PIXv3/PDQv3, ATNA auditing is defined and implemented.
Data model
Same as for all other HL7 v3-based transactions, no special data model has been introduced for XCPD. All messages are expected to be Strings containing XML payload.
Configuration
As of IPF 2.2, both ITI-55 (Cross Gateway Patient Discovery) and ITI-56 (Cross-Gateway Patient Location Query) transactions are supported. They are very similar to HL7v3-based transactions, therefore configuration steps are almost identical: the user has to state the corresponding dependency in pom.xml:
<dependency> <groupId>org.openehealth.ipf.platform-camel</groupId> <artifactId>platform-camel-ihe-xcpd</artifactId> <version>${ipf-version}</version> </dependency>
and, if message validation is required, activate DSL extensions:
<bean id="xcpdModelExtension" class="org.openehealth.ipf.platform.camel.ihe.xcpd.extend.XcpdModelExtension" /> <bean id="routeModelExtender" class="org.openehealth.ipf.platform.camel.core.extend.DefaultModelExtender"> <property name="routeModelExtensions"> <list> <ref bean="..." /> <ref bean="xcpdModelExtension" /> <ref bean="..." /> </list> </property> </bean>
Making synchronous and asynchronous calls
Synchronous calls to an XCPD endpoint can be made in the same way as in other IHE transactions, e.g.:
.to('xcpd-iti55://server.uri:8888/xcpd/services/iti55Service?audit=false')
To make an asynchronous call, three additional steps must be performed:
- arrange a message correlator;
- arrange a special receiver endpoint for asynchronous responses;
- store URI of this endpoint in the corresponding header of outgoing request messages.
These steps are described in corresponding sections below.
Message correlator
The purpose of this object is to provide a mechanism for the attribution of asynchronous responses to the corresponding requests (which is necessary in particular for ATNA auditing). Moreover, it provides the possibility to associate a user-defined key to a group of asynchronous requests in order to efficiently aggregate responses.
The user has to define an instance of a class which implements the org.openehealth.ipf.commons.ihe.ws.correlation.AsynchronyCorrelator interface. An in-memory correlator implementation is provided by the IPF out-of-box, so in the simplest case the instantiation will look like
<bean id="correlator" class="org.openehealth.ipf.commons.ihe.ws.correlation.InMemoryAsynchronyCorrelator" />
When a remote service fails to send a response, orphan data items remain in the correlator. To purge them from the InMemoryAsynchronyCorrelator mentioned above, the same mechanism can be used as for HL7 v2 continuation/fragmentation storages — in other words, the correlator's method purge(long ttl) should be called from time to time.
Receiver endpoint
A special endpoint should be arranged on the client side for serving asynchronous response messages. Component part of the endpoint URI corresponds to the transaction, with the suffix "-async-response":
from('xcpd-iti55-async-response:iti55service-response?correlator=#correlator')
.validate().iti55Response()
...
Obligatory paramater correlator must contain a reference to the correlator bean described above.
Per default, all messages arrived on this endpoint will be processed using InOnly exchange pattern.
Sending asynchronous requests
To send a request in asynchronous mode, the user has to put the URL of the response receiver endpoint into the Camel message header DefaultItiEndpoint.WSA_REPLYTO_HEADER_NAME. Note that this URL should be a "usual" HTTP(s) one, not a Camel endpoint URI. Moreover, the correlator bean should be referenced in the producer endpoint URI. Example:
from('direct:foobar')
.process {
...
it.in.headers[DefaultItiEndpoint.WSA_REPLYTO_HEADER_NAME] =
'http://localhost:8889/iti55service-response'
}
.to('xcpd-iti55://somehost.uri/XCPDRespondingGateway?param1=value2&correlator=#correlator')
In this case, the .to('xcpd...') statement will complete immediately (InOnly exchange pattern).
In the same way, a user-defined correlation key can be set via the request message header DefaultItiEndpoint.CORRELATION_KEY_HEADER_NAME. This header will be automatically restored in the asynchronous response message, when the latter arrives.
Serving calls
There are no dirrefences compared to PIXv3/PDQv3:
from('xcpd-iti55:iti55service')
.validate().iti55Request()
.process {
// prepare response
}
.validate().iti55Response()
Time-to-live
ITI-55 specification defines a "CorrelationTimeToLive" SOAP header which contains duration of the data actuality in requests and responses. The corresponding IPF ITI-55 component supports setting and getting this header in the following way:
- to set the TTL value for an outgoing message (i.e. a request on the Initiating Gateway side or a response on the Responding Gateway side), an instance of javax.xml.datatype.Duration should be put into Camel message header Iti55Component.XCPD_OUTPUT_TTL_HEADER_NAME;
- when an incoming message (i.e. a request on the Responding Gateway side or a response on the Initiating Gateway side) contains valid data in the TTL header, the IPF XCPD component will store its value as a Duration instance into the Camel message header Iti55Component.XCPD_INPUT_TTL_HEADER_NAME.
ATNA
ATNA auditing functionality is fully integrated into the corresponding IPF IHE components (excluding PIXv3/PDQv3 ones). The only thing the user has to configure is the URI of the target syslog server, as described in the next section.
Configuring auditors
Each of the currently supported IHE actor types has a corresponding singleton auditor, i.e. the following set is available:
- XDSRegistryAuditor
- XDSRepositoryAuditor
- XDSSourceAuditor
- XDSConsumerAuditor
- PIXManagerAuditor (serves the Patient Demographic Supplier actor as well)
- PIXSourceAuditor
- PIXConsumerAuditor
- PDQConsumerAuditor
- XCPDInitiatingGatewayAuditor
- XCPDRespondingGatewayAuditor
Auditors can be configured both individually and all together. Besides the syslog server URI mentioned above (actually the only mandatory parameter), the following optional parameters can be set up (see Section 5.4 of RFC 3881 for details):
- audit source ID
- audit enterprise site ID
| Warning Configuration of auditors is stored in instances of the class org.openhealthtools.ihe.atna.auditor.context.AuditorModuleConfig. These instances contain much more configurable fields than the three described here, but the user is actually not ought to change them. |
Individual configuration
To configure a particular auditor (for example, the XDS Registry-related one), the user can write
import org.openhealthtools.ihe.atna.auditor.context.AuditorModuleConfig; import org.openhealthtools.ihe.atna.auditor.XDSRegistryAuditor; ... AuditorModuleConfig config = new AuditorModuleConfig(); config.setAuditRepositoryHost("my.syslog.server"); config.setAuditRepositoryPort(514); config.setAuditSourceId(...); config.setAuditEnterpriseSiteId(...); XDSRegistryAuditor.getAuditor().setConfig(config);
To perform the same operation using Spring, the following obvious bean definitions can be used:
<bean id="config" class="org.openhealthtools.ihe.atna.auditor.context.AuditorModuleConfig"> <property name="auditRepositoryHost" value="my.syslog.server" /> <property name="auditRepositoryPort" value="514" /> <property name="auditSourceId" value="..." /> <property name="auditEnterpriseSiteId" value="..." /> </bean> <bean id="registryAuditor" class="org.openhealthtools.ihe.atna.auditor.XDSRegistryAuditor" factory-method="getAuditor"> <property name="config" ref="config" /> </bean>
Group configuration
From a Java application:
import org.openhealthtools.ihe.atna.auditor.context.AuditorModuleContext; ... AuditorModuleContext.getContext().getConfig().setAuditRepositoryHost("my.syslog.server"); AuditorModuleContext.getContext().getConfig().setAuditRepositoryPort(514);
Using Spring descriptor:
<bean id="iheAuditorContext" class="org.openhealthtools.ihe.atna.auditor.context.AuditorModuleContext" factory-method="getContext" /> </bean> <bean id="iheAuditorConfig" factory-bean="iheAuditorContext" factory-method="getConfig"> <property name="auditRepositoryHost" value="my.syslog.server" /> <property name="auditRepositoryPort" value="514" /> </bean>
Disabling auditing
In order to disable auditing for a particular service endpoint (i.e. a Camel consumer) or for a particular client invocation (i.e. a Camel producer), the corresponding URL should be extended with parameter audit=false, e.g.
to('xds-iti18://localhost:9091/xds-iti18-service?audit=false')
or
from('xds-iti18:xds-iti18-service?audit=false')
Note that this feature is (currently) not supported for ITI-17.
Writing down incomplete audit records
Under some circumstances (for example, when the request does not contain all required elements) the system is not able to collect all necessary data to construct a well-formed audit record. Per default, no audit is performed in this case, because it would violate the specification.
But — as an exception, e.g. for debug purposes — the user can change this behavior by setting the parameter allowIncompleteAudit in the URL of the corresponding XDS to true:
to('xds-iti18://localhost:9091/xds-iti18-service?allowIncompleteAudit=true')
Of course, this setting will not have any effect when the auditing functionality is generally switched off, i.e. when the parameter audit in the mentioned endpoint URL was set to false, as described in the previous section.
Note that this feature is (currently) not supported for ITI-17.
Configure auditing transport: Reliable and special auditing
Default implementation of ATNA auditing is based on unreliable UDP communication (Syslog protocol), as prescribed by the IHE IT TF, Vol. 2, Section 3.20.6.1. This choice is also explained in the ATNA FAQ.
In order to change this setting, a custom implementation of org.openhealthtools.ihe.atna.auditor.sender.AuditMessageSender must be provided and registered via AuditorModuleContext.getContext().setSender(mySender).
The delivery queue can be customized in a similar way, i.e. by implementing the interface org.openhealthtools.ihe.atna.auditor.queue.AuditMessageQueue and installing the corresponding class instance via AuditorModuleContext.getContext().setQueue(myQueue).
These settings will affect all auditors, because the auditor module context is a singleton.
Routing audit messages to Camel endpoints
This section is an application of the previous one. Instead of sending audit messages to a syslog server they can also be sent to Camel endpoints. For that purpose an CamelEndpointSender must be configured in the application context.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camel="http://camel.apache.org/schema/spring" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> <camel:camelContext id="camelContext"> <camel:routeBuilder ref="..."/> </camel:camelContext> <bean id="auditModuleConfig" factory-method="getConfig" factory-bean="auditModuleContext"> <property name="auditRepositoryHost" value="0.0.0.0" /> <property name="auditRepositoryPort" value="0" /> </bean> <bean id="auditModuleContext" factory-method="getContext" class="org.openhealthtools.ihe.atna.auditor.context.AuditorModuleContext"> <property name="sender" ref="camelEndpointSender" /> </bean> <bean id="camelEndpointSender" class="org.openehealth.ipf.platform.camel.ihe.atna.util.CamelEndpointSender"> <!-- autowired if not explicitly configured --> <property name="camelContext" ref="camelContext" /> <!-- endpoint registered in the Camel context --> <property name="endpointUri" value="direct:input" /> </bean> ... </beans>
In this example a CamelEndpointSender is configured to send audit messages to the direct:input endpoint that is registered at the Camel context. The AuditorModuleContext singleton is configured to use the custom audit message sender. Although ignored by the sender, the Open Health Tools require us to set the audit repository host and port. Hence, they can be set to arbitrary values, 0.0.0.0 and 0, respectively, in our example. These values are overwritten by the message sender. The sender derives them from the Camel endpoint URI. For exmple, direct:input yields 0.0.0.0 and -1, http://www.openehealth.org:7000 yields 174.143.206.54 and 7000.
The audit message is sent as in-only exchange to the endpoint where the in-message body contains a string-representation of the audit XML message. Additionally the following headers are defined:
| Header | Description |
|---|---|
| org.openehealth.ipf.platform.camel.ihe.atna.datetime | The date and time when this message was generated. |
| org.openehealth.ipf.platform.camel.ihe.atna.destination.address | The audit repository IP address derived from the configured endpoint URI. |
| org.openehealth.ipf.platform.camel.ihe.atna.destination.port | The audit repository port derived from the configured endpoint URI. |
The CamelEndpointSender is contained in the platform-camel-ihe-atna-util component which needs to be added as dependency in the Maven pom.xml.
<dependencies>
<dependency>
<groupId>org.openehealth.ipf.platform-camel</groupId>
<artifactId>platform-camel-ihe-atna</artifactId>
<version>${ipf-version}</version>
</dependency>
</dependencies>
URL Parameters' Summary for XDS, PIXv3, PDQv3, and XCPD transactions
The following table gives an overview of common URL parameters defined for Web Service based IPF endpoints for XDS, PIXv3, PDQv3, and XCPD (ITI-14..16, 18, 41..47, 55..56):
| Name | Type | Default value | Transaction numbers | Side | Short description |
|---|---|---|---|---|---|
| secure | boolean | false | all except 17 | client only | whether Transport Layer Security mechanisms should be applied when sending messages |
| audit | boolean | true | all except 17 and 44-47 | both service and client | whether ATNA auditing should be performed by the corresponding party |
| allowIncompleteAudit | boolean | false | all except 17 and 44-47 | both service and client | whether incomplete audit records should be sent to the ATNA repository as well |
| soap11 | boolean | false | 18 and 41-43 | client only | whether requests should be sent using SOAP 1.1 instead of SOAP 1.2 (not supported any more since 2010-02-10) |