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
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); } }
- Provides hyperlink to ComplexObsServlet instead of the heavyweight data.
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"> <map> <entry> <key><value>ImageHandler</value></key> <bean class="org.openmrs.web.controller.observation.handler.WebImageHandler"/> </entry> </map> </property> </bean>