Smart Container Technical Documentation for OpenMRS Developers
Primary objective of this module is to convert OpenMRS into a SMART container. After installing this module, OpenMRS users will be able to install and launch SMART Apps easily. Before going deep into the detail of the module architecture we have to understand some terminologies related to SMART Apps and SMART Containers.
What is a SMART App?
A 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 the SMART API to retrieve data from data sources. The data source may be a EMR like OpenMRS, a PHR like Indivo, or a data analytic platform such as i2b2. There are two types of SMART apps: SMART Connect app and SMART REST apps.
SMART Connect app
These are 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 use is called the SMART Connect API.
SMART REST apps
These are standalone applications(clients) that are running separately as a back-end server to a SMART connect app and uses a set of REST calls to get its data from the container. The API used by SMART REST apps is called as SMART REST API.
More information is available on the following page http://wiki.chip.org/smart-project/index.php/Main_Page#What_is_SMART.3F.
What is SMART Container?
A SMART container is a data source that exposes its data through the SMART API and provides 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 to this page: http://wiki.chip.org/smartproject/index.php/Developers_Documentation:_Terminology#SMART_Container.
How to convert OpenMRS into SMART Container
In order to convert OpenMRS into a SMART container the module should provide at least the following to the SMART Apps:
UI: where the SMART App is launched
Expose data: which are going to consumed by SMART Apps
Authentication: Enables secure way of transferring data.
Providing UI for SMART Apps
Almost all SMART Apps are centered around patient data. Therefore the apps are displayed as a tab on the patient dashboard.
.
SMART Apps are displayed at patient dashboard under the SMART tab. The SMART Apps which are selected by the user on the Manage User Apps admin page will be displayed at the side pane. When its 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 proxying SMART connect API with SMART REST API. This proxying 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
We created our own controllers which process the REST because of some technical difficulties in generating RDF payloads. 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/records/{patientId}/problems
In a nutshell
ProblemController asks the SmartProblemHandler to convert Problems (openmrs objects) to SmartProblem objects.
The SmartProblems are then passed to the ProblemRDFSource to be converted to RDF XML form.
In a bigger nutshell
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 which the mapping to SMART problem is done directly as follows.