se.skl.skltpservices.npoadapter.mapper.AbstractMapper.java Source code

Java tutorial

Introduction

Here is the source code for se.skl.skltpservices.npoadapter.mapper.AbstractMapper.java

Source

/**
 * Copyright (c) 2014 Inera AB, <http://inera.se/>
 *
 * This file is part of SKLTP.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package se.skl.skltpservices.npoadapter.mapper;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBElement;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.commons.lang.StringUtils;
import org.mule.api.MuleMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.soitoolkit.commons.mule.jaxb.JaxbUtil;
import org.xml.sax.SAXException;

import riv.ehr.patientsummary.getehrextractresponder._1.GetEhrExtractResponseType;
import riv.ehr.patientsummary.getehrextractresponder._1.GetEhrExtractType;
import se.rivta.en13606.ehrextract.v11.EHREXTRACT;
import se.rivta.en13606.ehrextract.v11.IDENTIFIEDENTITY;
import se.rivta.en13606.ehrextract.v11.IDENTIFIEDHEALTHCAREPROFESSIONAL;
import se.rivta.en13606.ehrextract.v11.ORGANISATION;
import se.rivta.en13606.ehrextract.v11.ObjectFactory;
import se.rivta.en13606.ehrextract.v11.RIV13606REQUESTEHREXTRACTRequestType;
import se.rivta.en13606.ehrextract.v11.RIV13606REQUESTEHREXTRACTResponseType;
import se.rivta.en13606.ehrextract.v11.ST;
import se.skl.skltpservices.npoadapter.mapper.util.EHRUtil;
import se.skl.skltpservices.npoadapter.mapper.util.SharedHeaderExtract;

/**
 * Abstracts all mapper implementations.
 *
 * @see se.skl.skltpservices.npoadapter.mapper.Mapper
 * @see se.skl.skltpservices.npoadapter.mapper.XMLBeanMapper
 *
 * @author Peter
 */
public abstract class AbstractMapper {

    protected static final Logger log = LoggerFactory.getLogger(AbstractMapper.class);

    // context for baseline (en 13606)
    private static final JaxbUtil enEhrExtractTypeJaxbUtil = new JaxbUtil("se.rivta.en13606.ehrextract.v11");
    private static final ObjectFactory enObjectFactory = new ObjectFactory();

    // context for the riv alternative
    private static final JaxbUtil rivEhrExtractTypeJaxbUtil = new JaxbUtil(
            "riv.itintegration.registry._1:riv.ehr.patientsummary._1:riv.ehr.patientsummary.getehrextractresponder._1");
    private static final riv.ehr.patientsummary.getehrextractresponder._1.ObjectFactory rivEhrExtractTypeObjectFactory = new riv.ehr.patientsummary.getehrextractresponder._1.ObjectFactory();

    // main supported information types,
    public static final String INFO_VKO = "vko";
    public static final String INFO_VOO = "voo";
    public static final String INFO_DIA = "dia";
    public static final String INFO_LKM_ORD = "lkm-ord";
    public static final String INFO_UND_KKM_KLI = "und-kkm-kli";
    public static final String INFO_UND_BDI = "und-bdi";
    public static final String INFO_UND_KON = "und-kon";
    public static final String INFO_UPP = "upp";

    static final String NS_EN_EXTRACT = "urn:riv13606:v1.1:RIV13606REQUEST_EHR_EXTRACT";
    public static final String NS_RIV_EXTRACT = "urn:riv:ehr:patientsummary:GetEhrExtractResponder:1:GetEhrExtract";

    static final String NS_ALERT_2 = "urn:riv:clinicalprocess:healthcond:description:GetAlertInformation:2:rivtabp21";
    static final String NS_CARECONTACTS_2 = "urn:riv:clinicalprocess:logistics:logistics:GetCareContacts:2:rivtabp21";
    static final String NS_CAREDOCUMENTATION_2 = "urn:riv:clinicalprocess:healthcond:description:GetCareDocumentation:2:rivtabp21";
    static final String NS_DIAGNOSIS_2 = "urn:riv:clinicalprocess:healthcond:description:GetDiagnosis:2:rivtabp21";
    static final String NS_IMAGING_1 = "urn:riv:clinicalprocess:healthcond:actoutcome:GetImagingOutcome:1:rivtabp21";
    static final String NS_LABORATORY_3 = "urn:riv:clinicalprocess:healthcond:actoutcome:GetLaboratoryOrderOutcome:3:rivtabp21";
    static final String NS_MEDICATIONHISTORY = "urn:riv:clinicalprocess:activityprescription:actoutcome:GetMedicationHistory:2:rivtabp21";
    static final String NS_REFERRALOUTCOME = "urn:riv:clinicalprocess:healthcond:actoutcome:GetReferralOutcome:3:rivtabp21";

    protected boolean schemaValidationActivated = false;

    private Schema schema; // each implementation instance will have its own schema

    // mapper implementation hash map with RIV service contract operation names (from WSDL) as a key
    private static final HashMap<String, Mapper> map = new HashMap<String, Mapper>();
    static {
        // alertinformation
        map.put(mapperKey(NS_EN_EXTRACT, NS_ALERT_2), new AlertInformationMapper());
        map.put(mapperKey(NS_RIV_EXTRACT, NS_ALERT_2), new RIVAlertInformationMapper());

        // carecontacts
        map.put(mapperKey(NS_EN_EXTRACT, NS_CARECONTACTS_2), new CareContactsMapper());
        map.put(mapperKey(NS_RIV_EXTRACT, NS_CARECONTACTS_2), new RIVCareContactsMapper());

        // caredocumentation
        map.put(mapperKey(NS_EN_EXTRACT, NS_CAREDOCUMENTATION_2), new CareDocumentationMapper());
        map.put(mapperKey(NS_RIV_EXTRACT, NS_CAREDOCUMENTATION_2), new RIVCareDocumentationMapper());

        // diagnosis
        map.put(mapperKey(NS_EN_EXTRACT, NS_DIAGNOSIS_2), new DiagnosisMapper());
        map.put(mapperKey(NS_RIV_EXTRACT, NS_DIAGNOSIS_2), new RIVDiagnosisMapper());

        // laboratoryorderoutcome
        map.put(mapperKey(NS_EN_EXTRACT, NS_LABORATORY_3), new LaboratoryOrderOutcomeMapper());
        map.put(mapperKey(NS_RIV_EXTRACT, NS_LABORATORY_3), new RIVLaboratoryOrderOutcomeMapper());

        // imagingoutcome
        map.put(mapperKey(NS_EN_EXTRACT, NS_IMAGING_1), new ImagingOutcomeMapper());
        map.put(mapperKey(NS_RIV_EXTRACT, NS_IMAGING_1), new RIVImagingOutcomeMapper());

        // medicationhistory
        map.put(mapperKey(NS_EN_EXTRACT, NS_MEDICATIONHISTORY), new MedicationHistoryMapper());
        map.put(mapperKey(NS_RIV_EXTRACT, NS_MEDICATIONHISTORY), new RIVMedicationHistoryMapper());

        // referraloutcome
        map.put(mapperKey(NS_EN_EXTRACT, NS_REFERRALOUTCOME), new ReferralOutcomeMapper());
        map.put(mapperKey(NS_RIV_EXTRACT, NS_REFERRALOUTCOME), new RIVReferralOutcomeMapper());
    }

    /**
     * Returns the actual mapper instance by the name of the (inbound SOAP) service operation.
     *
     * @param sourceNS the source service contract namespace.
     * @param  targetNS the target service contract namespace.
     * @return the corresponding mapper.
     * @throws java.lang.IllegalStateException when no mapper matches the name of the operation.
     */
    public static Mapper getInstance(final String sourceNS, final String targetNS) {
        assert (sourceNS != null) && (targetNS != null);
        final String key = mapperKey(sourceNS, targetNS);
        final Mapper mapper = map.get(key);
        log.debug("Lookup mapper for key: \"{}\" -> {}", key, mapper);
        if (mapper == null) {
            throw new IllegalStateException("Unable to lookup mapper for operation: \"" + key + "\"");
        }
        return mapper;
    }

    /**
     * Returns the {@link javax.xml.stream.XMLStreamReader} from the message.
     *
     * @param message the message.
     * @return the payload as the expected reader.
     */
    protected XMLStreamReader payloadAsXMLStreamReader(final MuleMessage message) {
        if (message.getPayload() instanceof Object[]) {
            final Object[] payload = (Object[]) message.getPayload();
            if (payload.length > 1 && payload[1] instanceof XMLStreamReader) {
                return (XMLStreamReader) payload[1];
            }
        } else if (message.getPayload() instanceof XMLStreamReader) {
            return (XMLStreamReader) message.getPayload();
        }
        throw new IllegalArgumentException(
                "Unexpected type of message payload (an Object[] with XMLStreamReader was expected): "
                        + message.getPayload());
    }

    //
    private static String mapperKey(final String src, final String dst) {
        return src + "-" + dst;
    }

    //
    protected RIV13606REQUESTEHREXTRACTResponseType riv13606REQUESTEHREXTRACTResponseType(
            final XMLStreamReader reader) {
        try {
            return (RIV13606REQUESTEHREXTRACTResponseType) enEhrExtractTypeJaxbUtil.unmarshal(reader);
        } finally {
            close(reader);
        }
    }

    //
    protected String riv13606REQUESTEHREXTRACTRequestType(final RIV13606REQUESTEHREXTRACTRequestType request) {
        final JAXBElement<RIV13606REQUESTEHREXTRACTRequestType> el = enObjectFactory
                .createRIV13606REQUESTEHREXTRACTRequest(request);
        return enEhrExtractTypeJaxbUtil.marshal(el);
    }

    //
    protected GetEhrExtractResponseType ehrExtractResponseType(final XMLStreamReader reader) {
        try {
            return (GetEhrExtractResponseType) rivEhrExtractTypeJaxbUtil.unmarshal(reader);
        } finally {
            close(reader);
        }
    }

    //
    protected String ehrExtractType(final GetEhrExtractType request) {
        final JAXBElement<GetEhrExtractType> el = rivEhrExtractTypeObjectFactory.createGetEhrExtract(request);
        return rivEhrExtractTypeJaxbUtil.marshal(el);
    }

    //
    protected void close(final XMLStreamReader reader) {
        try {
            reader.close();
        } catch (XMLStreamException | NullPointerException e) {
            ;
        }
    }

    protected SharedHeaderExtract extractInformation(final EHREXTRACT ehrExtract) {
        final Map<String, ORGANISATION> orgs = new LinkedHashMap<String, ORGANISATION>(); // LinkedHashMap preserves insertion order
        final Map<String, IDENTIFIEDHEALTHCAREPROFESSIONAL> hps = new LinkedHashMap<String, IDENTIFIEDHEALTHCAREPROFESSIONAL>();

        for (IDENTIFIEDENTITY entity : ehrExtract.getDemographicExtract()) {

            if (entity instanceof ORGANISATION) {
                final ORGANISATION org = (ORGANISATION) entity;
                if (org.getExtractId() != null) {
                    orgs.put(org.getExtractId().getExtension(), org);
                }
            }
            if (entity instanceof IDENTIFIEDHEALTHCAREPROFESSIONAL) {
                final IDENTIFIEDHEALTHCAREPROFESSIONAL hp = (IDENTIFIEDHEALTHCAREPROFESSIONAL) entity;
                if (hp.getExtractId() != null) {
                    hps.put(hp.getExtractId().getExtension(), hp);
                }
            }
        }

        return new SharedHeaderExtract(orgs, hps, EHRUtil.getSystemHSAId(ehrExtract), ehrExtract.getSubjectOfCare(),
                ehrExtract.getTimeCreated());
    }

    protected void initialiseValidator(String... xsds) {
        List<Source> schemaFiles = new ArrayList<Source>();
        for (String xsd : xsds) {
            schemaFiles.add(new StreamSource(getClass().getResourceAsStream(xsd)));
        }

        // Note - SchemaFactory is not threadsafe
        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        try {
            // Note - Schema is threadsafe
            schema = factory.newSchema(schemaFiles.toArray(new StreamSource[schemaFiles.size()]));
        } catch (SAXException s) {
            throw new RuntimeException(
                    new InstantiationException("Failed to instantiate schema: " + s.getMessage()));
        }

    }

    protected void validateXmlAgainstSchema(String xml, Logger log) {
        if (schemaValidationActivated) {
            if (StringUtils.isBlank(xml)) {
                log.error("Attempted to validate empty string");
            } else {
                try {
                    // Validator is not threadsafe - create new one for each invocation
                    Validator validator = schema.newValidator();
                    validator.validate(new StreamSource(new StringReader(xml)));
                    log.debug("response passed schema validation");
                } catch (SAXException e) {
                    log.error("response failed schema validation: " + e.getMessage());
                    log.debug(xml);
                } catch (IOException e) {
                    throw new RuntimeException("Unexpected exception whilst validating xml against schema", e);
                } catch (Exception e) {
                    log.error("response failed schema validation - unexpected error " + e.getMessage(), e);
                }
            }
        }
    }

    // Does the response contain a non-blank continuation token?
    // We have no test data to see what a continuation token looks like - meanwhile this is the default implementation.
    protected boolean continuation(RIV13606REQUESTEHREXTRACTResponseType response13606) {
        ST continuation = response13606.getContinuationToken();
        if (continuation != null) {
            if (StringUtils.isNotBlank(continuation.getValue())) {
                return true;
            }
        }
        return false;
    }

    protected void checkContinuation(Logger log, RIV13606REQUESTEHREXTRACTResponseType response13606) {
        if (continuation(response13606)) {
            log.warn("Continuation token detected - response is not complete, continuation will be ignored");
        }
    }

}