org.akaza.openclinica.control.submit.ImportCRFDataServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.akaza.openclinica.control.submit.ImportCRFDataServlet.java

Source

/*
 * OpenClinica is distributed under the
 * GNU Lesser General Public License (GNU LGPL).
    
 * For details see: http://www.openclinica.org/license
 * copyright 2003-2005 Akaza Research
 */
package org.akaza.openclinica.control.submit;

import org.akaza.openclinica.bean.core.DataEntryStage;
import org.akaza.openclinica.bean.core.Role;
import org.akaza.openclinica.bean.core.Status;
import org.akaza.openclinica.bean.rule.FileUploadHelper;
import org.akaza.openclinica.bean.rule.XmlSchemaValidationHelper;
import org.akaza.openclinica.bean.submit.CRFVersionBean;
import org.akaza.openclinica.bean.submit.DisplayItemBeanWrapper;
import org.akaza.openclinica.bean.submit.EventCRFBean;
import org.akaza.openclinica.bean.submit.crfdata.ODMContainer;
import org.akaza.openclinica.bean.submit.crfdata.SummaryStatsBean;
import org.akaza.openclinica.control.SpringServletAccess;
import org.akaza.openclinica.control.core.SecureController;
import org.akaza.openclinica.control.form.FormProcessor;
import org.akaza.openclinica.control.form.Validator;
import org.akaza.openclinica.core.form.StringUtil;
import org.akaza.openclinica.dao.core.CoreResources;
import org.akaza.openclinica.exception.OpenClinicaException;
import org.akaza.openclinica.i18n.core.LocaleResolver;
import org.akaza.openclinica.view.Page;
import org.akaza.openclinica.web.InsufficientPermissionException;
import org.akaza.openclinica.web.SQLInitServlet;
import org.akaza.openclinica.web.crfdata.ImportCRFDataService;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.xml.Unmarshaller;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

/**
 * Create a new CRF verison by uploading excel file. Makes use of several other classes to validate and provide accurate
 * validation. More specifically, uses XmlSchemaValidationHelper, ImportCRFDataService, ODMContainer, and others to
 * import all the XML in the ODM 1.3 standard.
 * 
 * @author Krikor Krumlian, Tom Hickerson updated Apr-May 2008
 */
public class ImportCRFDataServlet extends SecureController {

    Locale locale;

    private ImportCRFDataService dataService;

    XmlSchemaValidationHelper schemaValidator = new XmlSchemaValidationHelper();
    FileUploadHelper uploadHelper = new FileUploadHelper();

    // < ResourceBundleresword,resexception,respage;

    /**
     *
     */
    @Override
    public void mayProceed() throws InsufficientPermissionException {
        checkStudyLocked(Page.MENU_SERVLET, respage.getString("current_study_locked"));
        checkStudyFrozen(Page.MENU_SERVLET, respage.getString("current_study_frozen"));

        locale = LocaleResolver.getLocale(request);
        if (ub.isSysAdmin()) {
            return;
        }

        Role r = currentRole.getRole();
        if (r.equals(Role.STUDYDIRECTOR) || r.equals(Role.COORDINATOR) || r.equals(Role.INVESTIGATOR)
                || r.equals(Role.RESEARCHASSISTANT) || r.equals(Role.RESEARCHASSISTANT2)) {
            return;
        }

        addPageMessage(respage.getString("no_have_correct_privilege_current_study")
                + respage.getString("change_study_contact_sysadmin"));
        throw new InsufficientPermissionException(Page.MENU_SERVLET, resexception.getString("may_not_submit_data"),
                "1");
    }

    @Override
    public void processRequest() throws Exception {
        resetPanel();
        panel.setStudyInfoShown(false);
        panel.setOrderedData(true);

        FormProcessor fp = new FormProcessor(request);
        // checks which module the requests are from
        String module = fp.getString(MODULE);
        // keep the module in the session
        session.setAttribute(MODULE, module);

        String action = request.getParameter("action");
        CRFVersionBean version = (CRFVersionBean) session.getAttribute("version");

        File xsdFile = new File(SpringServletAccess.getPropertiesDir(context) + "ODM1-3-0.xsd");
        File xsdFile2 = new File(SpringServletAccess.getPropertiesDir(context) + "ODM1-2-1.xsd");

        if (StringUtil.isBlank(action)) {
            logger.info("action is blank");
            request.setAttribute("version", version);
            forwardPage(Page.IMPORT_CRF_DATA);
        }
        if ("confirm".equalsIgnoreCase(action)) {
            String dir = SQLInitServlet.getField("filePath");
            if (!new File(dir).exists()) {
                logger.info("The filePath in datainfo.properties is invalid " + dir);
                addPageMessage(respage.getString("filepath_you_defined_not_seem_valid"));
                forwardPage(Page.IMPORT_CRF_DATA);
            }
            // All the uploaded files will be saved in filePath/crf/original/
            String theDir = dir + "crf" + File.separator + "original" + File.separator;
            if (!new File(theDir).isDirectory()) {
                new File(theDir).mkdirs();
                logger.info("Made the directory " + theDir);
            }
            // MultipartRequest multi = new MultipartRequest(request, theDir, 50 * 1024 * 1024);
            File f = null;
            try {
                f = uploadFile(theDir, version);

            } catch (Exception e) {
                logger.warn("*** Found exception during file upload***");
                e.printStackTrace();

            }
            if (f == null) {
                forwardPage(Page.IMPORT_CRF_DATA);
            }

            // TODO
            // validation steps
            // 1. valid xml - validated by file uploader below

            // LocalConfiguration config = LocalConfiguration.getInstance();
            // config.getProperties().setProperty(
            // "org.exolab.castor.parser.namespaces",
            // "true");
            // config
            // .getProperties()
            // .setProperty("org.exolab.castor.sax.features",
            // "http://xml.org/sax/features/validation,
            // http://apache.org/xml/features/validation/schema,
            // http://apache.org/xml/features/validation/schema-full-checking");
            // // above sets to validate against namespace

            Mapping myMap = new Mapping();
            // @pgawade 18-April-2011 Fix for issue 8394
            String ODM_MAPPING_DIRPath = CoreResources.ODM_MAPPING_DIR;
            myMap.loadMapping(ODM_MAPPING_DIRPath + File.separator + "cd_odm_mapping.xml");

            Unmarshaller um1 = new Unmarshaller(myMap);
            // um1.addNamespaceToPackageMapping("http://www.openclinica.org/ns/odm_ext_v130/v3.1", "OpenClinica");
            // um1.addNamespaceToPackageMapping("http://www.cdisc.org/ns/odm/v1.3"
            // ,
            // "ODMContainer");
            boolean fail = false;
            ODMContainer odmContainer = new ODMContainer();
            session.removeAttribute("odmContainer");
            try {

                // schemaValidator.validateAgainstSchema(f, xsdFile);
                // utf-8 compliance, tbh 06/2009
                InputStreamReader isr = new InputStreamReader(new FileInputStream(f), "UTF-8");
                odmContainer = (ODMContainer) um1.unmarshal(isr);

                logger.debug("Found crf data container for study oid: "
                        + odmContainer.getCrfDataPostImportContainer().getStudyOID());
                logger.debug("found length of subject list: "
                        + odmContainer.getCrfDataPostImportContainer().getSubjectData().size());
                // 2. validates against ODM 1.3
                // check it all below, throw an exception and route to a
                // different
                // page if not working

                // TODO this block of code needs the xerces serializer in order
                // to
                // work

                // StringWriter myWriter = new StringWriter();
                // Marshaller m1 = new Marshaller(myWriter);
                //
                // m1.setProperty("org.exolab.castor.parser.namespaces",
                // "true");
                // m1
                // .setProperty("org.exolab.castor.sax.features",
                // "http://xml.org/sax/features/validation,
                // http://apache.org/xml/features/validation/schema,
                // http://apache.org/xml/features/validation/schema-full-checking
                // ");
                //
                // m1.setMapping(myMap);
                // m1.setNamespaceMapping("",
                // "http://www.cdisc.org/ns/odm/v1.3");
                // m1.setSchemaLocation("http://www.cdisc.org/ns/odm/v1.3
                // ODM1-3.xsd");
                // m1.marshal(odmContainer);
                // if you havent thrown it, you wont throw it here
                addPageMessage(respage.getString("passed_xml_validation"));
            } catch (Exception me1) {
                me1.printStackTrace();
                // expanding it to all exceptions, but hoping to catch Marshal
                // Exception or SAX Exceptions
                logger.info("found exception with xml transform");
                //
                logger.info("trying 1.2.1");
                try {
                    schemaValidator.validateAgainstSchema(f, xsdFile2);
                    // for backwards compatibility, we also try to validate vs
                    // 1.2.1 ODM 06/2008
                    InputStreamReader isr = new InputStreamReader(new FileInputStream(f), "UTF-8");
                    odmContainer = (ODMContainer) um1.unmarshal(isr);
                } catch (Exception me2) {
                    // not sure if we want to report me2
                    MessageFormat mf = new MessageFormat("");
                    mf.applyPattern(respage.getString("your_xml_is_not_well_formed"));
                    Object[] arguments = { me1.getMessage() };
                    addPageMessage(mf.format(arguments));
                    //
                    // addPageMessage("Your XML is not well-formed, and does not
                    // comply with the ODM 1.3 Schema. Please check it, and try
                    // again. It returned the message: "
                    // + me1.getMessage());
                    // me1.printStackTrace();
                    forwardPage(Page.IMPORT_CRF_DATA);
                    // you can't really wait to forward because then you throw
                    // NPEs
                    // in the next few parts of the code
                }
            }
            // TODO need to output further here
            // 2.a. is the study the same one that the user is in right now?
            // 3. validates against study metadata
            // 3.a. is that study subject in that study?
            // 3.b. is that study event def in that study?
            // 3.c. is that site in that study?
            // 3.d. is that crf version in that study event def?
            // 3.e. are those item groups in that crf version?
            // 3.f. are those items in that item group?

            List<String> errors = getImportCRFDataService().validateStudyMetadata(odmContainer,
                    ub.getActiveStudyId());
            if (errors != null) {
                // add to session
                // forward to another page
                logger.info(errors.toString());
                for (String error : errors) {
                    addPageMessage(error);
                }
                if (errors.size() > 0) {
                    // fail = true;
                    forwardPage(Page.IMPORT_CRF_DATA);
                } else {
                    addPageMessage(respage.getString("passed_study_check"));
                    addPageMessage(respage.getString("passed_oid_metadata_check"));
                }

            }
            logger.debug("passed error check");
            // TODO ADD many validation steps before we get to the
            // session-setting below
            // 4. is the event in the correct status to accept data import?
            // -- scheduled, data entry started, completed
            // (and the event should already be created)
            // (and the event should be independent, ie not affected by other
            // events)

            Boolean eventCRFStatusesValid = getImportCRFDataService().eventCRFStatusesValid(odmContainer, ub);
            ImportCRFInfoContainer importCrfInfo = new ImportCRFInfoContainer(odmContainer, sm.getDataSource());
            // The eventCRFBeans list omits EventCRFs that don't match UpsertOn rules. If EventCRF did not exist and
            // doesn't match upsert, it won't be created.
            List<EventCRFBean> eventCRFBeans = getImportCRFDataService().fetchEventCRFBeans(odmContainer, ub);
            List<DisplayItemBeanWrapper> displayItemBeanWrappers = new ArrayList<DisplayItemBeanWrapper>();
            HashMap<String, String> totalValidationErrors = new HashMap<String, String>();
            HashMap<String, String> hardValidationErrors = new HashMap<String, String>();
            // The following map is used for setting the EventCRF status post import.
            HashMap<Integer, String> importedCRFStatuses = getImportCRFDataService()
                    .fetchEventCRFStatuses(odmContainer);
            // @pgawade 17-May-2011 Fix for issue#9590 - collection of
            // eventCRFBeans is returned as null
            // when status of one the events in xml file is either stopped,
            // signed or locked.
            // Instead of repeating the code to fetch the events in xml file,
            // method in the ImportCRFDataService is modified for this fix.
            if (eventCRFBeans == null) {
                fail = true;
                addPageMessage(respage.getString("no_event_status_matching"));
            } else {
                ArrayList<Integer> permittedEventCRFIds = new ArrayList<Integer>();
                logger.info("found a list of eventCRFBeans: " + eventCRFBeans.toString());

                // List<DisplayItemBeanWrapper> displayItemBeanWrappers = new ArrayList<DisplayItemBeanWrapper>();
                // HashMap<String, String> totalValidationErrors = new
                // HashMap<String, String>();
                // HashMap<String, String> hardValidationErrors = new
                // HashMap<String, String>();
                logger.debug("found event crfs " + eventCRFBeans.size());
                // -- does the event already exist? if not, fail
                if (!eventCRFBeans.isEmpty()) {
                    for (EventCRFBean eventCRFBean : eventCRFBeans) {
                        DataEntryStage dataEntryStage = eventCRFBean.getStage();
                        Status eventCRFStatus = eventCRFBean.getStatus();

                        logger.info("Event CRF Bean: id " + eventCRFBean.getId() + ", data entry stage "
                                + dataEntryStage.getName() + ", status " + eventCRFStatus.getName());
                        if (eventCRFStatus.equals(Status.AVAILABLE)
                                || dataEntryStage.equals(DataEntryStage.INITIAL_DATA_ENTRY)
                                || dataEntryStage.equals(DataEntryStage.INITIAL_DATA_ENTRY_COMPLETE)
                                || dataEntryStage.equals(DataEntryStage.DOUBLE_DATA_ENTRY_COMPLETE)
                                || dataEntryStage.equals(DataEntryStage.DOUBLE_DATA_ENTRY)) {
                            // actually want the negative
                            // was status == available and the stage questions, but
                            // when you are at 'data entry complete' your status is
                            // set to 'unavailable'.
                            // >> tbh 09/2008
                            // HOWEVER, when one event crf is removed and the rest
                            // are good, what happens???
                            // need to create a list and inform that one is blocked
                            // and the rest are not...
                            //
                            permittedEventCRFIds.add(new Integer(eventCRFBean.getId()));
                        } else {
                            // fail = true;
                            // addPageMessage(respage.getString(
                            // "the_event_crf_not_correct_status"));
                            // forwardPage(Page.IMPORT_CRF_DATA);
                        }
                    }

                    // so that we don't repeat this following message
                    // did we exclude all the event CRFs? if not, pass, else fail
                    if (eventCRFBeans.size() >= permittedEventCRFIds.size()) {
                        addPageMessage(respage.getString("passed_event_crf_status_check"));
                    } else {
                        fail = true;
                        addPageMessage(respage.getString("the_event_crf_not_correct_status"));
                    }
                    // do they all have to have the right status to move
                    // forward? answer from bug tracker = no
                    // 5. do the items contain the correct data types?

                    // 6. are all the related OIDs present?
                    // that is to say, do we chain all the way down?
                    // this is covered by the OID Metadata Check

                    // 7. do the edit checks pass?
                    // only then can we pass on to VERIFY_IMPORT_SERVLET

                    // do we overwrite?

                    // XmlParser xp = new XmlParser();
                    // List<HashMap<String, String>> importedData =
                    // xp.getData(f);

                    // now we generate hard edit checks, and have to set that to the
                    // screen. get that from the service, generate a summary bean to
                    // set to either
                    // page in the workflow, either verifyImport.jsp or import.jsp

                    try {
                        List<DisplayItemBeanWrapper> tempDisplayItemBeanWrappers = new ArrayList<DisplayItemBeanWrapper>();
                        tempDisplayItemBeanWrappers = getImportCRFDataService().lookupValidationErrors(request,
                                odmContainer, ub, totalValidationErrors, hardValidationErrors,
                                permittedEventCRFIds);
                        logger.debug("generated display item bean wrappers " + tempDisplayItemBeanWrappers.size());
                        logger.debug("size of total validation errors: " + totalValidationErrors.size());
                        displayItemBeanWrappers.addAll(tempDisplayItemBeanWrappers);
                    } catch (NullPointerException npe1) {
                        // what if you have 2 event crfs but the third is a fake?
                        fail = true;
                        logger.debug("threw a NPE after calling lookup validation errors");
                        System.out.println(ExceptionUtils.getStackTrace(npe1));
                        addPageMessage(respage.getString("an_error_was_thrown_while_validation_errors"));
                        // npe1.printStackTrace();
                    } catch (OpenClinicaException oce1) {
                        fail = true;
                        logger.debug("threw an OCE after calling lookup validation errors "
                                + oce1.getOpenClinicaMessage());
                        addPageMessage(oce1.getOpenClinicaMessage());
                    }
                } else if (!eventCRFStatusesValid) {
                    fail = true;
                    addPageMessage(respage.getString("the_event_crf_not_correct_status"));
                } else {
                    fail = true;
                    addPageMessage(respage.getString("no_event_crfs_matching_the_xml_metadata"));
                }
                // for (HashMap<String, String> crfData : importedData) {
                // DisplayItemBeanWrapper displayItemBeanWrapper =
                // testing(request,
                // crfData);
                // displayItemBeanWrappers.add(displayItemBeanWrapper);
                // errors = displayItemBeanWrapper.getValidationErrors();
                //
                // }
            }
            if (fail) {
                logger.debug("failed here - forwarding...");
                forwardPage(Page.IMPORT_CRF_DATA);
            } else {
                addPageMessage(respage.getString("passing_crf_edit_checks"));
                session.setAttribute("odmContainer", odmContainer);
                session.setAttribute("importedData", displayItemBeanWrappers);
                session.setAttribute("validationErrors", totalValidationErrors);
                session.setAttribute("hardValidationErrors", hardValidationErrors);
                session.setAttribute("importedCRFStatuses", importedCRFStatuses);
                session.setAttribute("importCrfInfo", importCrfInfo);
                // above are updated 'statically' by the method that originally
                // generated the wrappers; soon the only thing we will use
                // wrappers for is the 'overwrite' flag

                logger.debug("+++ content of total validation errors: " + totalValidationErrors.toString());
                SummaryStatsBean ssBean = getImportCRFDataService().generateSummaryStatsBean(odmContainer,
                        displayItemBeanWrappers, importCrfInfo);
                session.setAttribute("summaryStats", ssBean);
                // will have to set hard edit checks here as well
                session.setAttribute("subjectData", odmContainer.getCrfDataPostImportContainer().getSubjectData());
                forwardPage(Page.VERIFY_IMPORT_SERVLET);
            }
            // }
        }
    }

    /*
     * Given the MultipartRequest extract the first File validate that it is an xml file and then return it.
     */
    private File getFirstFile() {
        File f = null;
        List<File> files = uploadHelper.returnFiles(request, context);
        for (File file : files) {
            // Enumeration files = multi.getFileNames();
            // if (files.hasMoreElements()) {
            // String name = (String) files.nextElement();
            // f = multi.getFile(name);
            f = file;
            if (f == null || f.getName() == null) {
                logger.info("file is empty.");
                Validator.addError(errors, "xml_file", "You have to provide an XML file!");
            } else if (f.getName().indexOf(".xml") < 0 && f.getName().indexOf(".XML") < 0) {
                logger.info("file name:" + f.getName());
                // TODO change the message below
                addPageMessage(respage.getString("file_you_uploaded_not_seem_xml_file"));
                f = null;
            }
        }
        return f;
    }

    /**
     * Uploads the xml file
     * 
     * @param version
     * @throws Exception
     */
    public File uploadFile(String theDir, CRFVersionBean version) throws Exception {

        return getFirstFile();
    }

    public ImportCRFDataService getImportCRFDataService() {
        dataService = this.dataService != null ? dataService : new ImportCRFDataService(sm.getDataSource(), locale);
        return dataService;
    }

    @Override
    protected String getAdminServlet() {
        if (ub.isSysAdmin()) {
            return SecureController.ADMIN_SERVLET_CODE;
        } else {
            return "";
        }
    }

}