Complex Obs Support

Introduction

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

Workflow

  • 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); obs.setComplexData(complexData); 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

Requirements

  • 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.

Example

WebImageHandler

  • 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