/* * OpenClinica is distributed under the * GNU Lesser General Public License (GNU LGPL). * For details see: http://www.openclinica.org/license * * Copyright 2003-2008 Akaza Research */ package org.akaza.openclinica.control.submit; import org.akaza.openclinica.bean.core.ItemDataType; import org.akaza.openclinica.bean.core.NullValue; import org.akaza.openclinica.bean.core.ResponseType; import org.akaza.openclinica.bean.core.Role; import org.akaza.openclinica.bean.managestudy.StudyEventDefinitionBean; import org.akaza.openclinica.bean.rule.XmlSchemaValidationHelper; import org.akaza.openclinica.bean.submit.DisplayItemBean; import org.akaza.openclinica.bean.submit.ItemBean; import org.akaza.openclinica.bean.submit.ItemFormMetadataBean; import org.akaza.openclinica.bean.submit.ResponseSetBean; 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.hibernate.RuleSetDao; import org.akaza.openclinica.dao.hibernate.RuleSetRuleDao; import org.akaza.openclinica.dao.submit.ItemDAO; import org.akaza.openclinica.dao.submit.ItemFormMetadataDAO; import org.akaza.openclinica.domain.rule.RuleSetBean; import org.akaza.openclinica.domain.rule.RuleSetRuleBean; import org.akaza.openclinica.domain.rule.action.DiscrepancyNoteActionBean; import org.akaza.openclinica.domain.rule.action.RuleActionBean; import org.akaza.openclinica.domain.rule.expression.Context; import org.akaza.openclinica.domain.rule.expression.ExpressionBean; import org.akaza.openclinica.domain.rule.expression.ExpressionObjectWrapper; import org.akaza.openclinica.domain.rule.expression.ExpressionProcessor; import org.akaza.openclinica.domain.rule.expression.ExpressionProcessorFactory; import org.akaza.openclinica.exception.OpenClinicaSystemException; import org.akaza.openclinica.i18n.core.LocaleResolver; import org.akaza.openclinica.service.rule.RulesPostImportContainerService; import org.akaza.openclinica.service.rule.expression.ExpressionService; import org.akaza.openclinica.view.Page; import org.akaza.openclinica.web.InsufficientPermissionException; import org.joda.time.DateTime; import org.joda.time.Duration; import org.joda.time.format.PeriodFormatter; import org.joda.time.format.PeriodFormatterBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.MessageFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; /** * Verify the Rule import , show records that have Errors as well as records that will be saved. * * @author Krikor krumlian */ public class TestRuleServlet extends SecureController { private static final long serialVersionUID = 9116068126651934226L; protected final Logger log = LoggerFactory.getLogger(TestRuleServlet.class); Locale locale; XmlSchemaValidationHelper schemaValidator = new XmlSchemaValidationHelper(); RuleSetRuleDao ruleSetRuleDao; RuleSetDao ruleSetDao; ItemDAO itemDAO; ItemFormMetadataDAO itemFormMetadataDAO; RulesPostImportContainerService rulesPostImportContainerService; private ExpressionService expressionService; private final String TARGET = "target"; private final String RULE = "rule"; private final String RULE_SET_RULE_ID = "ruleSetRuleId"; private final String RULE_SET_ID = "ruleSetId"; void putDummyActionInSession() { ArrayList<RuleActionBean> actions = new ArrayList<RuleActionBean>(); DiscrepancyNoteActionBean discNoteAction = new DiscrepancyNoteActionBean(); discNoteAction.setExpressionEvaluatesTo(true); discNoteAction.setMessage("TEST DISCREPANCY"); actions.add(discNoteAction); session.setAttribute("testRuleActions", actions); } void populteFormFields(FormProcessor fp) { String targetForm = fp.getString(TARGET).trim().replaceAll("(\n|\t|\r)", ""); String testRulesTarget = (String) session.getAttribute("testRulesTarget"); if (testRulesTarget != null) { // above added to avoid NPEs, tbh #6012 String targetSess = testRulesTarget.trim().replaceAll("(\n|\t|\r)", ""); if (!targetForm.equals(targetSess)) { putDummyActionInSession(); session.removeAttribute("testRulesTarget"); } } String textFields[] = { TARGET, RULE, RULE_SET_RULE_ID }; fp.setCurrentStringValuesAsPreset(textFields); HashMap presetValues = fp.getPresetValues(); setPresetValues(presetValues); } @Override public void processRequest() throws Exception { FormProcessor fp = new FormProcessor(request); String action = request.getParameter("action"); Validator v = new Validator(request); if (StringUtil.isBlank(action)) { request.setAttribute("result", resword.getString("test_rule_default_result")); Integer ruleSetRuleId = fp.getInt("ruleSetRuleId"); if (ruleSetRuleId != 0) { // If testing an existing ruleSetRule RuleSetRuleBean rsr = getRuleSetRuleDao().findById(ruleSetRuleId); rsr.getActions().size(); HashMap presetValues = new HashMap(); presetValues.put(TARGET, rsr.getRuleSetBean().getTarget().getValue()); presetValues.put(RULE, rsr.getRuleBean().getExpression().getValue()); presetValues.put(RULE_SET_RULE_ID, String.valueOf(ruleSetRuleId)); fp.setPresetValues(presetValues); setPresetValues(presetValues); session.setAttribute("testRuleActions", rsr.getActions()); session.setAttribute("testRulesTarget", rsr.getRuleSetBean().getTarget().getValue()); request.setAttribute("ruleSetRuleId", ruleSetRuleId); request.setAttribute("ruleSetId", rsr.getRuleSetBean().getId()); ItemBean item = getExpressionService().getItemBeanFromExpression(rsr.getRuleSetBean().getTarget().getValue()); if(item!=null) { request.setAttribute("itemName", item.getName()); request.setAttribute("itemDefinition", item.getDescription()); } else { StudyEventDefinitionBean studyEventDef= getExpressionService().getStudyEventDefinitionFromExpressionForEvents(rsr.getRuleSetBean().getTarget().getValue(),this.currentStudy); request.setAttribute("itemName", studyEventDef.getName()); request.setAttribute("itemDefinition", studyEventDef.getDescription()); } request.setAttribute("ruleSetRuleAvailable", true); } else { // free form testing putDummyActionInSession(); } session.removeAttribute("testValues"); request.setAttribute("action", "validate"); forwardPage(Page.TEST_RULES); } else if (action.equals("validate")) { HashMap<String, String> result = validate(v); if (result.get("ruleValidation").equals("rule_valid")) { addPageMessage(resword.getString("test_rules_message_valid")); } else { addPageMessage(resword.getString("test_rules_message_invalid")); } request.setAttribute("ruleValidation", result.get("ruleValidation")); request.setAttribute("validate", "on"); request.setAttribute("ruleEvaluatesTo", resword.getString("test_rules_validate_message")); request.setAttribute("ruleValidationFailMessage", result.get("ruleValidationFailMessage")); request.setAttribute("action", result.get("ruleValidation").equals("rule_valid") ? "test" : "validate"); result.remove("result"); result.remove("ruleValidation"); result.remove("ruleEvaluatesTo"); result.remove("ruleValidationFailMessage"); populateTooltip(result); session.setAttribute("testValues", result); populteFormFields(fp); forwardPage(Page.TEST_RULES); } else if (action.equals("test")) { HashMap<String, String> result = validate(v); HashMap errors = v.validate(); if (!errors.isEmpty()) { setInputMessages(errors); if (result.get("ruleValidation").equals("rule_valid")) { addPageMessage(resword.getString("test_rules_message_valid")); } else { addPageMessage(resword.getString("test_rules_message_invalid")); } request.setAttribute("ruleValidation", result.get("ruleValidation")); request.setAttribute("validate", "on"); request.setAttribute("ruleEvaluatesTo", resword.getString("test_rules_rule_fail_invalid_data_type") + " " + resword.getString("test_rules_rule_fail_invalid_data_type_desc")); request.setAttribute("ruleValidationFailMessage", result.get("ruleValidationFailMessage")); request.setAttribute("action", "test"); } else { if (result.get("ruleValidation").equals("rule_valid")) { addPageMessage(resword.getString("test_rules_message_valid")); } else { addPageMessage(resword.getString("test_rules_message_invalid")); } request.setAttribute("action", result.get("ruleValidation").equals("rule_valid") ? "test" : "validate"); request.setAttribute("ruleValidation", result.get("ruleValidation")); request.setAttribute("ruleEvaluatesTo", result.get("ruleEvaluatesTo")); request.setAttribute("ruleValidationFailMessage", result.get("ruleValidationFailMessage")); } if (result.get("ruleValidation").equals("rule_invalid")) { session.setAttribute("testValues", new HashMap<String, String>()); } else { session.setAttribute("testValues", result); } result.remove("result"); result.remove("ruleValidation"); result.remove("ruleEvaluatesTo"); result.remove("ruleValidationFailMessage"); populateTooltip(result); populteFormFields(fp); forwardPage(Page.TEST_RULES); } } private void itemDataTypeToValidatorId(String key, ItemBean item, Validator v) { switch (item.getItemDataTypeId()) { case 6: v.addValidation(key, Validator.IS_AN_INTEGER); break; case 7: v.addValidation(key, Validator.IS_A_NUMBER); break; case 9: v.addValidation(key, Validator.IS_A_DATE); break; default: break; } } private void itemDataTypeToValidatorIdMultiSelect(String key, ItemBean item, Validator v, ResponseSetBean responseSet) { v.addValidation(key, Validator.IN_RESPONSE_SET_COMMA_SEPERATED, responseSet); } private void populateTooltip(HashMap<String, String> testVariablesAndValues) { if (testVariablesAndValues != null) { for (Map.Entry<String, String> entry : testVariablesAndValues.entrySet()) { ItemBean item = getExpressionService().getItemBeanFromExpression(entry.getKey()); if(item!=null){ DisplayItemBean dib = new DisplayItemBean(); dib.setItem(item); request.setAttribute(entry.getKey() + "-tooltip", item.getName() + ": " + ItemDataType.get(item.getItemDataTypeId()).getName()); request.setAttribute(entry.getKey() + "-dib", dib); } else{ StudyEventDefinitionBean sed = getExpressionService().getStudyEventDefinitionFromExpressionForEvents(entry.getKey(), currentStudy); if(entry.getKey().contains(ExpressionService.STARTDATE)) { request.setAttribute(entry.getKey() + "-tooltip", sed.getName() + ": " + "date"); request.setAttribute("studyEventProperty", new Integer(9)); } else if(entry.getKey().contains(ExpressionService.STATUS)) { request.setAttribute(entry.getKey() + "-tooltip", sed.getName() + ": " + "status"); request.setAttribute("studyEventProperty", new Integer(5)); } } if ((item!=null &&item.getItemDataTypeId() == 9)||(item==null&&entry.getKey().contains(ExpressionService.STARTDATE))) {//so enter this in case if the rules are event action based or if item has date type try { SimpleDateFormat sdf = new SimpleDateFormat(resformat.getString("date_format_string")); SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd"); if(!entry.getValue().isEmpty()) { java.util.Date date = sdf2.parse(entry.getValue()); entry.setValue(sdf.format(date)); } } catch (Exception e) { logger.error(e.toString()); // TODO: handle exception } } } } } private HashMap<String, String> validate(Validator v) throws ParseException { FormProcessor fp = new FormProcessor(request); String targetString = fp.getString("target"); String ruleString = fp.getString("rule"); ruleString = ruleString.trim().replaceAll("(\n|\t|\r)", " "); targetString = targetString.trim().replaceAll("(\n|\t|\r)", ""); HashMap<String, String> p = session.getAttribute("testValues") != null ? (HashMap<String, String>) session.getAttribute("testValues") : new HashMap<String, String>(); if (p != null) { for (Map.Entry<String, String> entry : p.entrySet()) { entry.setValue(fp.getString(entry.getKey())); if(entry.getKey().startsWith(ExpressionService.STUDY_EVENT_OID_START_KEY)&&(entry.getKey().endsWith(ExpressionService.STATUS)||entry.getKey().endsWith(ExpressionService.STARTDATE))) { StudyEventDefinitionBean sed = getExpressionService().getStudyEventDefinitionFromExpressionForEvents(entry.getKey(), currentStudy); if(entry.getKey().endsWith(ExpressionService.STATUS)){ //TODO add the logic for status } else if(entry.getKey().endsWith(ExpressionService.STARTDATE)){ try { v.addValidation(entry.getKey(), Validator.IS_A_DATE); SimpleDateFormat sdf = new SimpleDateFormat(resformat.getString("date_format_string")); SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd"); if(!entry.getValue().isEmpty()) { java.util.Date date = sdf2.parse(entry.getValue()); entry.setValue(sdf.format(date)); } } catch (Exception e) { logger.error(e.toString()); // TODO: handle exception } } } else{ ItemBean item = getExpressionService().getItemBeanFromExpression(entry.getKey()); List<ItemFormMetadataBean> itemFormMetadataBeans = getItemFormMetadataDAO().findAllByItemId(item.getId()); ItemFormMetadataBean itemFormMetadataBean = itemFormMetadataBeans.size() > 0 ? itemFormMetadataBeans.get(0) : null; if (!entry.getValue().equals("") && NullValue.getByName(entry.getValue()) == NullValue.INVALID) { if (itemFormMetadataBean != null) { if (itemFormMetadataBean.getResponseSet().getResponseType() == ResponseType.SELECTMULTI || itemFormMetadataBean.getResponseSet().getResponseType() == ResponseType.CHECKBOX) { v.addValidation(entry.getKey(), Validator.IN_RESPONSE_SET_COMMA_SEPERATED, itemFormMetadataBean.getResponseSet()); } if (itemFormMetadataBean.getResponseSet().getResponseType() == ResponseType.SELECT || itemFormMetadataBean.getResponseSet().getResponseType() == ResponseType.RADIO) { v.addValidation(entry.getKey(), Validator.IN_RESPONSE_SET_SINGLE_VALUE, itemFormMetadataBean.getResponseSet()); } else { itemDataTypeToValidatorId(entry.getKey(), item, v); } } } if (item.getItemDataTypeId() == 9) { try { SimpleDateFormat sdf = new SimpleDateFormat(resformat.getString("date_format_string")); SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd"); if(!entry.getValue().isEmpty()) { java.util.Date date = sdf.parse(entry.getValue()); entry.setValue(sdf2.format(date)); } } catch (Exception e) { // TODO: handle exception } } } } } List<RuleActionBean> actions = session.getAttribute("testRuleActions") != null ? (List<RuleActionBean>) session.getAttribute("testRuleActions") : new ArrayList<RuleActionBean>(); if (actions != null) { for (int i = 0; i < actions.size(); i++) { actions.get(i).setExpressionEvaluatesTo(fp.getBoolean("actions" + i)); } } // Check Target if not valid report and return try { getExpressionService().ruleSetExpressionChecker(targetString); } catch (OpenClinicaSystemException e) { HashMap<String, String> result = new HashMap<String, String>(); MessageFormat mf = new MessageFormat(""); mf.applyPattern(respage.getString(e.getErrorCode())); Object[] arguments = e.getErrorParams(); result.put("ruleValidation", "target_invalid"); result.put("ruleValidationFailMessage", e.getErrorCode() + " : " + mf.format(arguments)); result.put("ruleEvaluatesTo", ""); request.setAttribute("targetFail", "on"); return result; } // Auto update itemName & itemDefinition based on target ItemBean item = getExpressionService().getItemBeanFromExpression(targetString); StudyEventDefinitionBean sed = null ; if (item != null) { request.setAttribute("itemName", item.getName()); request.setAttribute("itemDefinition", item.getDescription()); } else{ sed = getExpressionService().getStudyEventDefinitionFromExpressionForEvents(targetString, currentStudy); if(sed!=null) { request.setAttribute("itemName",sed.getName()); request.setAttribute("itemDefinition",sed.getDescription()); } } RuleSetBean ruleSet = new RuleSetBean(); ExpressionBean target = new ExpressionBean(); target.setContext(Context.OC_RULES_V1); target.setValue(targetString); ruleSet.setTarget(target); RuleSetBean persistentRuleSet = getRuleSetDao().findByExpressionAndStudy(ruleSet,currentStudy.getId()); if (persistentRuleSet != null) { if(item!=null) request.setAttribute("ruleSetId", item.getId()); else request.setAttribute("ruleSetId", sed.getId()); } ExpressionBean rule = new ExpressionBean(); rule.setContext(Context.OC_RULES_V1); rule.setValue(ruleString); ExpressionObjectWrapper eow = new ExpressionObjectWrapper(sm.getDataSource(), currentStudy, rule, ruleSet); ExpressionProcessor ep = ExpressionProcessorFactory.createExpressionProcessor(eow); ep.setRespage(respage); // Run expression with populated HashMap DateTime start = new DateTime(); HashMap<String, String> result = ep.testEvaluateExpression(p); DateTime end = new DateTime(); Duration dur = new Duration(start, end); PeriodFormatter yearsAndMonths = new PeriodFormatterBuilder().printZeroAlways().appendSecondsWithMillis().appendSuffix(" second", " seconds").toFormatter(); yearsAndMonths.print(dur.toPeriod()); // Run expression with empty HashMap to check rule validity, because // using illegal test values will cause invalidity HashMap<String, String> k = new HashMap<String, String>(); HashMap<String, String> theResult = ep.testEvaluateExpression(k); if (theResult.get("ruleValidation").equals("rule_valid") && result.get("ruleValidation").equals("rule_invalid")) { result.put("ruleValidation", "rule_valid"); result.put("ruleEvaluatesTo", resword.getString("test_rules_rule_fail") + " " + result.get("ruleValidationFailMessage")); result.remove("ruleValidationFailMessage"); } // Put on screen request.setAttribute("duration", yearsAndMonths.print(dur.toPeriod())); return result; } @Override protected String getAdminServlet() { if (ub.isSysAdmin()) { return SecureController.ADMIN_SERVLET_CODE; } else { return ""; } } @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)) { 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"); } private RuleSetRuleDao getRuleSetRuleDao() { ruleSetRuleDao = this.ruleSetRuleDao != null ? ruleSetRuleDao : (RuleSetRuleDao) SpringServletAccess.getApplicationContext(context).getBean("ruleSetRuleDao"); return ruleSetRuleDao; } private RuleSetDao getRuleSetDao() { ruleSetDao = this.ruleSetDao != null ? ruleSetDao : (RuleSetDao) SpringServletAccess.getApplicationContext(context).getBean("ruleSetDao"); return ruleSetDao; } private ItemDAO getItemDAO() { itemDAO = this.itemDAO != null ? itemDAO : new ItemDAO(sm.getDataSource()); return itemDAO; } private ItemFormMetadataDAO getItemFormMetadataDAO() { itemFormMetadataDAO = this.itemFormMetadataDAO != null ? itemFormMetadataDAO : new ItemFormMetadataDAO(sm.getDataSource()); return itemFormMetadataDAO; } private RulesPostImportContainerService getRulesPostImportContainerService() { rulesPostImportContainerService = this.rulesPostImportContainerService != null ? rulesPostImportContainerService : (RulesPostImportContainerService) SpringServletAccess .getApplicationContext(context).getBean("rulesPostImportContainerService"); rulesPostImportContainerService.setCurrentStudy(currentStudy); rulesPostImportContainerService.setRespage(respage); rulesPostImportContainerService.setUserAccount(ub); return rulesPostImportContainerService; } private ExpressionService getExpressionService() { expressionService = this.expressionService != null ? expressionService : new ExpressionService( new ExpressionObjectWrapper(sm.getDataSource(), currentStudy, (ExpressionBean) null, (RuleSetBean) null)); expressionService.setExpressionWrapper(new ExpressionObjectWrapper(sm.getDataSource(), currentStudy, (ExpressionBean) null, (RuleSetBean)null)); return expressionService; } }