RIMBAA: Java based Reference Implementation
This page uses terminology as defined in this whitepaper.
Description
The HL7 RIMBAA group has created a Java based reference implementation. The architecture of this implementation is based on the RP-RO-MS cells.
The work product starts in RO and uses an object-relational mapping solution (Hibernate) for the transition to RP. When it comes to the RP cell the reference implementation uses the Table per Hierarchy strategy. All internal objects are completely RIM based. We use Hibernate to generate the Schema for the database, and it is also used to persist the RIM objects. The transition between RO to MS is supported using MIFs (the reference implementation contains a MIF parsing API). The direct transition from RO to MS is the most complex part of the API and at every step it is guided by the parsed MIF file.
It works almost perfectly in the direction from MS to RO, it works almost perfectly between RP and RO using Hibernate, and it works fairly well in the direction of RO to MS. The V3 XML generated is 90% plus perfect but there are little quirks which require tweaking. The XML generated is so close to correct it can be mostly be tweaked using XSLT.
The advantage of using an object-relational mapping tool is the fact that database queries can be formulated using RIM classes/attributes. All SQL-details are hidden from the programmer. The following is an example of an SQL statement (RP style) that, based on the CDA model expressed in pure RIM terms, will pull all pulmonary function test results for patient 1234567 from the pure RIM based database:
SELECT new list(i.extension, name.givenName, name.familyName, clinicalStatement.value, clinicalStatement.value.unit, clinicalStatement.code.displayName) FROM PatientImpl patient INNER JOIN patient.id AS i inner join patient.player as person inner join person.name as name inner join patient.participation as part inner join part.act as document inner join document.outboundRelationship as component inner join component.target as body inner join body.outboundRelationship as component2 inner join component2.target as section inner join section.outboundRelationship as entry inner join entry.target as clinicalStatement where component.typeCode='COMP' and i.extension='1234567'
Another example which pulls all of the "Glucose Level" (using its code 64544) values from the pure RIM based database:
SELECT DISTINCT obs.Value_Number AS number, 'mg/dl' AS units, SUBSTR(obs.Effectivetime_low,5,4) AS time, patientid.extension AS patientid FROM ACT obs INNER JOIN PARTICIPATION participant ON(obs.internalId = participant.actInternalId) INNER JOIN Role_id patientid ON(patientid.roleInternalId = participant.roleInternalId) WHERE obs.Code_code = '64544' AND patientid.root ='2.16.840.1.113883.19.5' AND patientid.extension = '12345'
Does the use of large numbers of Joins scale, without additional tuning of the database? Part of the answer is to automatically "conduct" a copy of certain data elements (e.g. the patient identifier) to an optional more proximal spot in memory before you do the query - the logic of adding/overriding context would be a nightmare to do in a query. That eliminates the majority of the joins. It takes some time in memory to do the context conduction when we are processing the message before we persist it. Once it's persisted we can get what we want with fewer joins. The above query examples are relatively simple, a production system would more likely retrieve lists of clinicalStatement objects (see first example) instead of a list of string and number values. The query language used allows you to query for any object.
For any given use case, you can create a one off database that would perform better, but then you need a different schema for each use case. One of the big advantages of a RIMBAA approach is that you use the same schema for everything. You might sacrifice some performance, but you'd avoid creating countless new schemas. So we might be willing to sacrifice some peformance for the saved costs of not having to create and maintain numerous database schemas though out the enterprise.
Generating messages is really not that hard to accomplish if you have the data. Using any one of a number of XML generating API's (RO to MS) you create the XML which can be sent. Receiving any data if it's in HL7 V3 format is also not complicated - if you have the corresponding MIF file it will "magically" be converted to RO objects and magically transition to RP cell.