You are on page 1of 16

PatientOS

PatientOS Integration Administrator Guide

Version 1.0

Integration Administrator Guide

Last printed 4/18/2008 1:53:00 AM Version 1.0

Revision History
Date 04/17/2008 Version 1.0 Description Initial for version 0.70 Author Greg Caulton

Page 1 of 16

Integration Administrator Guide

Last printed 4/18/2008 1:53:00 AM Version 1.0

Contents
1. OVERVIEW........................................................................................................................................................................ 3 1.1 1.2 2. 2.1 2.2 2.3 3. 3.1 3.2 4. 4.1 4.2 5. 5.1 DEFAULT SETTINGS ............................................................................................ ERROR! BOOKMARK NOT DEFINED. DEFINITIONS ................................................................................................................................................................. 3 SETTINGS TOOL .................................................................................................. ERROR! BOOKMARK NOT DEFINED. CHANGING A SETTING ........................................................................................ ERROR! BOOKMARK NOT DEFINED. ADDING A SETTING ............................................................................................. ERROR! BOOKMARK NOT DEFINED. ADDING BATCH JOBS .......................................................................................... ERROR! BOOKMARK NOT DEFINED. SCHEDULING BATCH JOBS .................................................................................. ERROR! BOOKMARK NOT DEFINED. IDENTIFIER SOURCE TOOL .................................................................................. ERROR! BOOKMARK NOT DEFINED. ADDING AN IDENTFIER SOURCE ......................................................................... ERROR! BOOKMARK NOT DEFINED. LOGIN.................................................................................................................. ERROR! BOOKMARK NOT DEFINED.

SYSTEM SETTINGS ........................................................................................ERROR! BOOKMARK NOT DEFINED.

BATCH JOBS ....................................................................................................ERROR! BOOKMARK NOT DEFINED.

SYSTEM IDENTIFIERS ..................................................................................ERROR! BOOKMARK NOT DEFINED.

PATIENT PORTAL ..........................................................................................ERROR! BOOKMARK NOT DEFINED.

Page 2 of 16

Integration Administrator Guide

Last printed 4/18/2008 1:53:00 AM Version 1.0

Integration Administrator Guide


1.
1.1

Overview
Integration

There are a number of inbound and outbound interfaces for PatientOS using Mirth for the majority of the integration points. The list is not limited to: a) Standard HL7 Interfaces. a. ADT Inbound b. ADT Outbound c. Lab Results Inbound d. Lab Orders Outbound b) XML or any other format supporting by Mirth a. XML Forms/Clinical Results Inbound b. XML Clinical c) Web development a. Patient Portal running within the JBoss container d) Batch processing a. Scheduled scripts which can directly reference the EJB services e) JDBC a. Direct SQL (not recommended except for read only access)
1.2 Definitions

POS

Refers to the PatientOS software as a system.

Page 3 of 16

Integration Administrator Guide

Last printed 4/18/2008 1:53:00 AM Version 1.0

2.
2.1

XML Forms/Clinical Results Inbound


Overview

Mirth is an enterprise class integration engine with which PatientOS integrates. For inbound forms the basic flow is i) Mirth receives the XML file (from filesystem, JDBC, or port, etc) ii) Mirth maps the XML content into the PatientOS XML format for Records iii) Mirth inserts the XML into the interface_messages table iv) PatientOS interface controller (running as a JBoss service) picks up the file v) The appropriate Converter is called to map the XML to the PatientOS FormRecordModel vi) The model is stored writing to the records and record_details (if populated).
2.2 2.2.1 Mirth Setup Start Mirth

To setup mirth start Mirth using Start

Program Files

PatientOS

version

Interface Engine

Figure 1 Starting Mirth

For a production implementation Mirth would be installed as a service.


2.2.2 Start Mirth Manager

To setup the interface channels start the Mirth Manager using Start Manager. Login with admin/admin

Program Files

PatientOS

version

Interface

Figure 2 admin/admin

Page 4 of 16

Integration Administrator Guide

Last printed 4/18/2008 1:53:00 AM Version 1.0

2.2.3

Channels

Select the channels tab and view the existing channels (if the channels were not included download from http://www.patientos.org/documentation . Download the file oru_xml_file_pos_db.xml. The file name indicates it is a results file reading XML from a file and posting it into the PatientOS database. Select the channel ORU XML File POS DB and Edit Channel to edit the properties.

Figure 3 Channels

The first tab defines that XML is being read and this channel will auto start.

Figure 4 Summary tab

Page 5 of 16

Integration Administrator Guide

Last printed 4/18/2008 1:53:00 AM Version 1.0

2.2.4

XML Inbound Directory

Clicking on the Source tab will show which directory is being read to find the XML content and the file name format required to process. Note that the directory is defined as a relative path. It is relative from where the interface engine started (interfaces.bat or interfaces.sh). On windows this path would be C:\Program Files\PatientOS\<version>\server\interfaces\bin

Figure 5 Source tab

In the figure above you can see that the channel will search for xml files in the directory C:\Program Files\PatientOS\<version>\server\interfaces\activity\oru_xml_in

every second.

Page 6 of 16

Integration Administrator Guide

Last printed 4/18/2008 1:53:00 AM Version 1.0

2.2.5

Destination

On the destinations tab you can see the SQL used to insert into the PatientOS interface_messages table. Take careful note of the URL and ensure the correct database is being accessed. In this case qapos is shown though the default should be demopos with the correct username and password.

Figure 6 Destination tab

Click on the Edit Transformer link to open the Transformer. Paste your XML into the top right frame and the XML elements will be parsed and displayed in a tree below. It helps if your XML is populated with sample data.

Figure 7 Transformer incoming

Page 7 of 16

Integration Administrator Guide

Last printed 4/18/2008 1:53:00 AM Version 1.0

2.2.6

Transformer

PatientOS is setup with Javascript to map the incoming XML elements to the PatientOS XML elements. The Outgoing tab serves to display a template XML which is populated by the Javascript. For this reason we want as little data as possible (most is not needed). However in order to see all the fields you might like to populate you can paste into the frame the RecordTransaction.xml file from http://www.patientos.org/documentation When have finished mapping replace the contents with the original XML You may need to tailor the XML (for example we will add RecordDetailModel rows.

Figure 8 Outgoing data tab

The goal is to populate a) Enough of the PatientModel to match the patient name and MRN (matching is a large topic) unless you have the patient_id from the patients table. b) A single FormModel to reflect the form c) As many RecordModel has you have fields on this virtual form. d) As many RecordDetailModel if you have details for a specific Record. The concept of Record and RecordDetail is that the Record value is the significant value e.g. height, weight, lab results etc where as the RecordDetail are child details e.g. Clothing the patient had on when weighed or comments on the lab result. The script is written in Javascript and obviously you need some programming skills to understand the nuances of iterating through the XML elements and building up the target XML which is this tmp structure.

Page 8 of 16

Integration Administrator Guide


2.2.7 Example Mapping

Last printed 4/18/2008 1:53:00 AM Version 1.0

We will work with this sample XML <ns1:PorcupineDataSet xmlns:ns1="http://www.cs.uit.no/inf3793/xml"> <ns1:patientId>4</ns1:patientId> <ns1:measureFrequency>300</ns1:measureFrequency> <ns1:sensorType>motion</ns1:sensorType> <ns1:timeStart>2008-01-18T00:00:00.000+01:00</ns1:timeStart> <ns1:timeStop>2008-01-18T00:15:00.000+01:00</ns1:timeStop> <ns1:commaSeparatedValues>89,22,0,0,0,0,0,0,0,2,22,24,4,12,99,140,120,94,2,0,0,0,4,5,32,4,0,0,0,0,0,0,0,0,0,0,32,12,1,0,0, 3,0,0,0,2,5,0,0,0,0,1,4,9,10,4,0,0,0,0</ns1:commaSeparatedValues> <ns1:comment>commaSeparatedValues and sensorType are real:)!</ns1:comment> <ns1:dataUnit>hammed motion</ns1:dataUnit> <ns1:intervalUnit>minutes</ns1:intervalUnit> </ns1:PorcupineDataSet> The patientId is actually the MRN and so in the javascript we first create the MRN mapping by dragging the XML patientID over to the javascript page. If you have setup a facility other than the default you would enter the reference key (your facility name uppercase with spaces removed).

Figure 9 Drag patientid to be MRN 2.2.8 Records

On version 1.6 of Mith one way of creating the many iterations of RecordModel is to have the first defined in the template and then copy it each time to add to the XML. This section of Javascript will likely change to an easier to perform this in later version of Mirth. But essentially we know there are 8 records needed so we loop 8 times and within the loop duplicate the first RecordModel, map the values and where possible set common values outside each if statement. Not great but it works

Page 9 of 16

Integration Administrator Guide

Last printed 4/18/2008 1:53:00 AM Version 1.0

You must setup an Identifier Source (login to PatientOS as admin/admin and select Identifier Sources) specific to where this incoming data is coming from. PatientOS supports multiple interfaces and the source is a unique identifier for all external identifiers. In this example Porcupine Sensor was used as the identifier source.

Figure 10 Create identifier source

2.2.9

Javascript

Ideally all the record_items have been created in PatientOS. The display must be unique in the database in order to reduce confusion with multiple items with the same name (it is possible to have dups but not recommended). The short display is typically used on controls, reports etc. The display being the formal name. The interface will add these items on the fly (writes to the record_items and record_item_details tables). Ideally preload using a reference spreadsheet, then import the record items. Note dates must be formatted YYYYMMDD and mapped to the date component or YYYYMMDDHHMMSS and mapped to the date/time format. Rather than parsing we will hard code it to get started with testing // map the MRN to match the patient tmp['PatientModel']['IdentifierModel']['sourceRef']['idvalue'] = "DEFAULTFACILITY"; tmp['PatientModel']['IdentifierModel']['idvalue'] = msg['ns1:patientId'].toString();

for (i=0; i<8; i++){ startTime = "20080118000000"; stopTime = "20080118001500"; if (i==0) { // measure frequency tmp['RecordModel'][i]['recordItemRef']['idvalue'] = "MOTIONMEASUREFREQUENCY"; tmp['RecordModel'][i]['recordItemRef']['display'] = "Motion Measure Frequency"; Page 10 of 16

Integration Administrator Guide

Last printed 4/18/2008 1:53:00 AM Version 1.0

tmp['RecordModel'][i]['dataTypeRef']['id'] = 56990; // DOUBLE tmp['RecordModel'][i]['valueDouble'] = msg['ns1:measureFrequency'].toString(); } else if (i==1) { // sensor type tmp['RecordModel'][i]=tmp['RecordModel'][i-i]; // create xml element tmp['RecordModel'][i]['recordItemRef']['idvalue'] = "MOTIONSENSORTYPE"; tmp['RecordModel'][i]['recordItemRef']['display'] = "Motion Sensor Type"; tmp['RecordModel'][i]['dataTypeRef']['id'] = 79128; // STRING tmp['RecordModel'][i]['valueString'] = msg['ns1:sensorType'].toString(); } else if (i==2) { // timestart tmp['RecordModel'][i]=tmp['RecordModel'][i-i]; // create xml element tmp['RecordModel'][i]['recordItemRef']['idvalue'] = "MOTIONTIMESTART"; tmp['RecordModel'][i]['recordItemRef']['display'] = "Motion Time Start"; tmp['RecordModel'][i]['dataTypeRef']['id'] = 56992; // DATE tmp['RecordModel'][i]['valueDate']['datetime'] = startTime; } else if (i==3) { // timestop tmp['RecordModel'][i]=tmp['RecordModel'][i-i]; // create xml element tmp['RecordModel'][i]['recordItemRef']['idvalue'] = "MOTIONTIMESTOP"; tmp['RecordModel'][i]['recordItemRef']['display'] = "Motion Time Stop"; tmp['RecordModel'][i]['dataTypeRef']['id'] = 56992; // DATE tmp['RecordModel'][i]['valueDate']['datetime'] = stopTime; } else if (i==4) { // commaseparatedvalues tmp['RecordModel'][i]=tmp['RecordModel'][i-i]; // create xml element tmp['RecordModel'][i]['recordItemRef']['idvalue'] = "MOTIONHAMMEDMOTION"; tmp['RecordModel'][i]['recordItemRef']['display'] = "Motion Hammed Motion"; tmp['RecordModel'][i]['dataTypeRef']['id'] = 79128; // STRING tmp['RecordModel'][i]['valueString'] = msg['ns1:commaSeparatedValues'].toString(); } else if (i==5) { // comment tmp['RecordModel'][i]=tmp['RecordModel'][i-i]; // create xml element tmp['RecordModel'][i]['recordItemRef']['idvalue'] = "MOTIONCOMMENT"; tmp['RecordModel'][i]['recordItemRef']['display'] = "Motion Comment"; tmp['RecordModel'][i]['dataTypeRef']['id'] = 79128; // STRING tmp['RecordModel'][i]['valueString'] = msg['ns1:comment'].toString(); } else if (i==6) { // dataunit tmp['RecordModel'][i]=tmp['RecordModel'][i-i]; // create xml element tmp['RecordModel'][i]['recordItemRef']['idvalue'] = "MOTIONDATAUNIT"; tmp['RecordModel'][i]['recordItemRef']['display'] = "Motion Data Unit"; tmp['RecordModel'][i]['dataTypeRef']['id'] = 79128; // STRING tmp['RecordModel'][i]['valueString'] = msg['ns1:dataUnit'].toString(); } else if (i==7) { // intervalunit tmp['RecordModel'][i]=tmp['RecordModel'][i-i]; // create xml element tmp['RecordModel'][i]['recordItemRef']['idvalue'] = "MOTIONINTERVALUNIT"; tmp['RecordModel'][i]['recordItemRef']['display'] = "Motion Interval Unit"; tmp['RecordModel'][i]['dataTypeRef']['id'] = 79128; // STRING tmp['RecordModel'][i]['valueString'] = msg['ns1:intervalUnit'].toString(); } // Common tmp['RecordModel'][i]['recordDt']['datetime'] = startTime; tmp['RecordModel'][i]['recordItemRef']['identifierSource'] = "PORCUPINESENSOR"; } Page 11 of 16

Integration Administrator Guide


2.2.10 Deploy

Last printed 4/18/2008 1:53:00 AM Version 1.0

Make sure the Outgoing Data script is After saving the transformer changes the channel is deployed

Figure 11 Deploy changes

Now drop a copy of your xml file into the oru_xml_in directory identified earlier. The channel will remove the file and any errors will be written to the log. On the dashboard we can see an error occurred:

Figure 12 Dashboard

Selecting Events will show the log, selecting the first entry and scrolling down the exception log we find the error relates to the ns1 prefix used in the XML

Figure 13 Event log for errors

Page 12 of 16

Integration Administrator Guide

Last printed 4/18/2008 1:53:00 AM Version 1.0

After attempting some javascript tricks to remove or build the namespace the event log stopped filling with error messages. Instead by right clicking on the channel in the dashboard you can select View Messages You can select the message which errored and view the different states the message went through before and after the transformating Javascript. On the error tab we see the namespace is still an issue.

Figure 14 Message view for the big picture

To resolve the issue on the Summary tab we deselected Strip namespace from messages and as show above the message was transformed and sent i.e. written to the interface_messages table.

Page 13 of 16

Integration Administrator Guide


2.3 PatientOS Processing

Last printed 4/18/2008 1:53:00 AM Version 1.0

We can find our interface message in the interface_messages table

Figure 15 Interface messages table

Logging into PatientOS as admin/admin and opening the Interface Manager shows that the ResultTransaction processing had already started but has not processed anything yet.

But we posted a RecordTransaction so that is why it was not picked up yet. This will be included in the next version but I can add one (using SQL to assign the poll script). Restarting the server and this interface processor will start.

Page 14 of 16

Integration Administrator Guide


2.3.1 Errors

Last printed 4/18/2008 1:53:00 AM Version 1.0

A snippet of the error message is written to the interface_messages table (select * from interface_messages) but currently you need to have JBoss running in console mode so you can see the exact error. e.g. This error shows the MRN was not passed and confirm in Mirth on the messages tab. 23:38:01,125 WARN [JDBCExceptionReporter] SQL Error: 0, SQLState: 42883 23:38:01,125 ERROR [JDBCExceptionReporter] ERROR: operator does not exist: character varying = bytea 23:38:01,125 ERROR [Log] data.common.BaseData.sqlQuery:select p.patient_id from identifiers i, patient_identifier pi, patients p where i.id value = :idvalue and i.source_ref_id = :identifierSourceRefId and i.identifier_id = pi.identifier_id and pi.patient_id = p.patient_id and p.active_ind = 1 idvalue = null identifierSourceRefId = 1000447(sqlQueryquery) 23:38:01,125 ERROR [Log] org.hibernate.exception.SQLGrammarException could not execute query...

After fixing the mapping in Mirth (namespaces were causing problems again now removed from the XML) the message gets this error in the interface_messages table: com.patientis.model.clinical.FormModel.validateDataModel(FormModel.java:55) JBoss showed the desired exception 00:05:38,078 ERROR [Log] com.patientis.model.clinical.NoRecordsInFormException null...

The validation failed for the FormModel due to all records being discarded likely to each each FormRecordModel being rejected due to failed validation. Checking the FormRecordModel the patient id is required and not populated in this version so an upgrade is required to fix that issue.

Page 15 of 16

You might also like