Revision: Effective Date: 1 Author: 4/13/11 Allyson Weaver Bunker User Documentation for MDHT Runtime APIs User Guide User Documentation for MDHT Runtime APIs Document History Revision History Revision Number Revision Date 1 4/13/2011 2 4/15/2011 Summary of Changes Author Allyson Weaver Bunker Content Development/ Examples USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 2 of 18 Allyson Weaver Bunker User Documentation for MDHT Runtime APIs Table of Contents 1. Background ............................................................................................................... 4 2. Introduction – All About JARS ................................................................................... 5 2.1. Required JARS for Using APIs ........................................................................................................ 5 2.2. Instructions for Installation ............................................................................................................... 5 2.3. How to Export .................................................................................................................................. 5 2.4. MDHT Java Libraries Environment ................................................................................................. 5 2.5. APIs ................................................................................................................................................. 8 2.6. Patterns ........................................................................................................................................... 9 3. Using APIs .............................................................................................................. 10 3.1. Produce ......................................................................................................................................... 10 3.2. Consume ....................................................................................................................................... 15 3.3. Validate ........................................................................................... Error! Bookmark not defined. 3.4. Utility/Convenience ........................................................................................................................ 17 USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 3 of 18 User Documentation for MDHT Runtime APIs 1. Background An adapter for an EMR system essentially does one of the following: 1. Imports CDA documents into the EMR system and extracts information from the documents. 2. Extracts data from the EMR system to create a CDA document. USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 4 of 18 User Documentation for MDHT Runtime APIs 2. Introduction – setting up your environment 2.1. Required JARS for Using APIs 1. List of required JARS for Using APIs 2.2. Instructions for Installation 2.3. How to Export How to get the JARS out of the environment so that they can be used in an application. 2.4. MDHT Java Libraries Environment This describes the steps for creating the java libraries from the MDHT models and packaging them up with the set of EMF and OCL run-time dependency libraries that are needed to provide a basic runtime library for using MDHT artifacts. 1. Open the MDHT Workspace containing the models for which the run-time environment is needed. 2. Right-click on one of the projects and select "Export…" from the menu. 3. Expand the "Plug-in Development" folder USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 5 of 18 User Documentation for MDHT Runtime APIs 4. Select "Deployable plug-ins and fragments" and then click on "Next" 5. Select the projects that are to be exported as jar files… If doing all of the current ones then select the following: a. org.openhealthtools.mdht.uml.cda b. org.openhealthtools.mdht.uml.cda.ccd c. org.openhealthtools.mdht.uml.cda.cdt d. org.openhealthtools.mdht.uml.cda.consol e. org.openhealthtools.mdht.uml.cda.hitsp f. org.openhealthtools.mdht.uml.cda.ihe g. org.openhealthtools.mdht.uml.cda.datatypes h. org.openhealthtools.mdht.uml.cda.rim i. org.openhealthtools.mdht.uml.cda.vocab USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 6 of 18 User Documentation for MDHT Runtime APIs 6. Enter a directory for where to place the jar files on the "Destination" tab. 7. Click on "Finish" 8. This will create a jar file for each of the libraries in the location you specified. The current naming of the jar files will be <project-name>_<version>.<timestamp>.jar 9. Once the libraries are generated for the MDHT models, you will need some additional eclipse libraries in order to use these generated libraries. These libraries can be found in the eclipse environment. If you are using the all-in-one download, then these will be in the eclipse\plugins folder. The following is the list of libraries that are needed: a. lpg.runtime.java_2.0.17.v201004271640.jar (NOTE: for Eclipse 3.5.x the OCL parser runtime library may be net.sourceforge.lpg.lpgjavaruntime_1.1.0.v200803061910.jar) b. org.eclipse.emf.common_2.6.0.v20100914-1218.jar c. org.eclipse.emf.ecore_2.6.1.v20100914-1218.jar d. org.eclipse.emf.ecore.xmi_2.5.0.v20100521-1846.jar e. org.eclipse.ocl_3.0.1.R30x_v201008251030.jar f. org.eclipse.ocl.ecore_3.0.1.R30x_v201008251030.jar USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 7 of 18 User Documentation for MDHT Runtime APIs 2.5. APIs API’s delivered by the JARS can be divided into three different levels. Each level builds upon the other. API’s are an artifact that get generated or delivered by MDHT. You don’t need the user interface to be installed to be able to see the runtime API’s. HITSP C32, C83 APIs Higher Level IHE Patient Care Coordination (PCC) APIs Continuity of Care Document (CCD) APIs Base Level Base Model APIs (CDA, Datatypes, Vocab, RIM) Core Technology APIs (EMF, OCL) Java Platform APIs Low Level API Descriptions Low-level Technology APIs These APIs come from the technology decisions made by the MDHT project. MDHT is based on Eclipse and the Eclipse Modeling Framework. APIs at this level are related to the underlying EMF model and allow the programmer to manipulate EMF objects in a uniform way and access metamodel information (e.g. EClasses, EAnnotations, etc.). Typically, client code would not use the low-level APIs directly, however, there are certain circumstances where the EMF reflection API is useful. Generated CDA Base Model APIs The base model APIs are generated from the MDHT base models for CDA. This includes HL7 CDA R2, HL7 Datatypes R1, HL7 Vocabulary and HL7 RIM. MDHT uses class inheritance in the CDA template models. All methods defined at this level are inherited and available at higher levels. For example, a convenience method “addSection” has been added to the ClinicalDocument class. This method can be used to add a Section object directly to a ClinicalDocument object (without going through component.structuredBody.component). This method is available in all subclasses of ClinicalDocument (e.g. ContinuityOfCareDocument and HITSP PatientSummary). Generated CDA Template Model APIs This APIs, exist (logically) at a higher level in the stack as they are built on top of the APIs below them. They typically include domain-specific class names that follow the CDA templates that they represent (e.g. CCD ProblemAct, HITSP Condition). They also include “getter” methods to access subordinate templates. For example, if a document-level template has an association to a section-level template in the model, then a “getter’ method for the section-level template exists in the document-level template class. USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 8 of 18 User Documentation for MDHT Runtime APIs Utility / Convenience APIs There are additional Utility APIs that facilitate the process of producing, consuming and validating CDA documents. The CDAUtil class contains load/save/validate methods, a Query/Filter API, OCL check/query and a CDAXPath adapter API. The details of these APIs will be discussed later in the document. 2.6. Patterns Patterns used in the document are important to notice. There will be patterns that are dictated by the technology. This determines the way the generated code looks and how the API’s are used to produce, consume and validate CDA documents. Interface/Implementation Classes For every class defined in a CDA template UML model, there is a Java interface and Java implementation class generated. For example, the ContinuityOfCareDocument class becomes ContinuityOfCareDocument interface and ContinuityOfCareDocumentImpl class. Any client code that needs to use the ContinuityOfCareDocument will do so via the ContinuityOfCareDocument interface. Singleton Factory Class to Create Instances In order to create an instance of a class, client code must do so via a singleton factory class. Each CDA template model generates an EMF Package which corresponds to a set of generated Java packages. Each EMF Package also gets a singleton Factory class to create instances of classes in that package. ContinuityOfCareDocument ccdDocument = CCDFactory.eINSTANCE.createContinuityOfCareDocument().init(); ContinuityOfCareDocument // create an initialize an instance of This pattern applies to the generated base model APIs as well as the CDA template model APIs. In this example above, there is an additional method call to init(). This method is called to initialize the object where all default/fixed values get automatically populated. This reduces the amount of code necessary to create a conformant object. The init() method is only found in the generated CDA template model APIs EMF Package Registration for Deserialization In order to deserialize a CDA document into the appropriate template classes based on template identifiers in the template instance, EMF Package Registry needs to know what models exist in the environment. When using MDHT in standalone Java applications, the generated singleton Package class must but “touched” once at the beginning of the code: CCDPackage.eINSTANCE.eClass(); // static package registration In this example, we are telling the EMF Package registry that we have CCD (and all of it’s dependent) models available in the environment. If the deserializer encounters a template id from CCD, it will deserialize that part of the XML instance into the template class that corresponds to that template id. USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 9 of 18 User Documentation for MDHT Runtime APIs 3. Using APIs 3.1. Produce 1. Produce: GOAL Write/produce/construct a CDA document - Using the APIs to programmatically construct an instance. When someone needs to produce an instance they have clinical data and want to get it into CDA format. They will use Java APIs to programmatically construct a CDA in XML format. // create and initialize an instance of the ContinuityOfCareDocument class ContinuityOfCareDocument ccdDocument = CCDFactory.eINSTANCE.createContinuityOfCareDocument().init(); // create a patient role object and add it to the document PatientRole patientRole = CDAFactory.eINSTANCE.createPatientRole(); ccdDocument.addPatientRole(patientRole); II id = DatatypesFactory.eINSTANCE.createII(); patientRole.getIds().add(id); id.setRoot("996-756-495"); id.setExtension("2.16.840.1.113883.19.5"); // create an address object and add it to patient role AD addr = DatatypesFactory.eINSTANCE.createAD(); patientRole.getAddrs().add(addr); addr.getUses().add(PostalAddressUse.H); addr.addStreetAddressLine("1313 Mockingbird Lane"); addr.addCity("Janesville"); addr.addState("WI"); addr.addPostalCode("53545"); // create a patient object and add it to patient role Patient patient = CDAFactory.eINSTANCE.createPatient(); patientRole.setPatient(patient); PN name = DatatypesFactory.eINSTANCE.createPN(); patient.getNames().add(name); name.addGiven("Henry"); name.addFamily("Levin"); CE administrativeGenderCode = DatatypesFactory.eINSTANCE.createCE(); patient.setAdministrativeGenderCode(administrativeGenderCode); administrativeGenderCode.setCode("M"); administrativeGenderCode.setCodeSystem("2.16.840.1.113883.5.1"); TS birthTime = DatatypesFactory.eINSTANCE.createTS(); patient.setBirthTime(birthTime); birthTime.setValue("19320924"); USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 10 of 18 User Documentation for MDHT Runtime APIs [Discussion about creating document instance] // create and initialize the CCD alerts section AlertsSection alertsSection = CCDFactory.eINSTANCE.createAlertsSection().init(); ccdDocument.addSection(alertsSection); // set up the narrative (human-readable) text portion of the alerts section StringBuffer buffer = new StringBuffer(); buffer.append("<table border=\"1\" width=\"100%\">"); buffer.append("<thead>"); buffer.append("<tr>"); buffer.append("<th>Substance</th>"); buffer.append("<th>Reaction</th>"); buffer.append("<th>Status</th>"); buffer.append("</tr>"); buffer.append("</thead>"); buffer.append("<tbody>"); buffer.append("<tr>"); buffer.append("<td>Penicillin</td>"); buffer.append("<td>Hives</td>"); buffer.append("<td>Active</td>"); buffer.append("</tr>"); buffer.append("</tbody>"); buffer.append("</table>"); alertsSection.createStrucDocText(buffer.toString()); [Discussion about creating alerts section and narrative block] // create and initialize a CCD problem act ProblemAct problemAct = CCDFactory.eINSTANCE.createProblemAct().init(); alertsSection.addAct(problemAct); id = DatatypesFactory.eINSTANCE.createII(); problemAct.getIds().add(id); id.setRoot(UUID.randomUUID().toString()); [Discussion about creating problem act] // create and initialize an alert observation within the problem act AlertObservation alertObservation = CCDFactory.eINSTANCE.createAlertObservation().init(); problemAct.addObservation(alertObservation); ((EntryRelationship) alertObservation.eContainer()).setTypeCode(x_ActRelationshipEntryRelationship.SU BJ); id = DatatypesFactory.eINSTANCE.createII(); alertObservation.getIds().add(id); id.setRoot(UUID.randomUUID().toString()); USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 11 of 18 User Documentation for MDHT Runtime APIs CD code = DatatypesFactory.eINSTANCE.createCD(); alertObservation.setCode(code); code.setCode("ASSERTION"); code.setCodeSystem("2.16.840.1.113883.5.4"); CS statusCode = DatatypesFactory.eINSTANCE.createCS(); alertObservation.setStatusCode(statusCode); statusCode.setCode("completed"); CD value = DatatypesFactory.eINSTANCE.createCD(); alertObservation.getValues().add(value); value.setCode("282100009"); value.setCodeSystem("2.16.840.1.113883.6.96"); value.setDisplayName("Adverse reaction to substance"); [Discussion about creating alert observation] // playing entity contains coded information on the substance Participant2 participant = CDAFactory.eINSTANCE.createParticipant2(); alertObservation.getParticipants().add(participant); participant.setTypeCode(ParticipationType.CSM); ParticipantRole participantRole = CDAFactory.eINSTANCE.createParticipantRole(); participant.setParticipantRole(participantRole); participantRole.setClassCode(RoleClassRoot.MANU); PlayingEntity playingEntity = CDAFactory.eINSTANCE.createPlayingEntity(); participantRole.setPlayingEntity(playingEntity); playingEntity.setClassCode(EntityClassRoot.MMAT); CE playingEntityCode = DatatypesFactory.eINSTANCE.createCE(); playingEntity.setCode(playingEntityCode); playingEntityCode.setCode("70618"); playingEntityCode.setCodeSystem("2.16.840.1.113883.6.88"); playingEntityCode.setDisplayName("Penicillin"); [Discussion about creating playing entity] // reaction observation contains coded information on the adverse reaction ReactionObservation reactionObservation = CCDFactory.eINSTANCE.createReactionObservation().init(); alertObservation.addObservation(reactionObservation); ((EntryRelationship) reactionObservation.eContainer()).setTypeCode(x_ActRelationshipEntryRelationship .MFST); ((EntryRelationship) reactionObservation.eContainer()).setInversionInd(Boolean.TRUE); code = DatatypesFactory.eINSTANCE.createCD(); reactionObservation.setCode(code); USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 12 of 18 User Documentation for MDHT Runtime APIs code.setCode("ASSERTION"); code.setCodeSystem("2.16.840.1.113883.5.4"); statusCode = DatatypesFactory.eINSTANCE.createCS(); reactionObservation.setStatusCode(statusCode); statusCode.setCode("completed"); value = DatatypesFactory.eINSTANCE.createCD(); reactionObservation.getValues().add(value); value.setCode("247472004"); value.setCodeSystem("2.16.840.1.113883.6.96"); value.setDisplayName("Hives"); [Discussion about creating reaction observation] // alert status contains information about whether allergy is currently active AlertStatusObservation alertStatusObservation = CCDFactory.eINSTANCE.createAlertStatusObservation().init(); alertObservation.addObservation(alertStatusObservation); ((EntryRelationship) alertStatusObservation.eContainer()).setTypeCode(x_ActRelationshipEntryRelations hip.REFR); CE alertStatusObservationValue = DatatypesFactory.eINSTANCE.createCE(); alertStatusObservation.getValues().add(alertStatusObservationValue); alertStatusObservationValue.setCode("55561003"); alertStatusObservationValue.setCodeSystem("2.16.840.1.113883.6.96"); alertStatusObservationValue.setDisplayName("Active"); [Discussion about creating alert status] // write the document out to the console CDAUtil.save(ccdDocument, System.out); [Discussion about serializing the document to XML] <?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 CDA.xsd"> <templateId root="2.16.840.1.113883.10.20.1"/> <code code="34133-9" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" displayName="Summarization of episode note"/> <recordTarget> <patientRole> <id root="996-756-495" extension="2.16.840.1.113883.19.5"/> <addr use="H"><streetAddressLine>1313 Mockingbird Lane</streetAddressLine><city>Janesville</city><state>WI</state><postalCode>5354 5</postalCode></addr> USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 13 of 18 User Documentation for MDHT Runtime APIs <patient> <name><given>Henry</given><family>Levin</family></name> <administrativeGenderCode code="M" codeSystem="2.16.840.1.113883.5.1"/> <birthTime value="19320924"/> </patient> </patientRole> </recordTarget> <component> <structuredBody> <component> <section> <templateId root="2.16.840.1.113883.10.20.1.2"/> <code code="48765-2" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" displayName="Allergies, adverse reactions, alerts"/> <text><table border="1" width="100%"><thead><tr><th>Substance</th><th>Reaction</th><th>Status</th></tr>< /thead><tbody><tr><td>Penicillin</td><td>Hives</td><td>Active</td></tr></tbody>< /table></text> <entry> <act classCode="ACT" moodCode="EVN"> <templateId root="2.16.840.1.113883.10.20.1.27"/> <id root="a7140229-4a87-457a-b63e-50b79c57dfa1"/> <code nullFlavor="NA"/> <entryRelationship typeCode="SUBJ"> <observation moodCode="EVN"> <templateId root="2.16.840.1.113883.10.20.1.18"/> <id root="85d9039f-d254-4d5b-86d1-7500279f0454"/> <code code="ASSERTION" codeSystem="2.16.840.1.113883.5.4"/> <statusCode code="completed"/> <value xsi:type="CD" code="282100009" codeSystem="2.16.840.1.113883.6.96" displayName="Adverse reaction to substance"/> <participant typeCode="CSM"> <participantRole classCode="MANU"> <playingEntity classCode="MMAT"> <code code="70618" codeSystem="2.16.840.1.113883.6.88" displayName="Penicillin"/> </playingEntity> </participantRole> </participant> <entryRelationship typeCode="MFST" inversionInd="true"> <observation classCode="OBS" moodCode="EVN"> <templateId root="2.16.840.1.113883.10.20.1.54"/> <code code="ASSERTION" codeSystem="2.16.840.1.113883.5.4"/> <statusCode code="completed"/> <value xsi:type="CD" code="247472004" codeSystem="2.16.840.1.113883.6.96" displayName="Hives"/> </observation> </entryRelationship> <entryRelationship typeCode="REFR"> <observation classCode="OBS" moodCode="EVN"> <templateId root="2.16.840.1.113883.10.20.1.57"/> <templateId root="2.16.840.1.113883.10.20.1.39"/> USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 14 of 18 User Documentation for MDHT Runtime APIs <code code="33999-4" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" displayName="Status"/> <statusCode code="completed"/> <value xsi:type="CE" code="55561003" codeSystem="2.16.840.1.113883.6.96" displayName="Active"/> </observation> </entryRelationship> </observation> </entryRelationship> </act> </entry> </section> </component> </structuredBody> </component> </ClinicalDocument> [Discussion of XML instance] 3.2. Consume 1. Consume: Someone sends standard compliance document and needs to extract data and save to the system. Using API’s to extract specific information. 2. Query Filter Operation // static package registration CCDPackage.eINSTANCE.eClass(); [Discussion of static package registration] // load sample continuity of care document from file ContinuityOfCareDocument ccdDocument = (ContinuityOfCareDocument) CDAUtil.load(new FileInputStream("resources/SampleCCDDocument.xml")); [Discussion of loading document from file] // get the alerts section from the document using domain-specific "getter" method AlertsSection alertsSection = ccdDocument.getAlertsSection(); [Discussion of getting the alerts section from the document] // for each enclosing problem act USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 15 of 18 User Documentation for MDHT Runtime APIs for (ProblemAct problemAct : alertsSection.getProblemActs()) { // look at subordinate observations // we don't have a domain-specific "getter" method here so we use // entry relationship for (EntryRelationship entryRelationship : problemAct.getEntryRelationships()) { // check for alert observation if (entryRelationship.getObservation() instanceof AlertObservation) { // see below for details... } } } [Discussion of looping over problem acts looking for AlertObservations] // get coded value from alert observation AlertObservation alertObservation = (AlertObservation) entryRelationship.getObservation(); if (!alertObservation.getValues().isEmpty() && alertObservation.getValues().get(0) instanceof CD) { CD value = (CD) alertObservation.getValues().get(0); System.out.println("alert observation value: " + value.getCode() + ", " + value.getCodeSystem() + ", " + value.getDisplayName()); } [Discussion about getting the coded value from the alert observation[ // search through the participants for this alert observation to find // the playing entity that contains substance information PlayingEntity playingEntity = null; for (Participant2 participant : alertObservation.getParticipants()) { // here we must match on participation type if (ParticipationType.CSM.equals(participant.getTypeCode())) { ParticipantRole participantRole = participant.getParticipantRole(); // here we must match on class code if (participantRole != null && RoleClassRoot.MANU.equals(participantRole.getClassCode())) { playingEntity = participantRole.getPlayingEntity(); // here we match on class code if (playingEntity != null && EntityClassRoot.MMAT.equals(playingEntity.getClassCode())) { // we found it break; } else { playingEntity = null; } } } } USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 16 of 18 User Documentation for MDHT Runtime APIs if (playingEntity != null) { CE code = playingEntity.getCode(); if (code != null) { System.out.println("playing entity value: " + code.getCode() + ", " + code.getCodeSystem() + ", " + code.getDisplayName()); } } [Discussion about playing entity[ // get reaction observations using domain-specific "getter" method for (ReactionObservation reactionObservation : alertObservation.getReactionObservations()) { if (!reactionObservation.getValues().isEmpty() && alertObservation.getValues().get(0) instanceof CD) { CD value = (CD) reactionObservation.getValues().get(0); System.out.println("reaction observation value: " + value.getCode() + ", " + value.getCodeSystem() + ", " + value.getDisplayName()); } [Discussion about getting reaction observations[ // get alert status observation using domain-specific "getter" method AlertStatusObservation alertStatusObservation = alertObservation.getAlertStatusObservation(); if (alertStatusObservation != null && !alertStatusObservation.getValues().isEmpty() && alertObservation.getValues().get(0) instanceof CD) { CD value = (CD) alertStatusObservation.getValues().get(0); System.out.println("alert status observation value: " + value.getCode() + ", " + value.getCodeSystem() + ", " + value.getDisplayName()); } [Discussion about getting alert status observation] 3.3. Validate 1. Upfront discussion of how EMF does validation. Validate: Using general API’s to validate instance against constraints in the model. 3.4. Utility/Convenience 1. Another case of API’s is separate from the general model code. CDA utilities have numerous methods. USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 17 of 18 User Documentation for MDHT Runtime APIs USER DOCUMENTATION FOR MDHT RUNTIME APIS 4/13/2011 Page 18 of 18