com.indivica.olis.Driver.java Source code

Java tutorial

Introduction

Here is the source code for com.indivica.olis.Driver.java

Source

/**
 * Copyright (c) 2008-2012 Indivica Inc.
 *
 * This software is made available under the terms of the
 * GNU General Public License, Version 2, 1991 (GPLv2).
 * License details are available via "indivica.ca/gplv2"
 * and "gnu.org/licenses/gpl-2.0.html".
 */

package com.indivica.olis;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.SchemaFactory;

import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.DefaultSignedAttributeTableGenerator;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
import org.oscarehr.common.dao.OscarLogDao;
import org.oscarehr.common.model.OscarLog;
import org.oscarehr.util.LoggedInInfo;
import org.oscarehr.util.MiscUtils;
import org.oscarehr.util.SpringUtils;
import org.xml.sax.InputSource;

import oscar.OscarProperties;
import oscar.oscarMessenger.data.MsgProviderData;
import ca.ssha._2005.hial.ArrayOfError;
import ca.ssha._2005.hial.ArrayOfString;
import ca.ssha._2005.hial.Response;
import ca.ssha.www._2005.hial.OLISStub;
import ca.ssha.www._2005.hial.OLISStub.HIALRequest;
import ca.ssha.www._2005.hial.OLISStub.HIALRequestSignedRequest;
import ca.ssha.www._2005.hial.OLISStub.OLISRequest;
import ca.ssha.www._2005.hial.OLISStub.OLISRequestResponse;

import com.indivica.olis.queries.Query;

public class Driver {

    private static OscarLogDao logDao = (OscarLogDao) SpringUtils.getBean("oscarLogDao");

    public static String submitOLISQuery(HttpServletRequest request, Query query) {
        try {
            OLISMessage message = new OLISMessage(query);

            System.setProperty("javax.net.ssl.keyStore",
                    OscarProperties.getInstance().getProperty("olis_ssl_keystore").trim());
            System.setProperty("javax.net.ssl.keyStorePassword",
                    OscarProperties.getInstance().getProperty("olis_ssl_keystore_password").trim());
            System.setProperty("javax.net.ssl.trustStore",
                    OscarProperties.getInstance().getProperty("olis_truststore").trim());
            System.setProperty("javax.net.ssl.trustStorePassword",
                    OscarProperties.getInstance().getProperty("olis_truststore_password").trim());

            OLISRequest olisRequest = new OLISRequest();
            olisRequest.setHIALRequest(new HIALRequest());
            OLISStub olis = new OLISStub();

            olisRequest.getHIALRequest().setClientTransactionID(message.getTransactionId());
            olisRequest.getHIALRequest().setSignedRequest(new HIALRequestSignedRequest());

            String olisHL7String = message.getOlisHL7String().replaceAll("\n", "\r");
            String msgInXML = String.format(
                    "<Request xmlns=\"http://www.ssha.ca/2005/HIAL\"><Content><![CDATA[%s]]></Content></Request>",
                    olisHL7String);

            String signedRequest = Driver.signData(msgInXML);
            olisRequest.getHIALRequest().getSignedRequest().setSignedData(signedRequest);

            try {
                OscarLog logItem = new OscarLog();
                logItem.setAction("OLIS");
                logItem.setContent("query");
                logItem.setData(olisHL7String);

                if (LoggedInInfo.loggedInInfo.get() != null
                        && LoggedInInfo.loggedInInfo.get().loggedInProvider != null)
                    logItem.setProviderNo(LoggedInInfo.loggedInInfo.get().loggedInProvider.getProviderNo());

                logDao.persist(logItem);

            } catch (Exception e) {
                MiscUtils.getLogger().error("Couldn't write log message for OLIS query", e);
            }

            if (OscarProperties.getInstance().getProperty("olis_simulate", "no").equals("yes")) {
                String response = (String) request.getSession().getAttribute("olisResponseContent");
                request.setAttribute("olisResponseContent", response);
                request.getSession().setAttribute("olisResponseContent", null);
                return response;
            } else {
                OLISRequestResponse olisResponse = olis.oLISRequest(olisRequest);

                String signedData = olisResponse.getHIALResponse().getSignedResponse().getSignedData();
                String unsignedData = Driver.unsignData(signedData);
                //MiscUtils.getLogger().info(msgInXML);
                //MiscUtils.getLogger().info("---------------------------------");         
                //MiscUtils.getLogger().info(unsignedData);

                if (request != null) {
                    request.setAttribute("msgInXML", msgInXML);
                    request.setAttribute("signedRequest", signedRequest);
                    request.setAttribute("signedData", signedData);
                    request.setAttribute("unsignedResponse", unsignedData);
                }

                writeToFile(unsignedData);
                readResponseFromXML(request, unsignedData);

                return unsignedData;

            }
        } catch (Exception e) {
            MiscUtils.getLogger().error("Can't perform OLIS query due to exception.", e);
            if (request != null) {
                request.setAttribute("searchException", e);
            }
            notifyOlisError(e.getMessage());
            return "";
        }
    }

    public static void readResponseFromXML(HttpServletRequest request, String olisResponse) {

        olisResponse = olisResponse.replaceAll("<Content", "<Content xmlns=\"\" ");
        olisResponse = olisResponse.replaceAll("<Errors", "<Errors xmlns=\"\" ");

        try {
            DocumentBuilderFactory.newInstance().newDocumentBuilder();
            SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

            Source schemaFile = new StreamSource(
                    new File(OscarProperties.getInstance().getProperty("olis_response_schema")));
            factory.newSchema(schemaFile);

            JAXBContext jc = JAXBContext.newInstance("ca.ssha._2005.hial");
            Unmarshaller u = jc.createUnmarshaller();
            @SuppressWarnings("unchecked")
            Response root = ((JAXBElement<Response>) u.unmarshal(new InputSource(new StringReader(olisResponse))))
                    .getValue();

            if (root.getErrors() != null) {
                List<String> errorStringList = new LinkedList<String>();

                // Read all the errors
                ArrayOfError errors = root.getErrors();
                List<ca.ssha._2005.hial.Error> errorList = errors.getError();

                for (ca.ssha._2005.hial.Error error : errorList) {
                    String errorString = "";
                    errorString += "ERROR " + error.getNumber() + " (" + error.getSeverity() + ") : "
                            + error.getMessage();

                    ArrayOfString details = error.getDetails();
                    List<String> detailList = details.getString();
                    for (String detail : detailList) {
                        errorString += "\n" + detail;
                    }

                    errorStringList.add(errorString);
                }
                if (request != null)
                    request.setAttribute("errors", errorStringList);
            } else if (root.getContent() != null) {
                if (request != null)
                    request.setAttribute("olisResponseContent", root.getContent());
            }
        } catch (Exception e) {
            MiscUtils.getLogger().error("Couldn't read XML from OLIS response.", e);
            notifyOlisError("Couldn't read XML from OLIS response." + "\n" + e);
        }
    }

    public static String unsignData(String data) {

        byte[] dataBytes = Base64.decode(data);

        try {

            CMSSignedData s = new CMSSignedData(dataBytes);
            CertStore certs = s.getCertificatesAndCRLs("Collection", "BC");
            SignerInformationStore signers = s.getSignerInfos();
            @SuppressWarnings("unchecked")
            Collection<SignerInformation> c = signers.getSigners();
            Iterator<SignerInformation> it = c.iterator();
            while (it.hasNext()) {
                X509Certificate cert = null;
                SignerInformation signer = it.next();
                Collection certCollection = certs.getCertificates(signer.getSID());
                @SuppressWarnings("unchecked")
                Iterator<X509Certificate> certIt = certCollection.iterator();
                cert = certIt.next();
                if (!signer.verify(cert.getPublicKey(), "BC"))
                    throw new Exception("Doesn't verify");
            }

            CMSProcessableByteArray cpb = (CMSProcessableByteArray) s.getSignedContent();
            byte[] signedContent = (byte[]) cpb.getContent();
            String content = new String(signedContent);
            return content;
        } catch (Exception e) {
            MiscUtils.getLogger().error("error", e);
        }
        return null;

    }

    public static String signData(String data) {
        X509Certificate cert = null;
        PrivateKey priv = null;
        KeyStore keystore = null;
        String pwd = "Olis2011";
        String result = null;
        try {
            Security.addProvider(new BouncyCastleProvider());

            keystore = KeyStore.getInstance("PKCS12", "SunJSSE");
            // Load the keystore
            keystore.load(new FileInputStream(OscarProperties.getInstance().getProperty("olis_keystore")),
                    pwd.toCharArray());

            Enumeration e = keystore.aliases();
            String name = "";

            if (e != null) {
                while (e.hasMoreElements()) {
                    String n = (String) e.nextElement();
                    if (keystore.isKeyEntry(n)) {
                        name = n;
                    }
                }
            }

            // Get the private key and the certificate
            priv = (PrivateKey) keystore.getKey(name, pwd.toCharArray());
            cert = (X509Certificate) keystore.getCertificate(name);

            // I'm not sure if this is necessary

            Certificate[] certChain = keystore.getCertificateChain(name);
            ArrayList<Certificate> certList = new ArrayList<Certificate>();
            certList.add(cert);
            CertStore certs = null;

            certs = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList), "BC");

            // Encrypt data
            CMSSignedDataGenerator sgen = new CMSSignedDataGenerator();

            // What digest algorithm i must use? SHA1? MD5? RSA?...
            DefaultSignedAttributeTableGenerator attributeGenerator = new DefaultSignedAttributeTableGenerator();
            sgen.addSigner(priv, cert, CMSSignedDataGenerator.DIGEST_SHA1, attributeGenerator, null);

            // I'm not sure this is necessary
            sgen.addCertificatesAndCRLs(certs);

            // I think that the 2nd parameter need to be false (detached form)
            CMSSignedData csd = sgen.generate(new CMSProcessableByteArray(data.getBytes()), true, "BC");

            byte[] signedData = csd.getEncoded();
            byte[] signedDataB64 = Base64.encode(signedData);

            result = new String(signedDataB64);

        } catch (Exception e) {
            MiscUtils.getLogger().error("Can't sign HL7 message for OLIS", e);
        }
        return result;
    }

    private static void notifyOlisError(String errorMsg) {
        HashSet<String> sendToProviderList = new HashSet<String>();

        String providerNoTemp = "999998";
        sendToProviderList.add(providerNoTemp);

        LoggedInInfo loggedInInfo = LoggedInInfo.loggedInInfo.get();
        if (loggedInInfo != null && loggedInInfo.loggedInProvider != null) {
            // manual prompts always send to admin
            sendToProviderList.add(providerNoTemp);

            providerNoTemp = loggedInInfo.loggedInProvider.getProviderNo();
            sendToProviderList.add(providerNoTemp);
        }

        // no one wants to hear about the problem
        if (sendToProviderList.size() == 0)
            return;

        String message = "OSCAR attempted to perform a fetch of OLIS data at " + new Date()
                + " but there was an error during the task.\n\nSee below for the error message:\n" + errorMsg;

        oscar.oscarMessenger.data.MsgMessageData messageData = new oscar.oscarMessenger.data.MsgMessageData();

        ArrayList<MsgProviderData> sendToProviderListData = new ArrayList<MsgProviderData>();
        for (String providerNo : sendToProviderList) {
            MsgProviderData mpd = new MsgProviderData();
            mpd.providerNo = providerNo;
            mpd.locationId = "145";
            sendToProviderListData.add(mpd);
        }

        String sentToString = messageData.createSentToString(sendToProviderListData);
        messageData.sendMessage2(message, "OLIS Retrieval Error", "System", sentToString, "-1",
                sendToProviderListData, null, null);
    }

    static void writeToFile(String data) {
        try {
            File tempFile = new File(System.getProperty("java.io.tmpdir") + (Math.random() * 100) + ".xml");
            PrintWriter pw = new PrintWriter(new FileWriter(tempFile));
            pw.println(data);
            pw.flush();
            pw.close();
        } catch (Exception e) {
            MiscUtils.getLogger().error("Error", e);
        }
    }
}