Resolving the Mysteries of OpenMRS

DISCLAIMER: Before reading, know that the authors of this article are two undergrads that have worked on OpenMRS for about a week.

Basic Information
OpenMRS is an open source medical records system that was designed to be used in developing countries. From what we can figure out, its main capabilities are:
 * A system to store patient information
 * A comprehensive "Cohort Builder"
 * A concept dictionary

Check out a demo of OpenMRS here.

Overview
The backbone of OpenMRS is the API. This API defines all the basic functions of the application (adding patient information, looking up a concept) through services. Service classes (like PatientService, ConceptService) are interfaces that define methods for things that need to be done in the application.

The Context
The Context is a class that makes sure that only one service object of each type is instantiated. It helps the application save on memory. It is separated into a ServiceContext class and a UserContext class. One static ServiceContext class is instantiated the entire session, but a UserContext instance is created for every user.

Spring/Dependency Injection
All the basic service files (PatientService, ConceptService) are interfaces. The default implementations of them are called something like PatientServiceImpl, ConceptServiceImpl. Each of these implementations specifies a DAO (data access object) that controls access to the database. Spring's dependency injection controls which implementation of the services is used.

The Find/Create Patient Page
Maybe a quick look through how one particular feature works will help understand what's going on more clearly. When Find/Create Patient is clicked on the OpenMRS homepage, findPatient.htm is picked up by Spring and passed to the general Spring Controller. The spring controller replaces the .htm extension with.jsp and looks for the corresponding findPatient.jsp files in /WEB-INF/view/*. findPatient.jsp has a portlet called findPatient. A portlet is pluggable user interface component that is displayed in a web application.



This line of code, in WEB-INF/view/findPatient.jsp, tells it to include a portlet with the id findPatient. The parameters specify properties for the portlet. The findPatient portlet is located in WEB-INF/view/portlets, and its filename is findPatient.jsp, as well. The findPatient portlet contains most of the user interface code for the page. This portlet is mapped to its corresponding controller in the openmrs-servlet.xml file(located in WEB-INF), called PortletController. All other classes associated with creating and finding patients are assigned here, as well. In particular, the patient validator (probably used to validate data when creating a new patient) and the patient form controller are set up here.    true  patient  /admin/patients/patientForm  patient.form The controller builds the model and returns an object of type ModelAndView to the .jsp page. From here, OpenMRS uses the dojo toolkit to display a nifty search box that searches while you type in each character. Information from the form is then passed into a javascript file (I'm thinking its web/scripts/dojo/src/widget/openmrs/PatientSearch.js.withjstl) that contains a bunch of methods to search and display patient data. It probably calls doFindObjects at some point, which calls DWRPatientService.findPatients(src/web/org/openmrs/web/dwr/DWRPatientService.java). This method gets an implementation of PatientService from the Context, which is determined by Spring's dependency injection. PatientService ps = Context.getPatientService; We don't have to know which implementation it will be because we know what methods we can use from the PatientService interface. For example, say the Context served up the PatientServiceImpl.java implementation (this is the default implementation, located at src/api/org/openmrs/api/impl). The method findPatients is called, which calls a method called getPatients, which determines whether or not the user is searching by name or by patient identifier. Depending on what data they have passed in, it will call another getPatients method and pass in different parameters. This method calls a method in the PatientDAO object (DAO stands for Data Access Object), located at src/api/org/openmrs/api/db/PatientDAO.java. To be continued.

Data Validation on the Observation Form
It seems that any numeric data validation on the general add/edit observation form does not function properly. For example, a user can enter a decimal value for the Number of Siblings observation, or they can enter a number outside of the allowed range of numbers, like -5.

Numeric Data Validation Process

 * The user types in a value
 * obsForm.jsp calls a Javascript method located in the .jsp file called validateNumericRange and passes in the value
 * .. Stuff