Browse Source

任务地址支持配置多个,进行failover

xueli.xue 8 years ago
parent
commit
71e12272c3
23 changed files with 620 additions and 449 deletions
  1. 10 5
      db/tables_xxl_job.sql
  2. 13 196
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java
  3. 20 27
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java
  4. 58 27
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/jobbean/RemoteHttpJobBean.java
  5. 31 20
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java
  6. 21 13
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java
  7. 7 9
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/DynamicSchedulerUtil.java
  8. 2 5
      xxl-job-admin/src/main/java/com/xxl/job/admin/dao/impl/XxlJobLogDaoImpl.java
  9. 33 0
      xxl-job-admin/src/main/java/com/xxl/job/admin/service/IXxlJobService.java
  10. 241 0
      xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java
  11. 1 1
      xxl-job-admin/src/main/resources/applicationcontext-base.xml
  12. 1 3
      xxl-job-admin/src/main/resources/applicationcontext-database.xml
  13. 16 5
      xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml
  14. 18 5
      xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml
  15. 9 7
      xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/jobinfo.index.ftl
  16. 3 1
      xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl
  17. 21 32
      xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js
  18. 5 19
      xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js
  19. 0 2
      xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobInfoTest.java
  20. 0 1
      xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobLogTest.java
  21. 102 63
      xxl-job-core/src/main/java/com/xxl/job/core/handler/HandlerRepository.java
  22. 5 4
      xxl-job-core/src/main/java/com/xxl/job/core/handler/HandlerThread.java
  23. 3 4
      xxl-job-core/src/main/java/com/xxl/job/core/util/HttpUtil.java

+ 10 - 5
db/tables_xxl_job.sql

@@ -150,17 +150,19 @@ CREATE TABLE `xxl_job_qrtz_trigger_info` (
   `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN',
   `job_desc` varchar(255) NOT NULL,
   `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean',
-  `job_data` varchar(512) DEFAULT NULL COMMENT '任务执行数据',
   `add_time` datetime DEFAULT NULL,
   `update_time` datetime DEFAULT NULL,
   `author` varchar(64) DEFAULT NULL COMMENT '作者',
   `alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮件',
   `alarm_threshold` int(11) DEFAULT NULL COMMENT '报警阀值(连续失败次数)',
+  `executor_address` varchar(255) DEFAULT NULL COMMENT '执行器地址,有多个则逗号分隔',
+  `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
+  `executor_param` varchar(255) DEFAULT NULL COMMENT '执行器任务参数',
   `glue_switch` int(11) DEFAULT '0' COMMENT 'GLUE模式开关:0-否,1-是',
   `glue_source` text COMMENT 'GLUE源代码',
   `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注',
   PRIMARY KEY (`id`)
-);
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
 
 CREATE TABLE `xxl_job_qrtz_trigger_log` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -169,7 +171,9 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` (
   `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式',
   `job_desc` varchar(255) NOT NULL,
   `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean',
-  `job_data` varchar(512) DEFAULT NULL COMMENT '任务执行数据',
+  `executor_address` varchar(255) DEFAULT NULL COMMENT '执行器地址,本次执行的地址',
+  `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
+  `executor_param` varchar(255) DEFAULT NULL COMMENT 'executor_param',
   `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间',
   `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果',
   `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志',
@@ -177,7 +181,7 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` (
   `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态',
   `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志',
   PRIMARY KEY (`id`)
-);
+) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
 
 CREATE TABLE `xxl_job_qrtz_trigger_logglue` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -188,7 +192,8 @@ CREATE TABLE `xxl_job_qrtz_trigger_logglue` (
   `add_time` timestamp NULL DEFAULT NULL,
   `update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
   PRIMARY KEY (`id`)
-) ;
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
+
 
 
 commit;

+ 13 - 196
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java

@@ -1,14 +1,9 @@
 package com.xxl.job.admin.controller;
 
-import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import javax.annotation.Resource;
 
-import org.apache.commons.lang.StringUtils;
-import org.quartz.CronExpression;
-import org.quartz.SchedulerException;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -16,15 +11,8 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 
 import com.xxl.job.admin.core.constant.Constants.JobGroupEnum;
-import com.xxl.job.admin.core.jobbean.RemoteHttpJobBean;
 import com.xxl.job.admin.core.model.ReturnT;
-import com.xxl.job.admin.core.model.XxlJobInfo;
-import com.xxl.job.admin.core.util.DynamicSchedulerUtil;
-import com.xxl.job.admin.dao.IXxlJobInfoDao;
-import com.xxl.job.admin.dao.IXxlJobLogDao;
-import com.xxl.job.admin.dao.IXxlJobLogGlueDao;
-import com.xxl.job.core.handler.HandlerRepository;
-import com.xxl.job.core.util.JacksonUtil;
+import com.xxl.job.admin.service.IXxlJobService;
 
 /**
  * index controller
@@ -35,11 +23,7 @@ import com.xxl.job.core.util.JacksonUtil;
 public class JobInfoController {
 	
 	@Resource
-	private IXxlJobInfoDao xxlJobInfoDao;
-	@Resource
-	public IXxlJobLogDao xxlJobLogDao;
-	@Resource
-	private IXxlJobLogGlueDao xxlJobLogGlueDao;
+	private IXxlJobService xxlJobService;
 	
 	@RequestMapping
 	public String index(Model model) {
@@ -53,219 +37,52 @@ public class JobInfoController {
 			@RequestParam(required = false, defaultValue = "10") int length,
 			String jobGroup, String jobName, String filterTime) {
 		
-		// page list
-		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, jobName);
-		int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, jobName);
-		
-		// fill job info
-		if (list!=null && list.size()>0) {
-			for (XxlJobInfo jobInfo : list) {
-				DynamicSchedulerUtil.fillJobInfo(jobInfo);
-			}
-		}
-		
-		// package result
-		Map<String, Object> maps = new HashMap<String, Object>();
-	    maps.put("recordsTotal", list_count);		// 总记录数
-	    maps.put("recordsFiltered", list_count);	// 过滤后的总记录数
-	    maps.put("data", list);  					// 分页列表
-		return maps;
+		return xxlJobService.pageList(start, length, jobGroup, jobName, filterTime);
 	}
 	
 	@RequestMapping("/add")
 	@ResponseBody
 	public ReturnT<String> add(String jobGroup, String jobName, String jobCron, String jobDesc,
-			String handler_address, String handler_name, String handler_params, 
+			String executorAddress, String executorHandler, String executorParam, 
 			String author, String alarmEmail, int alarmThreshold, 
 			int glueSwitch, String glueSource, String glueRemark) {
 		
-		// valid
-		if (JobGroupEnum.match(jobGroup) == null) {
-			return new ReturnT<String>(500, "请选择“任务组”");
-		}
-		if (StringUtils.isBlank(jobName)) {
-			return new ReturnT<String>(500, "请输入“任务名”");
-		}
-		if (!CronExpression.isValidExpression(jobCron)) {
-			return new ReturnT<String>(500, "“corn”不合法");
-		}
-		if (StringUtils.isBlank(jobDesc)) {
-			return new ReturnT<String>(500, "请输入“任务描述”");
-		}
-		if (StringUtils.isBlank(handler_address)) {
-			return new ReturnT<String>(500, "请输入“执行器地址”");
-		}
-		if (glueSwitch==0 && StringUtils.isBlank(handler_name)) {
-			return new ReturnT<String>(500, "请输入“jobHandler”");
-		}
-		if (StringUtils.isBlank(author)) {
-			return new ReturnT<String>(500, "请输入“负责人”");
-		}
-		if (StringUtils.isBlank(alarmEmail)) {
-			return new ReturnT<String>(500, "请输入“报警邮件”");
-		}
-		if (alarmThreshold < 0) {
-			alarmThreshold = 0;
-		}
-		
-		try {
-			if (DynamicSchedulerUtil.checkExists(jobName, jobGroup)) {
-				return new ReturnT<String>(500, "此任务已存在,请更换任务组或任务名");
-			}
-		} catch (SchedulerException e1) {
-			e1.printStackTrace();
-			return new ReturnT<String>(500, "此任务已存在,请更换任务组或任务名");
-		}
-		
-		// parse jobDataMap
-		HashMap<String, String> jobDataMap = new HashMap<String, String>();
-		jobDataMap.put(HandlerRepository.HANDLER_ADDRESS, handler_address);
-		jobDataMap.put(HandlerRepository.HANDLER_NAME, handler_name);
-		jobDataMap.put(HandlerRepository.HANDLER_PARAMS, handler_params);
-		
-		// Backup to the database
-		XxlJobInfo jobInfo = new XxlJobInfo();
-		jobInfo.setJobGroup(jobGroup);
-		jobInfo.setJobName(jobName);
-		jobInfo.setJobCron(jobCron);
-		jobInfo.setJobDesc(jobDesc);
-		jobInfo.setJobClass(RemoteHttpJobBean.class.getName());
-		jobInfo.setJobData(JacksonUtil.writeValueAsString(jobDataMap));
-		jobInfo.setAuthor(author);
-		jobInfo.setAlarmEmail(alarmEmail);
-		jobInfo.setAlarmThreshold(alarmThreshold);
-		jobInfo.setGlueSwitch(glueSwitch);
-		jobInfo.setGlueSource(glueSource);
-		jobInfo.setGlueRemark(glueRemark);
-		xxlJobInfoDao.save(jobInfo);
-		
-		try {
-			// add job 2 quartz
-			boolean result = DynamicSchedulerUtil.addJob(jobInfo);
-			if (result) {
-				return ReturnT.SUCCESS;
-			} else {
-				xxlJobInfoDao.delete(jobGroup, jobName);
-				return new ReturnT<String>(500, "新增任务失败");
-			}
-		} catch (SchedulerException e) {
-			e.printStackTrace();
-		}
-		return ReturnT.FAIL;
+		return xxlJobService.add(jobGroup, jobName, jobCron, jobDesc, executorAddress, executorHandler, executorParam,
+				author, alarmEmail, alarmThreshold, glueSwitch, glueSource, glueRemark);
 	}
 	
 	@RequestMapping("/reschedule")
 	@ResponseBody
 	public ReturnT<String> reschedule(String jobGroup, String jobName, String jobCron, String jobDesc,
-			String handler_address, String handler_name, String handler_params, 
+			String executorAddress, String executorHandler, String executorParam, 
 			String author, String alarmEmail, int alarmThreshold, int glueSwitch) {
 		
-		// valid
-		if (JobGroupEnum.match(jobGroup) == null) {
-			return new ReturnT<String>(500, "请选择“任务组”");
-		}
-		if (StringUtils.isBlank(jobName)) {
-			return new ReturnT<String>(500, "请输入“任务名”");
-		}
-		if (!CronExpression.isValidExpression(jobCron)) {
-			return new ReturnT<String>(500, "“corn”不合法");
-		}
-		if (StringUtils.isBlank(jobDesc)) {
-			return new ReturnT<String>(500, "请输入“任务描述”");
-		}
-		if (StringUtils.isBlank(handler_address)) {
-			return new ReturnT<String>(500, "请输入“执行器地址”");
-		}
-		if (glueSwitch==0 && StringUtils.isBlank(handler_name)) {
-			return new ReturnT<String>(500, "请输入“jobHandler”");
-		}
-		if (StringUtils.isBlank(author)) {
-			return new ReturnT<String>(500, "请输入“负责人”");
-		}
-		if (StringUtils.isBlank(alarmEmail)) {
-			return new ReturnT<String>(500, "请输入“报警邮件”");
-		}
-		if (alarmThreshold < 0) {
-			alarmThreshold = 0;
-		}
-		
-		// parse jobDataMap
-		HashMap<String, String> jobDataMap = new HashMap<String, String>();
-		jobDataMap.put(HandlerRepository.HANDLER_ADDRESS, handler_address);
-		jobDataMap.put(HandlerRepository.HANDLER_NAME, handler_name);
-		jobDataMap.put(HandlerRepository.HANDLER_PARAMS, handler_params);
-		
-		XxlJobInfo jobInfo = xxlJobInfoDao.load(jobGroup, jobName);
-		jobInfo.setJobCron(jobCron);
-		jobInfo.setJobDesc(jobDesc);
-		jobInfo.setJobData(JacksonUtil.writeValueAsString(jobDataMap));
-		jobInfo.setAuthor(author);
-		jobInfo.setAlarmEmail(alarmEmail);
-		jobInfo.setAlarmThreshold(alarmThreshold);
-		jobInfo.setGlueSwitch(glueSwitch);
-		
-		try {
-			// fresh quartz
-			DynamicSchedulerUtil.rescheduleJob(jobInfo);
-			
-			// fresh db
-			xxlJobInfoDao.update(jobInfo);
-			return ReturnT.SUCCESS;
-		} catch (SchedulerException e) {
-			e.printStackTrace();
-		}
-		return ReturnT.FAIL;
+		return xxlJobService.reschedule(jobGroup, jobName, jobCron, jobDesc, executorAddress, executorHandler, executorParam, author,
+				alarmEmail, alarmThreshold, glueSwitch);
 	}
 	
 	@RequestMapping("/remove")
 	@ResponseBody
 	public ReturnT<String> remove(String jobGroup, String jobName) {
-		try {
-			DynamicSchedulerUtil.removeJob(jobName, jobGroup);
-			xxlJobInfoDao.delete(jobGroup, jobName);
-			xxlJobLogDao.delete(jobGroup, jobName);
-			xxlJobLogGlueDao.delete(jobGroup, jobName);
-			return ReturnT.SUCCESS;
-		} catch (SchedulerException e) {
-			e.printStackTrace();
-		}
-		return ReturnT.FAIL;
+		return xxlJobService.remove(jobGroup, jobName);
 	}
 	
 	@RequestMapping("/pause")
 	@ResponseBody
 	public ReturnT<String> pause(String jobGroup, String jobName) {
-		try {
-			DynamicSchedulerUtil.pauseJob(jobName, jobGroup);	// jobStatus do not store
-			return ReturnT.SUCCESS;
-		} catch (SchedulerException e) {
-			e.printStackTrace();
-			return ReturnT.FAIL;
-		}
+		return xxlJobService.pause(jobGroup, jobName);
 	}
 	
 	@RequestMapping("/resume")
 	@ResponseBody
 	public ReturnT<String> resume(String jobGroup, String jobName) {
-		try {
-			DynamicSchedulerUtil.resumeJob(jobName, jobGroup);
-			return ReturnT.SUCCESS;
-		} catch (SchedulerException e) {
-			e.printStackTrace();
-			return ReturnT.FAIL;
-		}
+		return xxlJobService.resume(jobGroup, jobName);
 	}
 	
 	@RequestMapping("/trigger")
 	@ResponseBody
 	public ReturnT<String> triggerJob(String jobGroup, String jobName) {
-		try {
-			DynamicSchedulerUtil.triggerJob(jobName, jobGroup);
-			return ReturnT.SUCCESS;
-		} catch (SchedulerException e) {
-			e.printStackTrace();
-			return ReturnT.FAIL;
-		}
+		return xxlJobService.triggerJob(jobGroup, jobName);
 	}
 	
 }

+ 20 - 27
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java

@@ -20,10 +20,10 @@ import com.xxl.job.admin.core.constant.Constants.JobGroupEnum;
 import com.xxl.job.admin.core.model.ReturnT;
 import com.xxl.job.admin.core.model.XxlJobLog;
 import com.xxl.job.admin.dao.IXxlJobLogDao;
-import com.xxl.job.core.handler.HandlerRepository;
+import com.xxl.job.core.handler.HandlerRepository.ActionEnum;
+import com.xxl.job.core.handler.HandlerRepository.HandlerParamEnum;
 import com.xxl.job.core.util.HttpUtil;
 import com.xxl.job.core.util.HttpUtil.RemoteCallBack;
-import com.xxl.job.core.util.JacksonUtil;
 
 /**
  * index controller
@@ -41,7 +41,7 @@ public class JobLogController {
 		model.addAttribute("jobGroup", jobGroup);
 		model.addAttribute("jobName", jobName);
 		model.addAttribute("JobGroupList", JobGroupEnum.values());
-		return "joblog/index";
+		return "joblog/joblog.index";
 	}
 	
 	@RequestMapping("/pageList")
@@ -101,21 +101,18 @@ public class JobLogController {
 		if (log == null) {
 			return new ReturnT<String>(500, "参数异常");
 		}
-		
-		// server address
-		@SuppressWarnings("unchecked")
-		Map<String, String> jobDataMap = JacksonUtil.readValue(log.getJobData(), Map.class);
-		String handler_address = jobDataMap.get(HandlerRepository.HANDLER_ADDRESS);
-		if (!handler_address.startsWith("http")){
-			handler_address = "http://" + handler_address + "/";
+		if (!RemoteCallBack.SUCCESS.equals(log.getTriggerStatus())) {
+			return new ReturnT<String>(500, "调度失败,无法查看执行日志");
 		}
+		
 		// trigger id, trigger time
 		Map<String, String> reqMap = new HashMap<String, String>();
-		reqMap.put(HandlerRepository.NAMESPACE, HandlerRepository.NameSpaceEnum.LOG.name());
-		reqMap.put(HandlerRepository.TRIGGER_LOG_ID, String.valueOf(id));
-		reqMap.put(HandlerRepository.TRIGGER_TIMESTAMP, String.valueOf(log.getTriggerTime().getTime()));
+		reqMap.put(HandlerParamEnum.TIMESTAMP.name(), String.valueOf(System.currentTimeMillis()));
+		reqMap.put(HandlerParamEnum.ACTION.name(), ActionEnum.LOG.name());
+		reqMap.put(HandlerParamEnum.LOG_ID.name(), String.valueOf(id));
+		reqMap.put(HandlerParamEnum.LOG_DATE.name(), String.valueOf(log.getTriggerTime().getTime()));
 		
-		RemoteCallBack callBack = HttpUtil.post(handler_address, reqMap);
+		RemoteCallBack callBack = HttpUtil.post(HttpUtil.addressToUrl(log.getExecutorAddress()), reqMap);
 		if (HttpUtil.RemoteCallBack.SUCCESS.equals(callBack.getStatus())) {
 			return new ReturnT<String>(callBack.getMsg());
 		} else {
@@ -138,23 +135,19 @@ public class JobLogController {
 		if (log == null) {
 			return new ReturnT<String>(500, "参数异常");
 		}
-		
-		// server address
-		@SuppressWarnings("unchecked")
-		Map<String, String> jobDataMap = JacksonUtil.readValue(log.getJobData(), Map.class);
-		String handler_address = jobDataMap.get(HandlerRepository.HANDLER_ADDRESS);
-		if (!handler_address.startsWith("http")){
-			handler_address = "http://" + handler_address + "/";
+		if (!RemoteCallBack.SUCCESS.equals(log.getTriggerStatus())) {
+			return new ReturnT<String>(500, "调度失败,无法终止日志");
 		}
-		String handler_name = jobDataMap.get(HandlerRepository.HANDLER_NAME);
 		
-		// trigger id, trigger time
+		// request
 		Map<String, String> reqMap = new HashMap<String, String>();
-		reqMap.put(HandlerRepository.NAMESPACE, HandlerRepository.NameSpaceEnum.KILL.name());
-		reqMap.put(HandlerRepository.HANDLER_NAME, handler_name);
-		reqMap.put(HandlerRepository.TRIGGER_TIMESTAMP, String.valueOf(System.currentTimeMillis()));
+		reqMap.put(HandlerParamEnum.TIMESTAMP.name(), String.valueOf(System.currentTimeMillis()));
+		reqMap.put(HandlerParamEnum.ACTION.name(), ActionEnum.KILL.name());
+		reqMap.put(HandlerParamEnum.EXECUTOR_HANDLER.name(), log.getExecutorHandler());
+		reqMap.put(HandlerParamEnum.JOB_GROUP.name(), log.getJobGroup());
+		reqMap.put(HandlerParamEnum.JOB_NAME.name(), log.getJobName());
 		
-		RemoteCallBack callBack = HttpUtil.post(handler_address, reqMap);
+		RemoteCallBack callBack = HttpUtil.post(HttpUtil.addressToUrl(log.getExecutorAddress()), reqMap);
 		if (HttpUtil.RemoteCallBack.SUCCESS.equals(callBack.getStatus())) {
 			log.setHandleStatus(HttpUtil.RemoteCallBack.FAIL);
 			log.setHandleMsg("人为操作主动终止");

+ 58 - 27
xxl-job-admin/src/main/java/com/xxl/job/admin/core/jobbean/RemoteHttpJobBean.java

@@ -1,8 +1,8 @@
 package com.xxl.job.admin.core.jobbean;
 
+import java.text.MessageFormat;
 import java.util.Date;
 import java.util.HashMap;
-import java.util.Map;
 
 import org.quartz.JobExecutionContext;
 import org.quartz.JobExecutionException;
@@ -16,10 +16,10 @@ import com.xxl.job.admin.core.model.XxlJobInfo;
 import com.xxl.job.admin.core.model.XxlJobLog;
 import com.xxl.job.admin.core.thread.JobMonitorHelper;
 import com.xxl.job.admin.core.util.DynamicSchedulerUtil;
-import com.xxl.job.core.handler.HandlerRepository;
+import com.xxl.job.core.handler.HandlerRepository.ActionEnum;
+import com.xxl.job.core.handler.HandlerRepository.HandlerParamEnum;
 import com.xxl.job.core.util.HttpUtil;
 import com.xxl.job.core.util.HttpUtil.RemoteCallBack;
-import com.xxl.job.core.util.JacksonUtil;
 
 /**
  * http job bean
@@ -30,14 +30,12 @@ import com.xxl.job.core.util.JacksonUtil;
 public class RemoteHttpJobBean extends QuartzJobBean {
 	private static Logger logger = LoggerFactory.getLogger(RemoteHttpJobBean.class);
 	
-	@SuppressWarnings("unchecked")
 	@Override
 	protected void executeInternal(JobExecutionContext context)
 			throws JobExecutionException {
 		JobKey jobKey = context.getTrigger().getJobKey();
 		
 		XxlJobInfo jobInfo = DynamicSchedulerUtil.xxlJobInfoDao.load(jobKey.getGroup(), jobKey.getName());
-		HashMap<String, String> jobDataMap = (HashMap<String, String>) JacksonUtil.readValueRefer(jobInfo.getJobData(), Map.class);
 		// save log
 		XxlJobLog jobLog = new XxlJobLog();
 		jobLog.setJobGroup(jobInfo.getJobGroup());
@@ -45,35 +43,30 @@ public class RemoteHttpJobBean extends QuartzJobBean {
 		jobLog.setJobCron(jobInfo.getJobCron());
 		jobLog.setJobDesc(jobInfo.getJobDesc());
 		jobLog.setJobClass(jobInfo.getJobClass());
-		jobLog.setJobData(jobInfo.getJobData());
-		
-		jobLog.setJobClass(RemoteHttpJobBean.class.getName());
-		jobLog.setJobData(jobInfo.getJobData());
 		DynamicSchedulerUtil.xxlJobLogDao.save(jobLog);
-		logger.info(">>>>>>>>>>> xxl-job trigger start, jobLog:{}", jobLog);
+		logger.info(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId());
 		
 		// trigger request
 		HashMap<String, String> params = new HashMap<String, String>();
-		params.put(HandlerRepository.TRIGGER_TIMESTAMP, String.valueOf(System.currentTimeMillis()));
-		params.put(HandlerRepository.NAMESPACE, HandlerRepository.NameSpaceEnum.RUN.name());
-		
-		params.put(HandlerRepository.TRIGGER_LOG_ID, String.valueOf(jobLog.getId()));
-		params.put(HandlerRepository.TRIGGER_LOG_ADDRESS, XxlJobLogCallbackServer.getTrigger_log_address());
+		params.put(HandlerParamEnum.TIMESTAMP.name(), String.valueOf(System.currentTimeMillis()));
+		params.put(HandlerParamEnum.ACTION.name(), ActionEnum.RUN.name());
 		
-		params.put(HandlerRepository.HANDLER_NAME, jobDataMap.get(HandlerRepository.HANDLER_NAME));
-		params.put(HandlerRepository.HANDLER_PARAMS, jobDataMap.get(HandlerRepository.HANDLER_PARAMS));
+		params.put(HandlerParamEnum.LOG_ADDRESS.name(), XxlJobLogCallbackServer.getTrigger_log_address());
+		params.put(HandlerParamEnum.LOG_ID.name(), String.valueOf(jobLog.getId()));
 		
-		params.put(HandlerRepository.HANDLER_GLUE_SWITCH, String.valueOf(jobInfo.getGlueSwitch()));
-		params.put(HandlerRepository.HANDLER_JOB_GROUP, jobInfo.getJobGroup());
-		params.put(HandlerRepository.HANDLER_JOB_NAME, jobInfo.getJobName());
+		params.put(HandlerParamEnum.EXECUTOR_HANDLER.name(), jobInfo.getExecutorHandler());
+		params.put(HandlerParamEnum.EXECUTOR_PARAMS.name(), jobInfo.getExecutorParam());
 		
+		params.put(HandlerParamEnum.GLUE_SWITCH.name(), String.valueOf(jobInfo.getGlueSwitch()));
+		params.put(HandlerParamEnum.JOB_GROUP.name(), jobInfo.getJobGroup());
+		params.put(HandlerParamEnum.JOB_NAME.name(), jobInfo.getJobName());
 
-		// handler address, jetty (servlet dead)
-		String handler_address = jobDataMap.get(HandlerRepository.HANDLER_ADDRESS);
-
-		RemoteCallBack callback = HttpUtil.post(HttpUtil.addressToUrl(handler_address), params);
-		logger.info(">>>>>>>>>>> xxl-job trigger http response, jobLog.id:{}, jobLog:{}, callback:{}", jobLog.getId(), jobLog, callback);
-
+		// failover trigger
+		RemoteCallBack callback = failoverTrigger(jobInfo.getExecutorAddress(), params, jobLog);
+		jobLog.setExecutorHandler(jobInfo.getGlueSwitch()==0?jobInfo.getExecutorHandler():"GLUE任务");
+		jobLog.setExecutorParam(jobInfo.getExecutorParam());
+		logger.info(">>>>>>>>>>> xxl-job failoverTrigger response, jobId:{}, callback:{}", jobLog.getId(), callback);
+		
 		// update trigger info
 		jobLog.setTriggerTime(new Date());
 		jobLog.setTriggerStatus(callback.getStatus());
@@ -83,7 +76,45 @@ public class RemoteHttpJobBean extends QuartzJobBean {
 		// monitor triger
 		JobMonitorHelper.monitor(jobLog.getId());
 		
-		logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog);
+		logger.info(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
     }
 	
+	
+	/**
+	 * failover for trigger remote address
+	 * @param addressArr
+	 * @return
+	 */
+	public RemoteCallBack failoverTrigger(String handler_address, HashMap<String, String> handler_params, XxlJobLog jobLog){
+		if (handler_address.split(",").length > 1) {
+			String failoverMessage = "";
+			for (String address : handler_address.split(",")) {
+				HashMap<String, String> params = new HashMap<String, String>();
+				params.put(HandlerParamEnum.TIMESTAMP.name(), String.valueOf(System.currentTimeMillis()));
+				params.put(HandlerParamEnum.ACTION.name(), ActionEnum.BEAT.name());
+				RemoteCallBack beatResult = HttpUtil.post(HttpUtil.addressToUrl(address), params);
+				failoverMessage += MessageFormat.format("BEAT running, <br>>>>[address] : {0}, <br>>>>[status] : {1}, <br>>>>[msg] : {2} <br><hr>", address, beatResult.getStatus(), beatResult.getMsg());
+				if (RemoteCallBack.SUCCESS.equals(beatResult.getStatus())) {
+					jobLog.setExecutorAddress(address);
+					RemoteCallBack triggerCallback = HttpUtil.post(HttpUtil.addressToUrl(address), handler_params);
+					triggerCallback.setStatus(RemoteCallBack.SUCCESS);
+					failoverMessage += MessageFormat.format("Trigger running, <br>>>>[address] : {0}, <br>>>>[status] : {1}, <br>>>>[msg] : {2} <br><hr>", address, triggerCallback.getStatus(), triggerCallback.getMsg());
+					triggerCallback.setMsg(failoverMessage);
+					return triggerCallback;
+				}
+			}
+			
+			RemoteCallBack result = new RemoteCallBack();
+			result.setStatus(RemoteCallBack.FAIL);
+			result.setMsg(failoverMessage);
+			return result;
+		} else {
+			jobLog.setExecutorAddress(handler_address);
+			RemoteCallBack triggerCallback = HttpUtil.post(HttpUtil.addressToUrl(handler_address), handler_params);
+			String failoverMessage = MessageFormat.format("Trigger running, <br>>>>[address] : {0}, <br>>>>[status] : {1}, <br>>>>[msg] : {2} <br><hr>", handler_address, triggerCallback.getStatus(), triggerCallback.getMsg());
+			triggerCallback.setMsg(failoverMessage);
+			return triggerCallback;
+		}
+	}
+	
 }

+ 31 - 20
xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java

@@ -15,7 +15,7 @@ public class XxlJobInfo {
 	private String jobCron;		// 任务执行CRON表达式 【base on quartz】
 	private String jobDesc;
 	private String jobClass;	// 任务执行JobBean 【base on quartz】
-	private String jobData;		// 任务执行数据 Map-JSON-String
+	//private String jobData;		// 任务执行数据 Map-JSON-String
 	
 	private Date addTime;
 	private Date updateTime;
@@ -24,6 +24,10 @@ public class XxlJobInfo {
 	private String alarmEmail;	// 报警邮件
 	private int alarmThreshold;	// 报警阀值
 	
+	private String executorAddress;	// 执行器地址,有多个则逗号分隔
+	private String executorHandler;	// 执行器,任务Handler名称
+	private String executorParam;	// 执行器,任务参数
+	
 	private int glueSwitch;		// GLUE模式开关:0-否,1-是
 	private String glueSource;	// GLUE源代码
 	private String glueRemark;	// GLUE备注
@@ -79,14 +83,6 @@ public class XxlJobInfo {
 		this.jobClass = jobClass;
 	}
 
-	public String getJobData() {
-		return jobData;
-	}
-
-	public void setJobData(String jobData) {
-		this.jobData = jobData;
-	}
-
 	public Date getAddTime() {
 		return addTime;
 	}
@@ -127,12 +123,28 @@ public class XxlJobInfo {
 		this.alarmThreshold = alarmThreshold;
 	}
 
-	public String getJobStatus() {
-		return jobStatus;
+	public String getExecutorAddress() {
+		return executorAddress;
 	}
 
-	public void setJobStatus(String jobStatus) {
-		this.jobStatus = jobStatus;
+	public void setExecutorAddress(String executorAddress) {
+		this.executorAddress = executorAddress;
+	}
+
+	public String getExecutorHandler() {
+		return executorHandler;
+	}
+
+	public void setExecutorHandler(String executorHandler) {
+		this.executorHandler = executorHandler;
+	}
+
+	public String getExecutorParam() {
+		return executorParam;
+	}
+
+	public void setExecutorParam(String executorParam) {
+		this.executorParam = executorParam;
 	}
 
 	public int getGlueSwitch() {
@@ -159,13 +171,12 @@ public class XxlJobInfo {
 		this.glueRemark = glueRemark;
 	}
 
-	@Override
-	public String toString() {
-		return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron
-				+ ", jobDesc=" + jobDesc + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime
-				+ ", updateTime=" + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail
-				+ ", alarmThreshold=" + alarmThreshold + ", glueSwitch=" + glueSwitch + ", glueSource=" + glueSource
-				+ ", glueRemark=" + glueRemark + ", jobStatus=" + jobStatus + "]";
+	public String getJobStatus() {
+		return jobStatus;
+	}
+
+	public void setJobStatus(String jobStatus) {
+		this.jobStatus = jobStatus;
 	}
 	
 }

+ 21 - 13
xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java

@@ -16,7 +16,10 @@ public class XxlJobLog {
 	private String jobCron;
 	private String jobDesc;
 	private String jobClass;
-	private String jobData;
+	
+	private String executorAddress;	// 执行器地址,有多个则逗号分隔
+	private String executorHandler;	// 执行器,任务Handler名称
+	private String executorParam;	// 执行器,任务参数
 	
 	// trigger info
 	private Date triggerTime;
@@ -27,6 +30,7 @@ public class XxlJobLog {
 	private Date handleTime;
 	private String handleStatus;
 	private String handleMsg;
+	
 	public int getId() {
 		return id;
 	}
@@ -63,11 +67,23 @@ public class XxlJobLog {
 	public void setJobClass(String jobClass) {
 		this.jobClass = jobClass;
 	}
-	public String getJobData() {
-		return jobData;
+	public String getExecutorAddress() {
+		return executorAddress;
+	}
+	public void setExecutorAddress(String executorAddress) {
+		this.executorAddress = executorAddress;
+	}
+	public String getExecutorHandler() {
+		return executorHandler;
 	}
-	public void setJobData(String jobData) {
-		this.jobData = jobData;
+	public void setExecutorHandler(String executorHandler) {
+		this.executorHandler = executorHandler;
+	}
+	public String getExecutorParam() {
+		return executorParam;
+	}
+	public void setExecutorParam(String executorParam) {
+		this.executorParam = executorParam;
 	}
 	public Date getTriggerTime() {
 		return triggerTime;
@@ -106,12 +122,4 @@ public class XxlJobLog {
 		this.handleMsg = handleMsg;
 	}
 	
-	@Override
-	public String toString() {
-		return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron
-				+ ", jobDesc=" + jobDesc + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime="
-				+ triggerTime + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime="
-				+ handleTime + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]";
-	}
-	
 }

+ 7 - 9
xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/DynamicSchedulerUtil.java

@@ -12,7 +12,6 @@ import org.quartz.CronScheduleBuilder;
 import org.quartz.CronTrigger;
 import org.quartz.Job;
 import org.quartz.JobBuilder;
-import org.quartz.JobDataMap;
 import org.quartz.JobDetail;
 import org.quartz.JobKey;
 import org.quartz.Scheduler;
@@ -35,7 +34,6 @@ import com.xxl.job.admin.core.callback.XxlJobLogCallbackServer;
 import com.xxl.job.admin.core.model.XxlJobInfo;
 import com.xxl.job.admin.dao.IXxlJobInfoDao;
 import com.xxl.job.admin.dao.IXxlJobLogDao;
-import com.xxl.job.core.util.JacksonUtil;
 
 /**
  * base quartz scheduler util
@@ -151,7 +149,7 @@ public final class DynamicSchedulerUtil implements ApplicationContextAware, Init
 	}
 
 	// addJob 新增
-    @SuppressWarnings("unchecked")
+	@SuppressWarnings("unchecked")
 	public static boolean addJob(XxlJobInfo jobInfo) throws SchedulerException {
     	// TriggerKey : name + group
         TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getJobName(), jobInfo.getJobGroup());
@@ -176,10 +174,11 @@ public final class DynamicSchedulerUtil implements ApplicationContextAware, Init
 		}
         
 		JobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).build();
-        if (jobInfo.getJobData()!=null) {
+        /*if (jobInfo.getJobData()!=null) {
         	JobDataMap jobDataMap = jobDetail.getJobDataMap();
-        	jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));	// JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
-		}
+        	jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));	
+        	// JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
+		}*/
         
         // schedule : jobDetail + cronTrigger
         Date date = scheduler.scheduleJob(jobDetail, cronTrigger);
@@ -189,7 +188,6 @@ public final class DynamicSchedulerUtil implements ApplicationContextAware, Init
     }
     
     // reschedule
-    @SuppressWarnings("unchecked")
 	public static boolean rescheduleJob(XxlJobInfo jobInfo) throws SchedulerException {
     	
     	// TriggerKey valid if_exists
@@ -210,9 +208,9 @@ public final class DynamicSchedulerUtil implements ApplicationContextAware, Init
         
         // JobDetail-JobDataMap fresh
         JobDetail jobDetail = scheduler.getJobDetail(jobKey);
-    	JobDataMap jobDataMap = jobDetail.getJobDataMap();
+    	/*JobDataMap jobDataMap = jobDetail.getJobDataMap();
     	jobDataMap.clear();
-    	jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));
+    	jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));*/
     	
     	// Trigger fresh
     	HashSet<Trigger> triggerSet = new HashSet<Trigger>();

+ 2 - 5
xxl-job-admin/src/main/java/com/xxl/job/admin/dao/impl/XxlJobLogDaoImpl.java

@@ -63,15 +63,12 @@ public class XxlJobLogDaoImpl implements IXxlJobLogDao {
 
 	@Override
 	public int save(XxlJobLog xxlJobLog) {
-		if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) {
-			xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000));
-		}
 		return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog);
 	}
 	
 	@Override
 	public int updateTriggerInfo(XxlJobLog xxlJobLog) {
-		if (xxlJobLog!=null && xxlJobLog.getTriggerMsg()!=null && xxlJobLog.getTriggerMsg().length()>2000) {
+		if (xxlJobLog.getTriggerMsg()!=null && xxlJobLog.getTriggerMsg().length()>2000) {
 			xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000));
 		}
 		return sqlSessionTemplate.update("XxlJobLogMapper.updateTriggerInfo", xxlJobLog);
@@ -79,7 +76,7 @@ public class XxlJobLogDaoImpl implements IXxlJobLogDao {
 
 	@Override
 	public int updateHandleInfo(XxlJobLog xxlJobLog) {
-		if (xxlJobLog!=null && xxlJobLog.getHandleMsg()!=null && xxlJobLog.getHandleMsg().length()>2000) {
+		if (xxlJobLog.getHandleMsg()!=null && xxlJobLog.getHandleMsg().length()>2000) {
 			xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg().substring(0, 2000));
 		}
 		return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog);

+ 33 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/service/IXxlJobService.java

@@ -0,0 +1,33 @@
+package com.xxl.job.admin.service;
+
+import java.util.Map;
+
+import com.xxl.job.admin.core.model.ReturnT;
+
+/**
+ * core job service for xxl-job
+ * 
+ * @author xuxueli 2016-5-28 15:30:33
+ */
+public interface IXxlJobService {
+	
+	public Map<String, Object> pageList(int start, int length, String jobGroup, String jobName, String filterTime);
+	
+	public ReturnT<String> add(String jobGroup, String jobName, String jobCron, String jobDesc, 
+			String executorAddress,	String executorHandler, String executorParam, 
+			String author, String alarmEmail, int alarmThreshold,
+			int glueSwitch, String glueSource, String glueRemark);
+	
+	public ReturnT<String> reschedule(String jobGroup, String jobName, String jobCron, String jobDesc,
+			String handler_address, String handler_name, String handler_params, 
+			String author, String alarmEmail, int alarmThreshold, int glueSwitch);
+	
+	public ReturnT<String> remove(String jobGroup, String jobName);
+	
+	public ReturnT<String> pause(String jobGroup, String jobName);
+	
+	public ReturnT<String> resume(String jobGroup, String jobName);
+	
+	public ReturnT<String> triggerJob(String jobGroup, String jobName);
+	
+}

+ 241 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java

@@ -0,0 +1,241 @@
+package com.xxl.job.admin.service.impl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.lang.StringUtils;
+import org.quartz.CronExpression;
+import org.quartz.SchedulerException;
+import org.springframework.stereotype.Service;
+
+import com.xxl.job.admin.core.constant.Constants.JobGroupEnum;
+import com.xxl.job.admin.core.jobbean.RemoteHttpJobBean;
+import com.xxl.job.admin.core.model.ReturnT;
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.util.DynamicSchedulerUtil;
+import com.xxl.job.admin.dao.IXxlJobInfoDao;
+import com.xxl.job.admin.dao.IXxlJobLogDao;
+import com.xxl.job.admin.dao.IXxlJobLogGlueDao;
+import com.xxl.job.admin.service.IXxlJobService;
+
+/**
+ * core job service for xxl-job
+ * @author xuxueli 2016-5-28 15:30:33
+ */
+@Service
+public class XxlJobServiceImpl implements IXxlJobService {
+
+	@Resource
+	private IXxlJobInfoDao xxlJobInfoDao;
+	@Resource
+	public IXxlJobLogDao xxlJobLogDao;
+	@Resource
+	private IXxlJobLogGlueDao xxlJobLogGlueDao;
+	
+	@Override
+	public Map<String, Object> pageList(int start, int length, String jobGroup, String jobName, String filterTime) {
+		
+		// page list
+		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, jobName);
+		int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, jobName);
+		
+		// fill job info
+		if (list!=null && list.size()>0) {
+			for (XxlJobInfo jobInfo : list) {
+				DynamicSchedulerUtil.fillJobInfo(jobInfo);
+			}
+		}
+		
+		// package result
+		Map<String, Object> maps = new HashMap<String, Object>();
+	    maps.put("recordsTotal", list_count);		// 总记录数
+	    maps.put("recordsFiltered", list_count);	// 过滤后的总记录数
+	    maps.put("data", list);  					// 分页列表
+		return maps;
+	}
+
+	@Override
+	public ReturnT<String> add(String jobGroup, String jobName, String jobCron, String jobDesc, 
+			String executorAddress,	String executorHandler, String executorParam, 
+			String author, String alarmEmail, int alarmThreshold,
+			int glueSwitch, String glueSource, String glueRemark) {
+		// valid
+		if (JobGroupEnum.match(jobGroup) == null) {
+			return new ReturnT<String>(500, "请选择“任务组”");
+		}
+		if (StringUtils.isBlank(jobName)) {
+			return new ReturnT<String>(500, "请输入“任务名”");
+		}
+		if (!CronExpression.isValidExpression(jobCron)) {
+			return new ReturnT<String>(500, "请输入格式正确的“corn”");
+		}
+		if (StringUtils.isBlank(jobDesc)) {
+			return new ReturnT<String>(500, "请输入“任务描述”");
+		}
+		if (StringUtils.isBlank(executorAddress)) {
+			return new ReturnT<String>(500, "请输入“执行器地址”");
+		}
+		if (glueSwitch==0 && StringUtils.isBlank(executorHandler)) {
+			return new ReturnT<String>(500, "请输入“jobHandler”");
+		}
+		if (StringUtils.isBlank(author)) {
+			return new ReturnT<String>(500, "请输入“负责人”");
+		}
+		if (StringUtils.isBlank(alarmEmail)) {
+			return new ReturnT<String>(500, "请输入“报警邮件”");
+		}
+		if (alarmThreshold < 0) {
+			alarmThreshold = 0;
+		}
+		
+		try {
+			if (DynamicSchedulerUtil.checkExists(jobName, jobGroup)) {
+				return new ReturnT<String>(500, "此任务已存在,请更换任务组或任务名");
+			}
+		} catch (SchedulerException e1) {
+			e1.printStackTrace();
+			return new ReturnT<String>(500, "此任务已存在,请更换任务组或任务名");
+		}
+		
+		// Backup to the database
+		XxlJobInfo jobInfo = new XxlJobInfo();
+		jobInfo.setJobGroup(jobGroup);
+		jobInfo.setJobName(jobName);
+		jobInfo.setJobCron(jobCron);
+		jobInfo.setJobDesc(jobDesc);
+		jobInfo.setJobClass(RemoteHttpJobBean.class.getName());
+		jobInfo.setAuthor(author);
+		jobInfo.setAlarmEmail(alarmEmail);
+		jobInfo.setAlarmThreshold(alarmThreshold);
+		jobInfo.setGlueSwitch(glueSwitch);
+		jobInfo.setGlueSource(glueSource);
+		jobInfo.setGlueRemark(glueRemark);
+		jobInfo.setExecutorAddress(executorAddress);
+		jobInfo.setExecutorHandler(executorHandler);
+		jobInfo.setExecutorParam(executorParam);
+		xxlJobInfoDao.save(jobInfo);
+		
+		try {
+			// add job 2 quartz
+			boolean result = DynamicSchedulerUtil.addJob(jobInfo);
+			if (result) {
+				return ReturnT.SUCCESS;
+			} else {
+				xxlJobInfoDao.delete(jobGroup, jobName);
+				return new ReturnT<String>(500, "新增任务失败");
+			}
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+		}
+		return ReturnT.FAIL;
+	}
+
+	@Override
+	public ReturnT<String> reschedule(String jobGroup, String jobName, String jobCron, String jobDesc,
+			String executorAddress,	String executorHandler, String executorParam, 
+			String author, String alarmEmail, int alarmThreshold, int glueSwitch) {
+		
+		// valid
+		if (JobGroupEnum.match(jobGroup) == null) {
+			return new ReturnT<String>(500, "请选择“任务组”");
+		}
+		if (StringUtils.isBlank(jobName)) {
+			return new ReturnT<String>(500, "请输入“任务名”");
+		}
+		if (!CronExpression.isValidExpression(jobCron)) {
+			return new ReturnT<String>(500, "请输入格式正确的“corn”");
+		}
+		if (StringUtils.isBlank(jobDesc)) {
+			return new ReturnT<String>(500, "请输入“任务描述”");
+		}
+		if (StringUtils.isBlank(executorAddress)) {
+			return new ReturnT<String>(500, "请输入“执行器地址”");
+		}
+		if (glueSwitch==0 && StringUtils.isBlank(executorHandler)) {
+			return new ReturnT<String>(500, "请输入“jobHandler”");
+		}
+		if (StringUtils.isBlank(author)) {
+			return new ReturnT<String>(500, "请输入“负责人”");
+		}
+		if (StringUtils.isBlank(alarmEmail)) {
+			return new ReturnT<String>(500, "请输入“报警邮件”");
+		}
+		if (alarmThreshold < 0) {
+			alarmThreshold = 0;
+		}
+		
+		XxlJobInfo jobInfo = xxlJobInfoDao.load(jobGroup, jobName);
+		jobInfo.setJobCron(jobCron);
+		jobInfo.setJobDesc(jobDesc);
+		jobInfo.setAuthor(author);
+		jobInfo.setAlarmEmail(alarmEmail);
+		jobInfo.setAlarmThreshold(alarmThreshold);
+		jobInfo.setGlueSwitch(glueSwitch);
+		jobInfo.setExecutorAddress(executorAddress);
+		jobInfo.setExecutorHandler(executorHandler);
+		jobInfo.setExecutorParam(executorParam);
+		
+		try {
+			// fresh quartz
+			DynamicSchedulerUtil.rescheduleJob(jobInfo);
+			
+			// fresh db
+			xxlJobInfoDao.update(jobInfo);
+			return ReturnT.SUCCESS;
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+		}
+		return ReturnT.FAIL;
+	}
+
+	@Override
+	public ReturnT<String> remove(String jobGroup, String jobName) {
+		try {
+			DynamicSchedulerUtil.removeJob(jobName, jobGroup);
+			xxlJobInfoDao.delete(jobGroup, jobName);
+			xxlJobLogDao.delete(jobGroup, jobName);
+			xxlJobLogGlueDao.delete(jobGroup, jobName);
+			return ReturnT.SUCCESS;
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+		}
+		return ReturnT.FAIL;
+	}
+
+	@Override
+	public ReturnT<String> pause(String jobGroup, String jobName) {
+		try {
+			DynamicSchedulerUtil.pauseJob(jobName, jobGroup);	// jobStatus do not store
+			return ReturnT.SUCCESS;
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+			return ReturnT.FAIL;
+		}
+	}
+
+	@Override
+	public ReturnT<String> resume(String jobGroup, String jobName) {
+		try {
+			DynamicSchedulerUtil.resumeJob(jobName, jobGroup);
+			return ReturnT.SUCCESS;
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+			return ReturnT.FAIL;
+		}
+	}
+
+	@Override
+	public ReturnT<String> triggerJob(String jobGroup, String jobName) {
+		try {
+			DynamicSchedulerUtil.triggerJob(jobName, jobGroup);
+			return ReturnT.SUCCESS;
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+			return ReturnT.FAIL;
+		}
+	}
+	
+}

+ 1 - 1
xxl-job-admin/src/main/resources/applicationcontext-base.xml

@@ -9,7 +9,7 @@
            http://www.springframework.org/schema/util 
            http://www.springframework.org/schema/util/spring-util.xsd">
 
-	<context:component-scan base-package="com.xxl.job.admin.dao" />
+	<context:component-scan base-package="com.xxl.job.admin.service, com.xxl.job.admin.dao" />
 
 	<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
 		<property name="templateLoaderPath" value="/WEB-INF/template/" />

+ 1 - 3
xxl-job-admin/src/main/resources/applicationcontext-database.xml

@@ -48,7 +48,6 @@
     </bean> 
     
     <!-- part 2 :for tx -->
-    <!--
     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 		<property name="dataSource" ref="dataSource" />
 	</bean>
@@ -68,9 +67,8 @@
 	</tx:advice>
 
 	<aop:config>
-		<aop:pointcut id="txoperation" expression="execution(* com.xxl.job.admin.service.imp.*.*(..))" />
+		<aop:pointcut id="txoperation" expression="execution(* com.xxl.job.admin.service.impl.*.*(..))" />
 		<aop:advisor pointcut-ref="txoperation" advice-ref="txAdvice" />
 	</aop:config>
-	-->
 	
 </beans>

+ 16 - 5
xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml

@@ -11,7 +11,6 @@
 	    <result column="job_cron" property="jobCron" />
 	    <result column="job_desc" property="jobDesc" />
 	    <result column="job_class" property="jobClass" />
-	    <result column="job_data" property="jobData" />
 	    
 	    <result column="add_time" property="addTime" />
 	    <result column="update_time" property="updateTime" />
@@ -20,6 +19,10 @@
 	    <result column="alarm_email" property="alarmEmail" />
 	    <result column="alarm_threshold" property="alarmThreshold" />
 	    
+	    <result column="executor_address" property="executorAddress" />
+	    <result column="executor_handler" property="executorHandler" />
+	    <result column="executor_param" property="executorParam" />
+	    
 	    <result column="glue_switch" property="glueSwitch" />
 	    <result column="glue_source" property="glueSource" />
 	    <result column="glue_remark" property="glueRemark" />
@@ -32,12 +35,14 @@
 		t.job_cron,
 		t.job_desc,
 		t.job_class,
-		t.job_data,
 		t.add_time,
 		t.update_time,
 		t.author,
 		t.alarm_email,
 		t.alarm_threshold,
+		t.executor_address,
+		t.executor_handler,
+		t.executor_param,
 		t.glue_switch,
 		t.glue_source,
 		t.glue_remark
@@ -78,12 +83,14 @@
 			job_cron,
 			job_desc,
 			job_class,
-			job_data,
 			add_time,
 			update_time,
 			author,
 			alarm_email,
 			alarm_threshold,
+			executor_address,
+			executor_handler,
+			executor_param,
 			glue_switch,
 			glue_source,
 			glue_remark
@@ -93,12 +100,14 @@
 			#{jobCron}, 
 			#{jobDesc}, 
 			#{jobClass}, 
-			#{jobData},
 			NOW(),
 			NOW(),
 			#{author},
 			#{alarmEmail},
 			#{alarmThreshold},
+			#{executorAddress},
+			#{executorHandler},
+			#{executorParam},
 			#{glueSwitch},
 			#{glueSource},
 			#{glueRemark}
@@ -120,11 +129,13 @@
 		SET 
 			job_cron = #{jobCron},
 			job_desc = #{jobDesc},
-			job_data = #{jobData},
 			update_time = NOW(),
 			author = #{author},
 			alarm_email = #{alarmEmail},
 			alarm_threshold = #{alarmThreshold},
+			executor_address = #{executorAddress},
+			executor_handler = #{executorHandler},
+			executor_param = #{executorParam},
 			glue_switch = #{glueSwitch},
 			glue_source = #{glueSource},
 			glue_remark = #{glueRemark}

+ 18 - 5
xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml

@@ -11,7 +11,10 @@
 	    <result column="job_cron" property="jobCron" />
 	    <result column="job_desc" property="jobDesc" />
 	    <result column="job_class" property="jobClass" />
-	    <result column="job_data" property="jobData" />
+	    
+	    <result column="executor_address" property="executorAddress" />
+	    <result column="executor_handler" property="executorHandler" />
+	    <result column="executor_param" property="executorParam" />
 	    
 	    <result column="trigger_time" property="triggerTime" />
 	    <result column="trigger_status" property="triggerStatus" />
@@ -20,6 +23,7 @@
 	    <result column="handle_time" property="handleTime" />
 	    <result column="handle_status" property="handleStatus" />
 	    <result column="handle_msg" property="handleMsg" />
+	    
 	</resultMap>
 
 	<sql id="Base_Column_List">
@@ -29,7 +33,9 @@
 		t.job_cron,
 		t.job_desc,
 		t.job_class,
-		t.job_data,
+		t.executor_address,
+		t.executor_handler,
+		t.executor_param,
 		t.trigger_time,
 		t.trigger_status,
 		t.trigger_msg,
@@ -98,14 +104,18 @@
 			`job_cron`, 
 			`job_desc`,
 			`job_class`, 
-			`job_data`
+			`executor_address`,
+			`executor_handler`,
+			`executor_param`
 		) VALUES (
 			#{jobGroup}, 
 			#{jobName},
 			#{jobCron},
 			#{jobDesc},
 			#{jobClass},
-			#{jobData}
+			#{executorAddress},
+			#{executorHandler},
+			#{executorParam}
 		);
 		<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id"> 
 			SELECT LAST_INSERT_ID() 
@@ -117,7 +127,10 @@
 		SET 
 			`trigger_time`= #{triggerTime}, 
 			`trigger_status`= #{triggerStatus}, 
-			`trigger_msg`= #{triggerMsg}
+			`trigger_msg`= #{triggerMsg},
+			`executor_address`= #{executorAddress},
+			`executor_handler`= #{executorHandler},
+			`executor_param`= #{executorParam}
 		WHERE `id`= #{id}
 	</update>
 	

+ 9 - 7
xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/jobinfo.index.ftl

@@ -72,7 +72,9 @@
 					                  	<th name="jobDesc" >描述</th>
 					                  	<th name="jobCron" >Cron</th>
 					                  	<th name="jobClass" >JobBean</th>
-					                  	<th name="jobData" >任务数据</th>
+					                  	<th name="executorAddress" >执行器地址</th>
+					                  	<th name="executorHandler" >JobHandler</th>
+					                  	<th name="executorParam" >任务参数</th>
 					                  	<th name="addTime" >新增时间</th>
 					                  	<th name="updateTime" >更新时间</th>
 					                  	<th name="author" >负责人</th>
@@ -126,13 +128,13 @@
 					</div>
 					<div class="form-group">
 						<label for="lastname" class="col-sm-2 control-label">执行器地址<font color="red">*</font></label>
-						<div class="col-sm-4"><input type="text" class="form-control" name="handler_address" placeholder="请输入“执行器地址”" maxlength="200" ></div>
+						<div class="col-sm-4"><input type="text" class="form-control" name="executorAddress" placeholder="请输入“执行器地址”,多个地址逗号分隔" maxlength="200" ></div>
 						<label for="lastname" class="col-sm-2 control-label">jobHandler<font color="red">*</font></label>
-						<div class="col-sm-4"><input type="text" class="form-control" name="handler_name" placeholder="请输入“jobHandler”" maxlength="200" ></div>
+						<div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="请输入“jobHandler”" maxlength="200" ></div>
 					</div>
 					<div class="form-group">
 						<label for="firstname" class="col-sm-2 control-label">执行参数<font color="black">*</font></label>
-						<div class="col-sm-4"><input type="text" class="form-control" name="handler_params" placeholder="请输入“执行参数”" maxlength="100" ></div>
+						<div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="请输入“执行参数”" maxlength="100" ></div>
 						<label for="lastname" class="col-sm-2 control-label">负责人<font color="red">*</font></label>
 						<div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="请输入“负责人”" maxlength="200" ></div>
 					</div>
@@ -207,13 +209,13 @@ public class DemoJobHandler extends IJobHandler {
 					
 					<div class="form-group">
 						<label for="lastname" class="col-sm-2 control-label">执行器地址<font color="red">*</font></label>
-						<div class="col-sm-4"><input type="text" class="form-control" name="handler_address" placeholder="请输入“执行器地址”" maxlength="200" ></div>
+						<div class="col-sm-4"><input type="text" class="form-control" name="executorAddress" placeholder="请输入“执行器地址”,多个地址逗号分隔" maxlength="200" ></div>
 						<label for="lastname" class="col-sm-2 control-label">jobHandler<font color="red">*</font></label>
-						<div class="col-sm-4"><input type="text" class="form-control" name="handler_name" placeholder="请输入“jobHandler”" maxlength="200" ></div>
+						<div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="请输入“jobHandler”" maxlength="200" ></div>
 					</div>
 					<div class="form-group">
 						<label for="firstname" class="col-sm-2 control-label">执行参数<font color="black">*</font></label>
-						<div class="col-sm-4"><input type="text" class="form-control" name="handler_params" placeholder="请输入“执行参数”" maxlength="100" ></div>
+						<div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="请输入“执行参数”" maxlength="100" ></div>
 						<label for="lastname" class="col-sm-2 control-label">负责人<font color="red">*</font></label>
 						<div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="请输入“负责人”" maxlength="200" ></div>
 					</div>

+ 3 - 1
xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl

@@ -78,7 +78,9 @@
 					                  	<th name="jobCron" >Cron</th>
 					                  	<th name="jobDesc" >描述</th>
 					                  	<th name="jobClass" >JobBean</th>
-					                  	<th name="jobData" >任务数据</th>
+					                  	<th name="executorAddress" >执行器地址</th>
+					                  	<th name="executorHandler" >JobHandler</th>
+					                  	<th name="executorParam" >任务参数</th>
 					                  	<th name="triggerTime" >调度时间</th>
 					                  	<th name="triggerStatus" >调度结果</th>
 					                  	<th name="triggerMsg" >调度日志</th>

+ 21 - 32
xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js

@@ -33,17 +33,9 @@ $(function() {
 	                { "data": 'jobDesc', "visible" : true},
 	                { "data": 'jobCron', "visible" : true},
 	                { "data": 'jobClass', "visible" : false},
-	                { 
-	                	"data": 'jobData',
-	                	"visible" : true,
-	                	"render": function ( data, type, row ) {
-	                		var _jobData = eval('(' + data + ')');	// row.jobData
-	                		var html = "<p title='" + data + "'>执行器:" + _jobData.handler_name +
-	                			"<br>执行参数:" + _jobData.handler_params + 
-	                			"<br>执行器地址:" + _jobData.handler_address + "</p>";
-	                		return html;
-	                	}
-	                },
+	                { "data": 'executorAddress', "visible" : false},
+	                { "data": 'executorHandler', "visible" : false},
+	                { "data": 'executorParam', "visible" : false},
 	                { 
 	                	"data": 'addTime', 
 	                	"visible" : false, 
@@ -90,15 +82,12 @@ $(function() {
 	                			var logUrl = base_url +'/joblog?jobGroup='+ row.jobGroup +'&jobName='+ row.jobName;
 	                			
 	                			// log url
-	                			var codeHtml = "";
-	                			if(row.glueSwitch != 0){
+	                			var codeBtn = "";
+	                			if(row.glueSwitch > 0){
 	                				var codeUrl = base_url +'/jobcode?jobGroup='+ row.jobGroup +'&jobName='+ row.jobName;
-	                				codeHtml = '<button class="btn btn-warning btn-xs" type="button" onclick="javascript:window.open(\'' + codeUrl + '\')" >GLUE</button>  '
+	                				codeBtn = '<button class="btn btn-warning btn-xs" type="button" onclick="javascript:window.open(\'' + codeUrl + '\')" >GLUE</button>  '
 	                			}
 	                			
-	                			// job data
-	                			var jobDataMap = eval('(' + row.jobData + ')');
-	                			
 	                			var html = '<p id="'+ row.id +'" '+
 	                							' jobGroup="'+ row.jobGroup +'" '+
 	                							' jobName="'+ row.jobName +'" '+
@@ -106,9 +95,9 @@ $(function() {
 	                							' jobDesc="'+ row.jobDesc +'" '+
 	                							' jobClass="'+ row.jobClass +'" '+
 	                							' jobData="'+ row.jobData +'" '+
-	                							' handler_params="'+jobDataMap.handler_params +'" '+
-	                							' handler_address="'+ jobDataMap.handler_address +'" '+
-	                							' handler_name="'+ jobDataMap.handler_name +'" '+
+	                							' executorAddress="'+row.executorAddress +'" '+
+	                							' executorHandler="'+ row.executorHandler +'" '+
+	                							' executorParam="'+ row.executorParam +'" '+
 	                							' author="'+ row.author +'" '+
 	                							' alarmEmail="'+ row.alarmEmail +'" '+
 	                							' alarmThreshold="'+ row.alarmThreshold +'" '+
@@ -118,7 +107,7 @@ $(function() {
 										pause_resume +
 										'<button class="btn btn-primary btn-xs" type="job_del" type="button" onclick="javascript:window.open(\'' + logUrl + '\')" >日志</button><br>  '+
 										'<button class="btn btn-warning btn-xs update" type="button">编辑</button>  '+
-										codeHtml +
+										codeBtn +
 								  		'<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</button>  '+
 									'</p>';
 									
@@ -236,11 +225,11 @@ $(function() {
             	required : true ,
                 maxlength: 200
             },
-            handler_address : {
+            executorAddress : {
             	required : true ,
                 maxlength: 200
             },
-            handler_name : {
+            executorHandler : {
             	required : true ,
                 maxlength: 200
             },
@@ -271,11 +260,11 @@ $(function() {
             	required :"请输入“任务描述”."  ,
                 maxlength:"“任务描述”长度不应超过200位"
             },  
-            handler_address : {
+            executorAddress : {
             	required :"请输入“执行器地址”."  ,
                 maxlength:"“执行器地址”长度不应超过200位"
             },
-            handler_name : {
+            executorHandler : {
             	required : "请输入“jobHandler”."  ,
                 maxlength: "“jobHandler”长度不应超过200位"
             },
@@ -359,9 +348,9 @@ $(function() {
 		$("#updateModal .form input[name='jobName']").val($(this).parent('p').attr("jobName"));
 		$("#updateModal .form input[name='jobCron']").val($(this).parent('p').attr("jobCron"));
 		$("#updateModal .form input[name='jobDesc']").val($(this).parent('p').attr("jobDesc"));
-		$("#updateModal .form input[name='handler_address']").val($(this).parent('p').attr("handler_address"));
-		$("#updateModal .form input[name='handler_name']").val($(this).parent('p').attr("handler_name"));
-		$("#updateModal .form input[name='handler_params']").val($(this).parent('p').attr("handler_params"));
+		$("#updateModal .form input[name='executorAddress']").val($(this).parent('p').attr("executorAddress"));
+		$("#updateModal .form input[name='executorHandler']").val($(this).parent('p').attr("executorHandler"));
+		$("#updateModal .form input[name='executorParam']").val($(this).parent('p').attr("executorParam"));
 		$("#updateModal .form input[name='author']").val($(this).parent('p').attr("author"));
 		$("#updateModal .form input[name='alarmEmail']").val($(this).parent('p').attr("alarmEmail"));
 		$("#updateModal .form input[name='alarmThreshold']").val($(this).parent('p').attr("alarmThreshold"));
@@ -393,11 +382,11 @@ $(function() {
             	required : true ,
                 maxlength: 200
             },
-            handler_address : {
+            executorAddress : {
             	required : true ,
                 maxlength: 200
             },
-            handler_name : {
+            executorHandler : {
             	required : true ,
                 maxlength: 200
             },
@@ -423,11 +412,11 @@ $(function() {
             	required :"请输入“任务描述”."  ,
                 maxlength:"“任务描述”长度不应超过200位"
             },  
-            handler_address : {
+            executorAddress : {
             	required :"请输入“执行器地址”."  ,
                 maxlength:"“执行器地址”长度不应超过200位"
             },
-            handler_name : {
+            executorHandler : {
             	required : "请输入“jobHandler”."  ,
                 maxlength: "“jobHandler”长度不应超过200位"
             },

+ 5 - 19
xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js

@@ -60,22 +60,14 @@ $(function() {
 	            			return data;
 	            		}
             		},
-	                { "data": 'jobName'},
+	                { "data": 'jobName', "visible" : false},
 	                { "data": 'jobCron', "visible" : false},
 	                { "data": 'jobDesc', "visible" : false},
 	                { "data": 'jobClass', "visible" : false},
-	                { 
-	                	"data": 'jobData',
-	                	"visible" : true,
-	                	"render": function ( data, type, row ) {
-	                		var _jobData = eval('(' + data + ')');	// row.jobData
-	                		var html = "<p title='" + data + "'>JobHandler:" + _jobData.handler_name +
-	                			"<br>执行参数:" + _jobData.handler_params + 
-	                			"<br>执行器地址:" + _jobData.handler_address + "</p>";
-	                		
-	                		return data?'<a class="logMsg" href="javascript:;" >查看<span style="display:none;">'+ html +'</span></a>':"无";
-	                	}
-	                },
+	                
+	                { "data": 'executorAddress', "visible" : true},
+	                { "data": 'executorHandler', "visible" : true},
+	                { "data": 'executorParam', "visible" : true},
 	                { 
 	                	"data": 'triggerTime', 
 	                	"render": function ( data, type, row ) {
@@ -106,12 +98,6 @@ $(function() {
 	                	"render": function ( data, type, row ) {
 	                		// better support expression or string, not function
 	                		return function () {
-	                			// local job do not support trigger detail log, now
-		                		var _jobData = eval('(' + row.jobData + ')'); 
-		                		if (!_jobData.handler_address) {
-		                			return;
-		                		}
-		                		
 		                		if (row.triggerStatus == 'SUCCESS'){
 		                			var temp = '<a href="javascript:;" class="logDetail" _id="'+ row.id +'">执行日志</a>';
 		                			if(!row.handleStatus){

+ 0 - 2
xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobInfoTest.java

@@ -34,7 +34,6 @@ public class XxlJobInfoTest {
 		info.setJobName("job_name");
 		info.setJobCron("jobCron");
 		info.setJobClass("jobClass");
-		info.setJobData("jobData");
 		int count = xxlJobInfoDao.save(info);
 		System.out.println(count);
 		System.out.println(info.getId());
@@ -48,7 +47,6 @@ public class XxlJobInfoTest {
 		XxlJobInfo item = xxlJobInfoDao.load(null ,"job_name");
 		
 		item.setJobCron("jobCron2");
-		item.setJobData("jobData2");
 		xxlJobInfoDao.update(item);
 	}
 	

+ 0 - 1
xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobLogTest.java

@@ -28,7 +28,6 @@ public class XxlJobLogTest {
 		xxlJobLog.setJobName("job_name");
 		xxlJobLog.setJobCron("jobCron");
 		xxlJobLog.setJobClass("jobClass");
-		xxlJobLog.setJobData("jobData");
 		int count = xxlJobLogDao.save(xxlJobLog);
 		System.out.println(count);
 		System.out.println(xxlJobLog.getId());

+ 102 - 63
xxl-job-core/src/main/java/com/xxl/job/core/handler/HandlerRepository.java

@@ -19,20 +19,49 @@ import com.xxl.job.core.util.JacksonUtil;
 public class HandlerRepository {
 	private static Logger logger = LoggerFactory.getLogger(HandlerRepository.class);
 	
-	public static final String NAMESPACE = "namespace";
-	public enum NameSpaceEnum{RUN, KILL, LOG}
-	
-	public static final String HANDLER_ADDRESS = "handler_address";
-	public static final String HANDLER_PARAMS = "handler_params";
-	
-	public static final String HANDLER_GLUE_SWITCH = "handler_glue_switch";
-	public static final String HANDLER_NAME = "handler_name";
-	public static final String HANDLER_JOB_GROUP = "handler_job_group";
-	public static final String HANDLER_JOB_NAME = "handler_job_name";
-	
-	public static final String TRIGGER_LOG_ID = "trigger_log_id";
-	public static final String TRIGGER_LOG_ADDRESS = "trigger_log_address";
-	public static final String TRIGGER_TIMESTAMP = "trigger_timestamp";
+	public enum HandlerParamEnum{
+		/**
+		 * trigger timestamp
+		 */
+		TIMESTAMP,
+		/**
+		 * trigger action
+		 */
+		ACTION,
+		/**
+		 * remote executor jobhandler
+		 */
+		EXECUTOR_HANDLER,
+		/**
+		 * params of jobhandler
+		 */
+		EXECUTOR_PARAMS,
+		/**
+		 * switch of job, if open glue model
+		 */
+		GLUE_SWITCH,
+		/**
+		 * job group
+		 */
+		JOB_GROUP,
+		/**
+		 * job name
+		 */
+		JOB_NAME,
+		/**
+		 * address for callback log
+		 */
+		LOG_ADDRESS,
+		/**
+		 * log id
+		 */
+		LOG_ID,
+		/**
+		 * log date
+		 */
+		LOG_DATE
+	}
+	public enum ActionEnum{RUN, KILL, LOG, BEAT}
 	
 	public static ConcurrentHashMap<String, HandlerThread> handlerTreadMap = new ConcurrentHashMap<String, HandlerThread>();
 	
@@ -53,27 +82,26 @@ public class HandlerRepository {
 		callback.setStatus(RemoteCallBack.FAIL);
 
 		// check namespace
-		String namespace = _param.get(HandlerRepository.NAMESPACE);
+		String namespace = _param.get(HandlerParamEnum.ACTION.name());
 		if (namespace==null || namespace.trim().length()==0) {
 			callback.setMsg("param[NAMESPACE] can not be null.");
 			return JacksonUtil.writeValueAsString(callback);
 		}
-		
-		// parse namespace
-		if (namespace.equals(HandlerRepository.NameSpaceEnum.RUN.name())) {
-			// encryption check
-			long timestamp = _param.get(HandlerRepository.TRIGGER_TIMESTAMP)!=null?Long.valueOf(_param.get(HandlerRepository.TRIGGER_TIMESTAMP)):-1;
-			if (System.currentTimeMillis() - timestamp > 60000) {
-				callback.setMsg("Timestamp check failed.");
-				return JacksonUtil.writeValueAsString(callback);
-			}
+		// encryption check
+		long timestamp = _param.get(HandlerParamEnum.TIMESTAMP.name())!=null?Long.valueOf(_param.get(HandlerParamEnum.TIMESTAMP.name())):-1;
+		if (System.currentTimeMillis() - timestamp > 60000) {
+			callback.setMsg("Timestamp check failed.");
+			return JacksonUtil.writeValueAsString(callback);
+		}
 					
+		// parse namespace
+		if (namespace.equals(ActionEnum.RUN.name())) {
 			// push data to queue
-			String handler_glue_switch = _param.get(HandlerRepository.HANDLER_GLUE_SWITCH);
+			String handler_glue_switch = _param.get(HandlerParamEnum.GLUE_SWITCH.name());
 			HandlerThread handlerThread = null;
 			if ("0".equals(handler_glue_switch)) {
 				// bean model
-				String handler_name = _param.get(HandlerRepository.HANDLER_NAME);
+				String handler_name = _param.get(HandlerParamEnum.EXECUTOR_HANDLER.name());
 				if (handler_name == null || handler_name.trim().length()==0) {
 					callback.setMsg("bean model handler[HANDLER_NAME] not found.");
 					return JacksonUtil.writeValueAsString(callback);
@@ -85,70 +113,81 @@ public class HandlerRepository {
 				}
 			} else {
 				// glue
-				String handler_job_group = _param.get(HandlerRepository.HANDLER_JOB_GROUP);
-				String handler_job_name = _param.get(HandlerRepository.HANDLER_JOB_NAME);
-				if (handler_job_group == null || handler_job_group.trim().length()==0 || handler_job_name == null || handler_job_name.trim().length()==0) {
+				String job_group = _param.get(HandlerParamEnum.JOB_GROUP.name());
+				String job_name = _param.get(HandlerParamEnum.JOB_NAME.name());
+				if (job_group == null || job_group.trim().length()==0 || job_name == null || job_name.trim().length()==0) {
 					callback.setMsg("glue model handler[job group or name] is null.");
 					return JacksonUtil.writeValueAsString(callback);
 				}
-				String glueHandleName = "glue_".concat(handler_job_group).concat("_").concat(handler_job_name);
+				String glueHandleName = "glue_".concat(job_group).concat("_").concat(job_name);
 				handlerThread = handlerTreadMap.get(glueHandleName);
 				if (handlerThread==null) {
-					HandlerRepository.regist(glueHandleName, new GlueJobHandler(handler_job_group, handler_job_name));
+					HandlerRepository.regist(glueHandleName, new GlueJobHandler(job_group, job_name));
 				}
 				handlerThread = handlerTreadMap.get(glueHandleName);
 			}
 			
 			handlerThread.pushData(_param);
 			callback.setStatus(RemoteCallBack.SUCCESS);
-		} else if (namespace.equals(HandlerRepository.NameSpaceEnum.LOG.name())) {
-			String trigger_log_id = _param.get(HandlerRepository.TRIGGER_LOG_ID);
-			String trigger_timestamp = _param.get(HandlerRepository.TRIGGER_TIMESTAMP);
-			if (trigger_log_id==null || trigger_timestamp==null) {
-				callback.setMsg("trigger_log_id | trigger_timestamp can not be null.");
+		} else if (namespace.equals(ActionEnum.LOG.name())) {
+			String log_id = _param.get(HandlerParamEnum.LOG_ID.name());
+			String log_date = _param.get(HandlerParamEnum.LOG_DATE.name());
+			if (log_id==null || log_date==null) {
+				callback.setMsg("LOG_ID | LOG_DATE can not be null.");
 				return JacksonUtil.writeValueAsString(callback);
 			}
 			int logId = -1;
 			Date triggerDate = null;
 			try {
-				logId = Integer.valueOf(trigger_log_id);
-				triggerDate = new Date(Long.valueOf(trigger_timestamp));
+				logId = Integer.valueOf(log_id);
+				triggerDate = new Date(Long.valueOf(log_date));
 			} catch (Exception e) {
 			}
 			if (logId<=0 || triggerDate==null) {
-				callback.setMsg("trigger_log_id | trigger_timestamp is not parsed valid.");
+				callback.setMsg("LOG_ID | LOG_DATE parse error.");
 				return JacksonUtil.writeValueAsString(callback);
 			}
-			String logConteng = XxlJobFileAppender.readLog(triggerDate, trigger_log_id);
+			String logConteng = XxlJobFileAppender.readLog(triggerDate, log_id);
 			callback.setStatus(RemoteCallBack.SUCCESS);
 			callback.setMsg(logConteng);
-		} else if (namespace.equals(HandlerRepository.NameSpaceEnum.KILL.name())) {
-			// encryption check
-			long timestamp = _param.get(HandlerRepository.TRIGGER_TIMESTAMP)!=null?Long.valueOf(_param.get(HandlerRepository.TRIGGER_TIMESTAMP)):-1;
-			if (System.currentTimeMillis() - timestamp > 60000) {
-				callback.setMsg("Timestamp check failed.");
-				return JacksonUtil.writeValueAsString(callback);
-			}
-			
+		} else if (namespace.equals(ActionEnum.KILL.name())) {
 			// kill handlerThread, and create new one
-			String handler_name = _param.get(HandlerRepository.HANDLER_NAME);
-			if (handler_name!=null && handler_name.trim().length()>0) {
-				HandlerThread handlerThread = handlerTreadMap.get(handler_name);
-				if (handlerThread != null) {
-					IJobHandler handler = handlerThread.getHandler();
-					handlerThread.toStop();
-					handlerThread.interrupt();
-					regist(handler_name, handler);
-					callback.setStatus(RemoteCallBack.SUCCESS);
-				} else {
-					callback.setMsg("handler[" + handler_name + "] not found.");
+			String handler_glue_switch = _param.get(HandlerParamEnum.GLUE_SWITCH.name());
+			String handlerName = null;
+			if ("0".equals(handler_glue_switch)) {
+				String executor_handler = _param.get(HandlerParamEnum.EXECUTOR_HANDLER.name());
+				if (executor_handler==null) {
+					callback.setMsg("bean job , param[EXECUTOR_HANDLER] is null");
+					return JacksonUtil.writeValueAsString(callback);
+				}
+				handlerName = executor_handler;
+			} else {
+				// glue
+				String job_group = _param.get(HandlerParamEnum.JOB_GROUP.name());
+				String job_name = _param.get(HandlerParamEnum.JOB_NAME.name());
+				if (job_group==null || job_group.trim().length()==0 || job_name==null || job_name.trim().length()==0) {
+					callback.setMsg("glue job , param[JOB_GROUP or JOB_NAME] is null");
+					return JacksonUtil.writeValueAsString(callback);
 				}
-			}else{
-				callback.setMsg("param[HANDLER_NAME] can not be null.");
+				handlerName = "glue_".concat(job_group).concat("_").concat(job_name);
+			}
+			
+			HandlerThread handlerThread = handlerTreadMap.get(handlerName);
+			if (handlerThread != null) {
+				IJobHandler handler = handlerThread.getHandler();
+				handlerThread.toStop();
+				handlerThread.interrupt();
+				regist(handlerName, handler);
+				callback.setStatus(RemoteCallBack.SUCCESS);
+			} else {
+				callback.setMsg("job handler[" + handlerName + "] not found.");
 			}
-						
+				
+		} else if (namespace.equals(ActionEnum.BEAT.name())) {
+			callback.setStatus(RemoteCallBack.SUCCESS);
+			callback.setMsg(null);
 		} else {
-			callback.setMsg("param[NAMESPACE] is not valid.");
+			callback.setMsg("param[Action] is not valid.");
 			return JacksonUtil.writeValueAsString(callback);
 		}
 		

+ 5 - 4
xxl-job-core/src/main/java/com/xxl/job/core/handler/HandlerThread.java

@@ -11,6 +11,7 @@ import org.eclipse.jetty.util.ConcurrentHashSet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.xxl.job.core.handler.HandlerRepository.HandlerParamEnum;
 import com.xxl.job.core.handler.IJobHandler.JobHandleStatus;
 import com.xxl.job.core.log.XxlJobFileAppender;
 import com.xxl.job.core.util.HttpUtil;
@@ -47,7 +48,7 @@ public class HandlerThread extends Thread{
 	}
 	
 	public void pushData(Map<String, String> param) {
-		if (param.get(HandlerRepository.TRIGGER_LOG_ID)!=null && !logIdSet.contains(param.get(HandlerRepository.TRIGGER_LOG_ID))) {
+		if (param.get(HandlerParamEnum.LOG_ID.name())!=null && !logIdSet.contains(param.get(HandlerParamEnum.LOG_ID.name()))) {
 			handlerDataQueue.offer(param);
 		}
 	}
@@ -60,9 +61,9 @@ public class HandlerThread extends Thread{
 				Map<String, String> handlerData = handlerDataQueue.poll();
 				if (handlerData!=null) {
 					i= 0;
-					String trigger_log_address = handlerData.get(HandlerRepository.TRIGGER_LOG_ADDRESS);
-					String trigger_log_id = handlerData.get(HandlerRepository.TRIGGER_LOG_ID);
-					String handler_params = handlerData.get(HandlerRepository.HANDLER_PARAMS);
+					String trigger_log_address = handlerData.get(HandlerParamEnum.LOG_ADDRESS.name());
+					String trigger_log_id = handlerData.get(HandlerParamEnum.LOG_ID.name());
+					String handler_params = handlerData.get(HandlerParamEnum.EXECUTOR_PARAMS.name());
 					logIdSet.remove(trigger_log_id);
 					
 					// parse param

+ 3 - 4
xxl-job-core/src/main/java/com/xxl/job/core/util/HttpUtil.java

@@ -1,8 +1,6 @@
 package com.xxl.job.core.util;
 
 import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -98,9 +96,10 @@ public class HttpUtil {
 			}
 		} catch (Exception e) {
 			e.printStackTrace();
-			StringWriter out = new StringWriter();
+			/*StringWriter out = new StringWriter();
 			e.printStackTrace(new PrintWriter(out));
-			callback.setMsg(out.toString());
+			callback.setMsg(out.toString());*/
+			callback.setMsg(e.getMessage());
 		} finally{
 			if (httpPost!=null) {
 				httpPost.releaseConnection();