org.iexhub.services.GetPatientDataService.java Source code

Java tutorial

Introduction

Here is the source code for org.iexhub.services.GetPatientDataService.java

Source

/*******************************************************************************
 * Copyright (c) 2015, 2016 Substance Abuse and Mental Health Services Administration (SAMHSA)
 *
 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
 * 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.
 *
 * Contributors:
 *     Eversolve, LLC - initial IExHub implementation for Health Information Exchange (HIE) integration
 *     Anthony Sute, Ioana Singureanu
 *******************************************************************************/
package org.iexhub.services;

import jersey.repackaged.com.google.common.base.Equivalence;
import jersey.repackaged.com.google.common.base.Predicate;
import jersey.repackaged.com.google.common.collect.Collections2;
import jersey.repackaged.com.google.common.collect.MapDifference;
import jersey.repackaged.com.google.common.collect.Maps;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.iexhub.config.IExHubConfig;
import org.iexhub.connectors.XdsB;
import org.iexhub.connectors.XdsBRepositoryManager;
import org.iexhub.exceptions.InvalidSourceModelException;
import org.iexhub.exceptions.InvalidTargetModelException;
import org.iexhub.exceptions.MessageTransformException;
import org.iexhub.exceptions.SourceMapMissingException;
import org.iexhub.exceptions.SourceMsgMissingException;
import org.iexhub.exceptions.TargetMapMissingException;
import org.iexhub.exceptions.UnexpectedServerException;
import org.iexhub.services.client.DocumentRegistry_ServiceStub.AdhocQueryResponse;
import org.iexhub.services.client.DocumentRegistry_ServiceStub.ExternalIdentifierType;
import org.iexhub.services.client.DocumentRegistry_ServiceStub.ExtrinsicObjectType;
import org.iexhub.services.client.DocumentRegistry_ServiceStub.IdentifiableType;
import org.iexhub.services.client.DocumentRegistry_ServiceStub.RegistryError_type0;
import org.iexhub.services.client.DocumentRegistry_ServiceStub.RegistryObjectListType;
import org.iexhub.services.client.DocumentRepository_ServiceStub.DocumentResponse_type0;
import org.iexhub.services.client.DocumentRepository_ServiceStub.RetrieveDocumentSetResponse;
import org.iexhub.services.dto.ClinicalDocumentRequest;
import org.iexhub.services.dto.ClinicalDocumentResponse;
import org.iexhub.services.dto.DocumentsResponseDto;
import org.iexhub.services.dto.PatientDocument;
import org.openhealthtools.mdht.mdmi.Mdmi;
import org.openhealthtools.mdht.mdmi.MdmiConfig;
import org.openhealthtools.mdht.mdmi.MdmiMessage;
import org.openhealthtools.mdht.mdmi.MdmiModelRef;
import org.openhealthtools.mdht.mdmi.MdmiTransferInfo;
import org.openhealthtools.mdht.mdmi.model.MdmiBusinessElementReference;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.activation.DataHandler;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import static java.nio.file.Files.readAllBytes;
import static java.nio.file.Paths.get;

/**
 * @author A. Sute
 *
 */
@Deprecated
@Path("/GetPatientData")
public class GetPatientDataService {
    /** Logger */
    public static Logger log = Logger.getLogger(GetPatientDataService.class);

    private static XdsB xdsB = null;
    private static boolean testMode = false;
    private static String xdsBRepositoryUniqueId = "1.3.6.1.4.1.21367.13.40.216";
    private static String cdaToJsonTransformXslt = null;
    private static String iExHubDomainOid = "1.3.6.1.4.1.21367.13.50.300132";
    private static String iExHubAssigningAuthority = "ISO";
    private static String testJSONDocumentPathname = null;
    private final String testOutputPath;

    public GetPatientDataService() {
        this.testOutputPath = IExHubConfig.getProperty("TestOutputPath");
        assert StringUtils.isNotBlank(this.testOutputPath) : "'TestOutputPath' property must be configured";
    }

    @GET
    @Consumes({ MediaType.APPLICATION_JSON })
    @Produces({ MediaType.APPLICATION_JSON })
    public Response getPatientData(@Context HttpHeaders headers) {
        log.info("Entered getPatientData service");

        boolean tls = false;

        tls = (IExHubConfig.getProperty("XdsBRegistryEndpointURI") == null) ? false
                : ((IExHubConfig.getProperty("XdsBRegistryEndpointURI").toLowerCase().contains("https") ? true
                        : false));
        GetPatientDataService.testMode = IExHubConfig.getProperty("TestMode", GetPatientDataService.testMode);
        GetPatientDataService.testJSONDocumentPathname = IExHubConfig.getProperty("TestJSONDocumentPathname",
                GetPatientDataService.testJSONDocumentPathname);
        GetPatientDataService.cdaToJsonTransformXslt = IExHubConfig.getProperty("CDAToJSONTransformXSLT",
                GetPatientDataService.cdaToJsonTransformXslt);
        GetPatientDataService.iExHubDomainOid = IExHubConfig.getProperty("IExHubDomainOID",
                GetPatientDataService.iExHubDomainOid);
        GetPatientDataService.iExHubAssigningAuthority = IExHubConfig.getProperty("IExHubAssigningAuthority",
                GetPatientDataService.iExHubAssigningAuthority);
        GetPatientDataService.xdsBRepositoryUniqueId = IExHubConfig.getProperty("XdsBRepositoryUniqueId",
                GetPatientDataService.xdsBRepositoryUniqueId);

        String retVal = "";
        GetPatientDataResponse patientDataResponse = new GetPatientDataResponse();
        StringBuilder jsonOutput = new StringBuilder();

        if (!testMode) {
            try {
                if (xdsB == null) {
                    log.info("Instantiating XdsB connector...");
                    xdsB = new XdsB(null, null, tls);
                    log.info("XdsB connector successfully started");
                }
            } catch (Exception e) {
                log.error("Error encountered instantiating XdsB connector, " + e.getMessage());
                throw new UnexpectedServerException("Error - " + e.getMessage());
            }

            try {
                MultivaluedMap<String, String> headerParams = headers.getRequestHeaders();
                String ssoAuth = headerParams.getFirst("ssoauth");
                log.info("HTTP headers successfully retrieved");

                // Extract patient ID, query start date, and query end date.  Expected format from the client is
                //   "PatientId={0}&LastName={1}&FirstName={2}&MiddleName={3}&DateOfBirth={4}&PatientGender={5}&MotherMaidenName={6}&AddressStreet={7}&AddressCity={8}&AddressState={9}&AddressPostalCode={10}&OtherIDsScopingOrganization={11}&StartDate={12}&EndDate={13}"
                String[] splitPatientId = ssoAuth.split("&LastName=");
                String patientId = (splitPatientId[0].split("=").length == 2) ? splitPatientId[0].split("=")[1]
                        : null;

                String[] parts = splitPatientId[1].split("&");
                String lastName = (parts[0].length() > 0) ? parts[0] : null;
                String firstName = (parts[1].split("=").length == 2) ? parts[1].split("=")[1] : null;
                String middleName = (parts[2].split("=").length == 2) ? parts[2].split("=")[1] : null;
                String dateOfBirth = (parts[3].split("=").length == 2) ? parts[3].split("=")[1] : null;
                String gender = (parts[4].split("=").length == 2) ? parts[4].split("=")[1] : null;
                String motherMaidenName = (parts[5].split("=").length == 2) ? parts[5].split("=")[1] : null;
                String addressStreet = (parts[6].split("=").length == 2) ? parts[6].split("=")[1] : null;
                String addressCity = (parts[7].split("=").length == 2) ? parts[7].split("=")[1] : null;
                String addressState = (parts[8].split("=").length == 2) ? parts[8].split("=")[1] : null;
                String addressPostalCode = (parts[9].split("=").length == 2) ? parts[9].split("=")[1] : null;
                String otherIDsScopingOrganization = (parts[10].split("=").length == 2) ? parts[10].split("=")[1]
                        : null;
                String startDate = (parts[11].split("=").length == 2) ? parts[11].split("=")[1] : null;
                String endDate = (parts[12].split("=").length == 2) ? parts[12].split("=")[1] : null;

                log.info("HTTP headers successfully parsed, now calling XdsB registry...");

                // Determine if a complete patient ID (including OID and ISO specification) was provided.  If not, then append IExHubDomainOid and IExAssigningAuthority...
                if (!patientId.contains("^^^&")) {
                    patientId = "'" + patientId + "^^^&" + GetPatientDataService.iExHubDomainOid + "&"
                            + GetPatientDataService.iExHubAssigningAuthority + "'";
                }

                AdhocQueryResponse registryResponse = xdsB.registryStoredQuery(patientId,
                        (startDate != null) ? DateFormat.getDateInstance().format(startDate) : null,
                        (endDate != null) ? DateFormat.getDateInstance().format(endDate) : null);

                log.info("Call to XdsB registry successful");

                // Determine if registry server returned any errors...
                if ((registryResponse.getRegistryErrorList() != null)
                        && (registryResponse.getRegistryErrorList().getRegistryError().length > 0)) {
                    for (RegistryError_type0 error : registryResponse.getRegistryErrorList().getRegistryError()) {
                        StringBuilder errorText = new StringBuilder();
                        if (error.getErrorCode() != null) {
                            errorText.append("Error code=" + error.getErrorCode() + "\n");
                        }
                        if (error.getCodeContext() != null) {
                            errorText.append("Error code context=" + error.getCodeContext() + "\n");
                        }

                        // Error code location (i.e., stack trace) only to be logged to IExHub error file
                        patientDataResponse.getErrorMsgs().add(errorText.toString());

                        if (error.getLocation() != null) {
                            errorText.append("Error location=" + error.getLocation());
                        }

                        log.error(errorText.toString());
                    }
                }

                // Try to retrieve documents...
                RegistryObjectListType registryObjectList = registryResponse.getRegistryObjectList();
                IdentifiableType[] documentObjects = registryObjectList.getIdentifiable();
                if ((documentObjects != null) && (documentObjects.length > 0)) {
                    log.info("Documents found in the registry, retrieving them from the repository...");

                    HashMap<String, String> documents = new HashMap<String, String>();
                    for (IdentifiableType identifiable : documentObjects) {
                        if (identifiable.getClass().equals(ExtrinsicObjectType.class)) {
                            // Determine if the "home" attribute (homeCommunityId in XCA parlance) is present...
                            String home = ((((ExtrinsicObjectType) identifiable).getHome() != null)
                                    && (((ExtrinsicObjectType) identifiable).getHome().getPath().length() > 0))
                                            ? ((ExtrinsicObjectType) identifiable).getHome().getPath()
                                            : null;

                            ExternalIdentifierType[] externalIdentifiers = ((ExtrinsicObjectType) identifiable)
                                    .getExternalIdentifier();

                            // Find the ExternalIdentifier that has the "XDSDocumentEntry.uniqueId" value...
                            String uniqueId = null;
                            for (ExternalIdentifierType externalIdentifier : externalIdentifiers) {
                                String val = externalIdentifier.getName().getInternationalStringTypeSequence()[0]
                                        .getLocalizedString().getValue().getFreeFormText();
                                if ((val != null) && (val.compareToIgnoreCase("XDSDocumentEntry.uniqueId") == 0)) {
                                    log.info("Located XDSDocumentEntry.uniqueId ExternalIdentifier, uniqueId="
                                            + uniqueId);
                                    uniqueId = externalIdentifier.getValue().getLongName();
                                    break;
                                }
                            }

                            if (uniqueId != null) {
                                documents.put(uniqueId, home);
                                log.info("Document ID added: " + uniqueId + ", homeCommunityId: " + home);
                            }
                        } else {
                            String home = ((identifiable.getHome() != null)
                                    && (identifiable.getHome().getPath().length() > 0))
                                            ? identifiable.getHome().getPath()
                                            : null;
                            documents.put(identifiable.getId().getPath(), home);
                            log.info("Document ID added: " + identifiable.getId().getPath() + ", homeCommunityId: "
                                    + home);
                        }
                    }

                    log.info("Invoking XdsB repository connector retrieval...");
                    RetrieveDocumentSetResponse documentSetResponse = xdsB
                            .retrieveDocumentSet(xdsBRepositoryUniqueId, documents, patientId);
                    log.info("XdsB repository connector retrieval succeeded");

                    // Invoke appropriate map(s) to process documents in documentSetResponse...
                    if (documentSetResponse.getRetrieveDocumentSetResponse()
                            .getRetrieveDocumentSetResponseTypeSequence_type0() != null) {
                        DocumentResponse_type0[] docResponseArray = documentSetResponse
                                .getRetrieveDocumentSetResponse().getRetrieveDocumentSetResponseTypeSequence_type0()
                                .getDocumentResponse();
                        if (docResponseArray != null) {
                            jsonOutput.append("{\"Documents\":[");
                            boolean first = true;
                            try {
                                for (DocumentResponse_type0 document : docResponseArray) {
                                    if (!first) {
                                        jsonOutput.append(",");
                                    }
                                    first = false;

                                    log.info("Processing document ID="
                                            + document.getDocumentUniqueId().getLongName());

                                    String mimeType = docResponseArray[0].getMimeType().getLongName();
                                    if (mimeType.compareToIgnoreCase("text/xml") == 0) {
                                        final String filename = this.testOutputPath + "/"
                                                + document.getDocumentUniqueId().getLongName() + ".xml";
                                        log.info("Persisting document to filesystem, filename=" + filename);
                                        DataHandler dh = document.getDocument();
                                        File file = new File(filename);
                                        FileOutputStream fileOutStream = new FileOutputStream(file);
                                        dh.writeTo(fileOutStream);
                                        fileOutStream.close();

                                        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
                                        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
                                        Document doc = dBuilder.parse(new FileInputStream(filename));
                                        XPath xPath = XPathFactory.newInstance().newXPath();

                                        //set namespace to xpath
                                        xPath.setNamespaceContext(new NamespaceContext() {
                                            private final String uri = "urn:hl7-org:v3";
                                            private final String prefix = "hl7";

                                            @Override
                                            public String getNamespaceURI(String prefix) {
                                                return this.prefix.equals(prefix) ? uri : null;
                                            }

                                            @Override
                                            public String getPrefix(String namespaceURI) {
                                                return this.uri.equals(namespaceURI) ? this.prefix : null;
                                            }

                                            @Override
                                            public Iterator getPrefixes(String namespaceURI) {
                                                return null;
                                            }
                                        });

                                        NodeList nodes = (NodeList) xPath.evaluate(
                                                "/hl7:ClinicalDocument/hl7:templateId", doc.getDocumentElement(),
                                                XPathConstants.NODESET);

                                        boolean templateFound = false;
                                        if (nodes.getLength() > 0) {
                                            log.info("Searching for /ClinicalDocument/templateId, document ID="
                                                    + document.getDocumentUniqueId().getLongName());

                                            for (int i = 0; i < nodes.getLength(); ++i) {
                                                String val = ((Element) nodes.item(i)).getAttribute("root");
                                                if ((val != null) && (val.compareToIgnoreCase(
                                                        "2.16.840.1.113883.10.20.22.1.2") == 0)) {
                                                    log.info("/ClinicalDocument/templateId node found, document ID="
                                                            + document.getDocumentUniqueId().getLongName());

                                                    log.info("Invoking XSL transform, document ID="
                                                            + document.getDocumentUniqueId().getLongName());

                                                    DocumentBuilderFactory factory = DocumentBuilderFactory
                                                            .newInstance();
                                                    factory.setNamespaceAware(true);
                                                    DocumentBuilder builder = factory.newDocumentBuilder();
                                                    Document mappedDoc = builder.parse(new File(filename));
                                                    DOMSource source = new DOMSource(mappedDoc);

                                                    TransformerFactory transformerFactory = TransformerFactory
                                                            .newInstance();

                                                    Transformer transformer = transformerFactory
                                                            .newTransformer(new StreamSource(
                                                                    GetPatientDataService.cdaToJsonTransformXslt));
                                                    final String jsonFilename = this.testOutputPath + "/"
                                                            + document.getDocumentUniqueId().getLongName()
                                                            + ".json";
                                                    File jsonFile = new File(jsonFilename);
                                                    FileOutputStream jsonFileOutStream = new FileOutputStream(
                                                            jsonFile);
                                                    StreamResult result = new StreamResult(jsonFileOutStream);
                                                    transformer.transform(source, result);
                                                    jsonFileOutStream.close();

                                                    log.info("Successfully transformed CCDA to JSON, filename="
                                                            + jsonFilename);

                                                    jsonOutput.append(new String(readAllBytes(get(jsonFilename))));

                                                    templateFound = true;
                                                }
                                            }
                                        }

                                        if (!templateFound) {
                                            // Document doesn't match the template ID - add to error list...
                                            patientDataResponse.getErrorMsgs().add(
                                                    "Document retrieved doesn't match required template ID - document ID="
                                                            + document.getDocumentUniqueId().getLongName());
                                        }
                                    } else {
                                        patientDataResponse.getErrorMsgs()
                                                .add("Document retrieved is not XML - document ID="
                                                        + document.getDocumentUniqueId().getLongName());
                                    }
                                }
                            } catch (Exception e) {
                                log.error("Error encountered, " + e.getMessage());
                                throw e;
                            }
                        }
                    }

                    if (jsonOutput.length() > 0) {
                        jsonOutput.append("]}");
                    }
                }
            } catch (Exception e) {
                log.error("Error encountered, " + e.getMessage());
                throw new UnexpectedServerException("Error - " + e.getMessage());
            }
        } else {
            // Return test document when testMode is true
            try {
                retVal = FileUtils.readFileToString(new File(GetPatientDataService.testJSONDocumentPathname));
                return Response.status(Response.Status.OK).entity(retVal).type(MediaType.APPLICATION_JSON).build();
            } catch (Exception e) {
                throw new UnexpectedServerException("Error - " + e.getMessage());
            }
        }

        return Response.status(Response.Status.OK).entity(jsonOutput.toString()).type(MediaType.APPLICATION_JSON)
                .build();
    }

    @GET
    @Path("/ccd")
    @Produces({ MediaType.APPLICATION_JSON })
    public Response getCCD(@Context HttpHeaders headers) {
        log.info("Entered getPatientData service");

        boolean tls = false;
        tls = (IExHubConfig.getProperty("XdsBRegistryEndpointURI") == null) ? false
                : ((IExHubConfig.getProperty("XdsBRegistryEndpointURI").toLowerCase().contains("https") ? true
                        : false));
        GetPatientDataService.testMode = IExHubConfig.getProperty("TestMode", GetPatientDataService.testMode);
        GetPatientDataService.testJSONDocumentPathname = IExHubConfig.getProperty("TestJSONDocumentPathname",
                GetPatientDataService.testJSONDocumentPathname);
        GetPatientDataService.cdaToJsonTransformXslt = IExHubConfig.getProperty("CDAToJSONTransformXSLT",
                GetPatientDataService.cdaToJsonTransformXslt);
        GetPatientDataService.iExHubDomainOid = IExHubConfig.getProperty("IExHubDomainOID",
                GetPatientDataService.iExHubDomainOid);
        GetPatientDataService.iExHubAssigningAuthority = IExHubConfig.getProperty("IExHubAssigningAuthority",
                GetPatientDataService.iExHubAssigningAuthority);
        GetPatientDataService.xdsBRepositoryUniqueId = IExHubConfig.getProperty("XdsBRepositoryUniqueId",
                GetPatientDataService.xdsBRepositoryUniqueId);

        String retVal = "";
        GetPatientDataResponse patientDataResponse = new GetPatientDataResponse();
        DocumentsResponseDto documentsResponseDto = new DocumentsResponseDto();
        List<PatientDocument> patientDocuments = new ArrayList<>();

        if (!testMode) {
            try {
                if (xdsB == null) {
                    log.info("Instantiating XdsB connector...");
                    xdsB = new XdsB(null, null, tls);
                    log.info("XdsB connector successfully started");
                }
            } catch (Exception e) {
                log.error("Error encountered instantiating XdsB connector, " + e.getMessage());
                throw new UnexpectedServerException("Error - " + e.getMessage());
            }

            try {
                MultivaluedMap<String, String> headerParams = headers.getRequestHeaders();
                String ssoAuth = headerParams.getFirst("ssoauth");

                log.info("HTTP headers successfully retrieved");
                String[] splitPatientId = ssoAuth.split("&LastName=");
                String patientId = (splitPatientId[0].split("=").length == 2) ? splitPatientId[0].split("=")[1]
                        : null;

                String[] parts = splitPatientId[1].split("&");
                String lastName = (parts[0].length() > 0) ? parts[0] : null;
                String firstName = (parts[1].split("=").length == 2) ? parts[1].split("=")[1] : null;
                String middleName = (parts[2].split("=").length == 2) ? parts[2].split("=")[1] : null;
                String dateOfBirth = (parts[3].split("=").length == 2) ? parts[3].split("=")[1] : null;
                String gender = (parts[4].split("=").length == 2) ? parts[4].split("=")[1] : null;
                String motherMaidenName = (parts[5].split("=").length == 2) ? parts[5].split("=")[1] : null;
                String addressStreet = (parts[6].split("=").length == 2) ? parts[6].split("=")[1] : null;
                String addressCity = (parts[7].split("=").length == 2) ? parts[7].split("=")[1] : null;
                String addressState = (parts[8].split("=").length == 2) ? parts[8].split("=")[1] : null;
                String addressPostalCode = (parts[9].split("=").length == 2) ? parts[9].split("=")[1] : null;
                String otherIDsScopingOrganization = (parts[10].split("=").length == 2) ? parts[10].split("=")[1]
                        : null;
                String startDate = (parts[11].split("=").length == 2) ? parts[11].split("=")[1] : null;
                String endDate = (parts[12].split("=").length == 2) ? parts[12].split("=")[1] : null;

                log.info("HTTP headers successfully parsed, now calling XdsB registry...");

                // Determine if a complete patient ID (including OID and ISO specification) was provided.  If not, then append IExHubDomainOid and IExAssigningAuthority...
                if (!patientId.contains("^^^&")) {
                    patientId = "'" + patientId + "^^^&" + GetPatientDataService.iExHubDomainOid + "&"
                            + GetPatientDataService.iExHubAssigningAuthority + "'";
                }

                AdhocQueryResponse registryResponse = xdsB.registryStoredQuery(patientId,
                        (startDate != null) ? DateFormat.getDateInstance().format(startDate) : null,
                        (endDate != null) ? DateFormat.getDateInstance().format(endDate) : null);

                log.info("Call to XdsB registry successful");

                // Determine if registry server returned any errors...
                if ((registryResponse.getRegistryErrorList() != null)
                        && (registryResponse.getRegistryErrorList().getRegistryError().length > 0)) {

                    for (RegistryError_type0 error : registryResponse.getRegistryErrorList().getRegistryError()) {
                        StringBuilder errorText = new StringBuilder();
                        if (error.getErrorCode() != null) {
                            errorText.append("Error code=" + error.getErrorCode() + "\n");
                        }
                        if (error.getCodeContext() != null) {
                            errorText.append("Error code context=" + error.getCodeContext() + "\n");
                        }

                        // Error code location (i.e., stack trace) only to be logged to IExHub error file
                        patientDataResponse.getErrorMsgs().add(errorText.toString());

                        if (error.getLocation() != null) {
                            errorText.append("Error location=" + error.getLocation());
                        }
                        log.error(errorText.toString());
                    }
                }

                // Try to retrieve documents...
                RegistryObjectListType registryObjectList = registryResponse.getRegistryObjectList();
                IdentifiableType[] documentObjects = registryObjectList.getIdentifiable();
                if ((documentObjects != null) && (documentObjects.length > 0)) {
                    log.info("Documents found in the registry, retrieving them from the repository...");

                    HashMap<String, String> documents = new HashMap<String, String>();
                    for (IdentifiableType identifiable : documentObjects) {
                        if (identifiable.getClass().equals(ExtrinsicObjectType.class)) {
                            // Determine if the "home" attribute (homeCommunityId in XCA parlance) is present...
                            String home = ((((ExtrinsicObjectType) identifiable).getHome() != null)
                                    && (((ExtrinsicObjectType) identifiable).getHome().getPath().length() > 0))
                                            ? ((ExtrinsicObjectType) identifiable).getHome().getPath()
                                            : null;

                            ExternalIdentifierType[] externalIdentifiers = ((ExtrinsicObjectType) identifiable)
                                    .getExternalIdentifier();

                            // Find the ExternalIdentifier that has the "XDSDocumentEntry.uniqueId" value...
                            String uniqueId = null;
                            for (ExternalIdentifierType externalIdentifier : externalIdentifiers) {
                                String val = externalIdentifier.getName().getInternationalStringTypeSequence()[0]
                                        .getLocalizedString().getValue().getFreeFormText();
                                if ((val != null) && (val.compareToIgnoreCase("XDSDocumentEntry.uniqueId") == 0)) {
                                    log.info("Located XDSDocumentEntry.uniqueId ExternalIdentifier, uniqueId="
                                            + uniqueId);
                                    uniqueId = externalIdentifier.getValue().getLongName();
                                    break;
                                }
                            }

                            if (uniqueId != null) {
                                documents.put(uniqueId, home);
                                log.info("Document ID added: " + uniqueId + ", homeCommunityId: " + home);
                            }
                        } else {
                            String home = ((identifiable.getHome() != null)
                                    && (identifiable.getHome().getPath().length() > 0))
                                            ? identifiable.getHome().getPath()
                                            : null;
                            documents.put(identifiable.getId().getPath(), home);
                            log.info("Document ID added: " + identifiable.getId().getPath() + ", homeCommunityId: "
                                    + home);
                        }
                    }

                    log.info("Invoking XdsB repository connector retrieval...");
                    RetrieveDocumentSetResponse documentSetResponse = xdsB
                            .retrieveDocumentSet(xdsBRepositoryUniqueId, documents, patientId);
                    log.info("XdsB repository connector retrieval succeeded");

                    // Invoke appropriate map(s) to process documents in documentSetResponse...
                    if (documentSetResponse.getRetrieveDocumentSetResponse()
                            .getRetrieveDocumentSetResponseTypeSequence_type0() != null) {
                        DocumentResponse_type0[] docResponseArray = documentSetResponse
                                .getRetrieveDocumentSetResponse().getRetrieveDocumentSetResponseTypeSequence_type0()
                                .getDocumentResponse();
                        if (docResponseArray != null) {
                            try {
                                for (DocumentResponse_type0 document : docResponseArray) {
                                    log.info("Processing document ID="
                                            + document.getDocumentUniqueId().getLongName());

                                    String mimeType = docResponseArray[0].getMimeType().getLongName();
                                    if (mimeType.compareToIgnoreCase("text/xml") == 0) {
                                        DataHandler dh = document.getDocument();
                                        String documentStr = dh.getContent().toString();
                                        String documentName = document.getDocumentUniqueId().getLongName();
                                        PatientDocument patientDocument = new PatientDocument(documentName,
                                                documentStr);
                                        patientDocuments.add(patientDocument);
                                    } else {
                                        patientDataResponse.getErrorMsgs()
                                                .add("Document retrieved is not XML - document ID="
                                                        + document.getDocumentUniqueId().getLongName());
                                    }
                                }
                            } catch (Exception e) {
                                log.error("Error encountered, " + e.getMessage());
                                throw e;
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("Error encountered, " + e.getMessage());
                throw new UnexpectedServerException("Error - " + e.getMessage());
            }
        } else {
            // Return test document when testMode is true
            try {
                retVal = FileUtils.readFileToString(new File(GetPatientDataService.testJSONDocumentPathname));
                return Response.status(Response.Status.OK).entity(retVal).type(MediaType.APPLICATION_JSON).build();
            } catch (Exception e) {
                throw new UnexpectedServerException("Error - " + e.getMessage());
            }
        }
        documentsResponseDto.setDocuments(patientDocuments);

        return Response.status(Response.Status.OK).entity(documentsResponseDto).type(MediaType.APPLICATION_JSON)
                .build();
    }

    @POST
    @Path("/publish")
    @Produces({ MediaType.APPLICATION_JSON })
    public Response publishDocument(ClinicalDocumentRequest clinicalDocumentRequest) {
        try {
            byte[] document = clinicalDocumentRequest.getDocument();
            String xdsBRegistryEndpointURI = IExHubConfig.getProperty("XdsBRegistryEndpointURI");
            String xdsBRepositoryEndpointURI = IExHubConfig.getProperty("XdsBRepositoryEndpointURI");
            XdsBRepositoryManager XdsBRepository = new XdsBRepositoryManager(xdsBRegistryEndpointURI,
                    xdsBRepositoryEndpointURI);
            XdsBRepository.provideAndRegisterDocumentSet(document, "text/xml");
        } catch (Exception e) {
            String msg = "Error encounter while publishing document to HIE: " + e.getMessage();
            log.error(msg);
            throw new UnexpectedServerException(msg);
        }

        return Response.status(Response.Status.OK).entity(new ClinicalDocumentResponse(true))
                .type(MediaType.APPLICATION_JSON).build();
    }

    private String invokeMap(String sourceFilename) {
        String trgMap = this.testOutputPath + "/PatientPortalMap.xmi";
        String trgMdl = "PatientPortal.CCD";
        String trgMsg = this.testOutputPath + "/PP_minimal.xml";
        String srcMap = null;
        String srcMdl = null;
        String cnvElm = "";
        File sourceDataSetFile = null;

        File rootDir = new File(this.testOutputPath);

        // initialize the runtime, using the current folder as the root folder
        Mdmi.INSTANCE.initialize(rootDir);
        Mdmi.INSTANCE.start();

        String retVal = null;
        try {
            srcMap = this.testOutputPath + "/CCDA.9.1.xmi";
            srcMdl = "CCDMessageGroup.CCD";

            // 1. check to make sure the maps and messages exist
            File f = Mdmi.INSTANCE.fileFromRelPath(srcMap);
            if (!f.exists() || !f.isFile()) {
                throw new SourceMapMissingException("Error - source map file '" + srcMap + "' does not exist");
            } else {
                f = Mdmi.INSTANCE.fileFromRelPath(trgMap);
                if (!f.exists() || !f.isFile()) {
                    throw new TargetMapMissingException("Error - target map file '" + trgMap + "' does not exist");
                } else {
                    sourceDataSetFile = Mdmi.INSTANCE.fileFromRelPath(sourceFilename);
                    if (!sourceDataSetFile.exists() || !sourceDataSetFile.isFile()) {
                        // The source message may be a URI - verify if that's the case...
                        sourceDataSetFile = new File(sourceFilename);
                    }

                    if (!sourceDataSetFile.exists() || !sourceDataSetFile.isFile()) {
                        throw new SourceMsgMissingException(
                                "Error - source message file '" + sourceFilename + "' does not exist");
                    } else {
                        f = Mdmi.INSTANCE.fileFromRelPath(trgMsg);
                        if (!f.exists() || !f.isFile()) {
                            throw new TargetMapMissingException(
                                    "Error - target message file '" + trgMsg + "' does not exist");
                        } else {
                            // 2. make sure the qualified message names are spelled right
                            String[] a = srcMdl.split("\\.");
                            if (a == null || a.length != 2) {
                                throw new InvalidSourceModelException("Error - invalid source model '" + srcMdl
                                        + "', must be formatted as MapName.MessageName");
                            } else {
                                String srcMapName = a[0];
                                String srcMsgMdl = a[1];

                                a = trgMdl.split("\\.");
                                if (a == null || a.length != 2) {
                                    throw new InvalidTargetModelException("Error - invalid target model '" + trgMdl
                                            + "', must be formatted as MapName.MessageName");
                                } else {
                                    try {
                                        String trgMapName = a[0];
                                        String trgMsgMdl = a[1];

                                        // 3. parse the elements array
                                        final ArrayList<String> elements = new ArrayList<String>();
                                        String[] ss = cnvElm.split(";");
                                        for (String s : ss) {
                                            if (s != null && s.trim().length() > 0) {
                                                elements.add(s);
                                            }
                                        }

                                        // 4. load the maps into the runtime.
                                        Mdmi.INSTANCE.getConfig()
                                                .putMapInfo(new MdmiConfig.MapInfo(srcMapName, srcMap));
                                        Mdmi.INSTANCE.getConfig()
                                                .putMapInfo(new MdmiConfig.MapInfo(trgMapName, trgMap));
                                        Mdmi.INSTANCE.getResolver().resolveConfig(Mdmi.INSTANCE.getConfig());

                                        // 5. Construct the parameters to the call based on the values passed in
                                        MdmiModelRef sMod = new MdmiModelRef(srcMapName, srcMsgMdl);
                                        MdmiMessage sMsg = new MdmiMessage(sourceDataSetFile);
                                        MdmiModelRef tMod = new MdmiModelRef(trgMapName, trgMsgMdl);
                                        MdmiMessage tMsg = new MdmiMessage(Mdmi.INSTANCE.fileFromRelPath(trgMsg));

                                        Map<String, MdmiBusinessElementReference> left = sMod.getModel()
                                                .getBusinessElementHashMap();

                                        Map<String, MdmiBusinessElementReference> right = tMod.getModel()
                                                .getBusinessElementHashMap();

                                        Equivalence<MdmiBusinessElementReference> valueEquivalence = new Equivalence<MdmiBusinessElementReference>() {
                                            @Override
                                            protected boolean doEquivalent(MdmiBusinessElementReference a,
                                                    MdmiBusinessElementReference b) {
                                                return a.getUniqueIdentifier().equals(b.getUniqueIdentifier());
                                            }

                                            @Override
                                            protected int doHash(MdmiBusinessElementReference t) {
                                                return t.getUniqueIdentifier().hashCode();
                                            }
                                        };

                                        MapDifference<String, MdmiBusinessElementReference> differences = Maps
                                                .difference(left, right, valueEquivalence);

                                        Predicate<MdmiBusinessElementReference> predicate = new Predicate<MdmiBusinessElementReference>() {
                                            @Override
                                            public boolean apply(MdmiBusinessElementReference input) {

                                                if (!elements.isEmpty()) {
                                                    for (String element : elements) {
                                                        if (input.getName().equalsIgnoreCase(element)) {
                                                            return true;
                                                        }

                                                    }
                                                    return false;
                                                }
                                                return true;

                                            }
                                        };
                                        ;

                                        ArrayList<MdmiBusinessElementReference> bers = new ArrayList<MdmiBusinessElementReference>();
                                        bers.addAll(Collections2.filter(differences.entriesInCommon().values(),
                                                predicate));

                                        MdmiTransferInfo ti = new MdmiTransferInfo(sMod, sMsg, tMod, tMsg, bers);
                                        ti.useDictionary = true;

                                        // 6. call the runtime
                                        Mdmi.INSTANCE.executeTransfer(ti);

                                        // 7. set the return value
                                        retVal = tMsg.getDataAsString();
                                    } catch (Exception e) {
                                        throw new MessageTransformException(e.getMessage());
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (InvalidSourceModelException | InvalidTargetModelException | MessageTransformException
                | SourceMapMissingException | SourceMsgMissingException | TargetMapMissingException ex) {
            throw ex;
        } catch (Exception ex) {
            throw ex;
        } finally {
            Mdmi.INSTANCE.stop();
        }

        return retVal;
    }
}