Have you implemented OpenMRS? Please participate in the Implementation Site Survey. If you already have, thank you!
Page tree
Skip to end of metadata
Go to start of metadata


This page describes the changes to OpenMRS to support Complex Observations. See ticket:656 and ticket:107.* 
Complex Obs Support gives OpenMRS the ability to store observations (Obs) on a patient with complex values such as an x-ray image, a document, or a media file. These complex data are large and so are stored on the file system outside of the OpenMRS database. In order to do this, a few things are necessary:

  • The Concept Dictionary must have at least one Concept with Datatype as Complex.
  • That ConceptComplex must be associated with a registered ComplexObsHandler
  • The question for the Obs (Obs.getConcept()) must be set to that ConceptComplex (a Concept with Datatype="Complex").

Intro to ComplexObsHandler

  • ComplexObsHandler classes are hidden from the user and only used by the ObsService.
  • They do the internal work of saving and retrieving ComplexData from an Obs that is "complex"
  • Each ComplexObsHandler is mapped in the Spring framework with a unique key.
  • ComplexObsHandlers can be registered in any of 4 places:
    • API level handlers: metadata/api/spring/applicationContextService.xml
    • Web layer handlers: web/WEB-INF/openmrs-servlet.xml
    • Module loaded handlers: metadata/moduleApplicationContext.xml
    • Programmatically using ObsService.registerHandler(Class handler)
  • If two handlers are mapped to the same key, the last one loaded by Spring will override the first.
    • The overriding class should save the complex data in the same place as the parent


  • Create a new Concept in the Concept Dictionary and set the Datatype to "Complex".
    • Now set the "Handler" for this concept to the built in ImageHandler
  • Create a new Obs
    • Set the concept (question) to be your new complex type of concept
    • Choose an image file to upload
    • Save the obs
  • View the newly created Obs and see the image and a link to download it


Technical Workflow

Save a complex obs and data:ConceptComplex conceptComplex = Context.getConceptService().getConceptComplex(1867);
// this is assumed to have happened
// conceptComplex.setHandler("ImageHandler");
// Set the required properties.
Obs obs = new Obs(new Person(48609), conceptComplex, new Date(), new Location());
BufferedImage img = ImageIO.read(new File("/home/bmckown/Desktop/test/logo.png"));
// or:
// InputStream img = new FileInputStream(new File("folder", "filename"));
ComplexData complexData = new ComplexData("test-image.jpg", img);
Context.getObsService().saveObs(obs, null);
// obs.getComplexData() will be null here
Retrieve a complex obs and its dataInteger obsId = obs.getObsId();
Obs complexObs = Context.getObsService().getComplexObs(obsId, OpenmrsConstants.RAW_VIEW);
ComplexData complexData = complexObs.getComplexData();
Object object = complexData.getData();
// object will be a BufferedImage object
Getting back binary-data / binary-stream compleObs – eg: for Video files, Zip files, kind of large files, etc
        Obs complexObs = Context.getObsService().getComplexObs(videoObsId, OpenmrsConstants.RAW_VIEW);
        ComplexData complexData = complexObs.getComplexData();
        byte[] videoObjectData = ((byte[]) complexData.getData()); // cast Object --to--> byte array object

How to Create a ComplexObsHandler


  • A ComplexObsHandler must implement the ComplexObsHandler interface
  • A ComplexObsHandler may extend one of the default API layer ComplexObsHandlers
  • The ComplexObsHandler must be registered by Spring with a key.



  • Found in the org.openmrs.web.controller.observation.handler package
  • Extends org.openmrs.obs.handler.ImageHandler
  • NOTE! Uses ImageHandler to saveObs().
  • Overrides the getComplexData() method to provide web-specific ComplexData
    • Provides hyperlink to ComplexObsServlet instead of the heavyweight data.

      public class WebImageHandler extends ImageHandler {
        public Obs getComplexData(Obs obs, String view) {
           if (Webutils.HYPERLINK_VIEW.equals(view)) {
               String link = "/ComplexObsServlet?obsId=" + obs.getObsId();
               obs.set(new ComplexData("some title", link);
               return obs;
           return super.getComplexObs(obs, view);

Register WebImageHandler

  • Register WebImageHandler in openmrs-servlet.xml so that it is only seen if used in the webapp...not in the jar alone.
  • Or alternatively, for a module register in ModuleApplicationContext.xml

        <bean parent="obsServiceTarget" >
            <property name="handlers">
                        <bean class="org.openmrs.web.controller.observation.handler.WebImageHandler"/>
  • No labels