Developing applications using openEHR.net (work in progress)

This document aims to provide an introduction to using openEHR.NET project to implement openEHR based solutions. If you find anything that is not correct in this document, please let me know. This document is expected to become a guide for developing various sample applications using openEHR.NET, and contributions are welcome.

openEHR.NET is a set of classes that implements AM and RM, along with various extra capabilities. Especially the capability to serialize/deserialize to and from XML is worth noting, since it allows other key components of openEHR implementation to talk to openEHR.NET. 

What can you do with openEHR.NET?

openEHR.NET allows you to build object models using Reference Model (RM) classes. It also has functionality to leverage models build by openEHR modeling tools, such as Ocean Archetype Editor or Ocean Template Editor, through Archetype Model (AM) classes. RM and AM classes allow you to implement actual clinical software that produces and processes clinical information that is always compatible with the clinical models that are developed by clinicians and domain experts.  This information can be serialized to XML and it can then be passed to a server such as OceanEHR, which will persist data. 

In a very rough layered view of openEHR based software development process, the modelling work can be called as the starting point, then these clinical models are created with real clinical data, and they are persisted to a repository such as OceanEHR. Therefore, the openEHR.NET is an implementation of the layer that is between modelling and persistence layers. It allows developers to build objects in the memory, which can be validated using openEHR templates and thus archetypes. We will provide more specific examples about validation of the created objects, but for the moment this document will focus on creating object instances that can encapsulate clinical data

Getting started

In order to get started with the current codebase, you need to check out the code from SVN or download it as a zip file. Both options are available through the Source Code page.

At the moment, the source code works with Visual C# 2008. This means that you need to have either Visual C# 2008 Express edition (free) or Visual Studio 2008. Users with Visual C# 2010 has reported problems in the source code, so until the code base is tested and validated with Visual C# 2010, use Visual C# 2008. Also, setting a .NET framework version that is equal to or higher than 3.5 seems to introduce compilation problems, so .NET 3.0 is the latest version of .NET runtime that you can use.

Projects under the TRUNK directory

When you either check out the code or download and extract it, you'll find the main project directories under the TRUNK directory. At the moment there are three projects:

  • OpenEHR
  • EhrGate.WsClient
  • EhrGate.WsClient.Tests

OpenEHR project contains the RM and AM class implementations, along with the utilities. You can build RM objects using this project.

The EhrGate.WSClient project allows sending the contents of RM objects over the wire, to OceanEHR server product using web services. Normally, SOAP based web services describe their operations via WSDL, and all major programming languages has some library or framework that creates proxy classes using WSDL. These classes can seamlessly send their content to web services, without users dealing with the lower level details of creating XML content and using HTTP protocol to move data around.

EhrGate.WSClient project contains a set of proxy classes which allow sending data in RM classes to OceanEHR web services. For example you can create a Composition instance using OpenEHR project, and EhrGateWsClient will take data from this Composition instance, put it into Composition proxy generated from WSDL and send it to web service.

openEHR specification defines both data and behaviour for RM and AM classes, but web services can only transfer data, therefore the autotomatically generated proxy classes can not support all the functionality that openEHR specification describes. Thanks to EhrGate.WSClient, developers can work only with fully implemneted RM classes from OpenEHR project, they do not need to deal with proxies that have limited capability.

EhrGate.WsClient.Tests project contains unit tests that provide a very good overview of the functionality that the OceanEHR web services API provides. The source code for these tests demonstrate how key operations can be performed. 

Both EhrGate.WsClient and EhrGate.WsClient.Tests projects will be used in upcoming tutorials, but as written above, creating RM instances it the first step for a developer in using openEHR. Therefore the next section explains the details of this process.

Creating RM instances

A key feature of the initial RM implementation in openEHR.NET was that it was immutable. That means that when an object is created, its state can not be changed, it is read only. Immutable types have their advantages, but they can be a little bit tricky when it comes to building complex object hierarchies.

Immutable objects expect values for their fields during construction phase, which means that these values must be passed as parameters to type constructor.  If these values themselves are immutable objects, they'd also expect the same. Take a look at this example:

 

Composition comp = new Composition(name, archetypeNodeId, null, null, archetypeDetails, null, language, territory, category, context, contents, composer);

 

This is a statement taken from an example project. The composition constructor is provided with the objects which will be assigned to its fields. The contents object is an array of ContentItem instances (ContentItem[]) .

This array must be initialized before it can be passed to Composition, so ContentItem instances such as Evaluation or Instruction must be created. Since they'll be immutable too, their constructor will ask for their fields.

This means that leaf nodes of the tree must be created first, and they must be added to their parent. This bottom up building of objects may feel a bit unusual, but it is the recommended way of working with openEHR.NET at the moment.

The code base actually has been modified to allow construction of objects top to bottom. That is, you can see setter methods for the fields but various test cases have led to minor bugs and issues with mutable object construction, so until those bugs are fixed, this tutorial will follow the immutable method. There are some coding style workarounds that may help developers cope with the bottom up thinking, Which we will see above.  Let us try to clarify our context a little bit more first.

Manually created RM code

The RM implementation in openEHR.NET allows the developer create openEHR based software. The RM classes in C# correspond to types defined in the openEHR specifications, and there is nothing stopping us from building RM types, such as a Composition, using these C# classes.

The relationship between openEHR clinical modeling artefacts and C# code can be confusing at first. Let us start with Archetypes first. Take a look at the following snippet from a Composition archetype:

 

definition
	COMPOSITION[at0000] matches {	-- Encounter (training sample)
		category matches {
			DV_CODED_TEXT matches {
				defining_code matches {[openehr::433]}
			}
		}
		

The Archetype, which is defined by ADL, defines a clinical model using COMPOSITION class from the openEHR specifications. ADL defines models by introducing constraints on their attributes, so in this case, it defines a Composition with its category attribute set to a DV_CODED_TEXT object. DV_CODED_TEXT is again another type from the openEHR specifications, and its defining_code attribute is set to an instance of CODE_PHRASE with terminology Id openehr and code  string 433. (For details of ADL, see the documentation at http://www.openehr.org )  This is the two level modelling approach of openEHR, the Archetype is a separate level from the RM objects (COMPOSITION, DV_CODED_TEXT...) and it constraints them to create more specific clinical models. The classic example is blood pressure archetype; it constraints RM instances to define a clinical concept.  Now look at the following C# code:

 

private void buildComposition()
        {
            Composition comp = new Composition();
            DvCodedText category = new DvCodedText( "433", "openehr");
            comp.Category = category;
            //....
        }

This code defines the exact same thing with the ADL snippet above. (For simplicity, it is not using the recommended method of creating an immutable composition). Using the C# implementation of openEHR specification, it creates a Composition, and sets its category attribute to an instance of DvCodedText with the same terminology id and code string. Obviously, the C# code could have given another value to DvCodedText instance that is assigned to category attribute. In that case the data that this C# object represents would not be valid according to this archetype. This is how two level modelling provides interoperability: system A can use a Java implementation of openEHR, creating the RM class (Composition), and system B can do the same with C#. If they both create objects which are valid based on the constraints given in this archetype, clinical data can be exchanged between systems A and B.  They can exchange data using XML for example, since openEHR also has a published XSD for data exchange. However, XSD based validation can only help with structure and format of data, it would not help validate the actual values, such as acceptable ranges for systolic blood pressure. This type of validation requires access to modeling artifact, the archteype.

openEHR standards defines Archetype Object Model (AOM) which guarantees that the modeling artefacts are accessible by code, just like the RM classes. Therefore, openEHR.NET users can load an archetype into memory in the form of an AOM object, and check if the values of Composition object comply with constraints in the archetype. The following is a high level description of the connection between these concepts. 

So it is possible for a developer to write code to express a clinical model, and this code can create and use clinical data. The developer can use AOM to check if the object that represents clinical model is valid according to a particular archetype or template, which provides the basis for interoperability.

Actually, the template designer has a feature that makes building C# representations of models a lot easier, but this feature is not usable with the openEHR.NET RM implementation. What template designer does is to take a template and generate a C# class source code which is a representation of this template. The high level overview of the process is as follows:

By using the template, the template designer creates a C# class (Template Data Object) that conforms to constraints expressed in the template. This saves a lot of time for the developers, since they do not have to build the complex object hierarchies by hand, and they can simply focus on using the output in their code. If a developer assigns a value to the generated Template Data Object (TDO), then the validation scenario can still warn the developer.

The bad news is, the code generated by the Template Editor references another RM implementation from Ocean Informatics that is only available to Ocean Informatics clients for the moment. The good news is, there is ongoing discussion about supporting openEHR.NET RM implementation. Until then, there are two options for openEHR.NET users.

  1. To build RM objects by hand
  2. To use XML and deserialize to RM object instances from that XML.

We will be building a Discharge Summary first, to demonstrate the use of first option.

Creating a Discharge Summary

Last edited Mar 19, 2012 at 5:38 PM by serefarikan, version 13

Comments

No comments yet.