You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Next »

The source code for this prototype module is currently located on GitHub within the feature_fw branch: https://github.com/jembi/openmrs-module-shr-cdahandler.git . This module is in early stages and there are still issues with it, it is intended to be an experiment and requires further work before being put "in the field".

Overall Design

The design of the CDA Content Handler Module prototype is based on a series of “processors” which are instantiated based on the template id that the structure currently in “scope” of processing. Processors implement the Processor interface which itself is specialized into document, section and entry processor interfaces.

Each processor is responsible for interpreting/converting the HL7v3 CDA RMIM structure, and performing any updates the OpenMRS data store. A processor is also responsible for validating that it can parse the structure provided to it (not only CDA conformance but conformance of the constructed OpenMRS objects) and throwing a DocumentValidationException if this validation fails.

Processors are constructed using one of three processor factories:

  • Document Processor Factory
  • Section Processor Factory
  • Entry Processor Factory

Each processor factor calls the ClassPathScannerUtil to construct the most appropriate processor for the particular structure. The utility uses the @ProcessTemplates annotation to determine which templateId a particular processor can handle. For example:

@ProcessTemplates( templateIds = { “x.x.x.x.x.x.x” })
public final class FooSectionProcessor implements SectionProcessor

Would indicate that any structure carrying “x.x.x.x.x.x” templateId should be processed by FooSectionProcessor. If a document/section/entry carries more than one templateId then the most specific implementation (that which is furthest down the inheritance tree) is selected. For example, consider the following processors:

@ProcessTemplates( templateIds = { “x.x.x.x.x.x.x” })
public class FooSectionProcessor implements SectionProcessor
@ProcessTemplates( templateIds = { “y.y.y.y.y.y.y” })
public final class BarSectionProcessor extends FooSectionProcessor

If a section has both OIDs (x.x.x.x.x.x and y.y.y.y.y.y) then BarSectionProcessor would be selected, even though FooSectionProcessor is able to process at least some of the constraints. Additionally processors carrying the @ProcessTemplates annotation may support more than one template identifier by adding additional OIDs to the templateIds annotation parameter.

All processors are responsible for cascading any values down the RMIM graph (for example: context conduction) and are responsible for calling processors for any sub-sections, entries, components, etc.

Any processor may obtain the context within which it is being executed via its getContext() method. This method returns the context within which a particular processor is being run, and does not represent the current node. For example, a SectionProcessor processing a section at the document level would have a getContext() value of DocumentProcessorContext (i.e. the document is the context not the section). Same applies to entries where the getContext() method would return the section which contains the entry.

Completed Document Processors

  • AntepartumHistoryAndPhysicalDocumentProcessor
  • MedcalDocumentsDocumentProcessor
  • MedicalSummariesDocumentProcessor
  • HistoryAndPhysicalDocumentProcessor
  • GenericDocumentProcessor

Completed Section Processors

  • ChiefComplaintSectionProcessor
  • ActiveProblemsSectionProcessor
  • AssessmentAndPlanSectionProcessor
  • CodedHistoryOfInfectionSectionProcessor
  • HistoryOfSurgicalProceduresSectionProcessor
  • PregnancyHistorySectionProcessor
  • DetailedPhysicalExaminationSectionProcessor (Coded and non-coded)
  • AllergiesAndOtherAdverseReactionsSectionProcessor
  • FamilyHistorySectionProcessor (Coded and non-coded)
  • SocialHistorySectionProcessor (Coded and non-coded)
  • ReviewOfSystemsSectionProcessor
  • VitalSignsSectionProcessor (Coded and non-coded)
  • HistoryOfPresentIllnessSectionProcessor
  • HistoryOfPastIllnessSectionProcessor
  • PhysicalExaminationSubSectionProcessor (handles all physical exam sub-sections)

Completed Entry Processors

  • VitalSignsObservationEntryProcessor
  • SimpleObservationEntryProcessor
  • FamilyHistoryOrganizerEntryProcessor
  • ConcernEntryProcessor
  • AllergiesAndIntolerancesConcernEntryProcessor
  • SeverityObservationEntryProcessor
  • AllergiesAndIntolerancesEntryProcessor
  • ProblemConcernEntryProcessor
  • FamilyHistoryObservationEntryProcessor
  • VitalSignsOrganizerEntryProcessor
  • PregnancyObservationEntryProcessor
  • PregnancyHistoryOrganizerEntryProcessor

Concept Dictionary

The OpenMRS concept dictionary is used extensively by this module. Each concept that requires association to an observation, allergy, problem, etc. is selected from a reference term within the code and concept source represented by the code/codeSystem attributes of a code in the CDA respectively. Once an appropriate reference term is found the concepts that are mapped to that term are searched based on suitability to store the CDA data. The type of concept used in OpenMRS’ concept dictionary and its mapping to the CDA datatype to be stored is shown below:

  • BL -> Boolean
  • CS/CV/CE/CD -> Coded
  • INT -> Numeric
  • PQ -> Numeric (units are also checked)
  • ST -> Text
  • ED / SD -> Complex
  • TS -> DateTime

If none of concept source, reference term, or concept are found then it is created and mapped accordingly. Where possible built in OpenMRS concepts are used. Additionally, whenever a Numeric concept is found to represent a PQ where the units do not match, the module will check to see if the units are convertible. For example, if an openMRS concept for Height is found however the PQ in the CDA is represented in m instead of cm the unit is converted to cm before storage.

Because CDA uses a variety of codes from SNOMED, LOINC and others, there is a need to bulk-import concepts and their mapping to MVP/CIEL upon module install. This is done via the ReferenceTermDictionary.xml file in the resources folder. Upon build, this XML file is transformed to a liquibase.xml file and placed in the omod file. This file contains mapping to CIEL concepts where appropriate and allows the module to use those mappings in an easy to maintain XML File (editable within Microsoft Excel as a table)

Known Issues / Todo

  1. Currently missing Medications and Coded Results section handlers for the APHP document import
  2. Currently there is some header elements which cannot be mapped appropriately into OpenMRS
  3. Updating of current observations that are identified doesn’t work as I want it to, the module stores the observation id in the accession number field and this is used to determine if an observation was previously recorded. The expected behavior is that the old version is voided, and the new version stored with a pointer to the voided version. The current module does this, however it has to get all obs for the patient and then then scan for accession numbers, a method to get Obs by accessionNumber is implemented but not in the released version.
  4. Family History observations are kind of hacked as the oMRS mechanism for storing these are similar to CDA but not identical.
  5. Performance is poor, it appears to be in the code that double checks if a concept name already exists prior to creating it, I’m not sure if this is a problem with the standalone instance of oMRS that I’m testing with or if it is an issue with the logic.
  6. For some reasons transactions aren’t working with the code, again not sure if this is a problem with oMRS instance I’m using. I am following the transaction guidance from the oMRS dev wiki.
  7. All observations are created within the oMRS database and are seen in the Observation management admin panel, however the encounter summary panel does not show grouped obs in the UI.
  • No labels