edu.mayo.informatics.lexgrid.convert.directConversions.hl7.HL7MapToLexGrid.java Source code

Java tutorial

Introduction

Here is the source code for edu.mayo.informatics.lexgrid.convert.directConversions.hl7.HL7MapToLexGrid.java

Source

/*
 * Copyright: (c) 2004-2010 Mayo Foundation for Medical Education and 
 * Research (MFMER). All rights reserved. MAYO, MAYO CLINIC, and the
 * triple-shield Mayo logo are trademarks and service marks of MFMER.
 *
 * Except as contained in the copyright notice above, or as used to identify 
 * MFMER as the author of this software, the trade names, trademarks, service
 * marks, or product names of the copyright holder shall not be used in
 * advertising, promotion or otherwise in connection with this software without
 * prior written authorization of the copyright holder.
 * 
 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 * 
 *      http://www.eclipse.org/legal/epl-v10.html
 * 
 */
package edu.mayo.informatics.lexgrid.convert.directConversions.hl7;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;

import org.LexGrid.LexBIG.Preferences.loader.LoadPreferences.LoaderPreferences;
import org.LexGrid.LexBIG.Utility.logging.LgMessageDirectorIF;
import org.LexGrid.codingSchemes.CodingScheme;
import org.LexGrid.commonTypes.EntityDescription;
import org.LexGrid.commonTypes.Property;
import org.LexGrid.commonTypes.PropertyQualifier;
import org.LexGrid.commonTypes.Source;
import org.LexGrid.commonTypes.Text;
import org.LexGrid.commonTypes.types.EntityTypes;
import org.LexGrid.concepts.Definition;
import org.LexGrid.concepts.Entities;
import org.LexGrid.concepts.Entity;
import org.LexGrid.concepts.Presentation;
import org.LexGrid.naming.Mappings;
import org.LexGrid.naming.SupportedAssociation;
import org.LexGrid.naming.SupportedCodingScheme;
import org.LexGrid.naming.SupportedContainerName;
import org.LexGrid.naming.SupportedHierarchy;
import org.LexGrid.naming.SupportedLanguage;
import org.LexGrid.naming.SupportedProperty;
import org.LexGrid.naming.SupportedPropertyQualifier;
import org.LexGrid.naming.SupportedSource;
import org.LexGrid.relations.AssociationEntity;
import org.LexGrid.relations.AssociationPredicate;
import org.LexGrid.relations.AssociationSource;
import org.LexGrid.relations.AssociationTarget;
import org.LexGrid.relations.Relations;
import org.LexGrid.custom.concepts.EntityFactory;
import org.LexGrid.custom.relations.RelationsUtil;
import org.LexGrid.util.sql.DBUtility;
import org.LexGrid.util.sql.lgTables.SQLTableConstants;
import org.apache.commons.lang.StringUtils;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.lexevs.logging.messaging.impl.CachingMessageDirectorImpl;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import edu.mayo.informatics.lexgrid.convert.utility.loaderPreferences.PreferenceLoaderConstants;

/**
 * This is the Main EMF conversion driver.  The virtually all of the conversion is driven from this
 * class. 
 * 
 * @author <A HREF="mailto:scott.bauer@mayo.edu">Scott Bauer</A>
 * @author <A HREF="mailto:stancl.craig@mayo.edu">Craig Stancl</A>
 * @author <A HREF="mailto:kanjamala.pradip@mayo.edu">Pradip Kanjamala</A>
 *
 */

public class HL7MapToLexGrid {
    private LgMessageDirectorIF messages_;
    private String accessConnectionString;
    private String driver;
    private Hashtable<Integer, Entity> internalIdToEntityHash;
    private LoaderPreferences loaderPrefs;

    public HL7MapToLexGrid(String database, String driver, LgMessageDirectorIF lg_messages) {

        this.messages_ = new CachingMessageDirectorImpl(lg_messages);
        accessConnectionString = database;
        this.driver = driver;
        internalIdToEntityHash = new Hashtable<Integer, Entity>();
    }

    void initRun(CodingScheme csclass) {

        try {

            loadCodingScheme(csclass);
            loadAssociationEntityAndSupportedMaps(csclass);
            loadConcepts(csclass);
            loadPresentations();
            loadDefinitions();
            loadConceptProperties();
            loadRelations(csclass, driver, internalIdToEntityHash);

            // Load Metadata if the path has been specified in the Loader
            // Preferences
            if (loaderPrefs != null && loaderPrefs.getXMLMetadataFilePath() != null) {
                loadMetaData(csclass, accessConnectionString, driver);
            } else {
                messages_.info(
                        "No metadata file path was specified in the Loader Preferences, not loading Metadata.");
            }

        } catch (Exception e) {
            messages_.error("Failed to connect to RIM Database, check connection values");
            e.printStackTrace();
        } finally {

        }
    }

    void loadCodingScheme(CodingScheme csclass) {
        Connection c = null;
        try {
            messages_.info("Loading coding scheme information");
            c = DBUtility.connectToDatabase(accessConnectionString, driver, null, null);
            PreparedStatement getCodingSchemeInfo = c
                    .prepareStatement("SELECT modelID, name, versionNumber, description FROM Model");
            ResultSet results = getCodingSchemeInfo.executeQuery();
            results.next();
            String name = results.getString("modelID");
            csclass.setCodingSchemeName(name);
            csclass.setCodingSchemeURI(HL72LGConstants.DEFAULT_URN);
            csclass.setFormalName(results.getString("name"));
            EntityDescription enDesc = new EntityDescription();
            enDesc.setContent(results.getString("description"));
            csclass.setEntityDescription(enDesc);
            csclass.setDefaultLanguage(HL72LGConstants.DEFAULT_LANGUAGE_EN);
            String version = results.getString("versionNumber");
            if (version != null && version.length() > 0)
                csclass.setRepresentsVersion(version);
            else {
                csclass.setRepresentsVersion(SQLTableConstants.TBLCOLVAL_MISSING);
            }
            Text txt = new Text();
            txt.setContent("copyrightNotice goes here");

            csclass.setCopyright(txt);
            csclass.setMappings(new Mappings());

            // Add SupportedCodingScheme and SupportedLanguage Mappings
            SupportedCodingScheme scs = new SupportedCodingScheme();
            scs.setLocalId(csclass.getCodingSchemeName());
            scs.setUri(csclass.getCodingSchemeURI());
            csclass.getMappings().addSupportedCodingScheme(scs);

            SupportedLanguage lang = new SupportedLanguage();
            lang.setLocalId(HL72LGConstants.DEFAULT_LANGUAGE_EN);
            csclass.getMappings().addSupportedLanguage(lang);

            // Add SupportedHierarchy Mappings
            SupportedHierarchy hierarchy = new SupportedHierarchy();
            hierarchy.setLocalId(HL72LGConstants.ASSOCIATION_HAS_SUBTYPE);
            ArrayList<String> list = new ArrayList<String>();
            list.add(HL72LGConstants.ASSOCIATION_HAS_SUBTYPE);
            hierarchy.setAssociationNames(list);
            hierarchy.setRootCode(HL72LGConstants.DEFAULT_ROOT_NODE);
            hierarchy.setIsForwardNavigable(true);
            csclass.getMappings().addSupportedHierarchy(hierarchy);

            hierarchy = new SupportedHierarchy();
            hierarchy.setLocalId(HL72LGConstants.ASSOCIATION_IS_A);
            list = new ArrayList<String>();
            list.add(HL72LGConstants.ASSOCIATION_HAS_SUBTYPE);
            hierarchy.setAssociationNames(list);
            hierarchy.setRootCode(HL72LGConstants.DEFAULT_ROOT_NODE);
            hierarchy.setIsForwardNavigable(true);
            csclass.getMappings().addSupportedHierarchy(hierarchy);
            results.close();

        } catch (Exception e) {
            messages_.error("Failed while preparing HL7 Coding Scheme Class", e);
            e.printStackTrace();
        } finally {
            try {
                c.close();
            } catch (SQLException e) {
                messages_.debug("An error occurred while closing the MS Access connection: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }

    void loadAssociationEntityAndSupportedMaps(CodingScheme csclass) {
        Connection con = null;
        Relations relations = null;
        Entities concepts = csclass.getEntities();
        if (concepts == null) {
            concepts = new Entities();
            csclass.setEntities(concepts);
        }

        try {
            messages_.info("Loading AssociationEntityAndSupportedMaps");
            con = DBUtility.connectToDatabase(accessConnectionString, driver, null, null);
            // Pre-Load the supported associations -- this will just be the
            // hasSubtype association for 99% of the contained coding schemes.
            relations = new Relations();
            relations.setContainerName("relations");
            csclass.addRelations(relations);
            SupportedContainerName scn = new SupportedContainerName();
            scn.setLocalId("relations");
            csclass.getMappings().addSupportedContainerName(scn);

            PreparedStatement getAssociations_ps = con
                    .prepareStatement("SELECT distinct(relationCode) FROM VCS_concept_relationship");
            ResultSet association_results = getAssociations_ps.executeQuery();

            // This assures that the single other association (smaller_than)
            // will be supported and provides future support for associations
            // other than hasSubtype
            while (association_results.next()) {
                String association_name = association_results.getString("relationCode");
                SupportedAssociation sa = new SupportedAssociation();
                sa.setLocalId(association_name);
                sa.setEntityCode(association_name);
                sa.setEntityCodeNamespace(csclass.getCodingSchemeName());
                csclass.getMappings().addSupportedAssociation(sa);

                AssociationPredicate parent_assoc = new AssociationPredicate();
                parent_assoc.setAssociationName(association_name);

                AssociationEntity parent_assocEntity = EntityFactory.createAssociation();
                parent_assocEntity.setEntityCode(association_name);
                parent_assocEntity.setForwardName(association_name);
                parent_assocEntity.setEntityCodeNamespace(csclass.getCodingSchemeName());

                concepts.addEntity(parent_assocEntity);

                RelationsUtil.subsume(relations, parent_assoc);

                if (association_name.equals("hasSubtype")) {
                    parent_assocEntity.setIsTransitive(true);
                }
            }

            association_results.close();

            // Pre-load all the supported properties
            PreparedStatement getProperties_ps = con
                    .prepareStatement("SELECT distinct(propertyCode) FROM VCS_concept_property");
            ResultSet property_results = getProperties_ps.executeQuery();

            String property = null;
            while (property_results.next()) {
                property = property_results.getString("propertyCode");
                SupportedProperty sp = new SupportedProperty();
                sp.setLocalId(property);
                if (!Arrays.asList(csclass.getMappings().getSupportedProperty()).contains(sp))
                    csclass.getMappings().addSupportedProperty(sp);
            }
            property_results.close();

            // Pre-load the supported property qualifier source-code
            String propertyQualifier = "source-code";
            SupportedPropertyQualifier spq = new SupportedPropertyQualifier();
            spq.setLocalId(propertyQualifier);
            if (!Arrays.asList(csclass.getMappings().getSupportedPropertyQualifier()).contains(spq))
                csclass.getMappings().addSupportedPropertyQualifier(spq);

            // Pre-load all the supported sources
            PreparedStatement getSources_ps = con
                    .prepareStatement("SELECT distinct(codeSystemName) FROM VCS_code_system");
            ResultSet source_results = getSources_ps.executeQuery();

            String source = null;
            while (source_results.next()) {
                source = source_results.getString("codeSystemName");
                SupportedSource ss = new SupportedSource();

                ss.setLocalId(source);
                if (!Arrays.asList(csclass.getMappings().getSupportedSource()).contains(ss))
                    csclass.getMappings().addSupportedSource(ss);
            }
            source_results.close();
        } catch (Exception e) {
            messages_.error("Failed while preparing HL7 concepts.", e);
            e.printStackTrace();
        } finally {
            try {
                con.close();
            } catch (SQLException e) {
                messages_.debug("An error occurred while closing the MS Access connection: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }

    void loadConcepts(CodingScheme csclass) {

        Connection c = null;
        ResultSet results = null;

        Entities concepts = csclass.getEntities();
        if (concepts == null) {
            concepts = new Entities();
            csclass.setEntities(concepts);
        }

        try {
            messages_.info("Loading concepts");
            c = DBUtility.connectToDatabase(accessConnectionString, driver, null, null);

            // Create the artificial top nodes, the @ node. Persist the top nodes to a list
            // Create a method do handle them as concepts.
            loadArtificialTopNodes(csclass, concepts, c);

            // Pre-load some concept data into hash tables but eliminate the
            // code system scheme.
            PreparedStatement getConcept_ps = c
                    .prepareStatement("SELECT internalId, conceptCode2, " + SQLTableConstants.TBLCOL_CONCEPTSTATUS
                            + " FROM VCS_concept_code_xref WHERE codeSystemId2 <> ? and codeInstance <> ?");

            getConcept_ps.setString(1, HL72LGConstants.CODE_SYSTEM_OID);
            // We want only the default case which happens to be uppercase.
            // Ignore the lower case code
            getConcept_ps.setInt(2, 1);
            results = getConcept_ps.executeQuery();
            while (results.next()) {
                int internalId = results.getInt("internalId");
                String conceptCode = Integer.toString(internalId) + ":" + results.getString("conceptCode2");
                String status = results.getString(SQLTableConstants.TBLCOL_CONCEPTSTATUS);
                Entity concept = new Entity();
                concept.setEntityCode(conceptCode);
                concept.setEntityType(new String[] { EntityTypes.CONCEPT.toString() });
                concept.setEntityCodeNamespace(csclass.getCodingSchemeName());
                internalIdToEntityHash.put(Integer.valueOf(internalId), concept);
                concepts.addEntity(concept);

            }
            results.close();

        } catch (Exception e) {
            messages_.error("Failed while preparing HL7 concepts.", e);
            e.printStackTrace();
        } finally {
            try {
                c.close();
            } catch (SQLException e) {
                messages_.debug("An error occurred while closing the MS Access connection: " + e.getMessage());
                e.printStackTrace();
            }
        }

        // process the concept data
        messages_.info("Processing " + internalIdToEntityHash.size() + " concepts...");
        csclass.setApproxNumConcepts(new Long(concepts.getEntity().length));

    }

    void loadArtificialTopNodes(CodingScheme csclass, Entities concepts, Connection c) {
        messages_.info("Processing code systems into top nodes");
        ResultSet topNode_results = null;
        try {
            // Create an "@" top node.
            Entity rootNode = new Entity();

            // Create and set the concept code for "@"
            String topNodeDesignation = "@";
            rootNode.setEntityCode(topNodeDesignation);
            rootNode.setEntityCodeNamespace(csclass.getCodingSchemeName());
            rootNode.setIsAnonymous(Boolean.TRUE);
            EntityDescription enDesc = new EntityDescription();
            enDesc.setContent("Root node for subclass relations.");
            rootNode.setEntityDescription(enDesc);
            concepts.addEntity(rootNode);

            AssociationSource ai = new AssociationSource();
            ai.setSourceEntityCode(rootNode.getEntityCode());
            ai.setSourceEntityCodeNamespace(csclass.getCodingSchemeName());
            AssociationPredicate parent_assoc = (AssociationPredicate) RelationsUtil
                    .resolveAssociationPredicates(csclass, HL72LGConstants.ASSOCIATION_HAS_SUBTYPE).get(0);
            ai = RelationsUtil.subsume(parent_assoc, ai);

            // Get all the code systems except the
            // legacy code system coding scheme in HL7
            PreparedStatement getArtificialTopNodeData = c
                    .prepareStatement("select cs.*, code.internalId FROM VCS_code_system AS cs "
                            + "LEFT JOIN  VCS_concept_code_xref AS code "
                            + "ON cs.codeSystemName= code.conceptCode2 "
                            + "where (code.codeSystemId2 = ? OR code.codeSystemId2 is null) AND cs.codesystemid <> ?");
            getArtificialTopNodeData.setString(1, HL72LGConstants.CODE_SYSTEM_OID);
            getArtificialTopNodeData.setString(2, HL72LGConstants.CODE_SYSTEM_OID);
            ResultSet dataResults = getArtificialTopNodeData.executeQuery();
            while (dataResults.next()) {
                Entity topNode = new Entity();
                String nodeName = dataResults.getString("codeSystemName");
                String entityDescription = dataResults.getString("fullName");
                String oid = dataResults.getString("codeSystemId");
                String def = dataResults.getString("description");
                String internalId = dataResults.getString("internalId");
                if (StringUtils.isNotBlank(def)) {
                    int begin = def.lastIndexOf("<p>");
                    int end = def.lastIndexOf("</p>");
                    if (begin > -1) {
                        if (begin + 3 < end)
                            def = def.substring(begin + 3, end);
                    }
                }

                if (StringUtils.isNotBlank(internalId)) {
                    topNode.setEntityCode(internalId + ":" + nodeName);
                } else {
                    topNode.setEntityCode(nodeName + ":" + nodeName);
                }
                topNode.setEntityCodeNamespace(csclass.getCodingSchemeName());

                EntityDescription enD = new EntityDescription();
                enD.setContent(entityDescription);
                topNode.setEntityDescription(enD);
                topNode.setIsActive(true);

                // Set presentation so it's a full fledged concept
                Presentation p = new Presentation();
                Text txt = new Text();
                txt.setContent((String) entityDescription);
                p.setValue(txt);
                p.setIsPreferred(Boolean.TRUE);
                p.setPropertyName(HL72LGConstants.PROPERTY_PRINTNAME);
                p.setPropertyId("T1");
                p.setLanguage(HL72LGConstants.DEFAULT_LANGUAGE_EN);
                topNode.addPresentation(p);

                // Set definition
                if (StringUtils.isNotBlank(def)) {
                    Definition definition = new Definition();
                    Text defText = new Text();
                    defText.setContent(def);
                    definition.setValue(defText);
                    definition.setPropertyName(HL72LGConstants.PROPERTY_DEFINITION);
                    definition.setPropertyId("D1");
                    definition.setIsActive(Boolean.TRUE);
                    definition.setIsPreferred(Boolean.TRUE);
                    definition.setLanguage(HL72LGConstants.DEFAULT_LANGUAGE_EN);
                    topNode.addDefinition(definition);
                }

                topNode.addEntityType(EntityTypes.CONCEPT.toString());
                concepts.addEntity(topNode);

                // This coding scheme is attached to an artificial root.
                AssociationTarget at = new AssociationTarget();
                at.setTargetEntityCode(topNode.getEntityCode());
                at.setTargetEntityCodeNamespace(csclass.getCodingSchemeName());
                RelationsUtil.subsume(ai, at);

                // Now find the top nodes of the scheme and subsume them to this
                // scheme's artificial top node.
                // First get a list of all nodes in the scheme.
                // but again exclude the code system nodes.
                ArrayList<String> topNodes = new ArrayList<String>();
                PreparedStatement getSystemCodes = c.prepareStatement(
                        "SELECT DISTINCT (internalId), conceptCode2 FROM VCS_concept_code_xref WHERE codeSystemId2 =? AND codeSystemId2 <> ?");
                getSystemCodes.setString(1, oid);
                getSystemCodes.setString(2, HL72LGConstants.CODE_SYSTEM_OID);
                ResultSet systemCodes = getSystemCodes.executeQuery();
                while (systemCodes.next()) {
                    String testCode = systemCodes.getString("internalId");
                    if (testCode != null)
                        topNodes.add(testCode);
                }
                if (systemCodes != null)
                    systemCodes.close();
                if (getSystemCodes != null)
                    getSystemCodes.close();

                // Drop any from the list that aren't top nodes.
                ArrayList<String> nodesToRemove = new ArrayList<String>();
                PreparedStatement checkForTopNode = null;
                for (int i = 0; i < topNodes.size(); i++) {
                    checkForTopNode = c.prepareStatement(
                            "SELECT targetInternalId FROM VCS_concept_relationship WHERE targetInternalId =?");
                    checkForTopNode.setString(1, (String) topNodes.get(i));
                    topNode_results = checkForTopNode.executeQuery();
                    if (topNode_results.next()) {
                        if (topNodes.get(i).equals(topNode_results.getString(1))) {
                            nodesToRemove.add(topNodes.get(i));
                        }
                    }
                    if (topNode_results != null)
                        topNode_results.close();
                    if (checkForTopNode != null)
                        checkForTopNode.close();
                }

                for (int i = 0; i < nodesToRemove.size(); i++) {
                    topNodes.remove(nodesToRemove.get(i));
                }
                // Get the full concept code for each.
                PreparedStatement getconceptSuffix = null;
                ResultSet conceptCode = null;
                for (int i = 0; i < topNodes.size(); i++) {
                    getconceptSuffix = c.prepareStatement(
                            "SELECT conceptCode2 FROM VCS_concept_code_xref where internalId = ?");

                    getconceptSuffix.setString(1, (String) topNodes.get(i));
                    conceptCode = getconceptSuffix.executeQuery();
                    conceptCode.next();
                    topNodes.set(i, topNodes.get(i) + ":" + conceptCode.getString(1));
                    if (conceptCode != null)
                        conceptCode.close();
                    if (getconceptSuffix != null)
                        getconceptSuffix.close();
                }

                // For each top node subsume to the current artificial node for
                // the scheme.
                for (int j = 0; j < topNodes.size(); j++) {
                    try {
                        AssociationSource atn = new AssociationSource();
                        atn.setSourceEntityCode(topNode.getEntityCode());
                        atn.setSourceEntityCodeNamespace(csclass.getCodingSchemeName());
                        atn = RelationsUtil.subsume(parent_assoc, atn);

                        AssociationTarget atopNode = new AssociationTarget();
                        atopNode.setTargetEntityCode((String) topNodes.get(j));
                        atopNode.setTargetEntityCodeNamespace(csclass.getCodingSchemeName());
                        RelationsUtil.subsume(atn, atopNode);
                    } catch (Exception e) {
                        messages_.error("Failed while processing HL7 psuedo top node hierarchy", e);
                        e.printStackTrace();
                    }
                }
            }
            dataResults.close();
            messages_.info("Top node processing complete");
        } catch (Exception e) {
            messages_.error("Top node processing failed", e);
            e.printStackTrace();
        }

    }

    void loadPresentations() {
        ResultSet designationResults = null;
        Connection con = null;
        try {
            messages_.info("Loading all presentations");
            con = DBUtility.connectToDatabase(accessConnectionString, driver, null, null);
            // Pull source code system name and designation
            PreparedStatement designation_ps = con.prepareStatement("SELECT DISTINCT a.internalId, a.designation, "
                    + "a.language, a.preferredForLanguage, b.codeSystemId2, c.codeSystemName "
                    + "FROM VCS_concept_designation AS a, VCS_concept_code_xref AS b, " + "VCS_code_system AS c "
                    + "WHERE a.internalId=b.internalId AND c.codeSystemid=b.codeSystemId2  AND b.codeSystemId2 <> ? ");

            designation_ps.setString(1, HL72LGConstants.CODE_SYSTEM_OID);
            designationResults = designation_ps.executeQuery();

            if (designationResults.next()) {
                do {
                    int internalId = designationResults.getInt("internalId");
                    Entity concept = this.internalIdToEntityHash.get(Integer.valueOf(internalId));
                    if (concept == null) {
                        System.out.println("Concept of InternalId " + internalId + " not found");
                        messages_.info("Concept of InternalId " + internalId + " not found");
                    } else {
                        // Determine the source coding scheme concept code
                        String conceptCodeFull = concept.getEntityCode();
                        int colonPosition = conceptCodeFull.lastIndexOf(":");
                        String conceptCode = conceptCodeFull.substring(colonPosition + 1);
                        String sourceCodeSystemName = designationResults.getString("codeSystemName");
                        String entityDescription = designationResults.getString("designation");

                        Presentation p = new Presentation();
                        Text txt = new Text();
                        txt.setContent((String) entityDescription);
                        p.setValue(txt);

                        if (designationResults.getString("preferredForLanguage").equals("1")) {
                            p.setIsPreferred(Boolean.TRUE);
                            EntityDescription ed = new EntityDescription();
                            ed.setContent(entityDescription);
                            concept.setEntityDescription(ed);
                        } else { // Designation is not preferred for language,
                                 // set
                                 // to false
                            p.setIsPreferred(Boolean.FALSE);
                        }
                        p.setPropertyName(HL72LGConstants.PROPERTY_PRINTNAME);
                        p.setPropertyId("T" + concept.getPresentationCount());
                        String propertyLanguage = designationResults.getString("language");
                        if (StringUtils.isBlank(propertyLanguage)) {
                            p.setLanguage(HL72LGConstants.DEFAULT_LANGUAGE_EN);
                        } else {
                            p.setLanguage(propertyLanguage);
                        }

                        // Set the Qualifier
                        PropertyQualifier propQual = new PropertyQualifier();
                        String tag = "source-code";
                        propQual.setPropertyQualifierName(tag);
                        txt = new Text();
                        txt.setContent((String) conceptCode);
                        propQual.setValue(txt);
                        p.addPropertyQualifier(propQual);

                        // Set the Source
                        Source s = new Source();
                        s.setContent(sourceCodeSystemName);
                        p.addSource(s);

                        concept.addPresentation(p);

                    }

                } while (designationResults.next());
            }
        } catch (Exception e) {
            messages_.error("Failed to load HL7 Concept presentation", e);
            e.printStackTrace();
        } finally {
            try {
                designationResults.close();
                con.close();
            } catch (SQLException e) {
                messages_.debug("An error occurred while closing the MS Access connection: " + e.getMessage());
                e.printStackTrace();
            }
        }

    }

    void loadDefinitions() {
        ResultSet desResults = null;
        Connection con = null;
        try {
            messages_.info("Loading all definitions");
            con = DBUtility.connectToDatabase(accessConnectionString, driver, null, null);
            PreparedStatement descriptions_ps = con
                    .prepareStatement("SELECT des.internalId, des.description, des.language "
                            + "FROM VCS_concept_description as des,  VCS_concept_code_xref AS code "
                            + " WHERE des.internalId= code.internalId AND  code.codeSystemId2 <> ? AND code.codeInstance <> ?");
            descriptions_ps.setString(1, HL72LGConstants.CODE_SYSTEM_OID);
            descriptions_ps.setInt(2, 1);
            desResults = descriptions_ps.executeQuery();

            String description = null;
            while (desResults.next()) {
                int internalId = desResults.getInt("internalId");
                Entity concept = this.internalIdToEntityHash.get(Integer.valueOf(internalId));
                if (concept == null) {
                    System.out.println("Concept of InternalId " + internalId + " not found");
                    messages_.info("Concept of InternalId " + internalId + " not found");
                } else {
                    // removes HTML tags from description text.
                    description = desResults.getString("description");
                    description = description.replaceAll("</?[A-Z]+\\b[^>]*>", "");
                    description = description.replaceAll("</?[a-z]+\\b[^>]*>", "");
                    if (StringUtils.isNotBlank(description)) {

                        Definition def = new Definition();
                        Text txt = new Text();
                        txt.setContent((String) description);
                        def.setValue(txt);
                        def.setIsPreferred(Boolean.TRUE);
                        def.setPropertyName(HL72LGConstants.PROPERTY_DEFINITION);
                        String propertyLanguage = desResults.getString("language");
                        if (StringUtils.isBlank(propertyLanguage)) {
                            def.setLanguage(HL72LGConstants.DEFAULT_LANGUAGE_EN);
                        } else {
                            def.setLanguage(propertyLanguage);
                        }

                        def.setPropertyId("D" + concept.getDefinitionCount());
                        concept.addDefinition(def);

                    }
                }

            }
        } catch (Exception e) {
            messages_.error("Failed to load HL7 Concept definitions", e);
            e.printStackTrace();
        } finally {
            try {

                desResults.close();
                con.close();
            } catch (SQLException e) {
                messages_.debug("An error occurred while closing the MS Access connection: " + e.getMessage());
                e.printStackTrace();
            }
        }

    }

    void loadConceptProperties() {
        ResultSet prop_results = null;
        Connection con = null;
        try {
            messages_.info("Loading all concept properties");
            con = DBUtility.connectToDatabase(accessConnectionString, driver, null, null);
            PreparedStatement properties_ps = con
                    .prepareStatement("SELECT p.internalId, p.propertyCode, p.propertyValue, p.language "
                            + "FROM VCS_concept_property AS p,  VCS_concept_code_xref AS code "
                            + " WHERE p.internalId= code.internalId AND  code.codeSystemId2 <> ? ");
            properties_ps.setString(1, HL72LGConstants.CODE_SYSTEM_OID);
            prop_results = properties_ps.executeQuery();

            while (prop_results.next()) {
                int internalId = prop_results.getInt("internalId");
                Entity concept = this.internalIdToEntityHash.get(Integer.valueOf(internalId));
                if (concept == null) {
                    System.out.println("Concept of InternalId " + internalId + " not found");
                    messages_.info("Concept of InternalId " + internalId + " not found");
                } else {
                    Property cp = new Property();
                    String propertyLanguage = prop_results.getString("language");
                    if (StringUtils.isBlank(propertyLanguage)) {
                        cp.setLanguage(HL72LGConstants.DEFAULT_LANGUAGE_EN);
                    } else {
                        cp.setLanguage(propertyLanguage);
                    }
                    String property = prop_results.getString("propertyCode");
                    cp.setPropertyName(property);
                    cp.setPropertyId("P" + concept.getProperty().length);
                    Text txt = new Text();
                    txt.setContent((String) prop_results.getString("propertyValue"));
                    cp.setValue(txt);
                    concept.addProperty(cp);
                }
            }

        } catch (Exception e) {
            messages_.error("Problem processing concept properties", e);
            e.printStackTrace();
        } finally {
            try {
                prop_results.close();
                con.close();
            } catch (SQLException e) {
                messages_.debug("An error occurred while closing the MS Access connection: " + e.getMessage());
                e.printStackTrace();
            }
        }

    }

    void loadRelations(CodingScheme csclass, String driver, Hashtable<Integer, Entity> internalId2codeMap) {
        Connection connection = null;
        ResultSet association_results = null;
        try {
            connection = DBUtility.connectToDatabase(accessConnectionString, driver, null, null);
            PreparedStatement relationship_ps = connection.prepareStatement(
                    "SELECT distinct relationCode, sourceInternalId, targetInternalId FROM VCS_concept_relationship");
            association_results = relationship_ps.executeQuery();

            while (association_results.next()) {
                int source = association_results.getInt("sourceInternalId");
                int target = association_results.getInt("targetInternalId");
                String association = association_results.getString("relationCode");
                AssociationPredicate parent_association = (AssociationPredicate) RelationsUtil
                        .resolveAssociationPredicates(csclass, association).get(0);
                Entity sourceEntity = internalId2codeMap.get(Integer.valueOf(source));
                Entity targetEntity = internalId2codeMap.get(Integer.valueOf(target));

                if (sourceEntity != null && targetEntity != null) {
                    AssociationSource ai = new AssociationSource();
                    ai.setSourceEntityCode(sourceEntity.getEntityCode());
                    ai.setSourceEntityCodeNamespace(csclass.getCodingSchemeName());
                    ai = RelationsUtil.subsume(parent_association, ai);

                    AssociationTarget at = new AssociationTarget();
                    at.setTargetEntityCode(targetEntity.getEntityCode());
                    at.setTargetEntityCodeNamespace(csclass.getCodingSchemeName());
                    at = RelationsUtil.subsume(ai, at);
                }
            }
        } catch (SQLException e) {
            messages_.error("Failed while getting HL7 relations from the RIM database", e);
            e.printStackTrace();
        } catch (Exception e) {
            messages_.debug(
                    "Error occurred while connecting to the RIM database. " + accessConnectionString + driver);
            e.printStackTrace();
        } finally {
            try {
                association_results.close();
                connection.close();
            } catch (SQLException e) {
                messages_.debug("An error occurred while closing the MS Access connections.");
                e.printStackTrace();
            }
        }
    }

    void loadMetaData(CodingScheme csclass, String connectionString, String driver) {

        messages_.info("Loading individual coding scheme metadata");
        Connection c = null;

        // create the filename of the metadata file to be created
        String filename = loaderPrefs.getXMLMetadataFilePath() + "/"
                + PreferenceLoaderConstants.META_HL7_METADATA_FILE_NAME;

        FileOutputStream fos;
        try {
            fos = new FileOutputStream(filename);

            OutputFormat of = new OutputFormat("XML", "ISO-8859-1", true);
            of.setIndent(1);
            of.setIndenting(true);
            XMLSerializer serializer = new XMLSerializer(fos, of);

            // SAX2.0 ContentHandler.
            ContentHandler hd = serializer.asContentHandler();
            hd.startDocument();

            // Element attributes.
            AttributesImpl atts = new AttributesImpl();

            // CODINGSCHEMES tag.
            hd.startElement("", "", "codingSchemes", atts);

            String defaultLanguage = "en";
            String isNative = "0";
            String codeSystemId;
            String codeSystemType;
            String codeSystemName;
            String fullName;
            String description;
            String releaseId;
            String copyrightNotice;
            Integer approximateNumberofConcepts;

            try {
                c = DBUtility.connectToDatabase(accessConnectionString, driver, null, null);

                PreparedStatement getCodingSchemeMetaData = c
                        .prepareStatement("SELECT b.codeSystemid, b.codeSystemType, b.codeSystemName, "
                                + "b.fullName, b.description, b.releaseId, b.copyrightNotice "
                                + "FROM VCS_code_system AS b");
                ResultSet codingSchemeMetaData = getCodingSchemeMetaData.executeQuery();

                PreparedStatement getCodingSchemeConceptCount = c
                        .prepareStatement("SELECT VCS_concept_code_xref.codeSystemId2, "
                                + "COUNT (VCS_concept_code_xref.codeSystemId2) as conceptcount "
                                + "FROM VCS_concept_code_xref " + "GROUP BY VCS_concept_code_xref.codeSystemId2;");

                ResultSet codingSchemeConceptCount = getCodingSchemeConceptCount.executeQuery();

                Hashtable<String, Integer> conceptCountList = new Hashtable<String, Integer>();

                while (codingSchemeConceptCount.next()) {

                    String codingSchemeId = codingSchemeConceptCount.getString("codeSystemId2");
                    String codingSchemeCount = codingSchemeConceptCount.getString("conceptcount");

                    conceptCountList.put(new String(codingSchemeId), new Integer(codingSchemeCount));
                }

                codingSchemeConceptCount.close();

                int codeSchemeCounter = 0;

                while (codingSchemeMetaData.next()) {
                    codeSystemId = codingSchemeMetaData.getString("codeSystemid");
                    if (codeSystemId == null) {
                        codeSystemId = SQLTableConstants.TBLCOLVAL_MISSING;
                    }

                    codeSystemType = codingSchemeMetaData.getString("codeSystemType");
                    if (codeSystemType == null) {
                        codeSystemType = SQLTableConstants.TBLCOLVAL_MISSING;
                    }

                    codeSystemName = codingSchemeMetaData.getString("codeSystemName");
                    if (codeSystemName == null) {
                        codeSystemName = SQLTableConstants.TBLCOLVAL_MISSING;
                    }

                    fullName = codingSchemeMetaData.getString("fullName");
                    if (fullName == null) {
                        fullName = SQLTableConstants.TBLCOLVAL_MISSING;
                    }

                    description = codingSchemeMetaData.getString("description");
                    if (description == null) {
                        description = SQLTableConstants.TBLCOLVAL_MISSING;
                    }
                    // The description contains HTML tags. We try to remove
                    // them.
                    else {
                        int begin = description.lastIndexOf("<p>");
                        int end = description.lastIndexOf("</p>");
                        if (begin > -1) {
                            if (begin + 3 < end)
                                description = description.substring(begin + 3, end);
                        }
                    }

                    releaseId = codingSchemeMetaData.getString("releaseId");
                    if (releaseId == null) {
                        releaseId = SQLTableConstants.TBLCOLVAL_MISSING;
                    }

                    copyrightNotice = codingSchemeMetaData.getString("copyrightNotice");
                    if (copyrightNotice == null) {
                        copyrightNotice = SQLTableConstants.TBLCOLVAL_MISSING;
                    }

                    approximateNumberofConcepts = ((Integer) conceptCountList.get(codeSystemId));
                    if (approximateNumberofConcepts == null) {
                        approximateNumberofConcepts = new Integer(0);
                    }

                    // Begin codingScheme element
                    atts.clear();
                    atts.addAttribute("", "", SQLTableConstants.TBLCOL_CODINGSCHEMENAME, "CDATA", codeSystemName);
                    // May want to change to _fullName
                    atts.addAttribute("", "", SQLTableConstants.TBLCOL_FORMALNAME, "CDATA", fullName);
                    atts.addAttribute("", "", SQLTableConstants.TBLCOL_CODINGSCHEMEURI, "CDATA", codeSystemId);
                    atts.addAttribute("", "", SQLTableConstants.TBLCOL_DEFAULTLANGUAGE, "CDATA", defaultLanguage);
                    atts.addAttribute("", "", SQLTableConstants.TBLCOL_REPRESENTSVERSION, "CDATA", releaseId);
                    atts.addAttribute("", "", SQLTableConstants.TBLCOL_ISNATIVE, "CDATA", isNative);
                    atts.addAttribute("", "", SQLTableConstants.TBLCOL_APPROXNUMCONCEPTS, "CDATA",
                            approximateNumberofConcepts.toString());
                    hd.startElement("", "", SQLTableConstants.TBLCOL_CODINGSCHEME, atts);

                    // localname
                    atts.clear();
                    hd.startElement("", "", "localName", atts);
                    hd.characters(codeSystemName.toCharArray(), 0, codeSystemName.length());
                    hd.endElement("", "", SQLTableConstants.TBLCOLVAL_LOCALNAME);

                    // entityDescription
                    atts.clear();
                    hd.startElement("", "", SQLTableConstants.TBLCOL_ENTITYDESCRIPTION, atts);
                    hd.characters(description.toCharArray(), 0, description.length());
                    hd.endElement("", "", SQLTableConstants.TBLCOL_ENTITYDESCRIPTION);

                    // copyright
                    atts.clear();
                    hd.startElement("", "", SQLTableConstants.TBLCOL_COPYRIGHT, atts);
                    hd.characters(copyrightNotice.toCharArray(), 0, copyrightNotice.length());
                    hd.endElement("", "", SQLTableConstants.TBLCOL_COPYRIGHT);

                    // May need to include as Property
                    // // CodingScheme
                    // atts.clear();
                    // hd.startElement("","","CodingScheme",atts);
                    // hd.characters(_codeSystemType.toCharArray(),0,_codeSystemType.length());
                    // hd.endElement("","","CodingScheme");

                    // End codingScheme element
                    hd.endElement("", "", SQLTableConstants.TBLCOL_CODINGSCHEME);

                    codeSchemeCounter++;

                } // End while there are result rows to process

                getCodingSchemeConceptCount.close();

                hd.endElement("", "", "codingSchemes");
                hd.endDocument();
                fos.close();

            } catch (Exception e) {
                messages_.error("Failed while preparing HL7 Code System MetaData.", e);
                e.printStackTrace();
            } finally {
                try {
                    c.close();
                } catch (SQLException e) {
                    messages_.debug("An error occurred while closing the MS Access connection: " + e.getMessage());
                    e.printStackTrace();
                }
            }

        } catch (FileNotFoundException fnfe) {
            messages_.debug("Loader Preferences file was not found, file: " + filename);
            fnfe.printStackTrace();
        } catch (IOException ioe) {
            messages_.debug("IOException, file: " + filename);
            ioe.printStackTrace();
        } catch (SAXException saxe) {
            messages_.debug("SAXException, file: " + filename);
            saxe.printStackTrace();
        }

    }

    public void setLoaderPrefs(LoaderPreferences loaderPrefs) {
        this.loaderPrefs = loaderPrefs;
    }

    public String getIntValue(String code) {
        char[] chars = code.toCharArray();

        StringBuffer buffer = new StringBuffer();
        for (char c : chars) {
            int integer = Character.getNumericValue(c);
            buffer.append(String.valueOf(integer));
        }
        return buffer.toString();
    }

}