MDHT Notes

Russell Bateman
November 2019

Table of contents

Introduction
Quick-start (recognition)
Quick-start (generation)
Validation
Shallow-copying objects
Deep-copying objects
Appendix: Library JARs, pom.xml and Maven
Appendix: Tricks—quick display

Introduction

Model-driven Health Tools (MDHT) constitute a Java-based set of libraries by which it is possible to generate Clinical Document Architecture (CDA) documents of most every sort. I have written copious amounts of code that take intermediate XML statements to guide calls into this library, then generate documents that pass various standard validators. The library works well, but is occasionally very complicated in its interfaces.

Website: https://github.com/mdht/mdht.

Related links:


Quick-start (recognition)

Also called "analysis." This is using the MDHT library API to read (ingest) a CDA (CCD, etc.) into a ClinicalDocument so that the resulting document-object model (DOM) is at your fingertips for whatever purpose you might have. For example, the MDHT library validation component uses this. If you're analyzing a CCD, Care Plan, QRDA I or III, etc., you can get this help too.

package com.windofkeltia.mdht;

import java.io.ByteArrayInputStream;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;

import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.mdht.uml.cda.ClinicalDocument;
import org.eclipse.mdht.uml.cda.Section;
import org.eclipse.mdht.uml.cda.util.CDAUtil;
import org.eclipse.mdht.uml.hl7.datatypes.ST;

import com.windofkeltia.utilities.TestUtilities;

public class MdhtAsParserTest
{
  @Rule   public TestName name = new TestName();
  @After  public void tearDown() { }
  @Before public void setUp()    { TestUtilities.setUp( name ); }

  private static final boolean VERBOSE = TestUtilities.VERBOSE;

  @Test
  public void test() throws Exception
  {
    final String PATHNAME = TestUtilities.TEST_FODDER + "sample-1.ccd";
    final String CONTENT  = TestUtilities.getLinesInFile( PATHNAME );

    ByteArrayInputStream inputStream = new ByteArrayInputStream( CONTENT.getBytes() );
    ClinicalDocument     document    = CDAUtil.load( inputStream );
    boolean              once        = false;

    for( Section section : document.getSections() )
    {
      int        entries                              = section.getEntries().size();
      ST         title                                = section.getTitle();
      FeatureMap featureMap                           = title.getMixed();
      FeatureMap.ValueListIterator< Object > iterator = featureMap.valueListIterator();

      if( !once )
      {
        System.out.println( "Sections found in " + PATHNAME + ":" );
        once = true;
      }

      while( iterator.hasNext() )
      {
        Object object = iterator.next();

        if( VERBOSE )
          System.out.println( "  " + entries + " " + object.toString() );
      }
    }
  }
}

sample-1.ccd is such that the output from the code above is:

Sections found in src/test/resources/fodder/sample-1.ccd:
  1 Encounters
  2 Social History
  1 Procedures
  1 Vital Signs
  1 Results
  1 Allergies, Adverse Reactions, Alerts
  1 Payers
  2 Problems
  2 Medications

Quick-start (generation)

Here's the general lay of the land in MDHT. You do something by making calls into MDHT. When you get the library JARS, you'll find examples of this in sample source code. You set up the general framework around this; see method getOutput().

package com.windofkeltia.mdht;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;

import static org.junit.Assert.assertTrue;

import org.junit.After;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runners.MethodSorters;

import org.eclipse.mdht.uml.cda.Act;
import org.eclipse.mdht.uml.cda.CDAFactory;
import org.eclipse.mdht.uml.cda.EntryRelationship;
import org.eclipse.mdht.uml.cda.Observation;
import org.eclipse.mdht.uml.cda.Section;
import org.eclipse.mdht.uml.cda.util.CDAUtil;

import org.eclipse.mdht.uml.hl7.vocab.ActClassObservation;
import org.eclipse.mdht.uml.hl7.vocab.x_ActMoodDocumentObservation;
import org.eclipse.mdht.uml.hl7.vocab.x_ActRelationshipEntryRelationship;
import org.openhealthtools.mdht.uml.cda.consol.ConsolFactory;
import org.openhealthtools.mdht.uml.cda.consol.ContinuityOfCareDocument2;

import com.windofkeltia.utilities.TestUtilities;

@FixMethodOrder( MethodSorters.JVM )
public class ShowOffMdhtTest
{
  @Rule   public TestName name = new TestName();
  @After  public void tearDown() { }
  @Before public void setUp()    { TestUtilities.setUp( name ); }

  private static final String[] TEST_EXPECTED = new String[]
  {
    // this is the output you'll see in the println()
    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
    "<ClinicalDocument xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"urn:hl7-org:v3\" xsi:schemaLocation=\"urn:hl7-org:v3 infrastructure/cda/CDA_SDTC.xsd\">",
    "  <realmCode code=\"US\"/>",
    "  <templateId root=\"2.16.840.1.113883.10.20.22.1.2\" extension=\"2015-08-01\"/>",
    "  <templateId root=\"2.16.840.1.113883.10.20.22.1.1\"/>",
    "  <templateId root=\"2.16.840.1.113883.10.20.22.1.1\" extension=\"2015-08-01\"/>",
    "  <code code=\"34133-9\" codeSystem=\"2.16.840.1.113883.6.1\" codeSystemName=\"LOINC\" displayName=\"Summarization of Episode Note\"/>",
    "  <confidentialityCode codeSystem=\"2.16.840.1.113883.5.25\" codeSystemName=\"ConfidentialityCode\"/>",
    "  <component>",
    "    <structuredBody>",
    "      <component>",
    "        <section>",
    "          <entry>",
    "            <observation classCode=\"OBS\" moodCode=\"EVN\"/>",
    "          </entry>",
    "        </section>",
    "      </component>",
    "    </structuredBody>",
    "  </component>",
    "</ClinicalDocument>"
  };

  @Test
  public void test() throws Exception
  {
    Observation observation = CDAFactory.eINSTANCE.createObservation();
    observation.setClassCode( ActClassObservation.OBS );
    observation.setMoodCode( x_ActMoodDocumentObservation.EVN );

    final String OUTPUT = getOutput( observation );

    System.out.print( OUTPUT );

    for( String expected : EXPECTED )
      assertTrue( OUTPUT.contains( expected ) );
  }

  private static String getOutput( Observation observation ) throws Exception
  {
    ContinuityOfCareDocument2 document = ConsolFactory.eINSTANCE.createContinuityOfCareDocument2().init();
    Section section = CDAFactory.eINSTANCE.createSection();
    section.addObservation( observation );
    document.addSection( section );
    OutputStream outputStream = new ByteArrayOutputStream();
    CDAUtil.save( document, outputStream );
    return outputStream.toString();
  }
}

Hidden wrappering (entryRelationship)...

On occasion, the method offered by Observation (or Organizer, probably by still other classes), addObservation(), will secretly wrap the new observation in an entry relationship. When it does this, there's no opportunity to control the latter's typeCode. You must reach in and perform surgery. Here's how.

Let's agree that we've just called something that creates an observation. We're adding a series of observations to a hierarchically superior observation we already have (or to an organizer, etc.) using addObservation( Observation newObservation ). We don't want it to come out in the output like this:

<entryRelationship>                                 <!-- what MDHT wraps you with -->
  <observation classCode="OBS" moodCode="EVN">     <!-- new observation you generated-->
    ...
    <entryRelationship inversionInd="true" typeCode="SUBJ">
      <observation classCode="OBS" moodCode="EVN">
        ...
      </observation>
    </entryRelationship>
    <reference typeCode="REF">
      <externalObservation ...>
        ...
      </externaObservation>
    </reference>
  </observation>
</entryRelationship>

Instead, you want this:

<entryRelationship typeCode="SUBJ">
  <observation classCode="OBS" moodCode="EVN">     <!-- new observation you generated-->
    etc. as above...
  </observation>
</entryRelationship>

The magic happens in the highlighted line. It cannot happen until the call to addObservation() has already been made. This is because the eContainer() method has nothing to report until after the wrapping has occurred. The wrapping occurs a couple of methods deep below addObservation().

Observation newObservation = createNewObservationToAdd(); // say an Encounter, Problem, etc.
observation.addObservation( newObservation );             // add the o
EntryRelationship entryRelationship = ( EntryRelationship ) newObservation.eContainer();
entryRelationship.setTypeCode( x_ActRelationshipEntryRelationship.SUBJ );

Example

Two examples contrasting—add this code to ShowOffMdhtTest above.

Also, we vet the output to ensure this is the case. The lines of code demanding our attention are highlighted.

  private static final String[] TEST2_EXPECTED = new String[]
  {
    // this is the output you'll see in the println()
    "  ",
    "    ",
    "      ",
    "        
", " ", " ", " ", " ", " ", " ", " ", "
", "
", "
", "
" }; @Test public void test2() throws Exception { Act act = CDAFactory.eINSTANCE.createAct(); Observation observation = CDAFactory.eINSTANCE.createObservation(); observation.setClassCode( ActClassObservation.OBS ); observation.setMoodCode( x_ActMoodDocumentObservation.EVN ); act.addObservation( observation ); final String OUTPUT = getOutput( act ); System.out.println( OUTPUT ); for( String expected : TEST2_EXPECTED ) assertTrue( OUTPUT.contains( expected ) ); } private static final String[] TEST2BIS_EXPECTED = new String[] { // this is the output you'll see in the println() " ", " ", " ", "
", " ", " ", " ", " ", " ", " ", " ", "
", "
", "
", "
" }; @Test public void test2bis() throws Exception { Act act = CDAFactory.eINSTANCE.createAct(); EntryRelationship entryRelationship = CDAFactory.eINSTANCE.createEntryRelationship(); Observation observation = CDAFactory.eINSTANCE.createObservation(); observation.setClassCode( ActClassObservation.OBS ); observation.setMoodCode( x_ActMoodDocumentObservation.EVN ); entryRelationship.setTypeCode( x_ActRelationshipEntryRelationship.SUBJ ); entryRelationship.setObservation( observation ); act.getEntryRelationships().add( entryRelationship ); final String OUTPUT = getOutput( act ); System.out.println( OUTPUT ); for( String expected : TEST2BIS_EXPECTED ) assertTrue( OUTPUT.contains( expected ) ); } . . . private static String getOutput( Act act ) throws Exception { ContinuityOfCareDocument2 document = ConsolFactory.eINSTANCE.createContinuityOfCareDocument2().init(); Section section = CDAFactory.eINSTANCE.createSection(); section.addAct( act ); document.addSection( section ); OutputStream outputStream = new ByteArrayOutputStream(); CDAUtil.save( document, outputStream ); return outputStream.toString(); }

Shallow-copying of MDHT library objects

This is fraught with considerabl peril. For example, the following code will destroy document to the benefit of copy. By "destroy," I mean it will in effect "suck its guts out" and put them into copy.

import org.eclipse.mdht.uml.cda.CDAFactory;
import org.eclipse.mdht.uml.cda.ClinicalDocument;

public static ClinicalDocument makeShallowCopy( ClinicalDocument document )
{
  ClinicalDocument copy = CDAFactory.eINSTANCE.createClinicalDocument();

  copy.unsetClassCode();
  copy.unsetMoodCode();
  copy.unsetNullFlavor();

  copy.setTypeId( document.getTypeId() );
  copy.setId( document.getId() );
  copy.setCode( document.getCode() );
  copy.setTitle( document.getTitle() );
  copy.setEffectiveTime( document.getEffectiveTime() );
  copy.setConfidentialityCode( document.getConfidentialityCode() );
  copy.setLanguageCode( document.getLanguageCode() );
  copy.setId( document.getSetId() );
  copy.setVersionNumber( document.getVersionNumber() );
  copy.setClassCode( document.getClassCode() );
  copy.setMoodCode( document.getMoodCode() );
  copy.setNullFlavor( document.getNullFlavor() );
  copy.setDataEnterer( document.getDataEnterer() );
  copy.setCopyTime( document.getCopyTime() );
  copy.setCustodian( document.getCustodian() );
  copy.setLegalAuthenticator( document.getLegalAuthenticator() );

  copy.getRealmCodes().addAll( document.getRealmCodes() );
  copy.getTemplateIds().addAll( document.getTemplateIds() );
  copy.getRecordTargets().addAll( document.getRecordTargets() );

  copy.getAuthors().addAll( document.getAuthors() );
  copy.getAuthenticators().addAll( document.getAuthenticators() );
  copy.getAuthorizations().addAll( document.getAuthorizations() );
  copy.getInformants().addAll( document.getInformants() );
  copy.getInformationRecipients().addAll( document.getInformationRecipients() );
  copy.getDocumentationOfs().addAll( document.getDocumentationOfs() );
  copy.getParticipants().addAll( document.getParticipants() );
  copy.getInFulfillmentOfs().addAll( document.getInFulfillmentOfs() );
  copy.getRelatedDocuments().addAll( document.getRelatedDocuments() );

  return copy;
}

The only thing left in document after execution of the code above will be its top-level...

<component>
  <structuredBody>

    list of section components...

  </structuredBody>
</component>

Cloning (or deep-copying) of EObjects

All (or most?) objects in the MDHT library inherit from base class Eobject (for ecore, it's an Eclipse thing).

It's easy to copy high-level or lower-level (subordinate) objects thus:

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.mdht.uml.cda.ClinicalDocument;

public static ClinicalDocument makeDeepCopy( ClinicalDocument document )
{
  EcoreUtil.Copier copier = new EcoreUtil.Copier();
  EObject          copy   = copier.copy( document );
  copier.copyReferences();
  return ( ClinicalDocument ) copy;
}

Once this is done, you can do anything you want to the copy with no repercussions for the original. If the original disappears from activation, the copy is still intact. This is "deep-copying" by any standard, I think.

See ValidationClass EcoreUtil.Copier (EMF Javadoc for more information.

Appendix: Validation

Note that validation requires a call to CDAUtil.loadPackages(), but ordinary use of MDHT library APIs (to generate a CCD) doesn't involve it.


Appendix: Library JARs, pom.xml and Maven

pom.xml additions:
  <properties>
    <!-- MDHT, Eclipse and other MDHT-relevant versions: -->
    <eclipse-emf.version>2.12.0.v20160420-0247</eclipse-emf.version>
    <eclipse-mdht.version>3.0.0.201802220601</eclipse-mdht.version>
    <openhealthtools.version>3.0.3.20180222</openhealthtools.version>
  </properties>

  <repositories>
    <repository>
      <id>maven-releases</id>
      <name>internal-libraries</name>
      <url>file://${project.basedir}/lib</url>
    </repository>
  </repositories>

  <dependency>
    <groupId>lpg.runtime.java</groupId>
    <artifactId>lpg.runtime.java</artifactId>
    <version>2.0.17.v201004271640</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.emf.ecore.xmi</groupId>
    <artifactId>org.eclipse.emf.ecore.xmi</artifactId>
    <version>${eclipse-emf.version}</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.emf.ecore</groupId>
    <artifactId>org.eclipse.emf.ecore</artifactId>
    <version>${eclipse-emf.version}</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.emf.common</groupId>
    <artifactId>org.eclipse.emf.common</artifactId>
    <version>${eclipse-emf.version}</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.ocl</groupId>
    <artifactId>org.eclipse.ocl</artifactId>
    <version>3.6.0.v20160523-1914</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.ocl.common</groupId>
    <artifactId>org.eclipse.ocl.common</artifactId>
    <version>1.4.0.v20160521-2033</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.ocl.ecore</groupId>
    <artifactId>org.eclipse.ocl.ecore</artifactId>
    <version>3.6.0.v20160523-1914</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.uml2.common</groupId>
    <artifactId>org.eclipse.uml2.common</artifactId>
    <version>2.1.0.v20170227-0935</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.uml2.types</groupId>
    <artifactId>org.eclipse.uml2.types</artifactId>
    <version>2.0.0.v20170227-0935</version>
  </dependency>
  <!-- MDHT Core dependencies -->
  <dependency>
    <groupId>org.eclipse.mdht.emf.runtime</groupId>
    <artifactId>org.eclipse.mdht.emf.runtime</artifactId>
    <version>${eclipse-mdht.version}</version>
  </dependency>
  <!-- MDHT CDA dependencies -->
  <dependency>
    <groupId>org.eclipse.mdht.uml.hl7.vocab</groupId>
    <artifactId>org.eclipse.mdht.uml.hl7.vocab</artifactId>
    <version>${eclipse-mdht.version}</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.mdht.uml.hl7.datatypes</groupId>
    <artifactId>org.eclipse.mdht.uml.hl7.datatypes</artifactId>
    <version>${eclipse-mdht.version}</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.mdht.uml.hl7.rim</groupId>
    <artifactId>org.eclipse.mdht.uml.hl7.rim</artifactId>
    <version>${eclipse-mdht.version}</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.mdht.uml.cda</groupId>
    <artifactId>org.eclipse.mdht.uml.cda</artifactId>
    <version>${eclipse-mdht.version}</version>
  </dependency>
  <!-- MDHT CDA Implementation Guide dependencies -->
  <dependency>
    <groupId>org.openhealthtools.mdht.uml.cda.consol2</groupId>
    <artifactId>org.openhealthtools.mdht.uml.cda.consol2</artifactId>
    <version>${openhealthtools.version}</version>
  </dependency>
  <!-- HL7 CDA dependencies -->
  <dependency>
    <groupId>org.hl7.cbcc.privacy.consentdirective</groupId>
    <artifactId>org.hl7.cbcc.privacy.consentdirective</artifactId>
    <version>1.0.0.20170920</version>
  </dependency>
  <dependency>
    <groupId>org.hl7.security.ds4p.contentprofile</groupId>
    <artifactId>org.hl7.security.ds4p.contentprofile</artifactId>
    <version>3.0.0.20170920</version>
  </dependency>

(For help dealing with using static copies of JARs out of a local subdirectory as is shown here, please read this note and others following for ways to do that. Please note that the .jar files are obtained from the web, Sean Muir, etc. while all other files, including .jar.md5, etc. are generated by the commands noted at this URL.) Below is an illustration of these static copies of JARs pieced together in such a way as to permit their direct use from Maven pom.xml.

The JAR list. There is no way to reach current versions of these via Maven. You can only include them statically in your (IntelliJ IDEA or Eclipse) project.

russ@nargothrond ~/sandboxes/mdht-sample $ tree lib
lib
├── lpg
│   └──runtime
│       └──java
│           └── lpg.runtime.java
│               ├── 2.0.17.v201004271640
│               │   ├── lpg.runtime.java-2.0.17.v201004271640.jar
│               │   ├── lpg.runtime.java-2.0.17.v201004271640.jar.md5
│               │   ├── lpg.runtime.java-2.0.17.v201004271640.jar.sha1
│               │   ├── lpg.runtime.java-2.0.17.v201004271640.pom
│               │   ├── lpg.runtime.java-2.0.17.v201004271640.pom.md5
│               │   └──lpg.runtime.java-2.0.17.v201004271640.pom.sha1
│               ├── maven-metadata-local.xml
│               ├── maven-metadata-local.xml.md5
│               └── maven-metadata-local.xml.sha1
└── org
    ├── eclipse
    │   ├── emf
    │   │   ├── common
    │   │   │   └── org.eclipse.emf.common
    │   │   │       ├── 2.12.0.v20160420-0247
    │   │   │       │   ├── org.eclipse.emf.common-2.12.0.v20160420-0247.jar
    │   │   │       │   ├── org.eclipse.emf.common-2.12.0.v20160420-0247.jar.md5
    │   │   │       │   ├── org.eclipse.emf.common-2.12.0.v20160420-0247.jar.sha1
    │   │   │       │   ├── org.eclipse.emf.common-2.12.0.v20160420-0247.pom
    │   │   │       │   ├── org.eclipse.emf.common-2.12.0.v20160420-0247.pom.md5
    │   │   │       │   └── org.eclipse.emf.common-2.12.0.v20160420-0247.pom.sha1
    │   │   │       ├── maven-metadata-local.xml
    │   │   │       ├── maven-metadata-local.xml.md5
    │   │   │       └── maven-metadata-local.xml.sha1
    │   │   └── ecore
    │   │       ├── org.eclipse.emf.ecore
    │   │       │   ├── 2.12.0.v20160420-0247
    │   │       │   │   ├── org.eclipse.emf.ecore-2.12.0.v20160420-0247.jar
    │   │       │   │   ├── org.eclipse.emf.ecore-2.12.0.v20160420-0247.jar.md5
    │   │       │   │   ├── org.eclipse.emf.ecore-2.12.0.v20160420-0247.jar.sha1
    │   │       │   │   ├── org.eclipse.emf.ecore-2.12.0.v20160420-0247.pom
    │   │       │   │   ├── org.eclipse.emf.ecore-2.12.0.v20160420-0247.pom.md5
    │   │       │   │   └── org.eclipse.emf.ecore-2.12.0.v20160420-0247.pom.sha1
    │   │       │   ├── maven-metadata-local.xml
    │   │       │   ├── maven-metadata-local.xml.md5
    │   │       │   └── maven-metadata-local.xml.sha1
    │   │       └── xmi
    │   │           └── org.eclipse.emf.ecore.xmi
    │   │               ├── 2.12.0.v20160420-0247
    │   │               │   ├── org.eclipse.emf.ecore.xmi-2.12.0.v20160420-0247.jar
    │   │               │   ├── org.eclipse.emf.ecore.xmi-2.12.0.v20160420-0247.jar.md5
    │   │               │   ├── org.eclipse.emf.ecore.xmi-2.12.0.v20160420-0247.jar.sha1
    │   │               │   ├── org.eclipse.emf.ecore.xmi-2.12.0.v20160420-0247.pom
    │   │               │   ├── org.eclipse.emf.ecore.xmi-2.12.0.v20160420-0247.pom.md5
    │   │               │   └── org.eclipse.emf.ecore.xmi-2.12.0.v20160420-0247.pom.sha1
    │   │               ├── maven-metadata-local.xml
    │   │               ├── maven-metadata-local.xml.md5
    │   │               └── maven-metadata-local.xml.sha1
    │   ├── mdht
    │   │   ├── emf
    │   │   │   └── runtime
    │   │   │       └── org.eclipse.mdht.emf.runtime
    │   │   │           ├── 3.0.0.201802220601
    │   │   │           │   ├── org.eclipse.mdht.emf.runtime-3.0.0.201802220601.jar
    │   │   │           │   ├── org.eclipse.mdht.emf.runtime-3.0.0.201802220601.jar.md5
    │   │   │           │   ├── org.eclipse.mdht.emf.runtime-3.0.0.201802220601.jar.sha1
    │   │   │           │   ├── org.eclipse.mdht.emf.runtime-3.0.0.201802220601.pom
    │   │   │           │   ├── org.eclipse.mdht.emf.runtime-3.0.0.201802220601.pom.md5
    │   │   │           │   └── org.eclipse.mdht.emf.runtime-3.0.0.201802220601.pom.sha1
    │   │   │           ├── maven-metadata-local.xml
    │   │   │           ├── maven-metadata-local.xml.md5
    │   │   │           └── maven-metadata-local.xml.sha1
    │   │   └── uml
    │   │       ├── cda
    │   │       │   └── org.eclipse.mdht.uml.cda
    │   │       │       ├── 3.0.0.201802220601
    │   │       │       │   ├── org.eclipse.mdht.uml.cda-3.0.0.201802220601.jar
    │   │       │       │   ├── org.eclipse.mdht.uml.cda-3.0.0.201802220601.jar.md5
    │   │       │       │   ├── org.eclipse.mdht.uml.cda-3.0.0.201802220601.jar.sha1
    │   │       │       │   ├── org.eclipse.mdht.uml.cda-3.0.0.201802220601.pom
    │   │       │       │   ├── org.eclipse.mdht.uml.cda-3.0.0.201802220601.pom.md5
    │   │       │       │   └── org.eclipse.mdht.uml.cda-3.0.0.201802220601.pom.sha1
    │   │       │       ├── maven-metadata-local.xml
    │   │       │       ├── maven-metadata-local.xml.md5
    │   │       │       └── maven-metadata-local.xml.sha1
    │   │       └── hl7
    │   │           ├── datatypes
    │   │           │   └── org.eclipse.mdht.uml.hl7.datatypes
    │   │           │       ├── 3.0.0.201802220601
    │   │           │       │   ├── org.eclipse.mdht.uml.hl7.datatypes-3.0.0.201802220601.jar
    │   │           │       │   ├── org.eclipse.mdht.uml.hl7.datatypes-3.0.0.201802220601.jar.md5
    │   │           │       │   ├── org.eclipse.mdht.uml.hl7.datatypes-3.0.0.201802220601.jar.sha1
    │   │           │       │   ├── org.eclipse.mdht.uml.hl7.datatypes-3.0.0.201802220601.pom
    │   │           │       │   ├── org.eclipse.mdht.uml.hl7.datatypes-3.0.0.201802220601.pom.md5
    │   │           │       │   └── org.eclipse.mdht.uml.hl7.datatypes-3.0.0.201802220601.pom.sha1
    │   │           │       ├── maven-metadata-local.xml
    │   │           │       ├── maven-metadata-local.xml.md5
    │   │           │       └── maven-metadata-local.xml.sha1
    │   │           ├── rim
    │   │           │   └── org.eclipse.mdht.uml.hl7.rim
    │   │           │       ├── 3.0.0.201802220601
    │   │           │       │   ├── org.eclipse.mdht.uml.hl7.rim-3.0.0.201802220601.jar
    │   │           │       │   ├── org.eclipse.mdht.uml.hl7.rim-3.0.0.201802220601.jar.md5
    │   │           │       │   ├── org.eclipse.mdht.uml.hl7.rim-3.0.0.201802220601.jar.sha1
    │   │           │       │   ├── org.eclipse.mdht.uml.hl7.rim-3.0.0.201802220601.pom
    │   │           │       │   ├── org.eclipse.mdht.uml.hl7.rim-3.0.0.201802220601.pom.md5
    │   │           │       │   └── org.eclipse.mdht.uml.hl7.rim-3.0.0.201802220601.pom.sha1
    │   │           │       ├── maven-metadata-local.xml
    │   │           │       ├── maven-metadata-local.xml.md5
    │   │           │       └── maven-metadata-local.xml.sha1
    │   │           └── vocab
    │   │               └── org.eclipse.mdht.uml.hl7.vocab
    │   │                   ├── 3.0.0.201802220601
    │   │                   │   ├── org.eclipse.mdht.uml.hl7.vocab-3.0.0.201802220601.jar
    │   │                   │   ├── org.eclipse.mdht.uml.hl7.vocab-3.0.0.201802220601.jar.md5
    │   │                   │   ├── org.eclipse.mdht.uml.hl7.vocab-3.0.0.201802220601.jar.sha1
    │   │                   │   ├── org.eclipse.mdht.uml.hl7.vocab-3.0.0.201802220601.pom
    │   │                   │   ├── org.eclipse.mdht.uml.hl7.vocab-3.0.0.201802220601.pom.md5
    │   │                   │   └── org.eclipse.mdht.uml.hl7.vocab-3.0.0.201802220601.pom.sha1
    │   │                   ├── maven-metadata-local.xml
    │   │                   ├── maven-metadata-local.xml.md5
    │   │                   └── maven-metadata-local.xml.sha1
    │   ├── ocl
    │   │   ├── common
    │   │   │   └── org.eclipse.ocl.common
    │   │   │       ├── 1.4.0.v20160521-2033
    │   │   │       │   ├── org.eclipse.ocl.common-1.4.0.v20160521-2033.jar
    │   │   │       │   ├── org.eclipse.ocl.common-1.4.0.v20160521-2033.jar.md5
    │   │   │       │   ├── org.eclipse.ocl.common-1.4.0.v20160521-2033.jar.sha1
    │   │   │       │   ├── org.eclipse.ocl.common-1.4.0.v20160521-2033.pom
    │   │   │       │   ├── org.eclipse.ocl.common-1.4.0.v20160521-2033.pom.md5
    │   │   │       │   └── org.eclipse.ocl.common-1.4.0.v20160521-2033.pom.sha1
    │   │   │       ├── maven-metadata-local.xml
    │   │   │       ├── maven-metadata-local.xml.md5
    │   │   │       └── maven-metadata-local.xml.sha1
    │   │   ├── ecore
    │   │   │   └── org.eclipse.ocl.ecore
    │   │   │       ├── 3.6.0.v20160523-1914
    │   │   │       │   ├── org.eclipse.ocl.ecore-3.6.0.v20160523-1914.jar
    │   │   │       │   ├── org.eclipse.ocl.ecore-3.6.0.v20160523-1914.jar.md5
    │   │   │       │   ├── org.eclipse.ocl.ecore-3.6.0.v20160523-1914.jar.sha1
    │   │   │       │   ├── org.eclipse.ocl.ecore-3.6.0.v20160523-1914.pom
    │   │   │       │   ├── org.eclipse.ocl.ecore-3.6.0.v20160523-1914.pom.md5
    │   │   │       │   └── org.eclipse.ocl.ecore-3.6.0.v20160523-1914.pom.sha1
    │   │   │       ├── maven-metadata-local.xml
    │   │   │       ├── maven-metadata-local.xml.md5
    │   │   │       └── maven-metadata-local.xml.sha1
    │   │   └── org.eclipse.ocl
    │   │       ├── 3.6.0.v20160523-1914
    │   │       │   ├── org.eclipse.ocl-3.6.0.v20160523-1914.jar
    │   │       │   ├── org.eclipse.ocl-3.6.0.v20160523-1914.jar.md5
    │   │       │   ├── org.eclipse.ocl-3.6.0.v20160523-1914.jar.sha1
    │   │       │   ├── org.eclipse.ocl-3.6.0.v20160523-1914.pom
    │   │       │   ├── org.eclipse.ocl-3.6.0.v20160523-1914.pom.md5
    │   │       │   └── org.eclipse.ocl-3.6.0.v20160523-1914.pom.sha1
    │   │       ├── maven-metadata-local.xml
    │   │       ├── maven-metadata-local.xml.md5
    │   │       └── maven-metadata-local.xml.sha1
    │   └── uml2
    │       ├── common
    │       │   └── org.eclipse.uml2.common
    │       │       ├── 2.1.0.v20170227-0935
    │       │       │   ├── org.eclipse.uml2.common-2.1.0.v20170227-0935.jar
    │       │       │   ├── org.eclipse.uml2.common-2.1.0.v20170227-0935.jar.md5
    │       │       │   ├── org.eclipse.uml2.common-2.1.0.v20170227-0935.jar.sha1
    │       │       │   ├── org.eclipse.uml2.common-2.1.0.v20170227-0935.pom
    │       │       │   ├── org.eclipse.uml2.common-2.1.0.v20170227-0935.pom.md5
    │       │       │   └── org.eclipse.uml2.common-2.1.0.v20170227-0935.pom.sha1
    │       │       ├── maven-metadata-local.xml
    │       │       ├── maven-metadata-local.xml.md5
    │       │       └── maven-metadata-local.xml.sha1
    │       └── types
    │           └── org.eclipse.uml2.types
    │               ├── 2.0.0.v20170227-0935
    │               │   ├── org.eclipse.uml2.types-2.0.0.v20170227-0935.jar
    │               │   ├── org.eclipse.uml2.types-2.0.0.v20170227-0935.jar.md5
    │               │   ├── org.eclipse.uml2.types-2.0.0.v20170227-0935.jar.sha1
    │               │   ├── org.eclipse.uml2.types-2.0.0.v20170227-0935.pom
    │               │   ├── org.eclipse.uml2.types-2.0.0.v20170227-0935.pom.md5
    │               │   └── org.eclipse.uml2.types-2.0.0.v20170227-0935.pom.sha1
    │               ├── maven-metadata-local.xml
    │               ├── maven-metadata-local.xml.md5
    │               └── maven-metadata-local.xml.sha1
    ├── hl7
    │   ├── cbcc
    │   │   └── privacy
    │   │       └── consentdirective
    │   │           └── org.hl7.cbcc.privacy.consentdirective
    │   │               ├── 1.0.0.20170920
    │   │               │   ├── org.hl7.cbcc.privacy.consentdirective-1.0.0.20170920.jar
    │   │               │   ├── org.hl7.cbcc.privacy.consentdirective-1.0.0.20170920.jar.md5
    │   │               │   ├── org.hl7.cbcc.privacy.consentdirective-1.0.0.20170920.jar.sha1
    │   │               │   ├── org.hl7.cbcc.privacy.consentdirective-1.0.0.20170920.pom
    │   │               │   ├── org.hl7.cbcc.privacy.consentdirective-1.0.0.20170920.pom.md5
    │   │               │   └── org.hl7.cbcc.privacy.consentdirective-1.0.0.20170920.pom.sha1
    │   │               ├── maven-metadata-local.xml
    │   │               ├── maven-metadata-local.xml.md5
    │   │               └── maven-metadata-local.xml.sha1
    │   └── security
    │       └── ds4p
    │           └── contentprofile
    │               └── org.hl7.security.ds4p.contentprofile
    │                   ├── 3.0.0.20170920
    │                   │   ├── org.hl7.security.ds4p.contentprofile-3.0.0.20170920.jar
    │                   │   ├── org.hl7.security.ds4p.contentprofile-3.0.0.20170920.jar.md5
    │                   │   ├── org.hl7.security.ds4p.contentprofile-3.0.0.20170920.jar.sha1
    │                   │   ├── org.hl7.security.ds4p.contentprofile-3.0.0.20170920.pom
    │                   │   ├── org.hl7.security.ds4p.contentprofile-3.0.0.20170920.pom.md5
    │                   │   └── org.hl7.security.ds4p.contentprofile-3.0.0.20170920.pom.sha1
    │                   ├── maven-metadata-local.xml
    │                   ├── maven-metadata-local.xml.md5
    │                   └── maven-metadata-local.xml.sha1
    └── openhealthtools
        └── mdht
            └── uml
                └── cda
                    ├── consol2
                    │   └── org.openhealthtools.mdht.uml.cda.consol2
                    │       ├── 3.0.3.20180222
                    │       │   ├── org.openhealthtools.mdht.uml.cda.consol2-3.0.3.20180222.jar
                    │       │   ├── org.openhealthtools.mdht.uml.cda.consol2-3.0.3.20180222.jar.md5
                    │       │   ├── org.openhealthtools.mdht.uml.cda.consol2-3.0.3.20180222.jar.sha1
                    │       │   ├── org.openhealthtools.mdht.uml.cda.consol2-3.0.3.20180222.pom
                    │       │   ├── org.openhealthtools.mdht.uml.cda.consol2-3.0.3.20180222.pom.md5
                    │       │   └── org.openhealthtools.mdht.uml.cda.consol2-3.0.3.20180222.pom.sha1
                    │       ├── maven-metadata-local.xml
                    │       ├── maven-metadata-local.xml.md5
                    │       └── maven-metadata-local.xml.sha1
                    └── mu2consol
                        └── org.openhealthtools.mdht.uml.cda.mu2consol
                            ├── 3.0.3.20180222
                            │   ├── org.openhealthtools.mdht.uml.cda.mu2consol-3.0.3.20180222.jar
                            │   ├── org.openhealthtools.mdht.uml.cda.mu2consol-3.0.3.20180222.jar.md5
                            │   ├── org.openhealthtools.mdht.uml.cda.mu2consol-3.0.3.20180222.jar.sha1
                            │   ├── org.openhealthtools.mdht.uml.cda.mu2consol-3.0.3.20180222.pom
                            │   ├── org.openhealthtools.mdht.uml.cda.mu2consol-3.0.3.20180222.pom.md5
                            │   └── org.openhealthtools.mdht.uml.cda.mu2consol-3.0.3.20180222.pom.sha1
                            ├── maven-metadata-local.xml
                            ├── maven-metadata-local.xml.md5
                            └── maven-metadata-local.xml.sha1

73 directories, 162 files



Appendix: Tricks—quick display...

...of any construct whose effect you wish to see or experiment with. In this example, we're going to test the effect of setting an observation value in different ways.

( You may ask, "What's the point of this example?" The answer is that, sometimes, you have to experiment to make sure you know what you're going to get. In this case, there's a real problem with observation values. Practically speaking, it's a lot of work to generate decimal-less output in the CCD if you want that. [See highlighted output line after code sample.] You'll have to pick BigDecimal to do it. And you're advised by Sonar Rules not to do that. So what do you do? If it's a round number, use BigDecimal and use the safer Double if there's going to be a decimal? Or just use a floating-point value no matter what? )

The most useful aspect to this example is, in general, the use of

CDAUtil.saveSnippet( EObject, OutputStream )

to yield a snapshot of what you're going to see in the generated CCD (or QRDA I or Care Plan, etc.).

Pdq.java
package com.windofkeltia.mdht;

import java.math.BigDecimal;

import org.eclipse.mdht.uml.cda.CDAFactory;
import org.eclipse.mdht.uml.cda.Observation;
import org.eclipse.mdht.uml.cda.util.CDAUtil;
import org.eclipse.mdht.uml.hl7.datatypes.PQ;

public class MdhtValueTests
{

  @Test
  public void test() throws Exception
  {
    Observation observation = CDAFactory.eINSTANCE.createObservation();
    PQ          pq          = DatatypesFactory.eINSTANCE.createPQ();

    pq.setValue( Double.valueOf( 1 ) );
    observation.getValues().add( pq );

    PQ pq2 = DatatypesFactory.eINSTANCE.createPQ();

    pq2.setValue( Double.valueOf( 1.1 ) );
    observation.getValues().add( pq2 );

    pq2.setValue( BigDecimal.valueOf( 2 ) );
    observation.getValues().add( pq3 );

    PQ pq4 = DatatypesFactory.eINSTANCE.createPQ();

    pq2.setValue( BigDecimal.valueOf( 2.1 ) );
    observation.getValues().add( pq4 );

    CDAUtil.saveSnippet( observation, System.out );
  }
}

Note that the only acceptable input types for PQ.setTypeValue() are Double and BigDecimal:

Produces:

<observation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:hl7-org:v3">
  <value xsi:type="PQ" value="1.0"/>
  <value xsi:type="PQ" value="1.1"/>
  <value xsi:type="PQ" value="2"/>
  <value xsi:type="PQ" value="2.1"/>
</observation>

On the disquieting use of BigDecimal, see note: Sonar Rules: Java static code analysis.