package org.akaza.openclinica.control.admin;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Calendar;
import javax.servlet.http.HttpServletRequest;
import org.akaza.openclinica.bean.extract.DatasetBean;
import org.akaza.openclinica.bean.extract.ExtractPropertyBean;
import org.akaza.openclinica.bean.login.UserAccountBean;
import org.akaza.openclinica.bean.managestudy.StudyBean;
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.core.CoreResources;
import org.akaza.openclinica.dao.extract.DatasetDAO;
import org.akaza.openclinica.dao.managestudy.StudyDAO;
import org.akaza.openclinica.i18n.core.LocaleResolver;
import org.akaza.openclinica.service.extract.ExtractUtils;
import org.akaza.openclinica.service.extract.XsltTriggerService;
import org.akaza.openclinica.view.Page;
import org.akaza.openclinica.web.InsufficientPermissionException;
import org.akaza.openclinica.web.SQLInitServlet;
import org.akaza.openclinica.web.job.ExampleSpringJob;
import org.akaza.openclinica.web.job.TriggerService;
import org.quartz.*;
import org.quartz.impl.StdScheduler;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
public class UpdateJobExportServlet extends SecureController {
private static String SCHEDULER = "schedulerFactoryBean";
private StdScheduler scheduler;
private SimpleTrigger trigger;
private JobDataMap dataMap;
public static final String PERIOD = "periodToRun";
public static final String FORMAT_ID = "formatId";
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 TRIGGER_GROUP_JOB = "XsltTriggersExportJobs";
@Override
protected void mayProceed() throws InsufficientPermissionException {
if (ub.isSysAdmin() || ub.isTechAdmin()) {
return;
}
// if (currentRole.getRole().equals(Role.STUDYDIRECTOR) || currentRole.getRole().equals(Role.COORDINATOR)) {
// return;
// }
// should it be only study directors and admins, not coordinators?
addPageMessage(respage.getString("no_have_correct_privilege_current_study") + respage.getString("change_study_contact_sysadmin"));
throw new InsufficientPermissionException(Page.MENU_SERVLET, resexception.getString("not_allowed_access_extract_data_servlet"), "1");// TODO
// above copied from create dataset servlet, needs to be changed to
// allow only admin-level users
}
private StdScheduler getScheduler() {
scheduler = this.scheduler != null ? scheduler : (StdScheduler) SpringServletAccess.getApplicationContext(context).getBean(SCHEDULER);
return scheduler;
}
private void setUpServlet(Trigger trigger) {
FormProcessor fp2 = new FormProcessor(request);
DatasetDAO dsdao = new DatasetDAO(sm.getDataSource());
Collection dsList = dsdao.findAllOrderByStudyIdAndName();
// TODO will have to dress this up to allow for sites then datasets
request.setAttribute("datasets", dsList);
request.setAttribute(CreateJobExportServlet.JOB_NAME, trigger.getKey().getName());
request.setAttribute(CreateJobExportServlet.JOB_DESC, trigger.getDescription());
dataMap = trigger.getJobDataMap();
String contactEmail = dataMap.getString(ExampleSpringJob.EMAIL);
int dsId = dataMap.getInt(XsltTriggerService.DATASET_ID);
int userId = dataMap.getInt(XsltTriggerService.USER_ID);
String period = dataMap.getString(XsltTriggerService.PERIOD);
int exportFormatId = dataMap.getInt(XsltTriggerService.EXPORT_FORMAT_ID);
request.setAttribute(FORMAT_ID, exportFormatId);
request.setAttribute(ExampleSpringJob.EMAIL, contactEmail);
// how to find out the period of time???
request.setAttribute(PERIOD, period);
request.setAttribute(DATASET_ID, dsId);
request.setAttribute("extractProperties", CoreResources.getExtractProperties());
// DatasetBean dataset = (DatasetBean)dsdao.findByPK(dsId);
// >> tbh 5639: collate the correct study id
// request.setAttribute("study_id", dataset.getStudyId());
Date jobDate = trigger.getNextFireTime();
HashMap presetValues = new HashMap();
Calendar calendar = new GregorianCalendar();
calendar.setTime(jobDate);
presetValues.put(CreateJobExportServlet.DATE_START_JOB + "Hour", calendar.get(Calendar.HOUR_OF_DAY));
presetValues.put(CreateJobExportServlet.DATE_START_JOB + "Minute", calendar.get(Calendar.MINUTE));
presetValues.put(CreateJobExportServlet.DATE_START_JOB + "Date", local_df.format(jobDate));
// (calendar.get(Calendar.MONTH) + 1) + "/" +
// calendar.get(Calendar.DATE) + "/"
// + calendar.get(Calendar.YEAR));
fp2.setPresetValues(presetValues);
setPresetValues(fp2.getPresetValues());
// request.setAttribute(DATE_START_JOB, fp2.getDateTime(DATE_START_JOB +
// "Date"));
// EMAIL, TAB, CDISC, SPSS, PERIOD, DATE_START_JOB
// TODO pick out the datasets and the date
}
@Override
protected void processRequest() throws Exception {
FormProcessor fp = new FormProcessor(request);
TriggerService triggerService = new TriggerService();
String action = fp.getString("action");
String triggerName = fp.getString("tname");
scheduler = getScheduler();
ExtractUtils extractUtils = new ExtractUtils();
Trigger updatingTrigger = scheduler.getTrigger(new TriggerKey(triggerName.trim(), XsltTriggerService.TRIGGER_GROUP_NAME));
if (StringUtil.isBlank(action)) {
setUpServlet(updatingTrigger);
forwardPage(Page.UPDATE_JOB_EXPORT);
} else if ("confirmall".equalsIgnoreCase(action)) {
// change and update trigger here
// validate first
// then update or send back
String name = XsltTriggerService.TRIGGER_GROUP_NAME;
Set<TriggerKey> triggerKeys = scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(name));
String[] triggerNames = triggerKeys.stream().toArray(String[]::new);
HashMap errors = validateForm(fp, request, triggerNames, updatingTrigger.getKey().getName());
if (!errors.isEmpty()) {
// send back
addPageMessage("Your modifications caused an error, please see the messages for more information.");
setUpServlet(updatingTrigger);
logger.error("errors : " + errors.toString());
forwardPage(Page.UPDATE_JOB_EXPORT);
} else {
// change trigger, update in database
StudyDAO studyDAO = new StudyDAO(sm.getDataSource());
StudyBean study = (StudyBean) studyDAO.findByPK(sm.getUserBean().getActiveStudyId());
DatasetDAO datasetDao = new DatasetDAO(sm.getDataSource());
CoreResources cr = new CoreResources();
UserAccountBean userBean = (UserAccountBean) request.getSession().getAttribute("userBean");
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);
Date startDateTime = fp.getDateTime(DATE_START_JOB);
Integer exportFormatId = fp.getInt(FORMAT_ID);
ExtractPropertyBean epBean = cr.findExtractPropertyBeanById(exportFormatId, "" + datasetId);
DatasetBean dsBean = (DatasetBean)datasetDao.findByPK(new Integer(datasetId).intValue());
String[] files = epBean.getFileName();
String exportFileName;
int fileSize = files.length;
int cnt = 0;
dsBean.setName(dsBean.getName().replaceAll(" ", "_"));
String[] exportFiles= epBean.getExportFileName();
String pattern = "yyyy" + File.separator + "MM" + File.separator + "dd" + File.separator + "HHmmssSSS" + File.separator;
SimpleDateFormat sdfDir = new SimpleDateFormat(pattern);
int i =0;
String[] temp = new String[exportFiles.length];
//JN: The following logic is for comma separated variables, to avoid the second file be treated as a old file and deleted.
String datasetFilePath = SQLInitServlet.getField("filePath")+"datasets";
while (i<exportFiles.length) {
temp[i] = extractUtils.resolveVars(exportFiles[i], dsBean, sdfDir, datasetFilePath);
i++;
}
epBean.setDoNotDelFiles(temp);
epBean.setExportFileName(temp);
XsltTriggerService xsltService = new XsltTriggerService();
String generalFileDir = SQLInitServlet.getField("filePath");
generalFileDir = generalFileDir + "datasets" + File.separator + dsBean.getId() + File.separator + sdfDir.format(new java.util.Date());
exportFileName = epBean.getExportFileName()[cnt];
String xsltPath = SQLInitServlet.getField("filePath") + "xslt" + File.separator +files[cnt];
String endFilePath = epBean.getFileLocation();
endFilePath = extractUtils.getEndFilePath(endFilePath, dsBean, sdfDir, datasetFilePath);
// exportFileName = resolveVars(exportFileName,dsBean,sdfDir);
if (epBean.getPostProcExportName() != null) {
String preProcExportPathName = extractUtils.resolveVars(epBean.getPostProcExportName(),dsBean,sdfDir, datasetFilePath);
epBean.setPostProcExportName(preProcExportPathName);
}
if (epBean.getPostProcLocation() != null) {
String prePocLoc = extractUtils.getEndFilePath(epBean.getPostProcLocation(), dsBean, sdfDir, datasetFilePath);
epBean.setPostProcLocation(prePocLoc);
}
extractUtils.setAllProps(epBean, dsBean, sdfDir, datasetFilePath);
SimpleTrigger trigger = null;
trigger = xsltService.generateXsltTrigger(scheduler, xsltPath,
generalFileDir, // xml_file_path
endFilePath + File.separator,
exportFileName,
dsBean.getId(),
epBean, userBean, LocaleResolver.getLocale(request).getLanguage(),cnt, SQLInitServlet.getField("filePath") + "xslt", TRIGGER_GROUP_JOB);
//Updating the original trigger with user given inputs
trigger.getTriggerBuilder().withDescription(jobDesc).startAt(startDateTime).forJob(jobName)
.withSchedule(simpleSchedule()
.withIntervalInSeconds(new Long(XsltTriggerService.getIntervalTime(period)).intValue()).withRepeatCount(64000)
.withMisfireHandlingInstructionNextWithExistingCount());
trigger.getJobDataMap().put(XsltTriggerService.EMAIL, email);
trigger.getJobDataMap().put(XsltTriggerService.PERIOD, period);
trigger.getJobDataMap().put(XsltTriggerService.EXPORT_FORMAT, epBean.getFiledescription());
trigger.getJobDataMap().put(XsltTriggerService.EXPORT_FORMAT_ID, exportFormatId);
trigger.getJobDataMap().put(XsltTriggerService.JOB_NAME, jobName);
JobDetailFactoryBean JobDetailFactoryBean = new JobDetailFactoryBean();
JobDetailFactoryBean.setGroup(xsltService.TRIGGER_GROUP_NAME);
JobDetailFactoryBean.setName(trigger.getKey().getName());
JobDetailFactoryBean.setJobClass(org.akaza.openclinica.job.XsltStatefulJob.class);
JobDetailFactoryBean.setJobDataMap(trigger.getJobDataMap());
JobDetailFactoryBean.setDurability(true); // need durability?
try {
// scheduler.unscheduleJob(triggerName, "DEFAULT");
scheduler.deleteJob(new JobKey(triggerName, XsltTriggerService.TRIGGER_GROUP_NAME));
Date dataStart = scheduler.scheduleJob(JobDetailFactoryBean.getObject(), trigger);
// Date dateStart = scheduler.rescheduleJob(triggerName,
// "DEFAULT", trigger);
// scheduler.rescheduleJob(triggerName, groupName,
// newTrigger)
addPageMessage("Your job has been successfully modified.");
forwardPage(Page.VIEW_JOB_SERVLET);
} catch (SchedulerException se) {
se.printStackTrace();
// set a message here with the exception message
setUpServlet(trigger);
addPageMessage("There was an unspecified error with your creation, please contact an administrator.");
forwardPage(Page.UPDATE_JOB_EXPORT);
}
}
}
}
public HashMap validateForm(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);
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
int formatId = fp.getInt(FORMAT_ID);
Date jobDate = fp.getDateTime(DATE_START_JOB);
HashMap errors = v.validate();
if (formatId == 0) {
// throw an error here, at least one should work
// errors.put(TAB, "Error Message - Pick one of the below");
v.addError(errors, FORMAT_ID, "Please pick at least one.");
}
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;
}
}