OpenMRS Open Medical Records System INF5750 Saptarshi Purkayastha, Research Fellow, NTNU, Norway (using material from EHSDI course)
OpenMRS A free open source medical record system A web application written in Java with a MySQL/Postgres/< > backend A framework rather than a single program - its functionality is typically provided through custom "modules Modules are deployable on runtime without having to restart the web server or web application
A global community (Impl map) Last release had 72 developers. Overall more than 300+ developers have written code in opensource way
Core EMR domain objects Obs is short for observation It can be measurement or a question, e.g. What is a person's HIV status? Are they pregnant? What is their height? What is their weight?
Many EMR's start as spreadsheets, using a flat table to hold observations of patients, e.g. Observations Patients
Table gets unmanageably big as we keep adding new observations Gets really complicated when we want multiple records of the same observation type, e.g. weight change over time Wasted space when columns aren't used
Each observation becomes a concept and a value like a question and an answer PATIENTS CONCEPTS OBSERVATIONS
Concept name is very specific and includes units Concept id
Observations typically come from an event such as: The patient visits a clinician A form is submitted which records observations An event such as this is called an Encounter It describes a formal interaction between a provider and a patient Encounters can have many observations
Thus for a single encounter we want to store the following: Patient Provider Time/date Location Observations
Disease-specific EMR (MDR-TB) Credit: WHO-TB and PIH
Inpatient Care Credit: Andrey Kozhushkov, Ghislain Kouematchoua (Göttingen)
Credit: Dave Thomas Research Data Coordination
Adaptive Turnaround Documents Credit: Vibha Anand, Paul Biondich (Regenstrief)
Eligibility Across Institutions Credit: Monica Waggoner
Google Maps Integration Credit: Owais Ahmed, Aamir Khan
Credit: Brian Mckown (AMPATH) ID Cards and Barcodes
Mateme Touchscreen Registration Credit: Jeff Rafter (Baobab), Evan Waters (PIH)
Credit: Rowan Seymour iphone App
Notifiable Condition Detector Credit: Shaun Grannis, Regenstrief Institute
OpenMRS Development Primer
Controllers use Service interfaces implement The different layers interact with each other through interfaces, making it easier to change implementations Service implementations use DAO interfaces implement DAO implementations use Session factory
All of the DAO methods need valid sessions and transactions This code has to be in every method public List<Example> getexamples() { Session session = sessionfactory.opensession(); session.begintransaction(); List<Example> examples = session.createcriteria(example.class).list(); session.gettransaction().commit(); session.close(); return examples; }
Is an architecture which separates the data (model) the business logic (controller) the presentation (view) Model Classes, DB Controller Servlets View JSPs
Model Helper Classes Controller Servlet classes Attributes View JSPs Request Response Client
The controller receives the request from the client Parameters are read from the request Model classes used for any business logic Controller doesn't return any HTML JSP creates the response Get parameters from request Consult the model classes Set attributes on request or session Forward request to JSP
public void doget(httpservletrequest request, HttpServletResponse) { String name = request.getparameter("name"); 1 String password = request.getparameter("password"); User user = Security.login(name, password); 2 request.setattribute("curuser", user); 3 } RequestDispatcher view = request.getrequestdispatcher("/login.jsp"); view.forward(request, response); 4 Gets parameters from the view Consults the model for any business logic Sets attributes to be used by view Forwards the request to the view 1 2 3 4
This JSP can now return an HTML response using the attributes set by the controller <p>result is: <%= ((User)request.getAttribute("user")).getName() %> </p> However, this still requires Java code, which might be quite complex if we need to generate something like a table of results One alternative to this is...
This requires the usebean and getproperty actions, e.g. <p>result is: <%= ((User)request.getAttribute("curUser")).getName() %> </p> <p>result is: <jsp:usebean id="curuser" class="user" scope="request" /> <jsp:getproperty name="curuser" property="name" /> </p>
The sole purpose of a Validator is to validate the command object of a form View Errors Validator Any errors it finds, it sends back to the view Command FormController Success Request Success
Controllers beans are configured with validator beans in XML, e.g. <bean id="personvalidator" class="ehsdi.personvalidator" /> <bean id="personform" class="ehsdi.personformcontroller"> <property name="commandname"><value>person</value></property> <property name="formview"><value>/personform</value></property> <property name="successview"><value>person.list</value></property> <property name="validator"> <ref bean="personvalidator" /> </property> </bean> Controller will now automatically validate the person when form is submitted
What if submitted values cannot even be bound to the command object? Spring will create its own error message, which will be displayed by <form:errors>, e.g. Failed to convert property value of type [java.lang.string] to required... Error Age: Command Object xa!fsb Binder Person Validator
Submission Binding Validation Form Editors Command object Validators Edit Person Person Name: Bob Smith name: Bob Smith NameValidator DOB: 28/05/81 Custom DateEditor DOB: 28-05-1981 PersonValidator Married: Yes Custom BooleanEditor married: true One validator can invoke another
login.jsp... <openmrs:portlet url="login"/>... portlet tag is handled by PortletTag login.htm
login Gets url attribute PortletTag.java /portlets/login.portlet Creates portlet URL Requests portlet URL openmrs-servlet.xml urlmapping *.portlet PortletController Maps URL to controller PortletController.java /portlets/login.portlet /portlets/login Gets servlet_path attribute Removes.portlet Forwards to view... openmrs-servlet.xml jspviewresolver /portlets/login /portlets/login.jsp Maps view to JSP login.jsp Displays JSP!
Much more details (openmrs.org) Lots of details but very flexible and modular