/** * Performs calculation. <br> * Notice: both parameter 'itemdata' and parameter 'errs' might be updated in this method. * * @param displayItems * @param items * @param itemdata * @param errs * @return * @author ywang (Jan. 2008) */ public String doCalculation( DisplayItemBean displayItem, HashMap<String, ItemBean> items, HashMap<String, String> itemdata, HashMap<Integer, TreeSet<Integer>> itemOrdinals, StringBuffer errs, int ordinal) { if (itemdata == null) { logger.error("In DataEntryServlet doCalculation(), itemdata map is empty!"); errs.append("Calculation cannot be started because needed items are empty" + "; "); return ""; } String value = ""; NumberFormat nf = NumberFormat.getInstance(); Parser parser = new Parser(items, itemdata); ItemBean ib = displayItem.getItem(); ItemFormMetadataBean ifm = displayItem.getMetadata(); ResponseOptionBean rob = (ResponseOptionBean) ifm.getResponseSet().getOptions().get(0); ArrayList<ScoreToken> parsedExp = new ArrayList<ScoreToken>(); int type = ifm.getResponseSet().getResponseTypeId(); if (type == 8) { parsedExp = parser.assignVariables(parser.parseScoreTokens(rob.getValue()), ordinal); } else if (type == 9) { // YW, 1-16-2008, for group-calculation type. Current restrictions: // 1. only calculate sum(), avg(), min(), max(), median(), stdev() // 2. formula arguments only contain item beans // 3. only one item bean per argument parsedExp = parser.assignVariables(parser.parseScoreTokens(rob.getValue()), itemOrdinals); } if (parser.getErrors().length() > 0) { errs.append(parser.getErrors()); } else { try { value = ScoreUtil.eval(parsedExp); } catch (ScoreException se) { logger.error(se.getMessage()); } ItemDataType idt = ib.getDataType(); if (value == null || value.length() == 0) { value = ""; String exp = rob.getValue(); exp = exp.replace("##", ","); errs.append("Result is empty in" + " " + exp + "; "); // errors.append(resexception.getString("result_is_empty_in") + // " " + exp + "; "); } else { value = this.getMathContextValue(value, ifm, idt, errs); } // idb.setStatus(Status.UNAVAILABLE); itemdata.put(ib.getId() + "_" + ordinal, value); } return value; }
protected String getMathContextValue( String value, ItemFormMetadataBean ifm, ItemDataType idt, StringBuffer errorMessage) { ResponseOptionBean rob = (ResponseOptionBean) ifm.getResponseSet().getOptions().get(0); String widthDecimal = ifm.getWidthDecimal(); int width = Validator.parseWidth(widthDecimal); int decimal = Validator.parseDecimal(widthDecimal); NumberFormat nf = NumberFormat.getInstance(); if (idt.equals(ItemDataType.INTEGER)) { try { Double d = nf.parse(value).doubleValue(); int p = 0; if (width > 0) { p = d >= 0 ? width : width - 1; } else { p = BigDecimal.valueOf(d).precision(); } MathContext mc = new MathContext(p, RoundingMode.valueOf(BigDecimal.ROUND_HALF_UP)); value = (new BigDecimal(d, mc)).setScale(0, BigDecimal.ROUND_HALF_UP).toPlainString(); } catch (ParseException e) { logger.error("Number was expected in " + rob.getValue() + " : " + value); String exp = rob.getValue(); exp = exp.replace("##", ","); errorMessage.append("Number was expected in" + " " + exp + " : " + value + "; "); // errors.append(resexception.getString("number_expected_in") // + " " + exp + ": " + value + "; "); value = ""; } } else if (idt.equals(ItemDataType.REAL)) { try { Double d = nf.parse(value).doubleValue(); // there should be no width specify for calculation item int p = BigDecimal.valueOf(d).precision(); // set default scale as 4 int scale = decimal > 0 ? decimal : DEFAULT_DECIMAL; MathContext mc = new MathContext(p, RoundingMode.valueOf(BigDecimal.ROUND_HALF_UP)); value = (new BigDecimal(d, mc)).setScale(scale, BigDecimal.ROUND_HALF_UP).toPlainString(); } catch (Exception ee) { String exp = rob.getValue(); exp = exp.replace("##", ","); logger.error("Number was expected in " + exp + " : " + value); errorMessage.append("Number was expected in" + " " + exp + " : " + value + "; "); // errors.append(resexception.getString("number_expected_in") // + " " + exp + ": " + value + "; "); value = ""; } } return value; }
/** * Re-do calculations if funcs include changed item(s) and funcs are not included in the current * section. If calculation can not sucessfully redo, old value will be erased and "<erased>" will * be saved in database. <br> * The parameter 'itemdata' might be overwritten. * * @param itemGroupSizes * @param items * @param itemdata * @param oldItemdata * @param updatedData * @param sectionId * @return ArrayList<String> which records left_item_text of items who failed to be updated into * database. */ public ArrayList<String> redoCalculations( HashMap<String, ItemBean> items, HashMap<String, String> itemdata, TreeSet<String> changedItems, HashMap<Integer, TreeSet<Integer>> itemOrdinals, int sectionId) { ArrayList<String> updateFailedItems = new ArrayList<String>(); if (itemdata == null) { logger.error("In ScoreCalculator redoCalculations(), itemdata is empty!"); errors.add("In ScoreCalculator redoCalculations(), 'itemdata' map is empty!"); return updateFailedItems; } if (changedItems == null) { logger.error("In ScoreCalculator redoCalculations(), 'changeItems' set is empty!"); errors.add("In ScoreCalculator redoCalculations(), 'changeItems' set is empty!"); return updateFailedItems; } ItemFormMetadataDAO ifmdao = new ItemFormMetadataDAO(sm.getDataSource()); ItemDAO idao = new ItemDAO(sm.getDataSource()); ItemDataDAO iddao = new ItemDataDAO(sm.getDataSource()); NumberFormat nf = NumberFormat.getInstance(); Parser parser = new Parser(items, itemdata); try { // for calculation type List<ItemFormMetadataBean> derivedItemList = ifmdao.findAllByCRFVersionIdAndResponseTypeId( ecb.getCRFVersionId(), ResponseType.CALCULATION.getId()); if (derivedItemList.size() > 0) { Collections.sort(derivedItemList); for (ItemFormMetadataBean ifmb : derivedItemList) { if (ifmb.getSectionId() != sectionId) { ItemBean ib = (ItemBean) idao.findByPK(ifmb.getItemId()); ResponseOptionBean rob = (ResponseOptionBean) ifmb.getResponseSet().getOptions().get(0); int groupsize = 1; if (itemOrdinals.containsKey(ib.getId())) { groupsize = itemOrdinals.get(ib.getId()).size(); } String value = ""; ArrayList<ScoreToken> parsedExp = new ArrayList<ScoreToken>(); for (int i = 0; i < groupsize; ++i) { ItemDataBean idb = iddao.findByItemIdAndEventCRFIdAndOrdinal(ifmb.getItemId(), ecb.getId(), i + 1); // is there any changed item Parser p = new Parser(items, itemdata); parsedExp = parser.parseScoreTokens(rob.getValue()); if (p.isChanged(changedItems, parsedExp)) { StringBuffer err = new StringBuffer(); parsedExp = parser.assignVariables(parsedExp, i + 1); // if parser has error and has been calculated // before, set "<erased>" if (parser.getErrors().length() > 0) { err.append(parser.getErrors()); if (idb.isActive()) { idb.setValue("<erased>"); idb.setStatus(Status.UNAVAILABLE); idb = (ItemDataBean) iddao.update(idb); if (!idb.isActive()) { String key = i + 1 > 1 ? ifmb.getLeftItemText() + "_" + (i + 1) : ifmb.getLeftItemText(); updateFailedItems.add(key); } } parser.setErrors(new StringBuffer()); } // otherwise do calculation else { try { value = ScoreUtil.eval(parsedExp); } catch (ScoreException se) { logger.error(se.getMessage()); } String exp = rob.getValue(); exp = exp.replace("##", ","); if (writeToDB(ib, ifmb, idb, exp, value, err)) { changedItems.add(ib.getName()); itemdata.put(ib.getId() + "_" + (i + 1), idb.getValue()); } else { String key = i + 1 > 1 ? ifmb.getLeftItemText() + "_" + (i + 1) : ifmb.getLeftItemText(); updateFailedItems.add(key); } } if (err.length() > 0) { String key = i + 1 > 1 ? ifmb.getLeftItemText() + "_" + (i + 1) : ifmb.getLeftItemText(); errors.add("Item " + key + " contains calculation errors: " + err.toString()); } } } } } } List<ItemFormMetadataBean> itemList = ifmdao.findAllByCRFVersionIdAndResponseTypeId( ecb.getCRFVersionId(), ResponseType.GROUP_CALCULATION.getId()); if (itemList.size() > 0) { Collections.sort(itemList); for (ItemFormMetadataBean ifmb : itemList) { if (ifmb.getSectionId() != sectionId) { ItemBean ib = (ItemBean) idao.findByPK(ifmb.getItemId()); ResponseOptionBean rob = (ResponseOptionBean) ifmb.getResponseSet().getOptions().get(0); String value = ""; Parser p = new Parser(items, itemdata); ArrayList<ScoreToken> parsedExp = parser.parseScoreTokens(rob.getValue()); if (p.isChanged(changedItems, parsedExp)) { StringBuffer err = new StringBuffer(); parser.setErrors(err); parsedExp = parser.assignVariables(parsedExp, itemOrdinals); ItemDataBean idb = iddao.findByItemIdAndEventCRFIdAndOrdinal(ifmb.getItemId(), ecb.getId(), 1); if (parser.getErrors().length() > 0) { err.append(parser.getErrors()); if (idb.isActive()) { idb.setValue("<erased>"); idb.setStatus(Status.UNAVAILABLE); idb = (ItemDataBean) iddao.update(idb); if (!idb.isActive()) { updateFailedItems.add(ifmb.getLeftItemText()); } } } else { try { value = ScoreUtil.eval(parsedExp); } catch (ScoreException se) { logger.error(se.getMessage()); } String exp = rob.getValue(); exp = exp.replace("##", ","); if (writeToDB(ib, ifmb, idb, exp, value, err)) { changedItems.add(ib.getName()); itemdata.put(ib.getId() + "_" + idb.getOrdinal(), idb.getValue()); } else { updateFailedItems.add(ifmb.getLeftItemText()); } } if (err.length() > 0) { errors.add( "Item " + ifmb.getLeftItemText() + " contains calculation errors: " + err.toString()); } } } } } } catch (OpenClinicaException e) { logger.error(e.getMessage()); } return updateFailedItems; }
@Override protected DisplayItemBean validateDisplayItemBean( DiscrepancyValidator v, DisplayItemBean dib, String inputName) { org.akaza.openclinica.bean.core.ResponseType rt = dib.getMetadata().getResponseSet().getResponseType(); boolean isSingleItem = false; if (StringUtil.isBlank(inputName)) { // for single items inputName = getInputName(dib); isSingleItem = true; } // we only give warning to user if data entered in DDE is different from // IDE when the first // time user hits 'save' int keyId = ecb.getId(); Integer validationCount = (Integer) session.getAttribute(COUNT_VALIDATE + keyId); ItemDataBean valueToCompare = dib.getData(); if (!isSingleItem) { valueToCompare = dib.getDbData(); } boolean showOriginalItem = getItemMetadataService() .isShown(dib.getItem().getId(), ecb, valueToCompare); // was dib.getData() boolean showItem = dib.getMetadata().isShowItem(); boolean showDuplicateItem = getItemMetadataService() .hasPassedDDE( dib.getMetadata(), ecb, valueToCompare); // .isShown(dib.getItem().getId(), ecb, dib.getDbData());// where // is the set db data? logger.debug( "*** show original item has value " + dib.getData().getValue() + " and show item has value " + valueToCompare.getValue()); logger.debug( "--- show original: " + showOriginalItem + " show duplicate: " + showDuplicateItem + " and just show item: " + showItem); logger.debug("VALIDATION COUNT " + validationCount); if (showOriginalItem && showDuplicateItem || showItem) { // it should either be shown already, OR shown in the database? // logger.debug("=== we passed, adding validation here"); Integer indValidationCount = (Integer) session.getAttribute(COUNT_VALIDATE + keyId + dib.getMetadata().getId()); if (rt.equals(org.akaza.openclinica.bean.core.ResponseType.TEXT) || rt.equals(org.akaza.openclinica.bean.core.ResponseType.TEXTAREA) || rt.equals(org.akaza.openclinica.bean.core.ResponseType.FILE)) { dib = validateDisplayItemBeanText(v, dib, inputName); // necessary? // if (indValidationCount == null || validationCount == null || validationCount.intValue() // == 0) { logger.debug("=== we passed, adding validation here TEXT " + valueToCompare.getId()); v.addValidation( inputName, Validator.MATCHES_INITIAL_DATA_ENTRY_VALUE, valueToCompare, false); v.setErrorMessage( respage.getString("value_you_specified") + " " + valueToCompare.getValue() + " " + respage.getString("from_initial_data_entry")); // session.setAttribute(COUNT_VALIDATE + keyId + dib.getMetadata().getId(), new Integer(1)); // } } else if (rt.equals(org.akaza.openclinica.bean.core.ResponseType.RADIO) || rt.equals(org.akaza.openclinica.bean.core.ResponseType.SELECT)) { dib = validateDisplayItemBeanSingleCV(v, dib, inputName); // ItemFormMetadataBean ifmdb = dib.getMetadata(); // ResponseSetBean rsBean = ifmdb.getResponseSet(); // logger.info("### found a response set count of "+inputName+" // "+rsBean.getOptions().size()); // TODO sees it at this end tbh 1878 // if (indValidationCount == null || validationCount == null || validationCount.intValue() // == 0) { logger.debug("=== we passed, adding validation here RADIO " + valueToCompare.getId()); v.addValidation( inputName, Validator.MATCHES_INITIAL_DATA_ENTRY_VALUE, valueToCompare, false); String errorValue = valueToCompare.getValue(); java.util.ArrayList options = dib.getMetadata().getResponseSet().getOptions(); for (int u = 0; u < options.size(); u++) { ResponseOptionBean rob = (ResponseOptionBean) options.get(u); if (rob.getValue().equals(errorValue)) { errorValue = rob.getText(); } } v.setErrorMessage( respage.getString("value_you_specified") + " " + errorValue + " " + respage.getString("from_initial_data_entry")); // session.setAttribute(COUNT_VALIDATE + keyId + dib.getMetadata().getId(), new Integer(1)); // } } else if (rt.equals(org.akaza.openclinica.bean.core.ResponseType.CHECKBOX) || rt.equals(org.akaza.openclinica.bean.core.ResponseType.SELECTMULTI)) { dib = validateDisplayItemBeanMultipleCV(v, dib, inputName); // if (indValidationCount == null || validationCount == null || validationCount.intValue() // == 0) { logger.debug("=== we passed, adding validation here CHECKBOX " + valueToCompare.getId()); v.addValidation( inputName, Validator.MATCHES_INITIAL_DATA_ENTRY_VALUE, valueToCompare, true); // repeated from above, tbh 112007 String errorValue = valueToCompare.getValue(); String errorTexts = ""; java.util.ArrayList options = dib.getMetadata().getResponseSet().getOptions(); for (int u = 0; u < options.size(); u++) { ResponseOptionBean rob = (ResponseOptionBean) options.get(u); if (errorValue.contains(rob.getValue())) { errorTexts = errorTexts + rob.getText(); if (u < options.size() - 1) { // the values for multi-select are seperated by // comma errorTexts = errorTexts + ", "; } } } v.setErrorMessage( respage.getString("value_you_specified") + " " + errorTexts + " " + respage.getString("from_initial_data_entry")); // session.setAttribute(COUNT_VALIDATE + keyId + dib.getMetadata().getId(), new Integer(1)); // } } } // only load form value when an item is not in a group, // if in group, the value is already loaded // see formGroups = loadFormValueForItemGroup(digb,digbs,formGroups); if (isSingleItem) { dib = loadFormValue(dib); } return dib; }
@Override protected DisplayItemBean validateDisplayItemBean( DiscrepancyValidator v, DisplayItemBean dib, String inputName, HttpServletRequest request) { org.akaza.openclinica.bean.core.ResponseType rt = dib.getMetadata().getResponseSet().getResponseType(); HttpSession session = request.getSession(); EventCRFBean ecb = (EventCRFBean) request.getAttribute(INPUT_EVENT_CRF); boolean isSingleItem = false; if (StringUtil.isBlank(inputName)) { // for single items inputName = getInputName(dib); isSingleItem = true; } // we only give warning to user if data entered in DDE is different from // IDE when the first // time user hits 'save' int keyId = ecb.getId(); Integer validationCount = (Integer) session.getAttribute(COUNT_VALIDATE + keyId); // @pgawade 12-Aug-2011 issue 10601: // 1. Moved the call to loadFormValue method setting values // from form here. It was at the end // of this method before that is after validations and so an extra // validation for checking value entered // against the data type was getting implemented for non-repeating group // items. // 2. Copying the form data into new object for non repeating items to // pass to validation // for matching IDE and DDE values. Id same reference is used, the way // code here was written, it affetcs // the value used in validation of data entered in DDE against the // related data type ItemDataBean valueToCompareTmp = dib.getData(); ItemDataBean valueToCompare = copyItemDataBean(valueToCompareTmp); if (!isSingleItem) { valueToCompare = dib.getDbData(); } // only load form value when an item is not in a group, // if in group, the value is already loaded // see formGroups = loadFormValueForItemGroup(digb,digbs,formGroups); if (isSingleItem) { dib = loadFormValue(dib, request); } boolean showOriginalItem = getItemMetadataService() .isShown(dib.getItem().getId(), ecb, valueToCompare); // was dib.getData() boolean showItem = dib.getMetadata().isShowItem(); if (!showItem && dib.getScdData().getScdItemMetadataBean().getScdItemFormMetadataId() > 0) { showItem = true; } boolean showDuplicateItem = getItemMetadataService() .hasPassedDDE( dib.getMetadata(), ecb, valueToCompare); // .isShown(dib.getItem().getId(), ecb, dib.getDbData());// where // is the set db data? logger.debug( "*** show original item has value " + dib.getData().getValue() + " and show item has value " + valueToCompare.getValue()); logger.debug( "--- show original: " + showOriginalItem + " show duplicate: " + showDuplicateItem + " and just show item: " + showItem); logger.debug("VALIDATION COUNT " + validationCount); if (showOriginalItem && showDuplicateItem || showItem) { if (rt.equals(org.akaza.openclinica.bean.core.ResponseType.TEXT) || rt.equals(org.akaza.openclinica.bean.core.ResponseType.TEXTAREA) || rt.equals(org.akaza.openclinica.bean.core.ResponseType.FILE)) { dib = validateDisplayItemBeanText(v, dib, inputName, request); if (validationCount == null || validationCount.intValue() == 0) { v.addValidation( inputName, Validator.MATCHES_INITIAL_DATA_ENTRY_VALUE, valueToCompare, false); v.setErrorMessage( respage.getString("value_you_specified") + " " + valueToCompare.getValue() + " " + respage.getString("from_initial_data_entry")); } } else if (rt.equals(org.akaza.openclinica.bean.core.ResponseType.RADIO) || rt.equals(org.akaza.openclinica.bean.core.ResponseType.SELECT)) { dib = validateDisplayItemBeanSingleCV(v, dib, inputName); // ItemFormMetadataBean ifmdb = dib.getMetadata(); // ResponseSetBean rsBean = ifmdb.getResponseSet(); // logger.info("### found a response set count of "+inputName+" // "+rsBean.getOptions().size()); // TODO sees it at this end tbh 1878 if (validationCount == null || validationCount.intValue() == 0) { v.addValidation( inputName, Validator.MATCHES_INITIAL_DATA_ENTRY_VALUE, valueToCompare, false); String errorValue = valueToCompare.getValue(); java.util.ArrayList options = dib.getMetadata().getResponseSet().getOptions(); for (int u = 0; u < options.size(); u++) { ResponseOptionBean rob = (ResponseOptionBean) options.get(u); if (rob.getValue().equals(errorValue)) { errorValue = rob.getText(); } } v.setErrorMessage( respage.getString("value_you_specified") + " " + errorValue + " " + respage.getString("from_initial_data_entry")); } } else if (rt.equals(org.akaza.openclinica.bean.core.ResponseType.CHECKBOX) || rt.equals(org.akaza.openclinica.bean.core.ResponseType.SELECTMULTI)) { dib = validateDisplayItemBeanMultipleCV(v, dib, inputName); if (validationCount == null || validationCount.intValue() == 0) { v.addValidation( inputName, Validator.MATCHES_INITIAL_DATA_ENTRY_VALUE, valueToCompare, true); // repeated from above, tbh 112007 String errorValue = valueToCompare.getValue(); String errorTexts = ""; java.util.ArrayList options = dib.getMetadata().getResponseSet().getOptions(); for (int u = 0; u < options.size(); u++) { ResponseOptionBean rob = (ResponseOptionBean) options.get(u); if (errorValue.contains(rob.getValue())) { errorTexts = errorTexts + rob.getText(); if (u < options.size() - 1) { // the values for multi-select are seperated by // comma errorTexts = errorTexts + ", "; } } } v.setErrorMessage( respage.getString("value_you_specified") + " " + errorTexts + " " + respage.getString("from_initial_data_entry")); } } } // // only load form value when an item is not in a group, // // if in group, the value is already loaded // // see formGroups = loadFormValueForItemGroup(digb,digbs,formGroups); // if (isSingleItem) { // dib = loadFormValue(dib, request); // } return dib; }