Java tutorial
/******************************************************************************* * Copyright SemanticBits, Northwestern University and Akaza Research * * Distributed under the OSI-approved BSD 3-Clause License. * See http://ncip.github.com/caaers/LICENSE.txt for details. ******************************************************************************/ package gov.nih.nci.cabig.caaers.web.ae; import gov.nih.nci.cabig.caaers.domain.*; import gov.nih.nci.cabig.caaers.utils.DateUtils; import gov.nih.nci.cabig.caaers.web.fields.*; import gov.nih.nci.cabig.caaers.web.utils.WebUtils; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.springframework.beans.BeanWrapper; import org.springframework.validation.Errors; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import java.util.*; /** * @author Biju Joseph * @author Ion C. Olaru * */ public class AdverseEventCaptureTab extends AdverseEventTab { // The names of the field groups private static final String MAIN_FIELD_GROUP = "main"; private static final String OUTCOME_FIELD_GROUP = "outcomes"; private static final String TAB_NAME = AdverseEventCaptureTab.class.getName(); //max characters allowed for Verbatim private static final Integer VERBATIM_MAX_SIZE = 65; public AdverseEventCaptureTab() { super("Enter Adverse Events", "Adverse Events", "ae/captureAdverseEvents"); setAutoPopulateHelpKey(true); } /** * This method will create the fields to be displayed on the screen. * For CTC/MedDRA Study the following fields will be created: * 0. Other(MedDRA) - [conditional, only appear for CTC studies, if term is otherspecify]. * 1. Verbatim * 2. Grade * 3. GradedDate * 4. StartDate * 5. End Date * 6. Attribution To Study * 7. Time Of Event * 8. Event Location * 9. Hospitalization * 10. Expectedness * 11. Outcome * Note:- We should run the adverse events against the index fixed list, since that list will have null items in it, we should skip if 'AdverseEvent' is null. */ @Override public Map<String, InputFieldGroup> createFieldGroups(CaptureAdverseEventInputCommand cmd) { InputFieldGroupMap fieldGrpMap = new InputFieldGroupMap(); MultipleFieldGroupFactory mainFieldFactory; if (cmd.getAdverseEventReportingPeriod() != null) { Study study = cmd.getAdverseEventReportingPeriod().getStudy(); boolean isMeddraStudy = study.getAeTerminology().getTerm() == Term.MEDDRA; int size = cmd.getAdverseEvents().size(); //create one field group - One row of main groups mainFieldFactory = new MultipleFieldGroupFactory(MAIN_FIELD_GROUP, "adverseEvents"); for (int i = 0; i < size; i++) { AdverseEvent ae = cmd.getAdverseEvents().get(i); if (ae == null) continue; boolean unRetired = !ae.isRetired(); //only add otherMedDRA on non MedDRA and otherRequired=true if (ae.getAdverseEventTerm().isOtherRequired()) { if (study.getOtherMeddra() != null) { //other MedDRA InputField otherMeddraField = (ae.getSolicited()) ? InputFieldFactory.createLabelField("lowLevelTerm.meddraTerm", "Other (MedDRA)", false & unRetired) : InputFieldFactory.createAutocompleterField("lowLevelTerm", "Other (MedDRA)", true & unRetired); mainFieldFactory.addField(otherMeddraField); } else { //other Specify InputField otherSpecifyField = InputFieldFactory.createTextField("otherSpecify", "Other (specify)", "aeReport.adverseEvents.otherSpecify", true & unRetired); mainFieldFactory.addField(otherSpecifyField); } } //verbatim - Is required when there is no other MedDRA boolean verbatimMandatory = (study.getOtherMeddra() == null) && (ae.getAdverseEventTerm().isOtherRequired()); boolean verbatimApplicable = caaersFieldConfigurationManager.isFieldApplicable(TAB_NAME, "adverseEvents[].detailsForOther"); boolean verbatimRequired = unRetired && verbatimApplicable && (verbatimMandatory || isFieldRequired(ae, "adverseEvents[].detailsForOther")); InputField verbatimField = InputFieldFactory.createTextField("detailsForOther", "Verbatim", "aeReport.adverseEvents.detailsForOther", verbatimRequired); InputFieldAttributes.setMaxLength(verbatimField, VERBATIM_MAX_SIZE); InputFieldAttributes.setSize(verbatimField, 25); mainFieldFactory.addField(verbatimField); //grade InputField gradeField = InputFieldFactory.createLongSelectField("grade", "Grade", "aeReport.adverseEvents.grade", unRetired && isFieldRequired(ae, "adverseEvents[].grade"), createGradeOptions(ae, isMeddraStudy ? "Meddra" : "Ctc")); mainFieldFactory.addField(gradeField); //graded date InputField gradedDateField = InputFieldFactory.createDateTimeField("gradedDate", "Awareness date", "aeReport.adverseEvents.gradedDate", unRetired && isFieldRequired(ae, "adverseEvents[].gradedDate")); mainFieldFactory.addField(gradedDateField); //startDate InputField startDateField = InputFieldFactory.createPastDateField("startDate", "Start date", "aeReport.adverseEvents.startDate", unRetired && isFieldRequired(ae, "adverseEvents[].startDate")); mainFieldFactory.addField(startDateField); //endDate InputField endDateField = InputFieldFactory.createPastDateField("endDate", "End date", "aeReport.adverseEvents.endDate", unRetired && isFieldRequired(ae, "adverseEvents[].endDate")); mainFieldFactory.addField(endDateField); //attribution InputField attributionField = InputFieldFactory.createSelectField("attributionSummary", "Attribution to study intervention", "aeReport.adverseEvents.attributionSummary", unRetired && isFieldRequired(ae, "adverseEvents[].attributionSummary"), createAttributionOptions()); mainFieldFactory.addField(attributionField); //Hospitalization InputField hospitalizationField = InputFieldFactory.createSelectField("hospitalization", "Did AE cause hospitalization?", "aeReport.adverseEvents.hospitalization", unRetired && isFieldRequired(ae, "adverseEvents[].hospitalization"), createHospitalizationOptions()); mainFieldFactory.addField(hospitalizationField); //expectedness InputField expectednessField = InputFieldFactory.createSelectField("expected", "Expected", "aeReport.adverseEvents.expected", unRetired && isFieldRequired(ae, "adverseEvents[].expected"), createExpectedOptions()); mainFieldFactory.addField(expectednessField); //Time of event InputField timeOfEventField = createTimeField("eventApproximateTime", "Event time", "aeReport.adverseEvents.eventApproximateTime.hourString", unRetired && isFieldRequired(ae, "adverseEvents[].eventApproximateTime.hourString")); mainFieldFactory.addField(timeOfEventField); //Participant at risk InputField riskField = InputFieldFactory.createBooleanSelectField("participantAtRisk", "Does this place participant at increased risk?", "aeReport.adverseEvents.participantAtRisk", unRetired && isFieldRequired(ae, "adverseEvents[].participantAtRisk")); mainFieldFactory.addField(riskField); //Event location InputField eventLocationField = InputFieldFactory.createTextField("eventLocation", "Where was the patient when the event occurred?", "aeReport.adverseEvents.eventLocation", unRetired && isFieldRequired(ae, "adverseEvents[].eventLocation")); mainFieldFactory.addField(eventLocationField); InputFieldGroup fieldGroup = mainFieldFactory.createGroup(i); mainFieldFactory.addFieldGroup(fieldGroup); mainFieldFactory.clearFields(); //now add the fields related to outcomes InputFieldGroup outcomeFieldGrp = new DefaultInputFieldGroup(OUTCOME_FIELD_GROUP + i); List<InputField> outcomeFields = outcomeFieldGrp.getFields(); Map<Integer, Boolean> oneOutcomeMap = cmd.getOutcomes().get(i); for (Integer code : oneOutcomeMap.keySet()) { OutcomeType outcomeType = OutcomeType.getByCode(code); outcomeFields.add(InputFieldFactory.createCheckboxField("outcomes[" + i + "][" + code + "]", outcomeType.getDisplayName())); if (outcomeType == OutcomeType.OTHER_SERIOUS) { outcomeFields.add(InputFieldFactory.createTextField("outcomeOtherDetails[" + i + "]", "")); } } fieldGrpMap.addInputFieldGroup(outcomeFieldGrp); } fieldGrpMap.addMultipleFieldGroupFactory(mainFieldFactory); } return fieldGrpMap; } private boolean isFieldRequired(AdverseEvent ae, String fieldPath) { if (ae.getSolicited() || ae.isRetired()) return false; return isFieldRequired(fieldPath); } public boolean isFieldRequired(String fieldPath) { return caaersFieldConfigurationManager.isFieldMandatory(TAB_NAME, fieldPath); } @Override public Map<String, Object> referenceData(CaptureAdverseEventInputCommand command) { //initalize the seriousness outcome indicators command.initializeOutcomes(); //initializing the review comments collection if (command.getAdverseEventReportingPeriod() != null && command.getAdverseEventReportingPeriod().getReviewComments() != null) { command.getAdverseEventReportingPeriod().getReviewCommentsInternal().size(); } command.getStudy().getExpectedAECtcTerms().size(); Map<String, Object> refData = super.referenceData(command); // Put a flag in the referenceData to mark Outcome as mandatory if configured so. refData.put("outcomesMandatory", isFieldRequired("adverseEvents[].outcomes")); refData.put("aeTermMandatory", isFieldRequired("adverseEvents[].adverseEventCtcTerm.term")); //return super.referenceData(command); return refData; } @Override public void postProcess(HttpServletRequest request, CaptureAdverseEventInputCommand command, Errors errors) { //eager load the outcomes. command.eagerLoadAdverseEventOutcomes(); if (findInRequest(request, CaptureAdverseEventController.AJAX_SUBVIEW_PARAMETER) != null || errors.hasErrors()) { // init the meddra terms. return; } // update all adverse events to set reporter email for (AdverseEvent adverseEvent : command.getAdverseEvents()) { if (StringUtils.isBlank(adverseEvent.getReporterEmail())) { adverseEvent.setReporterEmail(command.getLoggedInUserEmail()); } } //reset the reporting method and action command.set_action(null); command.setReportingMethod(null); command.setPrimaryAdverseEventId(null); //sync the seriousness outcomes command.synchronizeOutcome(); } public AdverseEvent checkAEsUniqueness(CaptureAdverseEventInputCommand command) { if (CollectionUtils.isEmpty(command.getAdverseEventReportingPeriod().getAdverseEvents())) { return null; } Study study = command.getAdverseEventReportingPeriod().getStudy(); boolean hasOtherMeddra = study.getOtherMeddra() != null; List<String> aeStringList = new ArrayList<String>(); for (AdverseEvent ae : command.getAdverseEventReportingPeriod().getAdverseEvents()) { if (ae.isRetired()) continue; // to support Verbatim First if (ae.getAdverseEventTerm().getTerm() == null) continue; StringBuffer key = new StringBuffer(String.valueOf(ae.getAdverseEventTerm().getTerm().getId())); if (ae.getAdverseEventTerm().isOtherRequired()) { if (hasOtherMeddra) { if (ae.getLowLevelTerm() == null) continue; key.append(String.valueOf(ae.getLowLevelTerm().getId())); } else { key.append(String.valueOf(ae.getDetailsForOther())); } } if (aeStringList.contains(key.toString())) return ae; aeStringList.add(key.toString()); } return null; } @Override protected void validate(CaptureAdverseEventInputCommand command, BeanWrapper commandBean, Map<String, InputFieldGroup> fieldGroups, Errors errors) { Term aeTerminologyTerm = command.getStudy().getAeTerminology().getTerm(); boolean ctcTerminology = aeTerminologyTerm == null ? false : aeTerminologyTerm == Term.CTC; boolean meddraTerminology = aeTerminologyTerm == null ? false : aeTerminologyTerm == Term.MEDDRA; short i = 0; for (AdverseEvent ae : command.getAdverseEventReportingPeriod().getAdverseEvents()) { if (ae.isRetired()) { i++; continue; } if (isFieldRequired(ae, "adverseEvents[].adverseEventCtcTerm.term")) { if (ae.getAdverseEventTerm() == null || ae.getAdverseEventTerm().getTerm() == null) { if (ctcTerminology) { errors.rejectValue("adverseEvents[" + i + "].ctcTerm", "SAE_045", new Object[] { ae.getDetailsForOther() }, ""); } if (meddraTerminology) { errors.rejectValue("adverseEvents[" + i + "].meddraTerm", "SAE_045", new Object[] { ae.getDetailsForOther() }, ""); } } } if (isFieldRequired(ae, "adverseEvents[].detailsForOther")) { if (StringUtils.isEmpty(ae.getDetailsForOther())) { errors.rejectValue("adverseEvents[" + i + "].detailsForOther", "CAE_018", "Missing Verbatim"); } } i++; } if (command.getStudy().getAeTermUnique()) { // START -> AE VALIDATION // AdverseEvent adverseEvent = checkAEsUniqueness(command); if (adverseEvent != null) { String name = adverseEvent.getDisplayName(); errors.reject("DUPLICATE_EXPECTED_AE", new Object[] { name }, "ERR."); } // STOP -> AE VALIDATION // } boolean foundGrade5 = false; i = 0; for (AdverseEvent ae : command.getAdverseEventReportingPeriod().getAdverseEvents()) { if (ae.isRetired()) { i++; continue; } if (ae.getGrade() != null && ae.getGrade().equals(Grade.DEATH)) { if (foundGrade5) { errors.rejectValue("adverseEvents[" + i + "].grade", "SAE_033", "Only one adverse event with grade DEATH is allowed in a course."); } foundGrade5 = true; } // CHECKING VERBATIM LENGTH if (ae.getDetailsForOther() != null && ae.getDetailsForOther().length() > VERBATIM_MAX_SIZE) { errors.rejectValue("adverseEvents[" + i + "].detailsForOther", "SAE_021", new Object[] { VERBATIM_MAX_SIZE }, "The size of the verbatim value should not exceed " + VERBATIM_MAX_SIZE + " characters."); } if (caaersFieldConfigurationManager.isFieldMandatory(TAB_NAME, "adverseEvents[].gradedDate") && ae.getGradedDate() == null) { errors.rejectValue("adverseEvents[" + i + "].gradedDate", "CAE_023", "The \"Awareness date\" can not be blank. It should be either be the same day as \"Start date\" or today when \"Start date\" is unknown."); } //Check if Graded Date is lesser than Start Date if (caaersFieldConfigurationManager.isFieldApplicable(TAB_NAME, "adverseEvents[].startDate") && caaersFieldConfigurationManager.isFieldApplicable(TAB_NAME, "adverseEvents[].gradedDate")) { if (ae.getStartDate() != null && ae.getGradedDate() != null && (DateUtils.compareDate(ae.getStartDate(), ae.getGradedDate()) > 0)) { errors.rejectValue("adverseEvents[" + i + "].gradedDate", "CAE_021", "The \"Awareness date\" can not be before the \"Start date\". It should be either be the same day or later."); } } // Check if end date is greater than the start date if (caaersFieldConfigurationManager.isFieldApplicable(TAB_NAME, "adverseEvents[].startDate") && caaersFieldConfigurationManager.isFieldApplicable(TAB_NAME, "adverseEvents[].endDate")) if (ae.getEndDate() != null && ae.getStartDate() != null && DateUtils.compareDate(ae.getStartDate(), ae.getEndDate()) > 0) errors.rejectValue("adverseEvents[" + i + "].endDate", "CAE_014", "The \"End date\" can not be before the \"Start date\". It should be either be the same day or later."); // Check if start date of course is greater than the start date of the ae. //if(command.getAdverseEventReportingPeriod().getStartDate() != null && ae.getStartDate() != null && // DateUtils.compareDate(command.getAdverseEventReportingPeriod().getStartDate(), ae.getStartDate()) > 0) // errors.rejectValue("adverseEvents[" + i + "].startDate", "CAE_015"); // Special validation for outcomes as it cannot be validated through the fieldgroup framework. if (caaersFieldConfigurationManager.isFieldMandatory(TAB_NAME, "adverseEvents[].outcomes") && !ae.getSolicited()) { LinkedHashMap<Integer, Boolean> oneOutcomeMap = (LinkedHashMap<Integer, Boolean>) command .getOutcomes().get(i); if (oneOutcomeMap == null || !oneOutcomeMap.containsValue(Boolean.TRUE)) { errors.rejectValue("adverseEvents[" + i + "].outcomes", "CAE_016", "Missing outcomes."); } } if (caaersFieldConfigurationManager.isFieldMandatory(TAB_NAME, "adverseEvents[].eventApproximateTime.hourString") && !ae.getSolicited()) { if (ae.getEventApproximateTime() == null || ae.getEventApproximateTime().getHourString() == null) errors.rejectValue("adverseEvents[" + i + "].eventApproximateTime.hourString", "CAE_019", "Missing event hour."); } if (caaersFieldConfigurationManager.isFieldMandatory(TAB_NAME, "adverseEvents[].eventApproximateTime.minuteString") && !ae.getSolicited()) { if (ae.getEventApproximateTime() == null || ae.getEventApproximateTime().getMinuteString() == null) errors.rejectValue("adverseEvents[" + i + "].eventApproximateTime.minuteString", "CAE_020", "Missing event minute."); } i++; } command.setErrorsForFields(new HashMap<String, Boolean>()); WebUtils.populateErrorFieldNames(command.getErrorsForFields(), errors); } @Override protected boolean methodInvocationRequest(HttpServletRequest request) { return org.springframework.web.util.WebUtils.hasSubmitParameter(request, "ajax") && Boolean.parseBoolean(request.getParameter("ajax")); } @Override public String getMethodName(HttpServletRequest request) { if (request.getParameter("action") != null) return request.getParameter("action"); return null; } public ModelAndView refreshGrades(HttpServletRequest request, Object cmd, Errors errors) { CaptureAdverseEventInputCommand command = (CaptureAdverseEventInputCommand) cmd; String index = request.getParameter("index"); ModelAndView modelAndView = new ModelAndView("ae/ajax/gradeFormSection"); modelAndView.getModel().put("index", index); AdverseEvent ae = command.getAdverseEvents().get(Integer.parseInt(index)); ae.setLowLevelTerm(null); modelAndView.getModel().put("ae", ae); return modelAndView; } }