??
Introduction">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">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">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">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">How to Create a ComplexObsHandler
Requirements">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">Example
WebImageHandler">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)Unknown macro: { if (Webutils.HYPERLINK_VIEW.equals(view))}Unknown macro: { 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.public class WebImageHandler extends ImageHandler {
Register WebImageHandler">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>