tim-connector: main changes in scheduler
* CRUD for scheduler * The UI job_scheduling.zul for CRUD is splits to _editJobScheduling.zul and _listJobScheduling.zul * Lots of changes in scheduler to make it generic - jobs can be scheduled, rescheduled and deleted - check if job has a connector and is enabled - check if job is allowed to be scheduled - do manual is moved to JobConfigurationController * attributes connectorName and scheduled added to JobSchedulerConfiguration modified * triggerGroup and triggerName deleted from JobScheduleerConfiguration * In JobConfigurationDAO findByConnectorName added * New JobClassNameEnum added to be used as data type for JobClassName in JobSchedulerConfiguration * Import/Export Jobs read the beans that do the real work from ApplicationContext * Some minor changes in ConfigurationController
This commit is contained in:
parent
21c788316a
commit
a610afa957
21 changed files with 1072 additions and 452 deletions
|
|
@ -33,6 +33,8 @@ public interface IJobSchedulerConfigurationDAO extends
|
|||
|
||||
List<JobSchedulerConfiguration> getAll();
|
||||
|
||||
List<JobSchedulerConfiguration> findByConnectorName(String connectorName);
|
||||
|
||||
JobSchedulerConfiguration findByJobGroupAndJobName(String jobGroup,
|
||||
String jobName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package org.libreplan.business.common.daos;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
|
|
@ -55,4 +56,14 @@ public class JobSchedulerConfigurationDAO extends
|
|||
.add(Restrictions.eq("jobName", jobName)).uniqueResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<JobSchedulerConfiguration> findByConnectorName(
|
||||
String connectorName) {
|
||||
Criteria c = getSession().createCriteria(
|
||||
JobSchedulerConfiguration.class).add(
|
||||
Restrictions.eq("connectorName", connectorName));
|
||||
return ((List<JobSchedulerConfiguration>) c.list());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,4 +112,10 @@ public class Connector extends BaseEntity {
|
|||
|
||||
}
|
||||
|
||||
public boolean isActivated() {
|
||||
return getPropertiesAsMap()
|
||||
.get(PredefinedConnectorProperties.ACTIVATED).equalsIgnoreCase(
|
||||
"Y");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.entities;
|
||||
|
||||
|
||||
/**
|
||||
* Defines the job class package and name to be used as data type in
|
||||
* {@link JobSchedulerConfiguration}
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public enum JobClassNameEnum {
|
||||
|
||||
IMPORT_ROSTER_FROM_TIM_JOB("org.libreplan.importers",
|
||||
"ImportRosterFromTimJob"), EXPORT_TIMESHEET_TO_TIM_JOB(
|
||||
"org.libreplan.importers",
|
||||
"ExportTimesheetToTimJob");
|
||||
|
||||
private String packageName;
|
||||
private String name;
|
||||
|
||||
private JobClassNameEnum(String packageName, String name) {
|
||||
this.packageName = packageName;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ package org.libreplan.business.common.entities;
|
|||
|
||||
import org.hibernate.validator.NotNull;
|
||||
import org.libreplan.business.common.BaseEntity;
|
||||
import org.libreplan.business.common.IHumanIdentifiable;
|
||||
|
||||
/**
|
||||
* JobSchedulerConfiguration entity, represents parameters for the jobs to be
|
||||
|
|
@ -33,7 +34,8 @@ import org.libreplan.business.common.BaseEntity;
|
|||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class JobSchedulerConfiguration extends BaseEntity {
|
||||
public class JobSchedulerConfiguration extends BaseEntity implements
|
||||
IHumanIdentifiable {
|
||||
|
||||
public static JobSchedulerConfiguration create() {
|
||||
return create(new JobSchedulerConfiguration());
|
||||
|
|
@ -49,13 +51,13 @@ public class JobSchedulerConfiguration extends BaseEntity {
|
|||
|
||||
private String jobName;
|
||||
|
||||
private String triggerGroup;
|
||||
|
||||
private String triggerName;
|
||||
|
||||
private String cronExpression;
|
||||
|
||||
private String jobClassName;
|
||||
private JobClassNameEnum jobClassName;
|
||||
|
||||
private boolean schedule;
|
||||
|
||||
private String connectorName;
|
||||
|
||||
@NotNull(message = "job group not specified")
|
||||
public String getJobGroup() {
|
||||
|
|
@ -75,24 +77,6 @@ public class JobSchedulerConfiguration extends BaseEntity {
|
|||
this.jobName = jobName;
|
||||
}
|
||||
|
||||
@NotNull(message = "trigger group not specified")
|
||||
public String getTriggerGroup() {
|
||||
return triggerGroup;
|
||||
}
|
||||
|
||||
public void setTriggerGroup(String triggerGroup) {
|
||||
this.triggerGroup = triggerGroup;
|
||||
}
|
||||
|
||||
@NotNull(message = "trigger name not specified")
|
||||
public String getTriggerName() {
|
||||
return triggerName;
|
||||
}
|
||||
|
||||
public void setTriggerName(String triggerName) {
|
||||
this.triggerName = triggerName;
|
||||
}
|
||||
|
||||
@NotNull(message = "cron expression not specified")
|
||||
public String getCronExpression() {
|
||||
return cronExpression;
|
||||
|
|
@ -103,11 +87,32 @@ public class JobSchedulerConfiguration extends BaseEntity {
|
|||
}
|
||||
|
||||
@NotNull(message = "job class name not specified")
|
||||
public String getJobClassName() {
|
||||
public JobClassNameEnum getJobClassName() {
|
||||
return jobClassName;
|
||||
}
|
||||
|
||||
public void setJobClassName(String jobClassName) {
|
||||
public void setJobClassName(JobClassNameEnum jobClassName) {
|
||||
this.jobClassName = jobClassName;
|
||||
}
|
||||
|
||||
public boolean isSchedule() {
|
||||
return schedule;
|
||||
}
|
||||
|
||||
public void setSchedule(boolean schedule) {
|
||||
this.schedule = schedule;
|
||||
}
|
||||
|
||||
public String getConnectorName() {
|
||||
return connectorName;
|
||||
}
|
||||
|
||||
public void setConnectorName(String connectorName) {
|
||||
this.connectorName = connectorName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHumanId() {
|
||||
return jobGroup == null ? "" : jobGroup;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -378,7 +378,6 @@
|
|||
referencedTableName="connector"
|
||||
referencesUniqueColumn="false"/>
|
||||
</changeSet>
|
||||
|
||||
<!-- scheduler configuration -->
|
||||
<changeSet author="miciele" id="create-table-job-scheduler-configuration">
|
||||
<comment>Create new table job_scheduler_configuration</comment>
|
||||
|
|
@ -395,39 +394,14 @@
|
|||
<column name="job_name" type="VARCHAR(255)" >
|
||||
<constraints nullable="false" primaryKey="true" />
|
||||
</column>
|
||||
<column name="trigger_group" type="VARCHAR(255)" >
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="trigger_name" type="VARCHAR(255)" >
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="cron_expression" type="VARCHAR(255)" >
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="job_class_name" type="VARCHAR(255)" >
|
||||
<column name="job_class_name" type="INTEGER" >
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="connector_name" type="VARCHAR(255)" />
|
||||
<column name="schedule" type="BOOLEAN" />
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="miciele" id="insert-predefined-jobs">
|
||||
<comment>Insert jobs to be scheduled with default cron-expression</comment>
|
||||
<insert tableName="job_scheduler_configuration">
|
||||
<column name="version" value="0"/>
|
||||
<column name="job_group" value="Tim"/>
|
||||
<column name="job_name" value="Import roster from Tim" />
|
||||
<column name="trigger_group" value="TimTrigger" />
|
||||
<column name="trigger_name" value="Import roster from Tim-trigger" />
|
||||
<column name="cron_expression" value="0 59 22 ? * *" />
|
||||
<column name="job_class_name" value="ImportRosterFromTimJob" />
|
||||
</insert>
|
||||
<insert tableName="job_scheduler_configuration">
|
||||
<column name="version" value="0"/>
|
||||
<column name="job_group" value="Tim"/>
|
||||
<column name="job_name" value="Export timesheet to Tim" />
|
||||
<column name="trigger_group" value="TimTrigger" />
|
||||
<column name="trigger_name" value="Export timesheet to Tim-trigger" />
|
||||
<column name="cron_expression" value="0 59 23 ? * *" />
|
||||
<column name="job_class_name" value="ExportTimesheetToTimJob" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
|
|
|
|||
|
|
@ -14,10 +14,14 @@
|
|||
|
||||
<property name="jobGroup" column="job_group" not-null="true" />
|
||||
<property name="jobName" column="job_name" not-null="true" />
|
||||
<property name="triggerGroup" column="trigger_group" not-null="true"/>
|
||||
<property name="triggerName" column="trigger_name" not-null="true"/>
|
||||
<property name="cronExpression" column="cron_expression" not-null="true"/>
|
||||
<property name="jobClassName" column="job_class_name" not-null="true"/>
|
||||
</class>
|
||||
<property name="cronExpression" column="cron_expression" not-null="true" />
|
||||
<property name="jobClassName" access="field" column="job_class_name" not-null="true">
|
||||
<type name="org.hibernate.type.EnumType">
|
||||
<param name="enumClass">org.libreplan.business.common.entities.JobClassNameEnum</param>
|
||||
</type>
|
||||
</property>
|
||||
<property name="connectorName" column="connector_name" />
|
||||
<property name="schedule" column="schedule" />
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
||||
|
|
|
|||
|
|
@ -18,36 +18,28 @@
|
|||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* A job that exports time sheets to Tim SOAP server
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class ExportTimesheetToTimJob extends QuartzJobBean {
|
||||
|
||||
private IExportTimesheetsToTim exportTimesheetsToTim;
|
||||
|
||||
public IExportTimesheetsToTim getExportTimesheetsToTim() {
|
||||
return exportTimesheetsToTim;
|
||||
}
|
||||
|
||||
public void setExportTimesheetsToTim(
|
||||
IExportTimesheetsToTim exportTimesheetsToTim) {
|
||||
this.exportTimesheetsToTim = exportTimesheetsToTim;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void executeInternal(JobExecutionContext context)
|
||||
throws JobExecutionException {
|
||||
ApplicationContext applicationContext = (ApplicationContext) context
|
||||
.getJobDetail().getJobDataMap().get("applicationContext");
|
||||
|
||||
IExportTimesheetsToTim exportTimesheetsToTim = (IExportTimesheetsToTim) applicationContext
|
||||
.getBean("exportTimesheetsToTim");
|
||||
|
||||
exportTimesheetsToTim.exportTimesheets();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,9 +19,8 @@
|
|||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.scheduling.quartz.CronTriggerBean;
|
||||
import org.springframework.scheduling.quartz.JobDetailBean;
|
||||
|
||||
|
|
@ -31,51 +30,73 @@ import org.springframework.scheduling.quartz.JobDetailBean;
|
|||
*
|
||||
* The start and destroy of the scheduler itself is managed by the Spring
|
||||
* framework. The scheduler starts automatically when the application starts and
|
||||
* destroyed when the application stops. The sole purpose of this manager is to
|
||||
* create jobs {@link JobDetailBean} and cron-triggers {@link CronTriggerBean}
|
||||
* when the scheduler is started. It links the triggers with the jobs and add
|
||||
* them to the scheduler.
|
||||
* destroyed when the application stops.
|
||||
*
|
||||
* The SchedulerManager reads the jobs to be scheduled and the cron-triggers to
|
||||
* fire the jobs form the {@link JobSchedulerConfiguration} entity. Hence the
|
||||
* {@link JobSchedulerConfiguration} entity must exist with predefined jobs and
|
||||
* valid cron-triggers
|
||||
* This manager (un)schedules the jobs based on the configuration
|
||||
* {@link JobSchedulerConfiguration} entity once the scheduler starts.
|
||||
*
|
||||
* This manager also supports the rescheduling of jobs.
|
||||
* <ul>
|
||||
* <li>Schedule job:create job {@link JobDetailBean} and cron-trigger
|
||||
* {@link CronTriggerBean}, associated the trigger with the job and add it to
|
||||
* the scheduler.
|
||||
* <li>
|
||||
* <li>Delete job: search the job in the scheduler and if found
|
||||
* unschedule(delete) the job</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public interface ISchedulerManager {
|
||||
|
||||
/**
|
||||
* Reads job configuration from the {@link JobSchedulerConfiguration} and
|
||||
* schedules the jobs as defined in the configuration
|
||||
* Reads the jobs to be scheduled from the {@link JobSchedulerConfiguration}
|
||||
* and schedules the jobs based on the cron expression defined for each job
|
||||
* in the {@link JobSchedulerConfiguration}
|
||||
*/
|
||||
void scheduleJobs();
|
||||
|
||||
/**
|
||||
* Reschedule the job.
|
||||
* Reads the jobs to be scheduled from the specified
|
||||
* <code>{@link JobSchedulerConfiguration}</code> and (un)schedule it
|
||||
* accordingly
|
||||
*
|
||||
* Reads the job to be rescheduled from the specified parameter
|
||||
* {@link JobSchedulerConfiguration} and reschedule the job accordingly
|
||||
* In the specified <code>{@link JobSchedulerConfiguration}</code>
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>{@link JobSchedulerConfiguration#getConnectorName()}</code>
|
||||
* check if job has a connector and the connector is activated</li>
|
||||
* <li><code>{@link JobSchedulerConfiguration#isSchedule()}</code> if true
|
||||
* the job would be scheduled, if not job deleted</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* the job scheduler configuration
|
||||
* configuration for job to be (un)scheduled
|
||||
* @throws SchedulerException
|
||||
* if unable to (un)schedule
|
||||
*/
|
||||
void rescheduleJob(JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
void scheduleOrUnscheduleJob(JobSchedulerConfiguration jobSchedulerConfiguration) throws SchedulerException;
|
||||
|
||||
/**
|
||||
* returns the scheduler info list. Can be useful to display in UI
|
||||
* Deletes the job from the scheduler for the specified job by
|
||||
* <code>{@link JobSchedulerConfiguration}</code>, if the job is already in
|
||||
* the scheduler
|
||||
*
|
||||
* @return list of scheduler info
|
||||
* @param jobSchedulerConfiguration
|
||||
* configuration for job to be deleted
|
||||
* @throws SchedulerException
|
||||
* if unable to delete
|
||||
*/
|
||||
List<SchedulerInfo> getSchedulerInfos();
|
||||
void deleteJob(JobSchedulerConfiguration jobSchedulerConfiguration) throws SchedulerException;
|
||||
|
||||
/**
|
||||
* To manually execute the job specified by <code>jobName</code>
|
||||
* gets the next fire time for the specified job from
|
||||
* {@link JobSchedulerConfiguration} if job is already scheduled. This is
|
||||
* only neede for UI
|
||||
*
|
||||
* @param jobName
|
||||
* the name of the job to be executed
|
||||
* @param jobSchedulerConfiguration
|
||||
* configuration to check for next fire time
|
||||
* @return next fire time or empty string
|
||||
*/
|
||||
void doManual(String jobName);
|
||||
String getNextFireTime(JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ package org.libreplan.importers;
|
|||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* A job that import rosters from Tim SOAP server
|
||||
|
|
@ -36,21 +36,17 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class ImportRosterFromTimJob extends QuartzJobBean {
|
||||
|
||||
private IImportRosterFromTim importRosterFromTim;
|
||||
|
||||
public IImportRosterFromTim getImportRosterFromTim() {
|
||||
return importRosterFromTim;
|
||||
}
|
||||
|
||||
public void setImportRosterFromTim(IImportRosterFromTim importRosterFromTim) {
|
||||
this.importRosterFromTim = importRosterFromTim;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
protected void executeInternal(JobExecutionContext context)
|
||||
throws JobExecutionException {
|
||||
ApplicationContext applicationContext = (ApplicationContext) context
|
||||
.getJobDetail().getJobDataMap().get("applicationContext");
|
||||
|
||||
IImportRosterFromTim importRosterFromTim = (IImportRosterFromTim) applicationContext
|
||||
.getBean("importRosterFromTim");
|
||||
|
||||
importRosterFromTim.importRosters();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -20,26 +20,30 @@
|
|||
package org.libreplan.importers;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.libreplan.business.common.daos.IJobSchedulerConfigurationDAO;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.JobClassNameEnum;
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
import org.libreplan.web.common.IConfigurationModel;
|
||||
import org.quartz.CronExpression;
|
||||
import org.quartz.CronTrigger;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.scheduling.quartz.CronTriggerBean;
|
||||
import org.springframework.scheduling.quartz.JobDetailBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Implementation of scheduler manager
|
||||
|
|
@ -55,15 +59,21 @@ public class SchedulerManager implements ISchedulerManager {
|
|||
@Autowired
|
||||
private Scheduler scheduler;
|
||||
|
||||
@Autowired
|
||||
private IImportRosterFromTim importRosterFromTim;
|
||||
|
||||
@Autowired
|
||||
private IExportTimesheetsToTim exportTimesheetsToTim;
|
||||
|
||||
@Autowired
|
||||
private IJobSchedulerConfigurationDAO jobSchedulerConfigurationDAO;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private IConfigurationModel configurationModel;
|
||||
|
||||
|
||||
/**
|
||||
* suffix for trigger -group and -name
|
||||
*/
|
||||
private static final String TRIGGER_SUFFIX = "-TRIGGER";
|
||||
|
||||
public Scheduler getScheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
|
|
@ -77,40 +87,163 @@ public class SchedulerManager implements ISchedulerManager {
|
|||
List<JobSchedulerConfiguration> jobSchedulerConfigurations = jobSchedulerConfigurationDAO
|
||||
.getAll();
|
||||
for (JobSchedulerConfiguration conf : jobSchedulerConfigurations) {
|
||||
CronTriggerBean cronTriggerBean = createCronTriggerBean(
|
||||
conf.getTriggerGroup(), conf.getTriggerName(),
|
||||
conf.getCronExpression());
|
||||
if (cronTriggerBean != null) {
|
||||
cronTriggerBean.setJobName(conf.getJobName());
|
||||
cronTriggerBean.setJobGroup(conf.getJobGroup());
|
||||
JobDetailBean jobDetailBean = createJobDetailBean(
|
||||
conf.getJobName(), conf.getJobGroup(),
|
||||
conf.getJobClassName());
|
||||
if (jobDetailBean != null) {
|
||||
scheduleJob(jobDetailBean, cronTriggerBean);
|
||||
}
|
||||
try {
|
||||
scheduleOrUnscheduleJob(conf);
|
||||
} catch (SchedulerException e) {
|
||||
LOG.error("Unable to schedule", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scheduleOrUnscheduleJob(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) throws SchedulerException {
|
||||
|
||||
if (hasConnector(jobSchedulerConfiguration.getConnectorName())) {
|
||||
if (isConnectorActivated(jobSchedulerConfiguration
|
||||
.getConnectorName())) {
|
||||
if (jobSchedulerConfiguration.isSchedule()) {
|
||||
scheduleNewJob(jobSchedulerConfiguration);
|
||||
return;
|
||||
}
|
||||
}
|
||||
deleteJob(jobSchedulerConfiguration);
|
||||
return;
|
||||
}
|
||||
if (!jobSchedulerConfiguration.isSchedule()) {
|
||||
deleteJob(jobSchedulerConfiguration);
|
||||
return;
|
||||
}
|
||||
scheduleNewJob(jobSchedulerConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns {@link CronTriggerBean}
|
||||
* Check if {@link JobSchedulerConfiguration} has a connector
|
||||
*
|
||||
* @param triggerGroup
|
||||
* the trigger group
|
||||
* @param triggerName
|
||||
* the trigger name
|
||||
* @param cronExpression
|
||||
* the cron expression string
|
||||
* @param connectorName
|
||||
* the connector to check for
|
||||
* @return true if connector is not null or empty
|
||||
*/
|
||||
private CronTriggerBean createCronTriggerBean(String triggerGroup,
|
||||
String triggerName, String cronExpression) {
|
||||
CronTriggerBean cronTriggerBean = new CronTriggerBean();
|
||||
cronTriggerBean.setGroup(triggerGroup);
|
||||
cronTriggerBean.setName(triggerName);
|
||||
private boolean hasConnector(String connectorName) {
|
||||
return !StringUtils.isBlank(connectorName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the specified <code>{@link Connector}</code> is activated
|
||||
*
|
||||
* @param connectorName
|
||||
* the connector to check for activated
|
||||
* @return true if activated
|
||||
*/
|
||||
private boolean isConnectorActivated(String connectorName) {
|
||||
configurationModel.initConnectorConfiguration();
|
||||
|
||||
Connector connector = configurationModel
|
||||
.getConnectorByName(connectorName);
|
||||
if (connector == null) {
|
||||
return false;
|
||||
}
|
||||
return connector.isActivated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteJob(JobSchedulerConfiguration jobSchedulerConfiguration) throws SchedulerException {
|
||||
String triggerName = jobSchedulerConfiguration.getJobName()
|
||||
+ TRIGGER_SUFFIX;
|
||||
String triggerGroup = jobSchedulerConfiguration.getJobGroup()
|
||||
+ TRIGGER_SUFFIX;
|
||||
|
||||
CronTriggerBean trigger = getTriggerBean(triggerName, triggerGroup);
|
||||
if (trigger == null) {
|
||||
LOG.warn("Trigger not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isJobCurrentlyExecuting(triggerName, triggerGroup)) {
|
||||
LOG.warn("Job is currently executing...");
|
||||
return;
|
||||
}
|
||||
|
||||
// deleteJob doesn't work using unscheduleJob
|
||||
this.scheduler.unscheduleJob(trigger.getName(), trigger.getGroup());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if job is currently running for the specified
|
||||
* <code>triggerName</code> and <code>triggerGroup</code>
|
||||
*
|
||||
* @param triggerName
|
||||
* the triggerName
|
||||
* @param triggerGroup
|
||||
* the triggerGroup
|
||||
* @return true if job is currently running, otherwise false
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean isJobCurrentlyExecuting(String triggerName,
|
||||
String triggerGroup) {
|
||||
try {
|
||||
List<JobExecutionContext> currentExecutingJobs = this.scheduler
|
||||
.getCurrentlyExecutingJobs();
|
||||
for (JobExecutionContext jobExecutionContext : currentExecutingJobs) {
|
||||
String name = jobExecutionContext.getTrigger().getName();
|
||||
String group = jobExecutionContext.getTrigger().getGroup();
|
||||
if (triggerName.equals(name) && triggerGroup.equals(group)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (SchedulerException e) {
|
||||
LOG.error("Unable to get currently executing jobs", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link CronTriggerBean} and {@link JobDetailBean} based on the
|
||||
* specified <code>{@link JobSchedulerConfiguration}</code>. First delete
|
||||
* job if exist and then schedule it
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* where to reade jobs to be scheduled
|
||||
* @throws SchedulerException
|
||||
* if unable to delete and/or schedule job
|
||||
*/
|
||||
private void scheduleNewJob(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) throws SchedulerException {
|
||||
CronTriggerBean cronTriggerBean = createCronTriggerBean(jobSchedulerConfiguration);
|
||||
if (cronTriggerBean == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
JobDetailBean jobDetailBean = createJobDetailBean(jobSchedulerConfiguration);
|
||||
if (jobDetailBean == null) {
|
||||
return;
|
||||
}
|
||||
deleteJob(jobSchedulerConfiguration);
|
||||
this.scheduler.scheduleJob(jobDetailBean, cronTriggerBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link CronTriggerBean} from the specified
|
||||
* <code>{@link JobSchedulerConfiguration}</code>
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* configuration to create <code>CronTriggerBean</>
|
||||
* @return the created <code>CronTriggerBean</code> or null if unable to
|
||||
* create it
|
||||
*/
|
||||
private CronTriggerBean createCronTriggerBean(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
CronTriggerBean cronTriggerBean = new CronTriggerBean();
|
||||
cronTriggerBean.setName(jobSchedulerConfiguration.getJobName() + TRIGGER_SUFFIX);
|
||||
cronTriggerBean.setGroup(jobSchedulerConfiguration.getJobGroup()
|
||||
+ TRIGGER_SUFFIX);
|
||||
|
||||
try {
|
||||
cronTriggerBean.setCronExpression(new CronExpression(
|
||||
jobSchedulerConfiguration.getCronExpression()));
|
||||
cronTriggerBean.setJobName(jobSchedulerConfiguration.getJobName());
|
||||
cronTriggerBean
|
||||
.setCronExpression(new CronExpression(cronExpression));
|
||||
.setJobGroup(jobSchedulerConfiguration.getJobGroup());
|
||||
return cronTriggerBean;
|
||||
} catch (ParseException e) {
|
||||
LOG.error("Unable to parse cron expression", e);
|
||||
|
|
@ -119,56 +252,33 @@ public class SchedulerManager implements ISchedulerManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates and returns {@link JobDetailBean}
|
||||
* Creates {@link JobDetailBean} from the specified
|
||||
* <code>{@link JobSchedulerConfiguration}</code>
|
||||
*
|
||||
* @param jobName
|
||||
* the job name
|
||||
* @param jobGroup
|
||||
* the job group
|
||||
* @param jobClassName
|
||||
* the job classname
|
||||
* @param jobSchedulerConfiguration
|
||||
* configuration to create <code>JobDetailBean</>
|
||||
* @return the created <code>JobDetailBean</code> or null if unable to it
|
||||
*/
|
||||
private JobDetailBean createJobDetailBean(String jobName, String jobGroup,
|
||||
String jobClassName) {
|
||||
private JobDetailBean createJobDetailBean(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
JobDetailBean jobDetailBean = new JobDetailBean();
|
||||
|
||||
Class jobClass = getJobClass(jobClassName);
|
||||
Class<?> jobClass = getJobClass(jobSchedulerConfiguration
|
||||
.getJobClassName());
|
||||
if (jobClass == null) {
|
||||
LOG.error("JobClass '" + jobClassName + "' not found");
|
||||
return null;
|
||||
}
|
||||
jobDetailBean.setGroup(jobGroup);
|
||||
jobDetailBean.setName(jobName);
|
||||
|
||||
jobDetailBean.setName(jobSchedulerConfiguration.getJobName());
|
||||
jobDetailBean.setGroup(jobSchedulerConfiguration.getJobGroup());
|
||||
jobDetailBean.setJobClass(jobClass);
|
||||
|
||||
Map<String, Object> jobDataAsMap = new HashMap<String, Object>();
|
||||
if (jobDetailBean.getJobClass().getSimpleName()
|
||||
.equals("ImportRosterFromTimJob")) {
|
||||
jobDataAsMap.put("importRosterFromTim", importRosterFromTim);
|
||||
} else {
|
||||
jobDataAsMap.put("exportTimesheetsToTim", exportTimesheetsToTim);
|
||||
}
|
||||
jobDataAsMap.put("applicationContext", applicationContext);
|
||||
jobDetailBean.setJobDataAsMap(jobDataAsMap);
|
||||
return jobDetailBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the job specified by <code>{@link JobDetailBean}</code> and
|
||||
* link it with the specified <code>{@link CronTriggerBean}</code>
|
||||
*
|
||||
* @param jobDetailBean
|
||||
* the jobDetailBean
|
||||
* @param cronTriggerBean
|
||||
* the cronTriggerBean
|
||||
*/
|
||||
private void scheduleJob(JobDetailBean jobDetailBean,
|
||||
CronTriggerBean cronTriggerBean) {
|
||||
try {
|
||||
this.scheduler.scheduleJob(jobDetailBean, cronTriggerBean);
|
||||
} catch (SchedulerException e) {
|
||||
LOG.error("unable to schedule job", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns jobClass based on <code>jobClassName</code> parameter
|
||||
|
|
@ -176,79 +286,52 @@ public class SchedulerManager implements ISchedulerManager {
|
|||
* @param jobClassName
|
||||
* job className
|
||||
*/
|
||||
private Class getJobClass(String jobClassName) {
|
||||
if (jobClassName.equals("ImportRosterFromTimJob")) {
|
||||
return org.libreplan.importers.ImportRosterFromTimJob.class;
|
||||
private Class<?> getJobClass(JobClassNameEnum jobClassName) {
|
||||
try {
|
||||
return Class.forName(jobClassName.getPackageName() + "."
|
||||
+ jobClassName.getName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
LOG.error("Unable to get class object '" + jobClassName + "'", e);
|
||||
}
|
||||
|
||||
if (jobClassName.equals("ExportTimesheetToTimJob")) {
|
||||
return org.libreplan.importers.ExportTimesheetToTimJob.class;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rescheduleJob(JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
CronTriggerBean cronTriggerBean = createCronTriggerBean(
|
||||
jobSchedulerConfiguration.getTriggerGroup(),
|
||||
jobSchedulerConfiguration.getTriggerName(),
|
||||
jobSchedulerConfiguration.getCronExpression());
|
||||
cronTriggerBean.setName(jobSchedulerConfiguration.getTriggerName());
|
||||
cronTriggerBean.setGroup(jobSchedulerConfiguration.getTriggerGroup());
|
||||
public String getNextFireTime(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
try {
|
||||
cronTriggerBean.setCronExpression(jobSchedulerConfiguration
|
||||
.getCronExpression());
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException("Invalid cron expression");
|
||||
}
|
||||
cronTriggerBean.setJobName(jobSchedulerConfiguration.getJobName());
|
||||
cronTriggerBean.setJobGroup(jobSchedulerConfiguration.getJobGroup());
|
||||
try {
|
||||
scheduler.rescheduleJob(jobSchedulerConfiguration.getTriggerName(),
|
||||
jobSchedulerConfiguration.getTriggerGroup(),
|
||||
cronTriggerBean);
|
||||
} catch (SchedulerException e) {
|
||||
throw new RuntimeException("Unable to reschedule the job");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<SchedulerInfo> getSchedulerInfos() {
|
||||
List<JobSchedulerConfiguration> jobSchedulerConfigurations = jobSchedulerConfigurationDAO
|
||||
.getAll();
|
||||
List<SchedulerInfo> results = new ArrayList<SchedulerInfo>();
|
||||
for (JobSchedulerConfiguration jobSchedulerConfiguration : jobSchedulerConfigurations) {
|
||||
SchedulerInfo schedulerInfo = new SchedulerInfo();
|
||||
schedulerInfo
|
||||
.setJobSchedulerConfiguration(jobSchedulerConfiguration);
|
||||
try {
|
||||
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(
|
||||
jobSchedulerConfiguration.getTriggerName(),
|
||||
jobSchedulerConfiguration.getTriggerGroup());
|
||||
if (trigger != null) {
|
||||
schedulerInfo.setNextFireTime(trigger.getNextFireTime()
|
||||
.toString());
|
||||
}
|
||||
results.add(schedulerInfo);
|
||||
} catch (SchedulerException e) {
|
||||
LOG.error("unable to get the trigger");
|
||||
CronTrigger trigger = (CronTrigger) this.scheduler.getTrigger(
|
||||
jobSchedulerConfiguration.getJobName() + TRIGGER_SUFFIX,
|
||||
jobSchedulerConfiguration.getJobGroup()
|
||||
+ TRIGGER_SUFFIX);
|
||||
if (trigger != null) {
|
||||
return trigger.getNextFireTime().toString();
|
||||
}
|
||||
} catch (SchedulerException e) {
|
||||
LOG.error("unable to get the trigger", e);
|
||||
}
|
||||
return results;
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doManual(String jobName) {
|
||||
if (jobName.equals("Import roster from Tim")) {
|
||||
importRosterFromTim.importRosters();
|
||||
return;
|
||||
}
|
||||
|
||||
if (jobName.equals("Export timesheet to Tim")) {
|
||||
exportTimesheetsToTim.exportTimesheets();
|
||||
return;
|
||||
/**
|
||||
* gets the {@link CronTriggerBean} for the specified
|
||||
* <code>triggerName</code> and <code>tirggerGroup</code>
|
||||
*
|
||||
* @param triggerName
|
||||
* the trigger name
|
||||
* @param triggerGroup
|
||||
* the trigger group
|
||||
* @return CronTriggerBean if found, otherwise null
|
||||
*/
|
||||
private CronTriggerBean getTriggerBean(String triggerName,
|
||||
String triggerGroup) {
|
||||
try {
|
||||
return (CronTriggerBean) this.scheduler.getTrigger(triggerName,
|
||||
triggerGroup);
|
||||
} catch (SchedulerException e) {
|
||||
LOG.error("Unable to get job trigger", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,6 +228,12 @@ public class ConfigurationController extends GenericForwardComposer {
|
|||
configurationModel.confirm();
|
||||
configurationModel.init();
|
||||
messages.showMessage(Level.INFO, _("Changes saved"));
|
||||
if (!configurationModel
|
||||
.scheduleOrUnscheduleJobs(getSelectedConnector())) {
|
||||
messages.showMessage(
|
||||
Level.ERROR,
|
||||
_("Scheduling or unscheduling of jobs for this connector is not completed"));
|
||||
}
|
||||
reloadWindow();
|
||||
reloadEntitySequences();
|
||||
reloadConnectors();
|
||||
|
|
|
|||
|
|
@ -96,6 +96,9 @@ public class ConfigurationModel implements IConfigurationModel {
|
|||
@Autowired
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
@Autowired
|
||||
private IJobSchedulerModel jobSchedulerModel;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<BaseCalendar> getCalendars() {
|
||||
|
|
@ -136,7 +139,9 @@ public class ConfigurationModel implements IConfigurationModel {
|
|||
}
|
||||
}
|
||||
|
||||
private void initConnectorConfiguration() {
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public void initConnectorConfiguration() {
|
||||
connectors = connectorDAO.getAll();
|
||||
forceLoadConnectors();
|
||||
}
|
||||
|
|
@ -748,4 +753,9 @@ public class ConfigurationModel implements IConfigurationModel {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scheduleOrUnscheduleJobs(Connector connector) {
|
||||
return jobSchedulerModel.scheduleOrUnscheduleJobs(connector);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,8 +195,12 @@ public interface IConfigurationModel {
|
|||
|
||||
void setJiraConnectorTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours);
|
||||
|
||||
void initConnectorConfiguration();
|
||||
|
||||
List<Connector> getConnectors();
|
||||
|
||||
Connector getConnectorByName(String name);
|
||||
|
||||
boolean scheduleOrUnscheduleJobs(Connector connector);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,20 +21,120 @@ package org.libreplan.web.common;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.importers.SchedulerInfo;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
|
||||
/**
|
||||
* Contract for {@link JobSchedulerModel}.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public interface IJobSchedulerModel {
|
||||
|
||||
List<SchedulerInfo> getSchedulerInfos();
|
||||
/**
|
||||
* returns all job scheduler configurations
|
||||
*
|
||||
* @return list of <code>JobSchedulerConfiguration</code>
|
||||
*/
|
||||
List<JobSchedulerConfiguration> getJobSchedulerConfigurations();
|
||||
|
||||
void doManual(SchedulerInfo schedulerInfo);
|
||||
/**
|
||||
* returns next fire time for the specified job from
|
||||
* <code>{@link JobSchedulerConfiguration}</code>
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* the job scheduler configuration
|
||||
*/
|
||||
String getNextFireTime(JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
|
||||
void saveJobConfigurationAndReschedule(String jobGroup, String jobName,
|
||||
String cronExp);
|
||||
/**
|
||||
* Do manual action(replacement of scheduling)
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* the job configuration
|
||||
*/
|
||||
void doManual(JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
|
||||
|
||||
/**
|
||||
* Prepares for create a new {@link JobSchedulerConfiguration}.
|
||||
*/
|
||||
void initCreate();
|
||||
|
||||
/**
|
||||
* Prepares for edit {@link JobSchedulerConfiguration}
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* object to be edited
|
||||
*/
|
||||
void initEdit(JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
|
||||
/**
|
||||
* Gets the current {@link JobSchedulerConfiguration}.
|
||||
*
|
||||
* @return A {@link JobSchedulerConfiguration}
|
||||
*/
|
||||
JobSchedulerConfiguration getJobSchedulerConfiguration();
|
||||
|
||||
/**
|
||||
* Saves the current {@link JobSchedulerConfiguration}
|
||||
*
|
||||
* @throws ValidationException
|
||||
* if validation fails
|
||||
*/
|
||||
void confirmSave() throws ValidationException;
|
||||
|
||||
/**
|
||||
* Cancels the current {@link JobSchedulerConfiguration}
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Removes the current {@link JobSchedulerConfiguration}
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* object to be removed
|
||||
*/
|
||||
void remove(JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
|
||||
/**
|
||||
* returns list of connectors
|
||||
*/
|
||||
List<Connector> getConnectors();
|
||||
|
||||
/**
|
||||
* Schedule or unschedule jobs for the specified <code>connector</code>
|
||||
*
|
||||
* schedule all jobs of the specified <code>connector</code>'s property
|
||||
* {@link PredefinedConnectorProperties#ACTIVATED} is 'Y', otherwise
|
||||
* unschedule the jobs
|
||||
*
|
||||
* @param connector
|
||||
* where to check if property is changed
|
||||
* @return true if (un)scheduling is successful, false otherwise
|
||||
*/
|
||||
boolean scheduleOrUnscheduleJobs(Connector connector);
|
||||
|
||||
/**
|
||||
* schedule or unschedule job for the specified job in
|
||||
* <code>{@link JobSchedulerConfiguration}</code>
|
||||
*
|
||||
* @return true if scheduling is succeeded, false otherwise
|
||||
*/
|
||||
boolean scheduleOrUnscheduleJob();
|
||||
|
||||
/**
|
||||
* Delete job specified in <code>{@link JobSchedulerConfiguration}</code>
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* configuration for the job to be deleted
|
||||
* @return true if job is successfully deleted from the scheduler, false
|
||||
* otherwise
|
||||
*/
|
||||
boolean deleteScheduledJob(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
|
||||
}
|
||||
|
|
@ -22,20 +22,23 @@ package org.libreplan.web.common;
|
|||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.JobClassNameEnum;
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
import org.libreplan.importers.SchedulerInfo;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.quartz.CronExpression;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.WrongValueException;
|
||||
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.Grid;
|
||||
import org.zkoss.zul.Hbox;
|
||||
|
|
@ -50,19 +53,21 @@ import org.zkoss.zul.api.Textbox;
|
|||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class JobSchedulerController extends GenericForwardComposer {
|
||||
public class JobSchedulerController extends
|
||||
BaseCRUDController<JobSchedulerConfiguration> {
|
||||
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(JobSchedulerController.class);
|
||||
|
||||
private Grid jobSchedulerGrid;
|
||||
private Grid listJobSchedulings;
|
||||
private Grid cronExpressionGrid;
|
||||
|
||||
private Popup cronExpressionInputPopup;
|
||||
|
||||
private Label jobGroup;
|
||||
|
||||
private Label jobName;
|
||||
|
||||
private Textbox cronExpressionTextBox;
|
||||
private Textbox cronExpressionSeconds;
|
||||
private Textbox cronExpressionMinutes;
|
||||
private Textbox cronExpressionHours;
|
||||
|
|
@ -76,89 +81,191 @@ public class JobSchedulerController extends GenericForwardComposer {
|
|||
@Override
|
||||
public void doAfterCompose(Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
comp.setAttribute("jobSchedulerController", this);
|
||||
listJobSchedulings = (Grid) listWindow
|
||||
.getFellowIfAny("listJobSchedulings");
|
||||
listJobSchedulings.getModel();
|
||||
initCronExpressionPopup();
|
||||
}
|
||||
|
||||
public List<SchedulerInfo> getSchedulerInfos() {
|
||||
return jobSchedulerModel.getSchedulerInfos();
|
||||
/**
|
||||
* initializes cron expressions for popup
|
||||
*/
|
||||
private void initCronExpressionPopup() {
|
||||
cronExpressionTextBox = (Textbox) editWindow
|
||||
.getFellow("cronExpressionTextBox");
|
||||
|
||||
cronExpressionInputPopup = (Popup) editWindow
|
||||
.getFellow("cronExpressionInputPopup");
|
||||
|
||||
jobGroup = (Label) cronExpressionInputPopup.getFellow("jobGroup");
|
||||
jobName = (Label) cronExpressionInputPopup.getFellow("jobName");
|
||||
|
||||
cronExpressionGrid = (Grid) cronExpressionInputPopup
|
||||
.getFellow("cronExpressionGrid");
|
||||
|
||||
cronExpressionSeconds = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionSeconds");
|
||||
cronExpressionMinutes = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionMinutes");
|
||||
cronExpressionHours = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionHours");
|
||||
cronExpressionDayOfMonth = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionDayOfMonth");
|
||||
cronExpressionMonth = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionMonth");
|
||||
cronExpressionDayOfWeek = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionDayOfWeek");
|
||||
cronExpressionYear = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionYear");
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a list of {@link JobSchedulerConfiguration}
|
||||
*/
|
||||
public List<JobSchedulerConfiguration> getJobSchedulerConfigurations() {
|
||||
return jobSchedulerModel.getJobSchedulerConfigurations();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns {@link JobSchedulerConfiguration}
|
||||
*/
|
||||
public JobSchedulerConfiguration getJobSchedulerConfiguration() {
|
||||
return jobSchedulerModel.getJobSchedulerConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all predefined jobs
|
||||
*/
|
||||
public JobClassNameEnum[] getJobNames() {
|
||||
return JobClassNameEnum.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* return list of connectorNames
|
||||
*/
|
||||
public List<String> getConnectorNames() {
|
||||
List<Connector> connectors = jobSchedulerModel.getConnectors();
|
||||
List<String> connectorNames = new ArrayList<String>();
|
||||
for (Connector connector : connectors) {
|
||||
connectorNames.add(connector.getName());
|
||||
}
|
||||
return connectorNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* renders job scheduling and returns {@link RowRenderer}
|
||||
*/
|
||||
public RowRenderer getJobSchedulingRenderer() {
|
||||
return new RowRenderer() {
|
||||
|
||||
@Override
|
||||
public void render(Row row, Object data) {
|
||||
SchedulerInfo schedulerInfo = (SchedulerInfo) data;
|
||||
final JobSchedulerConfiguration jobSchedulerConfiguration = (JobSchedulerConfiguration) data;
|
||||
row.setValue(data);
|
||||
|
||||
Util.appendLabel(row, schedulerInfo
|
||||
.getJobSchedulerConfiguration().getJobGroup());
|
||||
Util.appendLabel(row, schedulerInfo
|
||||
.getJobSchedulerConfiguration().getJobName());
|
||||
appendCronExpressionAndButton(row, schedulerInfo);
|
||||
Util.appendLabel(row, schedulerInfo.getNextFireTime());
|
||||
appendManualStart(row, schedulerInfo);
|
||||
Util.appendLabel(row, jobSchedulerConfiguration.getJobGroup());
|
||||
Util.appendLabel(row, jobSchedulerConfiguration.getJobName());
|
||||
Util.appendLabel(row,
|
||||
jobSchedulerConfiguration.getCronExpression());
|
||||
Util.appendLabel(row,
|
||||
getNextFireTime(jobSchedulerConfiguration));
|
||||
Hbox hbox = new Hbox();
|
||||
hbox.appendChild(createManualButton(new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
jobSchedulerModel.doManual(jobSchedulerConfiguration);
|
||||
}
|
||||
}));
|
||||
hbox.appendChild(Util.createEditButton(new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
goToEditForm(jobSchedulerConfiguration);
|
||||
}
|
||||
}));
|
||||
hbox.appendChild(Util.createRemoveButton(new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
confirmDelete(jobSchedulerConfiguration);
|
||||
}
|
||||
}));
|
||||
row.appendChild(hbox);
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void appendCronExpressionAndButton(final Row row,
|
||||
final SchedulerInfo schedulerInfo) {
|
||||
final Hbox hBox = new Hbox();
|
||||
hBox.setWidth("170px");
|
||||
|
||||
Label label = new Label(schedulerInfo.getJobSchedulerConfiguration()
|
||||
.getCronExpression());
|
||||
label.setHflex("1");
|
||||
hBox.appendChild(label);
|
||||
|
||||
Button button = Util.createEditButton(new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
setupCronExpressionPopup(schedulerInfo);
|
||||
cronExpressionInputPopup.open(hBox);
|
||||
}
|
||||
});
|
||||
hBox.appendChild(button);
|
||||
|
||||
row.appendChild(hBox);
|
||||
/**
|
||||
* returns the next fire time for the specified job in
|
||||
* {@link JobSchedulerConfiguration}
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* the job scheduler configuration
|
||||
*/
|
||||
private String getNextFireTime(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
return jobSchedulerModel.getNextFireTime(jobSchedulerConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates and returns a button
|
||||
*
|
||||
* @param eventListener
|
||||
* Event listener for this button
|
||||
*/
|
||||
private static Button createManualButton(EventListener eventListener) {
|
||||
Button button = new Button(_("Manual"));
|
||||
button.setTooltiptext(_("Manual"));
|
||||
button.addEventListener(Events.ON_CLICK, eventListener);
|
||||
return button;
|
||||
}
|
||||
|
||||
private void setupCronExpressionPopup(final SchedulerInfo schedulerInfo) {
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration = schedulerInfo.getJobSchedulerConfiguration();
|
||||
jobGroup.setValue(jobSchedulerConfiguration.getJobGroup());
|
||||
jobName.setValue(jobSchedulerConfiguration.getJobName());
|
||||
/**
|
||||
* Opens the <code>cronExpressionInputPopup</code>
|
||||
*/
|
||||
public void openPopup() {
|
||||
setupCronExpressionPopup(getJobSchedulerConfiguration());
|
||||
cronExpressionInputPopup.open(cronExpressionTextBox, "after_start");
|
||||
}
|
||||
|
||||
String cronExpression = jobSchedulerConfiguration.getCronExpression();
|
||||
String[] cronExpressionArray = StringUtils.split(cronExpression);
|
||||
/**
|
||||
* Sets the cronExpression values for <code>cronExpressionInputPopup</code>
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* where to read the values
|
||||
*/
|
||||
private void setupCronExpressionPopup(
|
||||
final JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
if (jobSchedulerConfiguration != null) {
|
||||
jobGroup.setValue(jobSchedulerConfiguration.getJobGroup());
|
||||
jobName.setValue(jobSchedulerConfiguration.getJobName());
|
||||
|
||||
cronExpressionSeconds.setValue(cronExpressionArray[0]);
|
||||
cronExpressionMinutes.setValue(cronExpressionArray[1]);
|
||||
cronExpressionHours.setValue(cronExpressionArray[2]);
|
||||
cronExpressionDayOfMonth.setValue(cronExpressionArray[3]);
|
||||
cronExpressionMonth.setValue(cronExpressionArray[4]);
|
||||
cronExpressionDayOfWeek.setValue(cronExpressionArray[5]);
|
||||
String cronExpression = jobSchedulerConfiguration
|
||||
.getCronExpression();
|
||||
if (cronExpression == null || cronExpression.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cronExpressionArray.length == 7) {
|
||||
cronExpressionYear.setValue(cronExpressionArray[6]);
|
||||
String[] cronExpressionArray = StringUtils.split(cronExpression);
|
||||
|
||||
cronExpressionSeconds.setValue(cronExpressionArray[0]);
|
||||
cronExpressionMinutes.setValue(cronExpressionArray[1]);
|
||||
cronExpressionHours.setValue(cronExpressionArray[2]);
|
||||
cronExpressionDayOfMonth.setValue(cronExpressionArray[3]);
|
||||
cronExpressionMonth.setValue(cronExpressionArray[4]);
|
||||
cronExpressionDayOfWeek.setValue(cronExpressionArray[5]);
|
||||
|
||||
if (cronExpressionArray.length == 7) {
|
||||
cronExpressionYear.setValue(cronExpressionArray[6]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
jobSchedulerModel.doManual(schedulerInfo);
|
||||
}
|
||||
});
|
||||
row.appendChild(rescheduleButton);
|
||||
}
|
||||
|
||||
public void reschedule() {
|
||||
/**
|
||||
* sets the <code>cronExpressionTextBox</code> value from the
|
||||
* <code>cronExpressionInputPopup</code>
|
||||
*/
|
||||
public void updateCronExpression() {
|
||||
String cronExpression = getCronExpressionString();
|
||||
try {
|
||||
// Check cron expression format
|
||||
|
|
@ -169,13 +276,16 @@ public class JobSchedulerController extends GenericForwardComposer {
|
|||
_("Unable to parse cron expression") + ":\n"
|
||||
+ e.getMessage());
|
||||
}
|
||||
|
||||
jobSchedulerModel.saveJobConfigurationAndReschedule(
|
||||
jobGroup.getValue(), jobName.getValue(), cronExpression);
|
||||
cronExpressionTextBox.setValue(cronExpression);
|
||||
cronExpressionInputPopup.close();
|
||||
Util.reloadBindings(jobSchedulerGrid);
|
||||
Util.saveBindings(cronExpressionTextBox);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenating the cronExpression values
|
||||
*
|
||||
* @return cronExpression string
|
||||
*/
|
||||
private String getCronExpressionString() {
|
||||
String cronExpression = "";
|
||||
cronExpression += StringUtils.trimToEmpty(cronExpressionSeconds.getValue()) + " ";
|
||||
|
|
@ -193,8 +303,61 @@ public class JobSchedulerController extends GenericForwardComposer {
|
|||
return cronExpression;
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
/**
|
||||
* closes the popup
|
||||
*/
|
||||
public void cancelPopup() {
|
||||
cronExpressionInputPopup.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getEntityType() {
|
||||
return _("Job scheduling");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPluralEntityType() {
|
||||
return _("Job scheduling");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initCreate() {
|
||||
jobSchedulerModel.initCreate();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initEdit(JobSchedulerConfiguration entity) {
|
||||
jobSchedulerModel.initEdit(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void save() throws ValidationException {
|
||||
jobSchedulerModel.confirmSave();
|
||||
if (jobSchedulerModel.scheduleOrUnscheduleJob()) {
|
||||
messagesForUser.showMessage(Level.INFO,
|
||||
_("Job is scheduled/unscheduled"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancel() {
|
||||
jobSchedulerModel.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JobSchedulerConfiguration getEntityBeingEdited() {
|
||||
return jobSchedulerModel.getJobSchedulerConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void delete(JobSchedulerConfiguration entity)
|
||||
throws InstanceNotFoundException {
|
||||
jobSchedulerModel.remove(entity);
|
||||
if (jobSchedulerModel.deleteScheduledJob(entity)) {
|
||||
messagesForUser.showMessage(Level.INFO,
|
||||
_("Job is deleted from scheduler"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,15 +19,20 @@
|
|||
|
||||
package org.libreplan.web.common;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.daos.IJobSchedulerConfigurationDAO;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.JobClassNameEnum;
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.importers.IExportTimesheetsToTim;
|
||||
import org.libreplan.importers.IImportRosterFromTim;
|
||||
import org.libreplan.importers.ISchedulerManager;
|
||||
import org.libreplan.importers.SchedulerInfo;
|
||||
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
|
@ -38,60 +43,132 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
* Model for UI operations related to {@link JobSchedulerConfiguration}.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@Service
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
@OnConcurrentModification(goToPage = "/common/job_scheduling.zul")
|
||||
public class JobSchedulerModel implements IJobSchedulerModel {
|
||||
|
||||
private JobSchedulerConfiguration jobSchedulerConfiguration;
|
||||
|
||||
@Autowired
|
||||
private ISchedulerManager schedulerManager;
|
||||
|
||||
@Autowired
|
||||
private IJobSchedulerConfigurationDAO jobSchedulerConfigurationDAO;
|
||||
|
||||
@Override
|
||||
public List<SchedulerInfo> getSchedulerInfos() {
|
||||
List<SchedulerInfo> schedulerInfoList = schedulerManager
|
||||
.getSchedulerInfos();
|
||||
Collections.sort(schedulerInfoList, new Comparator<SchedulerInfo>() {
|
||||
@Autowired
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
@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;
|
||||
@Autowired
|
||||
private IImportRosterFromTim importRosterFromTim;
|
||||
|
||||
@Autowired
|
||||
private IExportTimesheetsToTim exportTimesheetsToTim;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<JobSchedulerConfiguration> getJobSchedulerConfigurations() {
|
||||
return jobSchedulerConfigurationDAO.getAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doManual(SchedulerInfo schedulerInfo) {
|
||||
schedulerManager.doManual(schedulerInfo.getJobSchedulerConfiguration()
|
||||
.getJobName());
|
||||
public String getNextFireTime(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
return schedulerManager.getNextFireTime(jobSchedulerConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doManual(JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
String name = jobSchedulerConfiguration.getJobClassName().getName();
|
||||
if (name.equals(JobClassNameEnum.IMPORT_ROSTER_FROM_TIM_JOB.getName())) {
|
||||
importRosterFromTim.importRosters();
|
||||
return;
|
||||
}
|
||||
if (name.equals(JobClassNameEnum.EXPORT_TIMESHEET_TO_TIM_JOB.getName())) {
|
||||
exportTimesheetsToTim.exportTimesheets();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initCreate() {
|
||||
this.jobSchedulerConfiguration = JobSchedulerConfiguration.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initEdit(JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
this.jobSchedulerConfiguration = jobSchedulerConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobSchedulerConfiguration getJobSchedulerConfiguration() {
|
||||
return this.jobSchedulerConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void saveJobConfigurationAndReschedule(String jobGroup,
|
||||
String jobName, String cronExp) {
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration = jobSchedulerConfigurationDAO
|
||||
.findByJobGroupAndJobName(jobGroup, jobName);
|
||||
jobSchedulerConfiguration.setCronExpression(cronExp);
|
||||
public void confirmSave() throws ValidationException {
|
||||
jobSchedulerConfigurationDAO.save(jobSchedulerConfiguration);
|
||||
schedulerManager.rescheduleJob(jobSchedulerConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
jobSchedulerConfiguration = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void remove(JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
try {
|
||||
jobSchedulerConfigurationDAO.remove(jobSchedulerConfiguration
|
||||
.getId());
|
||||
} catch (InstanceNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<Connector> getConnectors() {
|
||||
return connectorDAO.getAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scheduleOrUnscheduleJobs(Connector connector) {
|
||||
List<JobSchedulerConfiguration> jobSchedulerConfigurations = jobSchedulerConfigurationDAO
|
||||
.findByConnectorName(connector.getName());
|
||||
|
||||
for (JobSchedulerConfiguration jobSchedulerConfiguration : jobSchedulerConfigurations) {
|
||||
try {
|
||||
schedulerManager.scheduleOrUnscheduleJob(jobSchedulerConfiguration);
|
||||
} catch (SchedulerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scheduleOrUnscheduleJob() {
|
||||
try {
|
||||
schedulerManager.scheduleOrUnscheduleJob(jobSchedulerConfiguration);
|
||||
} catch (SchedulerException e) {
|
||||
throw new RuntimeException("Failed to schedule job", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteScheduledJob(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
try {
|
||||
schedulerManager.deleteJob(jobSchedulerConfiguration);
|
||||
} catch (SchedulerException e) {
|
||||
throw new RuntimeException("Failed to delete job", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import static org.libreplan.web.I18nHelper._;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectors;
|
||||
import org.libreplan.business.orders.entities.OrderSyncInfo;
|
||||
import org.libreplan.importers.IExportTimesheetsToTim;
|
||||
|
|
@ -108,8 +107,6 @@ public class TimSynchronizationController extends GenericForwardComposer {
|
|||
if (connector == null) {
|
||||
return false;
|
||||
}
|
||||
return connector.getPropertiesAsMap()
|
||||
.get(PredefinedConnectorProperties.ACTIVATED)
|
||||
.equalsIgnoreCase("Y");
|
||||
return connector.isActivated();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
167
libreplan-webapp/src/main/webapp/common/_editJobScheduling.zul
Normal file
167
libreplan-webapp/src/main/webapp/common/_editJobScheduling.zul
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
<!--
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<window id="${arg.id}">
|
||||
<caption id="caption" sclass="caption-title" />
|
||||
<grid id="jobSchedulerGrid" fixedLayout="true">
|
||||
<columns>
|
||||
<column width="200px" />
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<label value="${i18n:_('Job group')}" />
|
||||
<textbox id="jobGroupTextBox" width="400px"
|
||||
constraint="no empty:${i18n:_('cannot be empty')}"
|
||||
value="@{controller.jobSchedulerConfiguration.jobGroup}"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Job name')}" />
|
||||
<textbox id="jobNameTextBox" width="400px"
|
||||
constraint="no empty:${i18n:_('cannot be empty')}"
|
||||
value="@{controller.jobSchedulerConfiguration.jobName}"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Cron expression')}" />
|
||||
<hbox>
|
||||
<textbox id="cronExpressionTextBox"
|
||||
value="@{controller.jobSchedulerConfiguration.cronExpression}"
|
||||
constraint="no empty:${i18n:_('cannot be empty')}"
|
||||
width="400px" disabled="true"/>
|
||||
<button sclass="icono" image="/common/img/ico_editar1.png"
|
||||
hoverImage="/common/img/ico_editar.png"
|
||||
tooltiptext="${i18n:_('Edit')}"
|
||||
onClick="controller.openPopup()"/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Job class name')}" />
|
||||
<combobox id="jobCombo" autodrop="true" width="400px"
|
||||
constraint="no empty:${i18n:_('cannot be empty')}"
|
||||
model="@{controller.jobNames}"
|
||||
selectedItem="@{controller.jobSchedulerConfiguration.jobClassName}">
|
||||
<comboitem
|
||||
self="@{each=jobNames}"
|
||||
label="@{jobNames.name}"
|
||||
value="@{jobNames}" />
|
||||
</combobox>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Connector')}" />
|
||||
<combobox id="connectorCombo" autodrop="true" width="400px"
|
||||
model="@{controller.connectorNames}"
|
||||
selectedItem="@{controller.jobSchedulerConfiguration.connectorName}">
|
||||
<comboitem
|
||||
self="@{each=connectorNames}"
|
||||
label="@{connectorNames.name}"
|
||||
value="@{connectorNames}" />
|
||||
</combobox>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Schedule')}" />
|
||||
<checkbox checked="@{controller.jobSchedulerConfiguration.schedule}" />
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<!-- Control buttons -->
|
||||
<button onClick="controller.saveAndExit()"
|
||||
label="${i18n:_('Save')}"
|
||||
sclass="save-button global-action" />
|
||||
<button onClick="controller.saveAndContinue()"
|
||||
label="${i18n:_('Save and Continue')}"
|
||||
sclass="save-button global-action" />
|
||||
<button onClick="controller.cancelForm()"
|
||||
label="${i18n:_('Cancel')}"
|
||||
sclass="cancel-button global-action" />
|
||||
|
||||
<div>
|
||||
<groupbox closable="false" >
|
||||
<caption label="${i18n:_('Cron expression format')}" />
|
||||
<grid width="500px">
|
||||
<columns>
|
||||
<column label="${i18n:_('Field')}" width="150px"/>
|
||||
<column label="${i18n:_('Allowed values')}" />
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<label value="${i18n:_('Seconds')}"/>
|
||||
<label value="0-59"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Minutes')}"/>
|
||||
<label value="0-59"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Hours')}"/>
|
||||
<label value="0-23"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Day of month')}"/>
|
||||
<label value="1-31"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Month')}"/>
|
||||
<span>1-12 (<label value="${i18n:_('or names')}"/> [JAN-DEC])</span>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Day of week')}"/>
|
||||
<span>0-7 (<label value="${i18n:_('0 or 7 is Sunday, or use names')}"/> [SUN-SAT])</span>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Year (optional)')}"/>
|
||||
<label value="1970-2099"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<div>
|
||||
${i18n:_("For more details on cron expression click")}
|
||||
<a href="http://www.manpagez.com/man/5/crontab/">${i18n:_('here')}.</a>
|
||||
</div>
|
||||
</groupbox>
|
||||
</div>
|
||||
|
||||
<popup id="cronExpressionInputPopup" width="525px">
|
||||
<label id="jobGroup" value="@{jobSchedulerController.jobGroup}"/>
|
||||
<label id="jobName" value="@{jobSchedulerController.jobName}"/>
|
||||
<grid id="cronExpressionGrid">
|
||||
<columns>
|
||||
<column label="${i18n:_('Seconds')}"/>
|
||||
<column label="${i18n:_('Minutes')}" />
|
||||
<column label="${i18n:_('Hours')}"/>
|
||||
<column label="${i18n:_('Day of month')}"/>
|
||||
<column label="${i18n:_('Month')}"/>
|
||||
<column label="${i18n:_('Day of week')}"/>
|
||||
<column label="${i18n:_('Year')}"/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<textbox id="cronExpressionSeconds" width="60px" />
|
||||
<textbox id="cronExpressionMinutes" width="60px" />
|
||||
<textbox id="cronExpressionHours" width="60px" />
|
||||
<textbox id="cronExpressionDayOfMonth" width="60px" />
|
||||
<textbox id="cronExpressionMonth" width="60px" />
|
||||
<textbox id="cronExpressionDayOfWeek" width="60px" />
|
||||
<textbox id="cronExpressionYear" width="60px" />
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<button onClick="controller.updateCronExpression();" label="${i18n:_('OK')}" />
|
||||
<button onClick="controller.cancelPopup();" label="${i18n:_('Cancel')}" />
|
||||
</popup>
|
||||
</window>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<!--
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<window id="${arg.id}" title="${i18n:_('Job Scheduling List')}">
|
||||
|
||||
<grid id="listJobSchedulings"
|
||||
rowRenderer="@{controller.jobSchedulingRenderer}"
|
||||
model="@{controller.jobSchedulerConfigurations}"
|
||||
mold="paging" pageSize="10" fixedLayout="true">
|
||||
<columns>
|
||||
<column label="${i18n:_('Job group')}" />
|
||||
<column label="${i18n:_('Job name')}" />
|
||||
<column label="${i18n:_('Cron expression')}" />
|
||||
<column label="${i18n:_('Next fire time')}" />
|
||||
<column label="${i18n:_('Operations')}" />
|
||||
</columns>
|
||||
</grid>
|
||||
<button label="${i18n:_('Create')}" onClick="controller.goToCreateForm()"
|
||||
sclass="create-button-global-action"/>
|
||||
</window>
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<?page id="exceptionDayTypesList" title="${i18n:_('LibrePlan: Job Scheduling')}" ?>
|
||||
<?page id="jobSchedulingList" title="${i18n:_('LibrePlan: Job Scheduling')}" ?>
|
||||
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
|
||||
<?init class="org.zkoss.zk.ui.util.Composition" arg0="/common/layout/template.zul"?>
|
||||
|
||||
|
|
@ -25,100 +25,14 @@
|
|||
<?link rel="stylesheet" type="text/css" href="/common/css/libreplan.css"?>
|
||||
<?link rel="stylesheet" type="text/css" href="/common/css/libreplan_zk.css"?>
|
||||
|
||||
<?component name="list" inline="true" macroURI="_listStretchesFunctionTemplates.zul"?>
|
||||
<?component name="edit" inline="true" macroURI="_editStretchesFunctionTemplate.zul"?>
|
||||
<?component name="list" inline="true" macroURI="_listJobScheduling.zul"?>
|
||||
<?component name="edit" inline="true" macroURI="_editJobScheduling.zul"?>
|
||||
|
||||
<zk>
|
||||
<window self="@{define(content)}"
|
||||
apply="org.libreplan.web.common.JobSchedulerController">
|
||||
|
||||
<grid id="jobSchedulerGrid"
|
||||
rowRenderer="@{jobSchedulerController.jobSchedulingRenderer}"
|
||||
model="@{jobSchedulerController.schedulerInfos}">
|
||||
<columns>
|
||||
<column label="${i18n:_('Job group')}" />
|
||||
<column label="${i18n:_('Job name')}" />
|
||||
<column label="${i18n:_('Cron expression')}" />
|
||||
<column label="${i18n:_('Next fire time')}" />
|
||||
<column label="${i18n:_('Action')}" />
|
||||
</columns>
|
||||
</grid>
|
||||
<div>
|
||||
<groupbox closable="false" >
|
||||
<caption label="${i18n:_('Cron expression format')}" />
|
||||
<grid width="500px">
|
||||
<columns>
|
||||
<column label="${i18n:_('Field')}" width="150px"/>
|
||||
<column label="${i18n:_('Allowed values')}" />
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<label value="${i18n:_('Seconds')}"/>
|
||||
<label value="0-59"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Minutes')}"/>
|
||||
<label value="0-59"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Hours')}"/>
|
||||
<label value="0-23"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Day of month')}"/>
|
||||
<label value="1-31"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Month')}"/>
|
||||
<span>1-12 (<label value="${i18n:_('or names')}"/> [JAN-DEC])</span>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Day of week')}"/>
|
||||
<span>0-7 (<label value="${i18n:_('0 or 7 is Sunday, or use names')}"/> [SUN-SAT])</span>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Year (optional)')}"/>
|
||||
<label value="1970-2099"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<div>
|
||||
${i18n:_("For more details on cron expression click")}
|
||||
<a href="http://www.manpagez.com/man/5/crontab/">${i18n:_('here')}.</a>
|
||||
</div>
|
||||
</groupbox>
|
||||
</div>
|
||||
|
||||
<popup id="cronExpressionInputPopup" width="525px">
|
||||
<label id="jobGroup" value="@{jobSchedulerController.schedulerInfo}"/>
|
||||
-
|
||||
<label id="jobName" value="@{jobSchedulerController.schedulerInfo}"/>
|
||||
<grid id="cronExpressionGrid">
|
||||
<columns>
|
||||
<column label="${i18n:_('Seconds')}"/>
|
||||
<column label="${i18n:_('Minutes')}" />
|
||||
<column label="${i18n:_('Hours')}"/>
|
||||
<column label="${i18n:_('Day of month')}"/>
|
||||
<column label="${i18n:_('Month')}"/>
|
||||
<column label="${i18n:_('Day of week')}"/>
|
||||
<column label="${i18n:_('Year')}"/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<textbox id="cronExpressionSeconds" width="60px" />
|
||||
<textbox id="cronExpressionMinutes" width="60px" />
|
||||
<textbox id="cronExpressionHours" width="60px" />
|
||||
<textbox id="cronExpressionDayOfMonth" width="60px" />
|
||||
<textbox id="cronExpressionMonth" width="60px" />
|
||||
<textbox id="cronExpressionDayOfWeek" width="60px" />
|
||||
<textbox id="cronExpressionYear" width="60px" />
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<button onClick="jobSchedulerController.reschedule();" label="${i18n:_('OK')}" />
|
||||
<button onClick="jobSchedulerController.cancel();" label="${i18n:_('Cancel')}" />
|
||||
</popup>
|
||||
|
||||
<vbox id="messagesContainer" />
|
||||
<list id="listWindow" />
|
||||
<edit id="editWindow" />
|
||||
</window>
|
||||
|
||||
</zk>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue