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