From 339a35a28d4064429dbbe9cdb948d85df8ace426 Mon Sep 17 00:00:00 2001 From: Miciele Ghiorghis Date: Wed, 16 Jan 2013 18:16:02 +0100 Subject: [PATCH] Tim-connector: A controller for job scheduling --- .../web/common/JobSchedulerController.java | 342 ++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100644 libreplan-webapp/src/main/java/org/libreplan/web/common/JobSchedulerController.java diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/common/JobSchedulerController.java b/libreplan-webapp/src/main/java/org/libreplan/web/common/JobSchedulerController.java new file mode 100644 index 000000000..724d9ad4c --- /dev/null +++ b/libreplan-webapp/src/main/java/org/libreplan/web/common/JobSchedulerController.java @@ -0,0 +1,342 @@ +/* + * This file is part of LibrePlan + * + * Copyright (C) 2013 St. Antoniusziekenhuis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package org.libreplan.web.common; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.StringTokenizer; + +import org.apache.commons.lang.Validate; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.libreplan.business.common.IAdHocTransactionService; +import org.libreplan.business.common.IOnTransaction; +import org.libreplan.business.common.daos.IJobSchedulerConfigurationDAO; +import org.libreplan.business.common.entities.JobSchedulerConfiguration; +import org.libreplan.importers.ISchedulerManager; +import org.libreplan.importers.SchedulerInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.zkoss.zk.ui.Component; +import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.EventListener; +import org.zkoss.zk.ui.event.Events; +import org.zkoss.zk.ui.util.GenericForwardComposer; +import org.zkoss.zul.Button; +import org.zkoss.zul.Cell; +import org.zkoss.zul.Grid; +import org.zkoss.zul.Hbox; +import org.zkoss.zul.Label; +import org.zkoss.zul.Popup; +import org.zkoss.zul.Row; +import org.zkoss.zul.RowRenderer; +import org.zkoss.zul.Rows; +import org.zkoss.zul.SimpleListModel; +import org.zkoss.zul.Toolbarbutton; + +/** + * Controller for job scheduler manager + * + * @author Miciele Ghiorghis + */ +public class JobSchedulerController extends GenericForwardComposer { + private static final Log LOG = LogFactory + .getLog(JobSchedulerController.class); + + private Grid jobSchedulerGrid, cronExpressionGrid; + + private Popup cronExpressionInputPopup; + + private Label jobGroupLabel, jobNameLable; + + @Autowired + ISchedulerManager schedulerManager; + + @Autowired + IJobSchedulerConfigurationDAO jobSchedulerConfigurationDAO; + + @Override + public void doAfterCompose(Component comp) throws Exception { + super.doAfterCompose(comp); + comp.setVariable("jobSchedulerController", this, true); + reloadSchedulerJobs(); + } + + public List getSchedulerInfo() { + List schedulerInfoList = schedulerManager + .getSchedulerInfos(); + Collections.sort(schedulerInfoList, new Comparator() { + + @Override + public int compare(SchedulerInfo o1, SchedulerInfo o2) { + int result = o1 + .getJobSchedulerConfiguration() + .getJobGroup() + .compareTo( + o2.getJobSchedulerConfiguration().getJobGroup()); + if (result == 0) { + result = o1 + .getJobSchedulerConfiguration() + .getJobName() + .compareTo( + o2.getJobSchedulerConfiguration() + .getJobName()); + } + return result; + } + }); + return schedulerInfoList; + } + + private void reloadSchedulerJobs() { + jobSchedulerGrid.setModel(new SimpleListModel(getSchedulerInfo())); + jobSchedulerGrid.invalidate(); + } + + public JobSchedulingRenderer getJobSchedulingRenderer() { + return new JobSchedulingRenderer(); + } + + public class JobSchedulingRenderer implements RowRenderer { + @Override + public void render(Row row, Object data) { + + SchedulerInfo schedulerInfo = (SchedulerInfo) data; + Util.appendLabel(row, schedulerInfo.getJobSchedulerConfiguration() + .getJobGroup()); + Util.appendLabel(row, schedulerInfo.getJobSchedulerConfiguration() + .getJobName()); + appendCronExpressionAndButton(row, schedulerInfo); + Util.appendLabel(row, schedulerInfo.getNextFireTime()); + appendManualStart(row, schedulerInfo); + } + } + + private void appendCronExpressionAndButton(final Row row, + final SchedulerInfo schedulerInfo) { + final Hbox hBox = new Hbox(); + hBox.setWidth("100%"); + Cell cell = new Cell(); + cell.setHflex("2"); + cell.setAlign("left"); + + Label label = new Label(schedulerInfo.getJobSchedulerConfiguration() + .getCronExpression()); + cell.appendChild(label); + + Cell cell2 = new Cell(); + cell2.setHflex("1"); + cell2.setWidth("10px"); + final Toolbarbutton button = new Toolbarbutton(); + button.setImage("/common/img/ico_editar.png"); + cell2.appendChild(button); + hBox.appendChild(cell); + hBox.appendChild(cell2); + + button.addEventListener(Events.ON_CLICK, new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + setupCronExpressionPopup(schedulerInfo); + cronExpressionInputPopup.open(jobSchedulerGrid, "at_pointer"); + } + }); + row.appendChild(hBox); + } + + + private void setupCronExpressionPopup(final SchedulerInfo schedulerInfo) { + List list = new ArrayList(); + list.add(getCronExpression(schedulerInfo.getJobSchedulerConfiguration() + .getCronExpression())); + cronExpressionGrid.setModel(new SimpleListModel(list)); + + jobGroupLabel = (Label) cronExpressionInputPopup + .getFellowIfAny("jobGroup"); + jobNameLable = (Label) cronExpressionInputPopup + .getFellowIfAny("jobName"); + jobGroupLabel.setValue(schedulerInfo.getJobSchedulerConfiguration() + .getJobGroup()); + jobNameLable.setValue(schedulerInfo.getJobSchedulerConfiguration() + .getJobName()); + } + + @Autowired + private IAdHocTransactionService adHocTransactionService; + + private void saveJobConfigurationAndReschedule( + final String jobGroup, final String jobName, final String cronExp) { + adHocTransactionService + .runOnAnotherTransaction(new IOnTransaction() { + @Override + public Void execute() { + JobSchedulerConfiguration jobSchedulerConfiguration = jobSchedulerConfigurationDAO + .findByJobGroupAndJobName(jobGroup, jobName); + jobSchedulerConfiguration.setCronExpression(cronExp); + jobSchedulerConfigurationDAO + .save(jobSchedulerConfiguration); + schedulerManager.rescheduleJob(jobSchedulerConfiguration); + reloadSchedulerJobs(); + return null; + } + }); + } + + private CronExpression getCronExpression(String cronExpressionStr) { + CronExpression cronExpression = new CronExpression(); + StringTokenizer st = new StringTokenizer(cronExpressionStr); + int countTokens = st.countTokens(); + if (countTokens < 6) { + throw new IllegalArgumentException("Cron expression is not valid"); + } + cronExpression.setSeconds(getNextToken(st.nextToken())); + cronExpression.setMinutes(getNextToken(st.nextToken())); + cronExpression.setHours(getNextToken(st.nextToken())); + cronExpression.setDayOfMonth(getNextToken(st.nextToken())); + cronExpression.setMonth(getNextToken(st.nextToken())); + cronExpression.setDayOfWeek(getNextToken(st.nextToken())); + if (countTokens > 6) { // optional + cronExpression.setYear(getNextToken(st.nextToken())); + } else { + cronExpression.setYear(""); + } + + return cronExpression; + } + + private String getNextToken(String token) { + return token.isEmpty() ? "" : token.trim(); + } + private void appendManualStart(final Row row, + final SchedulerInfo schedulerInfo) { + final Button rescheduleButton = new Button("Manual"); + rescheduleButton.addEventListener(Events.ON_CLICK, new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + schedulerManager.doManual(schedulerInfo + .getJobSchedulerConfiguration().getJobName()); + } + }); + row.appendChild(rescheduleButton); + } + + public void reschedule() { + jobGroupLabel = (Label) cronExpressionInputPopup + .getFellowIfAny("jobGroup"); + jobNameLable = (Label) cronExpressionInputPopup + .getFellowIfAny("jobName"); + + Rows rows = cronExpressionGrid.getRows(); + Row row = (Row) rows.getChildren().get(0); + CronExpression cronExp = (CronExpression) row.getValue(); + saveJobConfigurationAndReschedule(jobGroupLabel.getValue(), + jobNameLable.getValue(), convertToCronExpressionStr(cronExp)); + cronExpressionInputPopup.close(); + getJobSchedulingRenderer(); + } + + private String convertToCronExpressionStr(CronExpression cronExp) { + return String.format("%1$s %2$s %3$s %4$s %5$s %6$s %7$s", + cronExp.getSeconds(), cronExp.getMinutes(), cronExp.getHours(), + cronExp.getDayOfMonth(), cronExp.getMonth(), + cronExp.getDayOfWeek(), cronExp.getYear()).trim(); + } + + public void cancel() { + cronExpressionInputPopup.invalidate(); + cronExpressionInputPopup.close(); + } + + public class CronExpression { + private String seconds; + private String minutes; + private String hours; + private String dayOfMonth; + private String month; + private String dayOfWeek; + private String year; + + public String getSeconds() { + return seconds; + } + + public void setSeconds(String seconds) { + Validate.notEmpty(seconds, "Seconds is mandatory"); + this.seconds = seconds; + } + + public String getMinutes() { + return minutes; + } + + public void setMinutes(String minutes) { + Validate.notEmpty(minutes, "Minutes is mandatory"); + this.minutes = minutes; + } + + public String getHours() { + return hours; + } + + public void setHours(String hours) { + Validate.notEmpty(hours, "Hours is mandatory"); + this.hours = hours; + } + + public String getDayOfMonth() { + return dayOfMonth; + } + + public void setDayOfMonth(String dayOfMonth) { + Validate.notEmpty(dayOfMonth, "day of month is mandatory"); + this.dayOfMonth = dayOfMonth; + } + + public String getMonth() { + return month; + } + + public void setMonth(String month) { + Validate.notEmpty(month, "month is mandatory"); + this.month = month; + } + + public String getDayOfWeek() { + return dayOfWeek; + } + + public void setDayOfWeek(String dayOfWeek) { + Validate.notEmpty(dayOfWeek, "day of week is mandatory"); + this.dayOfWeek = dayOfWeek; + } + + public String getYear() { + return year; + } + + public void setYear(String year) { + this.year = year; + } + + } + +}