package org.akaza.openclinica.web.job; import java.math.BigInteger; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.ResourceBundle; import javax.servlet.http.HttpServletRequest; import org.akaza.openclinica.bean.login.UserAccountBean; import org.akaza.openclinica.bean.managestudy.StudyBean; import org.akaza.openclinica.bean.submit.crfdata.FormDataBean; import org.akaza.openclinica.bean.submit.crfdata.ImportItemDataBean; import org.akaza.openclinica.bean.submit.crfdata.ImportItemGroupDataBean; import org.akaza.openclinica.bean.submit.crfdata.StudyEventDataBean; import org.akaza.openclinica.bean.submit.crfdata.SubjectDataBean; import org.akaza.openclinica.bean.submit.crfdata.SummaryStatsBean; import org.akaza.openclinica.control.form.FormProcessor; import org.akaza.openclinica.control.form.Validator; import org.akaza.openclinica.control.submit.ImportCRFInfo; import org.akaza.openclinica.control.submit.ImportCRFInfoContainer; import org.quartz.JobDataMap; import org.quartz.SimpleTrigger; import static org.quartz.SimpleScheduleBuilder.simpleSchedule; import static org.quartz.TriggerBuilder.newTrigger; public class TriggerService { public TriggerService() { // do nothing, for the moment } public static final String PERIOD = "periodToRun"; public static final String TAB = "tab"; public static final String CDISC = "cdisc"; public static final String SPSS = "spss"; public static final String DATASET_ID = "dsId"; public static final String DATE_START_JOB = "job"; public static final String EMAIL = "contactEmail"; public static final String JOB_NAME = "jobName"; public static final String JOB_DESC = "jobDesc"; public static final String USER_ID = "user_id"; public static final String STUDY_NAME = "study_name"; public static final String STUDY_OID = "study_oid"; public static final String DIRECTORY = "filePathDir"; public static final String STUDY_ID = "studyId"; private static String IMPORT_TRIGGER = "importTrigger"; public SimpleTrigger generateTrigger(FormProcessor fp, UserAccountBean userAccount, StudyBean study, String locale) { Date startDateTime = fp.getDateTime(DATE_START_JOB); // check the above? int datasetId = fp.getInt(DATASET_ID); String period = fp.getString(PERIOD); String email = fp.getString(EMAIL); String jobName = fp.getString(JOB_NAME); String jobDesc = fp.getString(JOB_DESC); String spss = fp.getString(SPSS); String tab = fp.getString(TAB); String cdisc = fp.getString(CDISC); String cdisc12 = fp.getString(ExampleSpringJob.CDISC12); String cdisc13 = fp.getString(ExampleSpringJob.CDISC13); String cdisc13oc = fp.getString(ExampleSpringJob.CDISC13OC); BigInteger interval = new BigInteger("0"); if ("monthly".equalsIgnoreCase(period)) { interval = new BigInteger("2419200000"); // how many // milliseconds in // a month? should // be 24192000000 } else if ("weekly".equalsIgnoreCase(period)) { interval = new BigInteger("604800000"); // how many // milliseconds in // a week? should // be 6048000000 } else { // daily interval = new BigInteger("86400000");// how many // milliseconds in a // day? } // set up and commit job here // set the job detail name, // based on our choice of format above // what if there is more than one detail? // what is the number of times it should repeat? // arbitrary large number, 64K should be enough :) SimpleTrigger trigger = (SimpleTrigger) newTrigger() .forJob(jobName, "DEFAULT") .withDescription(jobDesc) .startAt(startDateTime) .withSchedule(simpleSchedule().withRepeatCount(64000).withIntervalInSeconds(interval.intValue()).withMisfireHandlingInstructionNextWithExistingCount()); // set job data map JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put(DATASET_ID, datasetId); jobDataMap.put(PERIOD, period); jobDataMap.put(EMAIL, email); jobDataMap.put(TAB, tab); jobDataMap.put(CDISC, cdisc); jobDataMap.put(ExampleSpringJob.CDISC12, cdisc12); jobDataMap.put(ExampleSpringJob.LOCALE, locale); // System.out.println("found 1.2: " + // jobDataMap.get(ExampleSpringJob.CDISC12)); jobDataMap.put(ExampleSpringJob.CDISC13, cdisc13); // System.out.println("found 1.3: " + // jobDataMap.get(ExampleSpringJob.CDISC13)); jobDataMap.put(ExampleSpringJob.CDISC13OC, cdisc13oc); // System.out.println("found 1.3oc: " + // jobDataMap.get(ExampleSpringJob.CDISC13OC)); jobDataMap.put(SPSS, spss); jobDataMap.put(USER_ID, userAccount.getId()); // StudyDAO studyDAO = new StudyDAO(); jobDataMap.put(STUDY_ID, study.getId()); jobDataMap.put(STUDY_NAME, study.getName()); jobDataMap.put(STUDY_OID, study.getOid()); trigger.getTriggerBuilder().usingJobData(jobDataMap); return trigger; } public SimpleTrigger generateImportTrigger(FormProcessor fp, UserAccountBean userAccount, StudyBean study, String locale) { Date startDateTime = new Date(System.currentTimeMillis()); return generateImportTrigger(fp, userAccount, study, startDateTime, locale); } public SimpleTrigger generateImportTrigger(FormProcessor fp, UserAccountBean userAccount, StudyBean study, Date startDateTime, String locale) { String jobName = fp.getString(JOB_NAME); String email = fp.getString(EMAIL); String jobDesc = fp.getString(JOB_DESC); String directory = fp.getString(DIRECTORY); // what kinds of periods do we have? hourly, daily, weekly? long interval = 0; int hours = fp.getInt("hours"); int minutes = fp.getInt("minutes"); if (hours > 0) { long hoursInt = hours * 3600000; interval = interval + hoursInt; } if (minutes > 0) { long minutesInt = minutes * 60000; interval = interval + minutesInt; } SimpleTrigger trigger = (SimpleTrigger) newTrigger() .forJob(jobName, IMPORT_TRIGGER) .withDescription(jobDesc) .startAt(startDateTime) .withSchedule(simpleSchedule().withRepeatCount(64000).withIntervalInSeconds(new Long(interval).intValue()).withMisfireHandlingInstructionNextWithExistingCount()); // set job data map JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put(EMAIL, email); jobDataMap.put(USER_ID, userAccount.getId()); jobDataMap.put(STUDY_NAME, study.getName()); jobDataMap.put(STUDY_OID, study.getOid()); jobDataMap.put(DIRECTORY, directory); jobDataMap.put(ExampleSpringJob.LOCALE, locale); jobDataMap.put("hours", hours); jobDataMap.put("minutes", minutes); trigger.getTriggerBuilder().usingJobData(jobDataMap); return trigger; } public HashMap validateForm(FormProcessor fp, HttpServletRequest request, String[] triggerNames, String properName) { Validator v = new Validator(request); v.addValidation(JOB_NAME, Validator.NO_BLANKS); // need to be unique too v.addValidation(JOB_DESC, Validator.NO_BLANKS); v.addValidation(EMAIL, Validator.IS_A_EMAIL); v.addValidation(PERIOD, Validator.NO_BLANKS); v.addValidation(DATE_START_JOB + "Date", Validator.IS_A_DATE); // v.addValidation(DATE_START_JOB + "Date", new Date(), Validator.DATE_IS_AFTER_OR_EQUAL); // TODO job names will have to be unique, tbh String tab = fp.getString(TAB); String cdisc = fp.getString(CDISC); String cdisc12 = fp.getString(ExampleSpringJob.CDISC12); String cdisc13 = fp.getString(ExampleSpringJob.CDISC13); String cdisc13oc = fp.getString(ExampleSpringJob.CDISC13OC); String spss = fp.getString(SPSS); Date jobDate = fp.getDateTime(DATE_START_JOB); HashMap errors = v.validate(); if ((tab == "") && (cdisc == "") && (spss == "") && (cdisc12 == "") && (cdisc13 == "") && (cdisc13oc == "")) { // throw an error here, at least one should work // errors.put(TAB, "Error Message - Pick one of the below"); v.addError(errors, TAB, "Please pick at least one of the below."); } for (String triggerName : triggerNames) { if (triggerName.equals(fp.getString(JOB_NAME)) && (!triggerName.equals(properName))) { v.addError(errors, JOB_NAME, "A job with that name already exists. Please pick another name."); } } if (jobDate.before(new Date())) { v.addError(errors, DATE_START_JOB + "Date", "This date needs to be later than the present time."); } return errors; } public String generateSummaryStatsMessage(SummaryStatsBean ssBean, ResourceBundle respage) { // TODO i18n StringBuffer sb = new StringBuffer(); sb.append("<table border=\'0\' cellpadding=\'0\' cellspacing=\'0\' width=\'100%\'>"); sb.append("<tr valign=\'top\'> <td class=\'table_header_row\'>Summary Statistics:</td> </tr> <tr valign=\'top\'>"); sb.append("<td class=\'table_cell_left\'>Subjects Affected: " + ssBean.getStudySubjectCount() + "</td> </tr>"); sb.append("<tr valign=\'top\'> <td class=\'table_cell_left\'>Total Event CRFs: " + ssBean.getEventCrfCount() + "</td> </tr> "); sb.append("<tr valign=\'top\'> <td class=\'table_cell_left\'>Event CRFs Available for Import: " + (ssBean.getEventCrfCount() - ssBean.getSkippedCrfCount()) + "</td> </tr> "); sb.append("<tr valign=\'top\'> <td class=\'table_cell_left\'>Event CRFs Skipped: " + ssBean.getSkippedCrfCount() + "</td> </tr> "); sb.append("<tr valign=\'top\'><td class=\'table_cell_left\'>Validation Rules Generated: " + ssBean.getDiscNoteCount() + "</td> </tr> </table>"); /* * <table border="0" cellpadding="0" cellspacing="0" width="100%"> * * <tr valign="top"> <td class="table_header_row">Summary Statistics:</td> </tr> <tr valign="top"> <td * class="table_cell_left">Subjects Affected: <c:out value="${summaryStats.studySubjectCount}" /></td> </tr> <tr * valign="top"> <td class="table_cell_left">Event CRFs Affected: <c:out value="${summaryStats.eventCrfCount}" * /></td> </tr> <tr valign="top"> <td class="table_cell_left">Validation Rules Generated: <c:out * value="${summaryStats.discNoteCount}" /></td> </tr> * * </table> */ return sb.toString(); } public String generateSkippedCRFMessage(ImportCRFInfoContainer importCRFList, ResourceBundle resword) { // TODO i18n StringBuffer sb = new StringBuffer(); sb.append("Skipped CRFs (due to import rules):<br/>"); sb.append("<table border=\'0\' cellpadding=\'0\' cellspacing=\'0\' width=\'100%\'>"); sb.append("<tr valign=\'top\'> <td>Study OID :</td> <td>Study Subject OID :</td> <td>Event CRF OID:</td> <td>CRF Version OID:</td> <td>Event CRF Status:</td> </tr>"); for (ImportCRFInfo importCrfInfo : importCRFList.getImportCRFList()) { String preImportStatus = ""; if (importCrfInfo.getPreImportStage().isInitialDE()) preImportStatus = resword.getString("initial_data_entry"); else if (importCrfInfo.getPreImportStage().isInitialDE_Complete()) preImportStatus = resword.getString("initial_data_entry_complete"); else if (importCrfInfo.getPreImportStage().isDoubleDE()) preImportStatus = resword.getString("double_data_entry"); else if (importCrfInfo.getPreImportStage().isDoubleDE_Complete()) preImportStatus = resword.getString("data_entry_complete"); else if (importCrfInfo.getPreImportStage().isAdmin_Editing()) preImportStatus = resword.getString("administrative_editing"); else if (importCrfInfo.getPreImportStage().isLocked()) preImportStatus = resword.getString("locked"); else preImportStatus = resword.getString("invalid"); if (!importCrfInfo.isProcessImport()) sb.append("<tr valign=\'top\'> <td>" + importCrfInfo.getStudyOID() + "</td> <td>" + importCrfInfo.getStudySubjectOID() + "</td>" + "<td>" + importCrfInfo.getStudyEventOID() + "</td>" + "<td>" + importCrfInfo.getFormOID() + "</td> <td>" + preImportStatus + "</td></tr>"); } sb.append("</table>"); return sb.toString(); } public String generateHardValidationErrorMessage(ArrayList<SubjectDataBean> subjectData, HashMap<String, String> hardValidationErrors, boolean isValid) { StringBuffer sb = new StringBuffer(); String studyEventRepeatKey = "1"; String groupRepeatKey = "1"; sb.append("<table border=\'0\' cellpadding=\'0\' cellspacing=\'0\' width=\'100%\'>"); for (SubjectDataBean subjectDataBean : subjectData) { sb.append("<tr valign=\'top\'> <td class=\'table_header_row\' colspan=\'4\'>Study Subject: " + subjectDataBean.getSubjectOID() + "</td> </tr>"); // next step here ArrayList<StudyEventDataBean> studyEventDataBeans = subjectDataBean.getStudyEventData(); for (StudyEventDataBean studyEventDataBean : studyEventDataBeans) { sb.append("<tr valign=\'top\'> <td class=\'table_header_row\'>Event CRF OID</td> <td class=\'table_header_row\' colspan=\'3\'></td>"); sb.append("</tr> <tr valign=\'top\'> <td class=\'table_cell_left\'>"); sb.append(studyEventDataBean.getStudyEventOID()); if (studyEventDataBean.getStudyEventRepeatKey() != null) { studyEventRepeatKey = studyEventDataBean.getStudyEventRepeatKey(); sb.append(" (Repeat key " + studyEventDataBean.getStudyEventRepeatKey() + ")"); } else { // reset studyEventRepeatKey = "1"; } sb.append("</td> <td class=\'table_cell\' colspan=\'3\'></td> </tr>"); ArrayList<FormDataBean> formDataBeans = studyEventDataBean.getFormData(); for (FormDataBean formDataBean : formDataBeans) { sb.append("<tr valign=\'top\'> <td class=\'table_header_row\'></td> "); sb.append("<td class=\'table_header_row\'>CRF Version OID</td> <td class=\'table_header_row\' colspan=\'2\'></td></tr>"); sb.append("<tr valign=\'top\'> <td class=\'table_cell_left\'></td> <td class=\'table_cell\'>"); sb.append(formDataBean.getFormOID()); sb.append("</td> <td class=\'table_cell\' colspan=\'2\'></td> </tr>"); ArrayList<ImportItemGroupDataBean> itemGroupDataBeans = formDataBean.getItemGroupData(); for (ImportItemGroupDataBean itemGroupDataBean : itemGroupDataBeans) { sb.append("<tr valign=\'top\'> <td class=\'table_header_row\'></td>"); sb.append("<td class=\'table_header_row\'></td> <td class=\'table_header_row\' colspan=\'2\'>"); sb.append(itemGroupDataBean.getItemGroupOID()); if (itemGroupDataBean.getItemGroupRepeatKey() != null) { groupRepeatKey = itemGroupDataBean.getItemGroupRepeatKey(); sb.append(" (Repeat key " + itemGroupDataBean.getItemGroupRepeatKey() + ")"); } else { groupRepeatKey = "1"; } sb.append("</td></tr>"); ArrayList<ImportItemDataBean> itemDataBeans = itemGroupDataBean.getItemData(); for (ImportItemDataBean itemDataBean : itemDataBeans) { String oidKey = itemDataBean.getItemOID() + "_" + studyEventRepeatKey + "_" + groupRepeatKey + "_" + subjectDataBean.getSubjectOID(); if (!isValid) { if (hardValidationErrors.containsKey(oidKey)) { sb.append("<tr valign=\'top\'> <td class=\'table_cell_left\'></td>"); sb.append("<td class=\'table_cell\'></td> <td class=\'table_cell\'><font color=\'red\'>"); sb.append(itemDataBean.getItemOID()); sb.append("</font></td> <td class=" + "\'table_cell\'>"); sb.append(itemDataBean.getValue() + "<br/>"); sb.append(hardValidationErrors.get(oidKey)); sb.append("</td></tr>"); /* * <tr valign="top"> <td class="table_cell_left"></td> <td class="table_cell"></td> * <td class="table_cell"><font color="red"><c:out * value="${itemData.itemOID}"/></font></td> <td class="table_cell"> <c:out * value="${itemData.value}"/><br/> <c:out value="${hardValidationErrors[oidKey]}"/> * </td> </tr> */ } } else { if (!hardValidationErrors.containsKey(oidKey)) { sb.append("<tr valign=\'top\'> <td class=\'table_cell_left\'></td>"); sb.append("<td class=\'table_cell\'></td> <td class=\'table_cell\'>"); sb.append(itemDataBean.getItemOID()); sb.append("</td> <td class=" + "\'table_cell\'>"); sb.append(itemDataBean.getValue()); sb.append("</td></tr>"); } } } } } } } sb.append("</table>"); return sb.toString(); } public String generateValidMessage(ArrayList<SubjectDataBean> subjectData, HashMap<String, String> totalValidationErrors) { return generateHardValidationErrorMessage(subjectData, totalValidationErrors, true); } public HashMap validateImportJobForm(FormProcessor fp, HttpServletRequest request, String[] triggerNames, String properName) { Validator v = new Validator(request); v.addValidation(JOB_NAME, Validator.NO_BLANKS); v.addValidation(JOB_NAME, Validator.NO_LEADING_OR_TRAILING_SPACES); // need to be unique too v.addValidation(JOB_DESC, Validator.NO_BLANKS); if (!"".equals(fp.getString(EMAIL))) { v.addValidation(EMAIL, Validator.IS_A_EMAIL); } // << tbh we are now allowing email to be optional // v.addValidation(PERIOD, Validator.NO_BLANKS); // v.addValidation(DIRECTORY, Validator.NO_BLANKS); // v.addValidation(DATE_START_JOB + "Date", Validator.IS_A_DATE); // TODO job names will have to be unique, tbh String hours = fp.getString("hours"); String minutes = fp.getString("minutes"); HashMap errors = v.validate(); if ((hours.equals("0")) && (minutes.equals("0"))) { // System.out.println("got in the ERROR LOOP"); // throw an error here, at least one should be greater than zero // errors.put(TAB, "Error Message - Pick one of the below"); v.addError(errors, "hours", "At least one of the following should be greater than zero."); } for (String triggerName : triggerNames) { if (triggerName.equals(fp.getString(JOB_NAME)) && (!triggerName.equals(properName))) { v.addError(errors, JOB_NAME, "A job with that name already exists. Please pick another name."); } } return errors; } public HashMap validateImportJobForm(FormProcessor fp, HttpServletRequest request, String[] triggerNames) { return validateImportJobForm(fp, request, triggerNames, ""); } public HashMap validateForm(FormProcessor fp, HttpServletRequest request, String[] triggerNames) { return validateForm(fp, request, triggerNames, ""); } public HashMap validateImportForm(HttpServletRequest request) { Validator v = new Validator(request); HashMap errors = v.validate(); return errors; } }