edu.duke.cabig.c3pr.webservice.integration.StudyImportExportWebServiceTest.java Source code

Java tutorial

Introduction

Here is the source code for edu.duke.cabig.c3pr.webservice.integration.StudyImportExportWebServiceTest.java

Source

/*******************************************************************************
 * Copyright Duke Comprehensive Cancer Center and SemanticBits
 * 
 * Distributed under the OSI-approved BSD 3-Clause License.
 * See http://ncip.github.com/c3pr/LICENSE.txt for details.
 ******************************************************************************/
/**
 * 
 */
package edu.duke.cabig.c3pr.webservice.integration;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URL;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import javax.xml.ws.soap.SOAPFaultException;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.dbunit.Assertion;
import org.dbunit.DatabaseUnitException;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.filter.DefaultColumnFilter;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * This test will run C3PR in embedded Tomcat and test Study Import web service
 * against it. <br>
 * <br>
 * 
 * @author dkrylov
 * @version 1.0
 */
public class StudyImportExportWebServiceTest extends C3PREmbeddedTomcatTestBase {

    private static final String TESTDATA_PACKAGE = "/edu/duke/cabig/c3pr/webservice/integration/" + TESTDATA;
    private static final String SERVICE_NS = "http://enterpriseservices.nci.nih.gov/StudyImportExportService";
    private static final String WS_ENDPOINT_SERVLET_PATH = "/services/services/StudyImportExport";

    private final String STUDY_ID = RandomStringUtils.randomAlphanumeric(16);

    private static final QName SERVICE_NAME = new QName(SERVICE_NS, "StudyImportExportService");
    private static final QName PORT_NAME = new QName(SERVICE_NS, "StudyImportExport");

    private static final String DBUNIT_DATASET_PREFIX = TESTDATA_PACKAGE + "/StudyImportExportWebServiceTest_";

    private static final String SQL_IDENTIFIERS = "SELECT identifiers.primary_indicator, identifiers.type, identifiers.dtype, identifiers.system_name, organizations.name FROM identifiers LEFT JOIN organizations on hcs_id=organizations.id WHERE value='${STUDY_ID}' ORDER BY identifiers.id desc";
    private static final String SQL_CONSENT_QUESTIONS = "SELECT * FROM consent_questions WHERE EXISTS (SELECT id from consents where consents.id=consent_questions.con_id AND EXISTS (SELECT Id FROM study_versions where study_versions.id=consents.stu_version_id AND EXISTS (SELECT Id from studies where study_versions.study_id=studies.id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}')))) ORDER BY consent_questions.id";
    private static final String SQL_CONSENTS = "SELECT * FROM consents WHERE EXISTS (SELECT Id FROM study_versions where study_versions.id=consents.stu_version_id AND EXISTS (SELECT Id from studies where study_versions.study_id=studies.id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}')))";
    private static final String SQL_STUDY_ORGS = "SELECT study_organizations.type, organizations.name FROM study_organizations INNER JOIN organizations ON study_organizations.hcs_id=organizations.id WHERE EXISTS (SELECT Id FROM studies where studies.id=study_organizations.study_id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}')) ORDER BY study_organizations.id";
    private static final String SQL_STUDY_VERSIONS = "SELECT * FROM study_versions WHERE EXISTS (SELECT Id FROM studies where studies.id=study_versions.study_id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}'))";
    private static final String SQL_STUDIES = "SELECT * FROM studies WHERE EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}')";
    private static final String SQL_EPOCHS = "SELECT * FROM epochs WHERE EXISTS (SELECT Id FROM study_versions where study_versions.id=epochs.stu_version_id AND EXISTS (SELECT Id from studies where study_versions.study_id=studies.id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}')))";
    private static final String SQL_ARMS = "SELECT * FROM arms WHERE EXISTS (SELECT id from epochs where epochs.id=arms.eph_id AND EXISTS (SELECT Id FROM study_versions where study_versions.id=epochs.stu_version_id AND EXISTS (SELECT Id from studies where study_versions.study_id=studies.id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}')))) ORDER BY arms.id";
    private static final String SQL_RANDOMIZATIONS = "select * from randomizations r where r.id in (SELECT epochs.RNDM_ID FROM epochs WHERE EXISTS (SELECT Id FROM study_versions where study_versions.id=epochs.stu_version_id AND EXISTS (SELECT Id from studies where study_versions.study_id=studies.id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}'))))";
    private static final String SQL_ELIGIBILITY_CRITERIA = "SELECT * FROM eligibility_criteria WHERE EXISTS (SELECT id from epochs where epochs.id=eligibility_criteria.eph_id AND EXISTS (SELECT Id FROM study_versions where study_versions.id=epochs.stu_version_id AND EXISTS (SELECT Id from studies where study_versions.study_id=studies.id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}')))) ORDER BY id";
    private static final String SQL_STRAT_CRITERIA = "SELECT * FROM strat_criteria WHERE EXISTS (SELECT id from epochs where epochs.id=strat_criteria.eph_id AND EXISTS (SELECT Id FROM study_versions where study_versions.id=epochs.stu_version_id AND EXISTS (SELECT Id from studies where study_versions.study_id=studies.id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}')))) ORDER BY id";
    private static final String SQL_STRAT_CRI_PER_ANS = "SELECT * FROM strat_cri_per_ans WHERE strat_cri_per_ans.str_cri_id IN (SELECT Id FROM strat_criteria WHERE EXISTS (SELECT id from epochs where epochs.id=strat_criteria.eph_id AND EXISTS (SELECT Id FROM study_versions where study_versions.id=epochs.stu_version_id AND EXISTS (SELECT Id from studies where study_versions.study_id=studies.id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}'))))) ORDER BY ID";
    private static final String SQL_STRATUM_GROUPS = "SELECT * FROM stratum_groups WHERE EXISTS (SELECT id from epochs where epochs.id=stratum_groups.epochs_id AND EXISTS (SELECT Id FROM study_versions where study_versions.id=epochs.stu_version_id AND EXISTS (SELECT Id from studies where study_versions.study_id=studies.id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}')))) ORDER BY id";
    private static final String SQL_DISEASE_TERMS = "select medra_code from disease_terms t where t.id in (SELECT study_diseases.disease_term_id FROM study_diseases WHERE EXISTS (SELECT Id FROM study_versions where study_versions.id=study_diseases.stu_version_id AND EXISTS (SELECT Id from studies where study_versions.study_id=studies.id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}')))) order by id";
    private static final String SQL_STUDY_INVESTIGATORS = "SELECT study_investigators.role_code, study_investigators.status_code, investigators.assigned_identifier, organizations.name FROM study_investigators INNER JOIN hc_site_investigators ON study_investigators.hsi_id=hc_site_investigators.id INNER JOIN investigators ON investigators.id=hc_site_investigators.inv_id INNER JOIN organizations ON organizations.id=hc_site_investigators.hcs_id WHERE study_investigators.sto_id IN (SELECT Id FROM study_organizations WHERE EXISTS (SELECT Id FROM studies where studies.id=study_organizations.study_id and EXISTS (SELECT Id from Identifiers WHERE Identifiers.stu_id=studies.id and Identifiers.value='${STUDY_ID}'))) ORDER BY role_code";

    private URL endpointURL;
    private URL wsdlLocation;

    /**
     * Set this JVM property to true if this test should not bring up an
     * instance of embedded Tomcat and use one already running locally at
     * <b>https://localhost:8443/c3pr.
     */
    private boolean noEmbeddedTomcat = Boolean.valueOf(System.getProperty("noEmbeddedTomcat", "false"));

    @Override
    protected void setUp() throws Exception {
        initDataSourceFile();
        if (noEmbeddedTomcat) {
            endpointURL = new URL("https://localhost:8443/c3pr" + WS_ENDPOINT_SERVLET_PATH);
        } else {
            cleanupDatabaseData();
            super.setUp();
            endpointURL = new URL("https://" + InetAddress.getLocalHost().getHostName() + ":" + sslPort
                    + C3PR_CONTEXT + WS_ENDPOINT_SERVLET_PATH);
        }

        wsdlLocation = new URL(endpointURL.toString() + "?wsdl");

        logger.info("endpointURL: " + endpointURL);
        logger.info("wsdlLocation: " + wsdlLocation);
    }

    /**
     * Need to do some DELETEs which could not be done via DbUnit.
     * 
     * @throws SQLException
     * @throws Exception
     */
    private void cleanupDatabaseData() throws SQLException, Exception {
        try {
            Connection conn = getConnection().getConnection();
            Statement st = conn.createStatement();
            st.execute("DELETE FROM identifiers where stu_id is not null");
            st.close();
        } catch (Exception e) {
            logger.severe("cleanupDatabaseData() failed.");
            logger.severe(ExceptionUtils.getFullStackTrace(e));
            e.printStackTrace();
        }
    }

    @Override
    protected void tearDown() throws Exception {
        if (!noEmbeddedTomcat) {
            cleanupDatabaseData();
            super.tearDown();
        }
    }

    /**
     * @throws InterruptedException
     * @throws IOException
     * 
     */
    public void testStudyImportExport() throws InterruptedException, IOException {

        try {
            // order of the following calls matters! Sorry.
            doUnopenableStudyCheck();
            doMalformedStudyCheck();
            doSuccessfulImportStudyCheck();
            doDuplicateStudyCheck();
            doStudyExportCheck();
        } catch (Exception e) {
            logger.severe(ExceptionUtils.getFullStackTrace(e));
            fail(ExceptionUtils.getFullStackTrace(e));
        }
    }

    private void doStudyExportCheck()
            throws DOMException, SOAPException, IOException, SAXException, ParserConfigurationException {
        String xmlFile = "StudyIdentifier";

        Dispatch<SOAPMessage> dispatch = getDispatch();
        SOAPMessage reqMsg = prepareExportRequestEnvelope(xmlFile);
        SOAPMessage respMsg = dispatch.invoke(reqMsg);

        SOAPPart part = respMsg.getSOAPPart();
        SOAPEnvelope env = part.getEnvelope();
        SOAPBody body = env.getBody();
        NodeList nodes = body.getElementsByTagNameNS(SERVICE_NS, "ExportStudyResponse");
        assertEquals(1, nodes.getLength());
        Element responseEl = (Element) nodes.item(0);
        assertEquals(1, responseEl.getChildNodes().getLength());

        Element exportedStudy = (Element) responseEl.getChildNodes().item(0);
        // this study element must match the one used to create the study in the first place
        Element originalStudy = (Element) getSOAPBodyFromXML("Study");
        assertTrue(XMLUtils.isDeepEqual(exportedStudy, originalStudy));

    }

    private void doMalformedStudyCheck()
            throws SOAPException, DOMException, IOException, SAXException, ParserConfigurationException {

        Dispatch<SOAPMessage> dispatch = getDispatch();

        // malformed study.
        try {
            dispatch.invoke(prepareImportRequestEnvelope("Study_Malformed"));
            fail("Malformed study went through.");
        } catch (SOAPFaultException e) {
            logger.info("Malformed study check passed.");
        }

        // malformed study # 2.
        try {
            dispatch.invoke(prepareImportRequestEnvelope("Study_Malformed2"));
            fail("Malformed study went through.");
        } catch (SOAPFaultException e) {
            logger.info("Malformed study check passed.");
        }

    }

    private void doUnopenableStudyCheck()
            throws SOAPException, DOMException, IOException, SAXException, ParserConfigurationException {
        String xmlFile = "Study_Unopenable";
        Dispatch<SOAPMessage> dispatch = getDispatch();

        // study cannot be opened. biz checks must fail.
        try {
            dispatch.invoke(prepareImportRequestEnvelope(xmlFile));
            fail("Unopenable study went through.");
        } catch (SOAPFaultException e) {
            logger.info("Unopenable study check passed.");
        }
    }

    private void doDuplicateStudyCheck()
            throws SOAPException, DOMException, IOException, SAXException, ParserConfigurationException {
        String xmlFile = "Study";
        Dispatch<SOAPMessage> dispatch = getDispatch();

        // duplicate study: second request with same study must fail
        try {
            dispatch.invoke(prepareImportRequestEnvelope(xmlFile));
            fail("Duplicate study went through.");
        } catch (SOAPFaultException e) {
            logger.info("Duplicate study check passed.");
        }
    }

    /**
     * @throws Exception
     * @throws DatabaseUnitException
     * @throws SQLException
     * @throws DataSetException
     * 
     */
    private void doSuccessfulImportStudyCheck()
            throws DataSetException, SQLException, DatabaseUnitException, Exception {
        String xmlFile = "Study";

        // successful study save.
        Dispatch<SOAPMessage> dispatch = getDispatch();
        SOAPMessage reqMsg = prepareImportRequestEnvelope(xmlFile);
        SOAPMessage respMsg = dispatch.invoke(reqMsg);
        verifySuccessulImportResponse(respMsg);

        // verify database data.
        verifyStudyDatabaseData("");
    }

    /**
     * @param xmlFile
     * @return
     * @throws SOAPException
     * @throws DOMException
     * @throws IOException
     * @throws SAXException
     * @throws ParserConfigurationException
     */
    private SOAPMessage prepareImportRequestEnvelope(String xmlFile)
            throws SOAPException, DOMException, IOException, SAXException, ParserConfigurationException {
        return prepareRequestEnvelope(xmlFile, "ImportStudyRequest");
    }

    private SOAPMessage prepareExportRequestEnvelope(String xmlFile)
            throws SOAPException, DOMException, IOException, SAXException, ParserConfigurationException {
        return prepareRequestEnvelope(xmlFile, "ExportStudyRequest");
    }

    private SOAPMessage prepareRequestEnvelope(String xmlFile, String wrapperElement)
            throws SOAPException, DOMException, IOException, SAXException, ParserConfigurationException {
        MessageFactory mf = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
        SOAPMessage reqMsg = mf.createMessage();
        SOAPPart part = reqMsg.getSOAPPart();
        SOAPEnvelope env = part.getEnvelope();
        SOAPBody body = env.getBody();

        SOAPElement operation = body.addChildElement(wrapperElement, "stud", SERVICE_NS);
        operation.appendChild(env.getOwnerDocument().importNode(getSOAPBodyFromXML(xmlFile), true));
        reqMsg.saveChanges();
        return reqMsg;
    }

    private void verifySuccessulImportResponse(SOAPMessage respMsg) throws SOAPException {
        SOAPPart part = respMsg.getSOAPPart();
        SOAPEnvelope env = part.getEnvelope();
        SOAPBody body = env.getBody();
        NodeList nodes = body.getElementsByTagNameNS(SERVICE_NS, "ImportStudyResponse");
        assertEquals(1, nodes.getLength());
        // element should be empty
        Element responseEl = (Element) nodes.item(0);
        assertEquals(0, responseEl.getChildNodes().getLength());
    }

    /**
     * @return
     */
    private Dispatch<SOAPMessage> getDispatch() {
        Service service = getService();
        Dispatch<SOAPMessage> dispatch = service.createDispatch(PORT_NAME, SOAPMessage.class, Service.Mode.MESSAGE);
        return dispatch;
    }

    private Node getSOAPBodyFromXML(String xmlBaseFileName)
            throws IOException, SAXException, ParserConfigurationException {
        InputStream is = getResource(null, TESTDATA_PACKAGE + "/" + xmlBaseFileName + ".xml");
        String xmlStr = IOUtils.toString(is);
        xmlStr = xmlStr.replace("${STUDY_ID}", STUDY_ID);
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        dbf.setIgnoringComments(true);
        org.w3c.dom.Document doc = dbf.newDocumentBuilder().parse(IOUtils.toInputStream(xmlStr));
        IOUtils.closeQuietly(is);
        return doc.getChildNodes().item(0);
    }

    private void verifyStudyDatabaseData(String fileNameAppendix)
            throws DataSetException, IOException, SQLException, DatabaseUnitException, Exception {
        verifyData("Identifiers", fileNameAppendix, "identifiers", SQL_IDENTIFIERS);
        verifyData("Studies", fileNameAppendix, "studies", SQL_STUDIES);
        verifyData("StudyVersions", fileNameAppendix, "study_versions", SQL_STUDY_VERSIONS);
        verifyData("StudyOrganizations", fileNameAppendix, "study_organizations", SQL_STUDY_ORGS);
        verifyData("Consents", fileNameAppendix, "consents", SQL_CONSENTS);
        verifyData("ConsentQuestions", fileNameAppendix, "consent_questions", SQL_CONSENT_QUESTIONS);
        verifyData("Epochs", fileNameAppendix, "epochs", SQL_EPOCHS);
        verifyData("Arms", fileNameAppendix, "arms", SQL_ARMS);
        verifyData("Randomizations", fileNameAppendix, "randomizations", SQL_RANDOMIZATIONS);
        verifyData("EligibilityCriteria", fileNameAppendix, "eligibility_criteria", SQL_ELIGIBILITY_CRITERIA);
        verifyData("StratCriteria", fileNameAppendix, "strat_criteria", SQL_STRAT_CRITERIA);
        verifyData("StratCriPerAns", fileNameAppendix, "strat_cri_per_ans", SQL_STRAT_CRI_PER_ANS);
        verifyData("StratumGroups", fileNameAppendix, "stratum_groups", SQL_STRATUM_GROUPS);
        verifyData("DiseaseTerms", fileNameAppendix, "disease_terms", SQL_DISEASE_TERMS);
        verifyData("StudyInvestigators", fileNameAppendix, "study_investigators", SQL_STUDY_INVESTIGATORS);

    }

    /**
     * @param xmlDataSetBaseName
     * @param tableName
     * @param querySql
     * @throws IOException
     * @throws DataSetException
     * @throws SQLException
     * @throws Exception
     * @throws DatabaseUnitException
     */
    protected void verifyData(final String xmlDataSetBaseName, String appendix, final String tableName,
            String querySql) throws IOException, DataSetException, SQLException, Exception, DatabaseUnitException {
        querySql = StringUtils.replace(querySql, "${STUDY_ID}", STUDY_ID);
        IDataSet expectedDataSet = getExpectedDataSet(xmlDataSetBaseName, appendix);
        ITable expectedTable = expectedDataSet.getTable(tableName);
        ITable actualData = getConnection().createQueryTable(tableName, querySql);
        ITable filteredTable = DefaultColumnFilter.includedColumnsTable(actualData,
                expectedTable.getTableMetaData().getColumns());
        Assertion.assertEquals(expectedTable, filteredTable);
    }

    /**
     * @param xmlDataSetBaseName
     * @return
     * @throws IOException
     * @throws DataSetException
     */
    private IDataSet getExpectedDataSet(final String xmlDataSetBaseName, String appendix)
            throws IOException, DataSetException {
        final String prefix = DBUNIT_DATASET_PREFIX;
        IDataSet expectedDataSet = new FlatXmlDataSet((InputStream) ObjectUtils.defaultIfNull(
                getClass().getResourceAsStream(prefix + xmlDataSetBaseName + appendix + ".xml"),
                getClass().getResourceAsStream(prefix + xmlDataSetBaseName + ".xml")));
        return expectedDataSet;
    }

    private Service getService() {
        Service service = Service.create(SERVICE_NAME);
        service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, endpointURL.toString());
        SOAPUtils.installSecurityHandler(service);
        return service;
    }

}