com.vangent.hieos.services.xds.bridge.mapper.CDAToXDSMapper.java Source code

Java tutorial

Introduction

Here is the source code for com.vangent.hieos.services.xds.bridge.mapper.CDAToXDSMapper.java

Source

/*
 * This code is subject to the HIEOS License, Version 1.0
 *
 * Copyright(c) 2011 Vangent, Inc.  All rights reserved.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.vangent.hieos.services.xds.bridge.mapper;

import com.vangent.hieos.subjectmodel.CodedValue;
import com.vangent.hieos.subjectmodel.SubjectIdentifier;
import com.vangent.hieos.services.xds.bridge.message.XDSPnRMessage;
import com.vangent.hieos.services.xds.bridge.model.Document;
import com.vangent.hieos.services.xds.bridge.utils.SubjectIdentifierUtils;
import com.vangent.hieos.services.xds.bridge.utils.UUIDUtils;
import com.vangent.hieos.xutil.exception.XMLParserException;
import com.vangent.hieos.xutil.exception.XPathHelperException;
import com.vangent.hieos.xutil.exception.XdsFormatException;
import com.vangent.hieos.xutil.exception.XdsValidationException;
import com.vangent.hieos.xutil.hl7.date.Hl7Date;
import com.vangent.hieos.xutil.template.TemplateUtil;

import org.apache.axiom.om.OMElement;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import org.json.XML;

import java.util.Map;
import java.util.UUID;

/**
 * Class description
 *
 *
 * @version        v1.0, 2011-06-09
 * @author         Vangent
 */
public class CDAToXDSMapper implements IXDSMapper {

    /** The logger instance. */
    private static final Logger logger = Logger.getLogger(CDAToXDSMapper.class);

    /** Field description */
    private final ContentParser contentParser;

    /** Field description */
    private final ContentParserConfig contentParserConfig;

    /**
     * Constructs ...
     *
     *
     *
     * @param parser
     * @param config
     */
    public CDAToXDSMapper(ContentParser parser, ContentParserConfig config) {

        super();
        this.contentParser = parser;
        this.contentParserConfig = config;
    }

    /**
     * Method description
     *
     *
     * @param cfg
     * @param result
     */
    private void applyStaticValues(ContentParserConfig cfg, Map<String, String> result) {

        Map<String, Map<String, String>> staticValues = cfg.getStaticValues();

        for (String key : staticValues.keySet()) {

            if (StringUtils.isBlank(result.get(key))) {

                Map<String, String> values = staticValues.get(key);

                for (Map.Entry<String, String> entry : values.entrySet()) {

                    result.put(entry.getKey(), entry.getValue());
                }
            }
        }
    }

    /**
     * This method will convert a uuid to an OID. It should be called
     * after an UUIDUtils.isUUID() is called to ensure an exception
     * will not occur... the exception is eaten in this method.
     *
     * @param uuid the uuid string to convert
     *
     * @return the uuid as an oid
     */
    private String convertUUIDToOID(String uuid) {

        String result = null;

        try {
            result = UUIDUtils.toOIDFromUUIDString(uuid);
        } catch (XdsFormatException e) {

            logger.warn(e.getMessage());
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param sequence
     *
     * @retur
     *
     * @return
     */
    protected String createExtrinsicObjectId(int sequence) {
        return String.format("Document%02d", sequence);
    }

    /**
     * Method description
     *
     *
     *
     * @param document
     *
     * @return
     *
     *
     * @throws XMLParserException
     * @throws XPathHelperException
     */
    protected Map<String, String> createReplaceVariables(Document document)
            throws XMLParserException, XPathHelperException {

        ContentParser parser = getContentParser();
        ContentParserConfig cfg = getContentParserConfig();

        Map<String, String> result = parser.parse(cfg, document.getContent());

        // ////
        // apply business rules

        CodedValue documentType = document.getType();

        // ///
        // ExtrinsicObject

        // authorInstitution
        remapForXON(result, ContentVariableName.AuthorInstitutionRoot,
                ContentVariableName.AuthorInstitutionExtension);

        // authorPerson
        remapForXON(result, ContentVariableName.AuthorPersonRoot, ContentVariableName.AuthorPersonExtension);

        // symbolic Document01
        String symbolicId = createExtrinsicObjectId(1);

        result.put(ContentVariableName.DocumentSymbolicId.toString(), symbolicId);
        document.setSymbolicId(symbolicId);

        // document type, pull from SDR
        result.put(ContentVariableName.DocumentTypeCode.toString(), documentType.getCode());
        result.put(ContentVariableName.DocumentTypeCodeSystem.toString(), documentType.getCodeSystem());
        result.put(ContentVariableName.DocumentTypeDisplayName.toString(), documentType.getDisplayName());

        // formatCode
        CodedValue format = document.getFormat();

        result.put(ContentVariableName.DocumentFormatCode.toString(), format.getCode());
        result.put(ContentVariableName.DocumentFormatCodeSystem.toString(), format.getCodeSystem());
        result.put(ContentVariableName.DocumentFormatDisplayName.toString(), format.getDisplayName());

        // mime type
        result.put(ContentVariableName.DocumentMimeType.toString(), document.getMimeType());

        // legal Authenticator
        remapForXON(result, ContentVariableName.LegalAuthenticatorRoot,
                ContentVariableName.LegalAuthenticatorExtension);

        // patientId, create an identifier and store in document
        String patIdExt = result.get(ContentVariableName.PatientIdExtension.toString());

        String patIdRoot = result.get(ContentVariableName.PatientIdRoot.toString());

        SubjectIdentifier patId = SubjectIdentifierUtils.createSubjectIdentifier(patIdRoot, patIdExt);

        document.setPatientId(patId);

        // patientId
        remapForCX(result, ContentVariableName.PatientIdRoot, ContentVariableName.PatientIdExtension,
                ContentVariableName.PatientIdCX);

        // sourcePatientId
        remapForCX(result, ContentVariableName.SourcePatientIdRoot, ContentVariableName.SourcePatientIdExtension,
                ContentVariableName.SourcePatientIdCX);

        // title
        String title = result.get(ContentVariableName.DocumentTitle.toString());

        if (StringUtils.isBlank(title)) {

            // default to displayName
            result.put(ContentVariableName.DocumentTitle.toString(),
                    result.get(ContentVariableName.DocumentDisplayName.toString()));
        }

        // confidentialityCode, rules:
        // use SDR
        // if null, use CDA (do nothing, already pulled/parsed using expressions)
        // if null, let static content handle it (below)
        CodedValue confidentialityCode = document.getConfidentialityCode();

        if (confidentialityCode != null) {

            // the SDR trumps all other values, use it
            result.put(ContentVariableName.DocumentConfidentialityCode.toString(), confidentialityCode.getCode());
            result.put(ContentVariableName.DocumentConfidentialityCodeSystem.toString(),
                    confidentialityCode.getCodeSystem());

            String displayName = StringUtils.trimToEmpty(confidentialityCode.getDisplayName());

            result.put(ContentVariableName.DocumentConfidentialityDisplayName.toString(), displayName);
        }

        // uniqueId, rules:
        // use SDR id
        // if null, use CDA id
        // if null, generate one
        String uuidField = ContentVariableName.DocumentUniqueId.toString();

        if (StringUtils.isNotBlank(document.getId())) {

            // document id from SDR is preferred
            String docIdAsOID = document.getId();

            if (UUIDUtils.isUUID(docIdAsOID)) {

                // if UUID then we need to convert to OID
                docIdAsOID = convertUUIDToOID(docIdAsOID);
            }

            result.put(uuidField, docIdAsOID);
            document.setDocumentIdAsOID(docIdAsOID);

        } else {

            // if document content had internal id use that
            // else generate one

            String docId = result.get(uuidField);

            if (StringUtils.isBlank(docId)) {

                // uses 2.25 prefix
                docId = UUIDUtils.toOID(UUID.randomUUID());

                result.put(uuidField, docId);

                // sync up with the document object
                document.setId(docId);
                document.setDocumentIdAsOID(docId);
                document.setGeneratedDocumentId(true);

            } else {

                String docIdAsOID = docId;

                // if inner document id is a UUID then we need to convert
                if (UUIDUtils.isUUID(docId)) {

                    // uses 2.25 prefix
                    docIdAsOID = convertUUIDToOID(docIdAsOID);
                    result.put(uuidField, docIdAsOID);
                }

                // sync up with the document object
                document.setDocumentIdAsOID(docIdAsOID);
            }
        }

        // convert the replace id to an OID from UUID (as necessary)
        String replIdAsOID = document.getReplaceId();

        if (StringUtils.isNotBlank(replIdAsOID) && UUIDUtils.isUUID(replIdAsOID)) {

            replIdAsOID = convertUUIDToOID(replIdAsOID);
        }

        logger.debug(String.format("Setting replaceIdAsOID: [%s].", replIdAsOID));
        document.setReplaceIdAsOID(replIdAsOID);

        // ///
        // Submission Set

        // content type, pull from SDR
        result.put(ContentVariableName.ContentTypeCode.toString(), documentType.getCode());
        result.put(ContentVariableName.ContentTypeCodeSystem.toString(), documentType.getCodeSystem());
        result.put(ContentVariableName.ContentTypeDisplayName.toString(), documentType.getDisplayName());

        String sourceIdRoot = result.get(ContentVariableName.SourceIdRoot.toString());
        String sourceIdExt = result.get(ContentVariableName.SourceIdExtension.toString());

        if (StringUtils.isBlank(sourceIdExt)) {

            result.put(ContentVariableName.SourceId.toString(), sourceIdRoot);

        } else {

            result.put(ContentVariableName.SourceId.toString(), String.format("%s^%s", sourceIdRoot, sourceIdExt));
        }

        // Convert Submission Time to DTM_UTC format (if required).
        //String submissionTime;
        //Map<String, String> contentConversions = cfg.getContentConversions();
        //if (contentConversions != null) {
        // See if a converter exists for the submission time.
        //    String contentConversion = contentConversions.get(ContentVariableName.SubmissionTime.toString());
        //    if (contentConversion != null)
        //    {
        //        System.out.println("SubmissionTime CONVERSION would go here!!!");
        //    }
        //}
        result.put(ContentVariableName.SubmissionTime.toString(), Hl7Date.nowUTC());

        // uses 2.25 prefix
        result.put(ContentVariableName.SubmissionSetUniqueId.toString(), UUIDUtils.toOID(UUID.randomUUID()));

        // ///
        // Static Values
        // set all the static values (or overrides)
        applyStaticValues(cfg, result);

        return result;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    protected ContentParser getContentParser() {
        return contentParser;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    protected ContentParserConfig getContentParserConfig() {
        return contentParserConfig;
    }

    /**
     * Method description
     *
     *
     * @param patientId
     * @param document
     *
     * @return
     *
     *
     * @throws Exception
     */
    @Override
    public XDSPnRMessage map(SubjectIdentifier patientId, Document document) throws Exception {

        Map<String, String> repl = createReplaceVariables(document);

        validate(patientId, document, repl);

        for (Map.Entry<String, String> entry : repl.entrySet()) {

            // sanitize values (& becomes &amp;)
            String value = entry.getValue();

            if (StringUtils.isNotBlank(value)) {
                entry.setValue(XML.escape(value));
            }
        }

        String template = this.contentParserConfig.retrieveTemplateFileAsString();

        OMElement elem = TemplateUtil.getOMElementFromTemplate(template, repl);

        XDSPnRMessage result = new XDSPnRMessage(elem);

        result.attachDocument(document);

        return result;
    }

    /**
     * Method description
     *
     *
     *
     * @param contentVariables
     * @param rootField
     * @param extensionField
     * @param cxField
     */
    private void remapForCX(Map<String, String> contentVariables, ContentVariableName rootField,
            ContentVariableName extensionField, ContentVariableName cxField) {

        String root = contentVariables.get(rootField.toString());
        String ext = contentVariables.get(extensionField.toString());

        SubjectIdentifier subjectIdentifier = SubjectIdentifierUtils.createSubjectIdentifier(root, ext);

        contentVariables.put(cxField.toString(), subjectIdentifier.getCXFormatted());
    }

    /**
     * Method description
     *
     *
     * @param result
     * @param rootField
     * @param extensionField
     */
    private void remapForXON(Map<String, String> result, ContentVariableName rootField,
            ContentVariableName extensionField) {

        String root = result.get(rootField.toString());

        root = StringUtils.trimToEmpty(root);

        String ext = result.get(extensionField.toString());

        ext = StringUtils.trimToEmpty(ext);

        if (StringUtils.isBlank(ext)) {

            // "Case 1 - root only"
            // extension becomes root, root becomes blank
            result.put(extensionField.toString(), root);
            result.put(rootField.toString(), "");

        } else {

            // "Case 2 - root and extension"
            // put root into proper format
            String isoroot = String.format("&%s&ISO", root);

            result.put(rootField.toString(), isoroot);
        }
    }

    /**
     * Method description
     *
     *
     * @param patientId
     * @param document
     * @param repl
     *
     * @throws XdsValidationException
     */
    private void validate(SubjectIdentifier patientId, Document document, Map<String, String> repl)
            throws XdsValidationException {

        StringBuilder sb = new StringBuilder();

        // check patient identifier

        SubjectIdentifier docPatientId = document.getPatientId();

        // TODO the equals in subjectIdentifier is non-standard
        if (patientId.equals(docPatientId) == false) {

            sb.append(
                    String.format("SubmitDocumentRequest patient id [%s] does not match document patient id [%s].",
                            patientId.getCXFormatted(), docPatientId.getCXFormatted()));
        }

        if (sb.length() > 0) {
            throw new XdsValidationException(sb.toString());
        }
    }
}