/* * 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 java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import javax.sql.DataSource; import org.akaza.openclinica.bean.core.DataEntryStage; import org.akaza.openclinica.bean.core.DiscrepancyNoteType; import org.akaza.openclinica.bean.core.ItemDataType; import org.akaza.openclinica.bean.core.ResolutionStatus; import org.akaza.openclinica.bean.core.Role; import org.akaza.openclinica.bean.core.Status; import org.akaza.openclinica.bean.core.Utils; import org.akaza.openclinica.bean.login.UserAccountBean; import org.akaza.openclinica.bean.managestudy.DiscrepancyNoteBean; import org.akaza.openclinica.bean.managestudy.StudyBean; import org.akaza.openclinica.bean.managestudy.StudySubjectBean; import org.akaza.openclinica.bean.submit.DisplayItemBean; import org.akaza.openclinica.bean.submit.DisplayItemBeanWrapper; import org.akaza.openclinica.bean.submit.EventCRFBean; import org.akaza.openclinica.bean.submit.ItemBean; import org.akaza.openclinica.bean.submit.ItemDataBean; import org.akaza.openclinica.bean.submit.crfdata.ODMContainer; import org.akaza.openclinica.bean.submit.crfdata.SubjectDataBean; import org.akaza.openclinica.control.SpringServletAccess; import org.akaza.openclinica.control.core.SecureController; import org.akaza.openclinica.control.form.FormProcessor; import org.akaza.openclinica.dao.managestudy.DiscrepancyNoteDAO; import org.akaza.openclinica.dao.managestudy.StudySubjectDAO; import org.akaza.openclinica.dao.submit.EventCRFDAO; import org.akaza.openclinica.dao.submit.ItemDAO; import org.akaza.openclinica.dao.submit.ItemDataDAO; import org.akaza.openclinica.i18n.core.LocaleResolver; import org.akaza.openclinica.logic.rulerunner.ExecutionMode; import org.akaza.openclinica.logic.rulerunner.ImportDataRuleRunnerContainer; import org.akaza.openclinica.service.rule.RuleSetServiceInterface; import org.akaza.openclinica.view.Page; import org.akaza.openclinica.web.InsufficientPermissionException; import org.akaza.openclinica.web.job.CrfBusinessLogicHelper; import org.akaza.openclinica.web.job.ImportSpringJob; /** * View the uploaded data and verify what is going to be saved into the system and what is not. * * @author Krikor Krumlian */ public class VerifyImportedCRFDataServlet extends SecureController { Locale locale; /** * */ @Override public void mayProceed() throws InsufficientPermissionException { 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"); } public static DiscrepancyNoteBean createDiscrepancyNote(ItemBean itemBean, String message, EventCRFBean eventCrfBean, DisplayItemBean displayItemBean, Integer parentId, UserAccountBean uab, DataSource ds, StudyBean study) { // DisplayItemBean displayItemBean) { DiscrepancyNoteBean note = new DiscrepancyNoteBean(); StudySubjectDAO ssdao = new StudySubjectDAO(ds); note.setDescription(message); note.setDetailedNotes("Failed Validation Check"); note.setOwner(uab); note.setCreatedDate(new Date()); note.setResolutionStatusId(ResolutionStatus.OPEN.getId()); note.setDiscrepancyNoteTypeId(DiscrepancyNoteType.FAILEDVAL.getId()); if (parentId != null) { note.setParentDnId(parentId); } note.setField(itemBean.getName()); note.setStudyId(study.getId()); note.setEntityName(itemBean.getName()); note.setEntityType(DiscrepancyNoteBean.ITEM_DATA); note.setEntityValue(displayItemBean.getData().getValue()); note.setEventName(eventCrfBean.getName()); note.setEventStart(eventCrfBean.getCreatedDate()); note.setCrfName(displayItemBean.getEventDefinitionCRF().getCrfName()); StudySubjectBean ss = (StudySubjectBean) ssdao.findByPK(eventCrfBean.getStudySubjectId()); note.setSubjectName(ss.getName()); note.setEntityId(displayItemBean.getData().getId()); note.setColumn("value"); DiscrepancyNoteDAO dndao = new DiscrepancyNoteDAO(ds); note = (DiscrepancyNoteBean) dndao.create(note); // so that the below method works, need to set the entity above // System.out.println("trying to create mapping with " + note.getId() + // " " + note.getEntityId() + " " + note.getColumn() + " " + // note.getEntityType()); dndao.createMapping(note); // System.out.println("just created mapping"); return note; } @Override @SuppressWarnings(value = "unchecked") public void processRequest() throws Exception { ItemDataDAO itemDataDao = new ItemDataDAO(sm.getDataSource()); itemDataDao.setFormatDates(false); EventCRFDAO eventCrfDao = new EventCRFDAO(sm.getDataSource()); CrfBusinessLogicHelper crfBusinessLogicHelper = new CrfBusinessLogicHelper(sm.getDataSource()); String action = request.getParameter("action"); FormProcessor fp = new FormProcessor(request); // checks which module the requests are from String module = fp.getString(MODULE); request.setAttribute(MODULE, module); resetPanel(); panel.setStudyInfoShown(false); panel.setOrderedData(true); setToPanel(resword.getString("create_CRF"), respage.getString("br_create_new_CRF_entering")); setToPanel(resword.getString("create_CRF_version"), respage.getString("br_create_new_CRF_uploading")); setToPanel(resword.getString("revise_CRF_version"), respage.getString("br_if_you_owner_CRF_version")); setToPanel(resword.getString("CRF_spreadsheet_template"), respage.getString("br_download_blank_CRF_spreadsheet_from")); setToPanel(resword.getString("example_CRF_br_spreadsheets"), respage.getString("br_download_example_CRF_instructions_from")); if ("confirm".equalsIgnoreCase(action)) { List<DisplayItemBeanWrapper> displayItemBeanWrappers = (List<DisplayItemBeanWrapper>) session.getAttribute("importedData"); logger.info("Size of displayItemBeanWrappers : " + displayItemBeanWrappers.size()); forwardPage(Page.VERIFY_IMPORT_CRF_DATA); } if ("save".equalsIgnoreCase(action)) { // setup ruleSets to run if applicable RuleSetServiceInterface ruleSetService = (RuleSetServiceInterface) SpringServletAccess.getApplicationContext(context).getBean("ruleSetService"); List<ImportDataRuleRunnerContainer> containers = this.ruleRunSetup(sm.getDataSource(), currentStudy, ub, ruleSetService); List<DisplayItemBeanWrapper> displayItemBeanWrappers = (List<DisplayItemBeanWrapper>) session.getAttribute("importedData"); // System.out.println("Size of displayItemBeanWrappers : " + // displayItemBeanWrappers.size()); HashMap<Integer, String> importedCRFStatuses = (HashMap<Integer, String>) session.getAttribute("importedCRFStatuses"); for (DisplayItemBeanWrapper wrapper : displayItemBeanWrappers) { boolean resetSDV = false; int eventCrfBeanId = -1; EventCRFBean eventCrfBean = new EventCRFBean(); // TODO : tom , the wrapper object has all the necessary data - // as you see we check the // is to see if this data is Savable if it is then we go ahead // and save it. if not we discard. // So the change needs to happen here , instead of discarding we // need to file discrepancy notes // and save the data. If you look in the // Page.VERIFY_IMPORT_CRF_DATA jsp file you can see how I am // pulling the errors. and use that in the same way. logger.info("right before we check to make sure it is savable: " + wrapper.isSavable()); if (wrapper.isSavable()) { ArrayList<Integer> eventCrfInts = new ArrayList<Integer>(); // based on the use case: "If any of the data does not meet // validations specified in the CRF // Template, a discrepancy note is automatically logged. // The DN will have a type of Failed Validation Check, and // a message of Failed Validation check." // System.out.println("wrapper problems found : " + // wrapper.getValidationErrors().toString()); for (DisplayItemBean displayItemBean : wrapper.getDisplayItemBeans()) { eventCrfBeanId = displayItemBean.getData().getEventCRFId(); eventCrfBean = (EventCRFBean) eventCrfDao.findByPK(eventCrfBeanId); logger.info("found value here: " + displayItemBean.getData().getValue()); logger.info("found status here: " + eventCrfBean.getStatus().getName()); // System.out.println("found event crf bean name here: " // + // eventCrfBean.getEventName()+" id "+eventCrfBean.getId // ()); // SO, items can be created in a wrapper which is set to // overwrite // we get around this by checking the bean first, to // make sure it's not null ItemDataBean itemDataBean = new ItemDataBean(); itemDataBean = itemDataDao.findByItemIdAndEventCRFIdAndOrdinal(displayItemBean.getItem().getId(), eventCrfBean.getId(), displayItemBean .getData().getOrdinal()); if (wrapper.isOverwrite() && itemDataBean.getStatus() != null) { // ItemDataBean itemDataBean = new ItemDataBean(); // itemDataBean = // itemDataDao.findByItemIdAndEventCRFIdAndOrdinal( // displayItemBean.getItem().getId(), // eventCrfBean.getId(), displayItemBean // .getData().getOrdinal()); // itemDataBean = // itemDataDao.findByEventCRFIdAndItemName( // eventCrfBean, // displayItemBean.getItem().getName()); if (!itemDataBean.getValue().equals(displayItemBean.getData().getValue())) resetSDV = true; logger.info("just tried to find item data bean on item name " + displayItemBean.getItem().getName()); itemDataBean.setUpdatedDate(new Date()); itemDataBean.setUpdater(ub); itemDataBean.setValue(displayItemBean.getData().getValue()); // set status? itemDataDao.update(itemDataBean); logger.info("updated: " + itemDataBean.getItemId()); // need to set pk here in order to create dn displayItemBean.getData().setId(itemDataBean.getId()); } else { resetSDV = true; itemDataDao.create(displayItemBean.getData()); logger.info("created: " + displayItemBean.getData().getItemId() + "event CRF ID = " + eventCrfBean.getId() + "CRF VERSION ID =" + eventCrfBean.getCRFVersionId()); // does this dao function work for repeating // events/groups? // ItemDataBean itemDataBean = // itemDataDao.findByEventCRFIdAndItemName( // eventCrfBean, // displayItemBean.getItem().getName()); ItemDataBean itemDataBean2 = itemDataDao.findByItemIdAndEventCRFIdAndOrdinal(displayItemBean.getItem().getId(), eventCrfBean.getId(), displayItemBean.getData().getOrdinal()); logger.info("found: id " + itemDataBean2.getId() + " name " + itemDataBean2.getName()); displayItemBean.getData().setId(itemDataBean2.getId()); } // logger.info("created item data bean: // "+displayItemBean.getData().getId()); // logger.info("created: // "+displayItemBean.getData().getName()); // logger.info("continued: // "+displayItemBean.getData().getItemId()); ItemDAO idao = new ItemDAO(sm.getDataSource()); ItemBean ibean = (ItemBean) idao.findByPK(displayItemBean.getData().getItemId()); // logger.info("continued2: getName " + // ibean.getName()); // System.out.println("*** checking for validation errors: " // + ibean.getName()); String itemOid = displayItemBean.getItem().getOid() + "_" + wrapper.getStudyEventRepeatKey() + "_" + displayItemBean.getData().getOrdinal() + "_" + wrapper.getStudySubjectOid(); if (wrapper.getValidationErrors().containsKey(itemOid)) { ArrayList messageList = (ArrayList) wrapper.getValidationErrors().get(itemOid); // if // (wrapper.getValidationErrors().containsKey(ibean // .getName())) { // ArrayList messageList = (ArrayList) // wrapper.getValidationErrors // ().get(ibean.getName()); // could be more then one will have to iterate // could it be more than one? tbh 08/2008 for (int iter = 0; iter < messageList.size(); iter++) { String message = (String) messageList.get(iter); DiscrepancyNoteBean parentDn = ImportSpringJob.createDiscrepancyNote(ibean, message, eventCrfBean, displayItemBean, null, ub, sm.getDataSource(), currentStudy); ImportSpringJob.createDiscrepancyNote(ibean, message, eventCrfBean, displayItemBean, parentDn.getId(), ub, sm.getDataSource(), currentStudy); // System.out.println("*** created disc note with message: " // + message); // displayItemBean); } } // logger.info("created: // "+displayItemBean.getDbData().getName()); if (!eventCrfInts.contains(new Integer(eventCrfBean.getId()))) { String eventCRFStatus = importedCRFStatuses.get(new Integer(eventCrfBean.getId())); if (eventCRFStatus != null && eventCRFStatus.equals(DataEntryStage.INITIAL_DATA_ENTRY.getName()) && eventCrfBean.getStatus().isAvailable()) { crfBusinessLogicHelper.markCRFStarted(eventCrfBean, ub); } else { crfBusinessLogicHelper.markCRFComplete(eventCrfBean, ub); } eventCrfInts.add(new Integer(eventCrfBean.getId())); } } // Reset the SDV status if item data has been changed or added if (eventCrfBean != null && resetSDV) eventCrfDao.setSDVStatus(false, ub.getId(), eventCrfBean.getId()); // end of item datas, tbh // crfBusinessLogicHelper.markCRFComplete(eventCrfBean, ub); // System .out.println("*** just updated event crf bean: "+ // eventCrfBean.getId()); // need to update the study event status as well, tbh // crfBusinessLogicHelper.updateStudyEvent(eventCrfBean, // ub); // above should do it for us, tbh 08/2008 } } addPageMessage(respage.getString("data_has_been_successfully_import")); addPageMessage(this.ruleActionWarnings(this.runRules(currentStudy, ub, containers, ruleSetService, ExecutionMode.SAVE))); // forwardPage(Page.SUBMIT_DATA_SERVLET); forwardPage(Page.LIST_STUDY_SUBJECTS_SERVLET); // replaced tbh, 06/2009 } } private List<ImportDataRuleRunnerContainer> ruleRunSetup(DataSource dataSource, StudyBean studyBean, UserAccountBean userBean, RuleSetServiceInterface ruleSetService) { List<ImportDataRuleRunnerContainer> containers = new ArrayList<ImportDataRuleRunnerContainer>(); ODMContainer odmContainer = (ODMContainer) session.getAttribute("odmContainer"); if (odmContainer != null) { ArrayList<SubjectDataBean> subjectDataBeans = odmContainer.getCrfDataPostImportContainer().getSubjectData(); if (ruleSetService.getCountByStudy(studyBean) > 0) { ImportDataRuleRunnerContainer container; for (SubjectDataBean subjectDataBean : subjectDataBeans) { container = new ImportDataRuleRunnerContainer(); container.initRuleSetsAndTargets(dataSource, studyBean, subjectDataBean, ruleSetService); if (container.getShouldRunRules()) containers.add(container); } if (containers != null && !containers.isEmpty()) ruleSetService.runRulesInImportData(containers, studyBean, userBean, ExecutionMode.DRY_RUN); } } return containers; } private List<String> runRules(StudyBean studyBean, UserAccountBean userBean, List<ImportDataRuleRunnerContainer> containers, RuleSetServiceInterface ruleSetService, ExecutionMode executionMode) { List<String> messages = new ArrayList<String>(); if (containers != null && !containers.isEmpty()) { HashMap<String, ArrayList<String>> summary = ruleSetService.runRulesInImportData(containers, studyBean, userBean, executionMode); messages = extractRuleActionWarnings(summary); } return messages; } private List<String> extractRuleActionWarnings(HashMap<String, ArrayList<String>> summaryMap) { List<String> messages = new ArrayList<String>(); if (summaryMap != null && !summaryMap.isEmpty()) { for (String key : summaryMap.keySet()) { StringBuilder mesg = new StringBuilder(key + " : "); for (String s : summaryMap.get(key)) { mesg.append(s + ", "); } messages.add(mesg.toString()); } } return messages; } private String ruleActionWarnings(List<String> warnings) { if (warnings.isEmpty()) return ""; else { StringBuilder mesg = new StringBuilder("Rule Action Warnings: "); for (String s : warnings) { mesg.append(s + "; "); } return mesg.toString(); } } }