SMART container module
Primary objective of this module is to convert OpenMRS into a SMART container.After installing this module, OpenMRS user will be able to install and launch SMART Apps easily.Before going deep into the detail of the module architecture we have to uderstand some terminologies related to SMART Apps and SMART Container.
1)What is a SMART App?
SMART app is a substitutable medical app built using reusable techniques.It can be a web app built using reusable technologies such as HTML and JavaScript.It uses SMART API to retrieve data from data sources.The data source may be a EMR likeOpenMRS or PHR like Indivo or data analytic platform such asi2b2.There are two types of SMART apps called SMART Connect app and SMART REST apps.SMART Connect app is embedded in to the SMART container using HTML iframes and uses interframe communication(using javaScript callbacks) to get the data from the container.The API that SMART connect apps are using is called as SMART Connect API.SMART REST apps are standalone applications(clients) that are running separately as a back-end server to a SMART connect app and uses set of REST calls to get its data from the container.The API used by SMART REST apps is called as SMART REST API. To get more information refer following page http://wiki.chip.org/smart-project/index.php/Main_Page#What_is_SMART.3F .
2)What is SMART Container?
SMART container is a data source that exposes its data through the SMART API and provide a UI for SMART connect apps.Every EMR can be a SMART container when it is providing the SMART API,UI and secure way of accessing the API. Additionally it can provide its own way of installing and managing of the SMART apps.
For more information refer http://wiki.chip.org/smartproject/index.php/Developers_Documentation:_Terminology#SMART_Container .
3)How to convert an EMR into SMART Container?
In order to convert OpenMRS into a SMART container the module should provide at least followings to the SMART Apps.
- UI :where the SMART App is launched
- Data:which are going to consumed by SMART Apps
- Authentication:Enables secure way of transferring data.
How OpenMRS is Converted into SMART Container?
Providing UI for SMART Apps
Almost all SMART Apps are running around a patient data.The place where the UI is placed should be suitable to display data related to a selected patient.So in OpenMRS the patient dashboard is the best place to display SMART Apps.
.
SMART Apps are displayed at patient dashboard under the SMART tab.The SMART Apps which are selected by user at manage user app page will be displayed at the side pane and when the respective icon is clicked the app will be launched within the HTML iframe.Using the available extension point(PatientDashboardTabExt) at the patient dashboard the SMART app tab was created.
Exposing Data
The idea the smartcontainer module adopts is initially expose SMART REST API and convert SMART connect javaScript callback into a ajax call to SMART REST API.so the smartcontainer module is proxiying SMART connect API with SMART REST API.This proxiying mechanism is done at smartAppForm.jsp as following.
$j.ajax({ beforeSend : function(xhr) { xhr.setRequestHeader("Authorization", " "); }, dataType : "text", url : "${pageContext.request.contextPath}" + "/ws/smartcontainer/api" +api_call.func, contentType : activity.contentType, data : activity.params, type : activity.method, success : callback, error : function(data) { alert("error"); } });
SMART REST API
previously it was planed to use OpenMRS REST Module to expose the REST API.But we decided not to use REST modules and created our own controllers which process the REST because of some technical difficulties in generating RDF payloads.For each SMART data types smartcontainer has a controller.For example there is a ProblemController to serve the requests which are asking problems.Those requests are in following form.
GET http://localhost:8080/openmrs/ws/smartcontainer/api/reords/{patientId}/{datatype(problems)}
The controller renders the RDF payloads corresponding to the request in XML form as SMART App expects the response in this form.The RDFSource corresponding to the data type is responsible for generating RDF payload from supplied SMART domain objects.Smartcontainer uses OpenRDF library to generate RDF payloads.The SmartDataService is responsible for generating appropriate SMART domain objects such as SmartProblem from a selected patient.Appropriate handlers are supplied to the SmartDataService class through the moduleApplicationContext.xml which are used to convert the OpenMRS domain object into SMART domain object.Currently the module has handlers and RDFSources for following SMART data types.
* Patient demographics
SMART field |
Description |
Data format |
OpenMRS terminology |
---|---|---|---|
Given name |
A person's given, or first, name |
Free text |
patient.getFamilyName() |
Family name |
A person's family, or last, name |
Free text |
patient.getGivenName() |
Gender |
A person's gender |
'male' or 'female' |
patient.getGender().equals("M") ? "male" : "female" |
Zip code |
A person's zip code |
Free text |
patient.getPersonAddress().getPostalCode() |
Birth day |
A person's birth date |
ISO-8601 string |
patient.getBirthdate() |
*Medication(mapped to RxNorm)
SMART field |
Description |
Data format |
OpenMRS terminology |
---|---|---|---|
Drug name |
RxNorm Concept ID for this medication |
RDF CodedValue node with code drawn from |
DrugOder.getDrug().getConcept() is used to retrieve the mapped RxNorm concept code, if the code available it is used to set the code of the drug name concept and the title of the coded value is still filled with OpenMRS concept name. |
Instruction |
Clinician-supplied instructions from the prescription signature |
Free text |
DrugOder.getFrequency() |
Quantity |
For a medication with a simple dosing schedule, record the amount to take with each administration. |
RDF ValueAndUnit node |
value:DrugOder.getQuantity() |
Frequency |
For a medication with a simple dosing schedule, record how often to take the medication |
RDF ValueAndUnit node |
DrugOder.getFrequency() is first split-ed for '/' and then first part is converted into number,it gives the value .The second part is mapped from Openmrs format("daily") to SMART format("/d") or if the OpenMRS format is different it gives unstructured unit as "\'{my units}". |
Start date |
when the patient started taking a medication |
ISO-8601 string |
DrugOrder.getStartDate() |
End date |
when the patient stopped taking a medication |
ISO-8601 string |
First DrugOder.getDiscontinued() is checked if it so the end date is set to that otherwise DruOrder.getAutoExpireDate() is set . |
Fulfilment |
|
RDF Fulfillment node |
NOT IMPLEMENTED YET |
* Problems(Mapped to SNOMED CT)
OpenMRS data model represents problem in two way.First is using problem table for wich the mapping to SMART problem is done directly as follows.
SMART field |
Description |
Data format |
OpenMRS terminology |
---|---|---|---|
Notes |
Additional notes about the problem |
Free text |
Problem.getComments(); |
Problem name |
SNOMED-CT Concept for the problem |
CodedValue node referencinghttp://www.ihtsdo.org/snomed-ct/concepts/{concept_id} |
Problem.getProblem() is used to retrieve related mapped SNOMED-CT concept code and this value is used to set the code of the coded value node and the OpenMRS concept name is used to fill the title of the coded value node. |
Resolution |
Date of problem resolution |
ISO-8601 string |
Problem.getEndDate() |
Title |
Human-readable problem name |
Free text |
It is already included within the problem name |
Onset |
Date of problem onset |
ISO-8601 string |
Problem.getStartDate() |
Second way is using problem added/problem removed obs to represent the problems.
SMART field |
Description |
Data format |
OpenMRS terminology |
---|---|---|---|
Notes |
Additional notes about the problem |
Free text |
|
Problem name |
SNOMED-CT Concept for the problem |
CodedValue node referencing[[http://www.ihtsdo.org/snomed-ct/concepts/]{concept_id} |
|
Resolution |
Date of problem resolution |
ISO-8601 string |
|
Title |
Human-readable problem name |
Free text |
|
Onset |
Date of problem onset |
ISO-8601 string |
|
From both method user have to select one method at Administration->Set up problem object page
*Lab result
The Obs related to lab result are separated by only taking the obs whose concept.conceptClass is "Test".
SMART field |
Description |
Data format |
OpenMRS terminology |
|
---|---|---|---|---|
Lab name |
LOINC Coded Value for result |
RDF CodedValue node *drawn from LOINC |
Obs.getConcept() is used to retrieve related mapped LOINC concept code and this value is used to set the code of the coded value node and the OpenMRS concept name is used to fill the title of the coded value node. |
|
Quantitative result |
Qualitative result, if any |
RDF QuantitativeResult node |
If the obs.concept is numeric then |
|
Nominal result |
Nominal result, if any |
RDF NominalResult node |
NOT IMPLEMENTED |
|
Narrative result |
Narrative result, if any |
RDF NarrativeResult node |
NOT IMPLEMENTED |
|
Ordinal result |
Ordinal result, if any |
RDF OrdinalResult node |
NOT IMPLEMENTED |
|
Accession number |
External accession number for a lab result |
Free Text |
Obs.accessionNumber |
|
Status |
Status of this lab |
RDF CodedValue node, drawn fromhttp://smartplatforms.org/terms/code/LabResultStatus# |
NOT IMPLEMENTED |
|
Abnormal interpretation |
Abnormal interpretation status for this lab |
RDF CodedValue node, drawn fromhttp://smartplatforms.org/terms/code/LabResultInterpretation# |
NOT IMPLEMENTED |
|
Specimen collected |
Attribution for who collected the specimen for this result, and when |
RDF Attribution node |
Start date:Obs.ObsDateTime |
|
Specimen received |
Attribution for who received the specimen for this result, and when |
RDF Attribution node |
NOT IMPLEMENTED |
|
Resulted |
Attribution for who determined this result from the specimen, and when |
RDF Attribution node |
NOT IMPLEMENTED |
|
Comments |
Narrative comments for this result |
Free Text |
NOT IMPLEMENTED |
* Vital Signs
Obs whose concepts match a fixed list of LOINC codes
SMART field |
Description |
Data format |
OpenMRS terminology |
|
---|---|---|---|---|
Encounter |
Encounter during which vital signs were taken |
RDF Encounter node |
Currently typical OpenMRS installation has following encounter types ADULTINITIAL,ADULTRETURN,PEDSINITIAL and PEDSRETURN which are actually |
|
Date |
Date + time when vital signs were recorded |
ISO-8601 string |
Encounter.encounterDateTime |
|
height |
Patient's height in meters |
RDF ValueAndUnit node where unit is: "m" |
if Obs.concept's mapped conceptCode.equals("8302-2") |
|
weight |
Patient's weight in kg |
RDF ValueAndUnit node where unit is: "kg" |
if Obs.concept's mapped conceptCode.equals("3141-9") |
|
Body Mass Index |
Patient's Body Mass Index |
RDF ValueAndUnit node where unit is: "{BMI}" |
if Obs.concept's mapped conceptCode.equals("39156-5") |
|
Respiratory Rate |
Patient's Respiratory Rate per minute |
RDF ValueAndUnit node where unit is: "{breaths}/min" |
if Obs.concept's mapped conceptCode.equals("9279-1") |
|
Heart Rate |
Patient's Heart Rate per minute |
RDF ValueAndUnit node where unit is: "{beats}/min" |
if Obs.concept's mapped conceptCode.equals("8867-4") |
|
Temperature |
Patient's Temperature in Celcius |
RDF ValueAndUnit node where unit is: "Cel" |
if Obs.concept's mapped conceptCode.equals("8310-5") |
|
Oxygen Saturation |
Patient's Oxygen Saturation in percent hemoglobin |
RDF ValueAndUnit node where unit is: "%{HemoglobinSaturation}" |
if Obs.concept's mapped conceptCode.equals("2710-2") |
|
Blood Pressure |
Patient's systolic + diastolic Blood Pressure in mmHg, with optinal position coding |
RDF BloodPressure Node |
if Obs.concept's mapped conceptCode.equals("8462-4") |
|
Authentication
Currently smartcontainer dose not use any authentication for REST API.
Managing Apps
OpenMRS administrator can add or remove SMART Apps in smartcontainer module.The actual hosting of the SMART apps is outside of this module.The container gets all information necessary to launch the remotely hosted SMARt app from the uploaded manifest file of the SMART app.The ManifestParser is responsible for parsing the manifest file and the AppFactory generates the App object which can be saved in database.
The added Apps are only available at patient dashboard after user adds SMART apps at Administration->Manage user app.
Detail presentation:[http://vimeo.com/23265477|http://vimeo.com/23265477]