001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.components.schedule; 017 018import com.jfinal.aop.Aop; 019import com.jfinal.kit.Prop; 020import com.jfinal.kit.StrKit; 021import com.jfinal.plugin.IPlugin; 022import com.jfinal.plugin.cron4j.ITask; 023import it.sauronsoftware.cron4j.ProcessTask; 024import it.sauronsoftware.cron4j.Scheduler; 025import it.sauronsoftware.cron4j.Task; 026 027import java.util.ArrayList; 028import java.util.List; 029 030 031public class JbootCron4jPlugin implements IPlugin { 032 033 private List<TaskInfo> taskInfoList = new ArrayList<>(); 034 public static final String defaultConfigName = "cron4j"; 035 036 public JbootCron4jPlugin() { 037 038 } 039 040 public JbootCron4jPlugin(String configFile) { 041 this(new Prop(configFile), defaultConfigName); 042 } 043 044 public JbootCron4jPlugin(Prop configProp) { 045 this(configProp, defaultConfigName); 046 } 047 048 public JbootCron4jPlugin(String configFile, String configName) { 049 this(new Prop(configFile), configName); 050 } 051 052 public JbootCron4jPlugin(Prop configProp, String configName) { 053 try { 054 addTask(configProp, configName); 055 } catch (RuntimeException e) { 056 throw e; 057 } catch (Exception e) { 058 throw new RuntimeException(e); 059 } 060 } 061 062 /* 063 * 考虑添加对 ProcessTask 的配置支持,目前不支持 ProcessTask 对象的构造方法的参数配置 064 * 对于 ProcessTask 型的任务调度,建议对 ProcessTask 的创建使用 java 代码 065 */ 066 private void addTask(Prop configProp, String configName) throws Exception { 067 String configNameValue = configProp.get(configName); 068 if (StrKit.isBlank(configNameValue)) { 069 throw new IllegalArgumentException("The value of configName: " + configName + " can not be blank."); 070 } 071 String[] taskNameArray = configNameValue.trim().split(","); 072 for (String taskName : taskNameArray) { 073 if (StrKit.isBlank(taskName)) { 074 throw new IllegalArgumentException("taskName can not be blank."); 075 } 076 taskName = taskName.trim(); 077 078 String taskCron = configProp.get(taskName + ".cron"); 079 if (StrKit.isBlank(taskCron)) { 080 throw new IllegalArgumentException(taskName + ".cron" + " not found."); 081 } 082 taskCron = taskCron.trim(); 083 084 String taskClass = configProp.get(taskName + ".class"); 085 if (StrKit.isBlank(taskClass)) { 086 throw new IllegalArgumentException(taskName + ".class" + " not found."); 087 } 088 taskClass = taskClass.trim(); 089 090 Object taskObj = Class.forName(taskClass).newInstance(); 091 if (!(taskObj instanceof Runnable) && !(taskObj instanceof Task)) { 092 throw new IllegalArgumentException("Task 必须是 Runnable、ITask、ProcessTask 或者 Task 类型"); 093 } 094 095 boolean taskDaemon = configProp.getBoolean(taskName + ".daemon", false); 096 boolean taskEnable = configProp.getBoolean(taskName + ".enable", true); 097 taskInfoList.add(new JbootCron4jPlugin.TaskInfo(taskCron, taskObj, taskDaemon, taskEnable)); 098 } 099 } 100 101 public JbootCron4jPlugin addTask(String cron, Runnable task, boolean daemon, boolean enable) { 102 taskInfoList.add(new JbootCron4jPlugin.TaskInfo(cron, task, daemon, enable)); 103 return this; 104 } 105 106 public JbootCron4jPlugin addTask(String cron, Runnable task, boolean daemon) { 107 return addTask(cron, task, daemon, true); 108 } 109 110 public JbootCron4jPlugin addTask(String cron, Runnable task) { 111 return addTask(cron, task, false, true); 112 } 113 114 public JbootCron4jPlugin addTask(String cron, ProcessTask processTask, boolean daemon, boolean enable) { 115 taskInfoList.add(new JbootCron4jPlugin.TaskInfo(cron, processTask, daemon, enable)); 116 return this; 117 } 118 119 public JbootCron4jPlugin addTask(String cron, ProcessTask processTask, boolean daemon) { 120 return addTask(cron, processTask, daemon, true); 121 } 122 123 public JbootCron4jPlugin addTask(String cron, ProcessTask processTask) { 124 return addTask(cron, processTask, false, true); 125 } 126 127 public JbootCron4jPlugin addTask(String cron, Task task, boolean daemon, boolean enable) { 128 taskInfoList.add(new JbootCron4jPlugin.TaskInfo(cron, task, daemon, enable)); 129 return this; 130 } 131 132 public JbootCron4jPlugin addTask(String cron, Task task, boolean daemon) { 133 return addTask(cron, task, daemon, true); 134 } 135 136 public JbootCron4jPlugin addTask(String cron, Task task) { 137 return addTask(cron, task, false, true); 138 } 139 140 @Override 141 public boolean start() { 142 for (JbootCron4jPlugin.TaskInfo taskInfo : taskInfoList) { 143 taskInfo.schedule(); 144 } 145 for (JbootCron4jPlugin.TaskInfo taskInfo : taskInfoList) { 146 taskInfo.start(); 147 } 148 return true; 149 } 150 151 @Override 152 public boolean stop() { 153 taskInfoList.forEach(TaskInfo::stop); 154 taskInfoList.clear(); 155 return true; 156 } 157 158 private static class TaskInfo { 159 Scheduler scheduler; 160 161 String cron; 162 Object task; 163 boolean daemon; 164 boolean enable; 165 166 TaskInfo(String cron, Object task, boolean daemon, boolean enable) { 167 if (StrKit.isBlank(cron)) { 168 throw new IllegalArgumentException("cron 不能为空."); 169 } 170 if (task == null) { 171 throw new IllegalArgumentException("task 不能为 null."); 172 } 173 174 Aop.inject(task); 175 176 this.cron = cron.trim(); 177 this.task = task; 178 this.daemon = daemon; 179 this.enable = enable; 180 } 181 182 void schedule() { 183 if (enable) { 184 scheduler = new Scheduler(); 185 if (task instanceof Runnable) { 186 scheduler.schedule(cron, (Runnable) task); 187 } else if (task instanceof Task) { 188 scheduler.schedule(cron, (Task) task); 189 } else { 190 scheduler = null; 191 throw new IllegalStateException("Task 必须是 Runnable、ITask、ProcessTask 或者 Task 类型"); 192 } 193 scheduler.setDaemon(daemon); 194 } 195 } 196 197 void start() { 198 if (enable) { 199 scheduler.start(); 200 } 201 } 202 203 void stop() { 204 if (enable) { 205 if (task instanceof ITask) { // 如果任务实现了 ITask 接口,则回调 ITask.stop() 方法 206 ((ITask) task).stop(); 207 } 208 scheduler.stop(); 209 } 210 } 211 } 212}