Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.alogic.timer.core.Timer Maven / Gradle / Ivy
package com.alogic.timer.core;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.alogic.timer.matcher.Crontab;
import com.anysoft.util.Configurable;
import com.anysoft.util.DefaultProperties;
import com.anysoft.util.Factory;
import com.anysoft.util.JsonTools;
import com.anysoft.util.KeyGen;
import com.anysoft.util.Properties;
import com.anysoft.util.PropertiesConstants;
import com.anysoft.util.Reportable;
import com.anysoft.util.XMLConfigurable;
import com.anysoft.util.XmlElementProperties;
import com.anysoft.util.XmlTools;
/**
* 定时器
*
* @author duanyy
* @since 1.6.3.37
*
* @version 1.6.3.38 [duanyy 20150812]
* - 增加集群功能
*
* @version 1.6.4.16 [duanyy 20151110]
* - 根据sonar建议优化代码
*
* @version 1.6.5.36 [duanyy 20160729]
* - 增加stop接口,优化清理工作
*
* @version 1.6.5.36 [duanyy 20160729]
* - 增加reload接口,可以刷新配置
*
* @version 1.6.7.9 [20170201 duanyy]
* - 采用SLF4j日志框架输出日志
*
* @version 1.6.9.2 [20170601 duanyy]
* - 改造TaskCenter模型,以便提供分布式任务处理支持;
*
* @version 1.6.9.3 [20170615 duanyy]
* - 修正taskId不规范问题
*
* @version 1.6.9.8 [20170821]
* - 任务id修改为18位数字(当前时间戳+随机数字)
*/
public interface Timer extends Configurable,XMLConfigurable,Reportable {
/**
* 定时器状态
* @author duanyy
*
*/
public enum State {
Init,Running,Paused,Stopping,Stopped,Idle
}
/**
* 获取定时器ID
* @return ID
*/
public String getId();
/**
* 获取定时器状态
*
* 定时器状态包括:Running|Paused
*
* @return state
*/
public State getState();
/**
* 调度
* @param committer 任务提交者
*/
public void schedule(DoerCommitter committer);
/**
* 暂停定时器
*/
public void pause();
/**
* 恢复定时器状态为Running
*/
public void resume();
/**
* 停止
*/
public void stop();
/**
* 刷新配置
*/
public void reload();
/**
* 预测1个月内下一次调度时间
*
* 预测需要耗费资源,慎用
* @return 下一次调度时间
*/
public Date forecastNextDate();
/**
* 是否可以清除
* @return true|false
*/
public boolean isTimeToClear();
/**
* 创建新的任务
* @return 任务
*/
public Task newTask();
/**
* Abstract
* @author duanyy
* @since 1.6.3.37
*/
abstract public static class Abstract implements Timer{
/**
* logger of log4j
*/
protected static final Logger logger = LoggerFactory.getLogger(Timer.class);
/**
* 上次调度时间
*/
protected Date lastDate = null;
/**
* 任务执行者
*/
protected Doer doer = null;
/**
* 匹配器
*/
protected Matcher matcher = null;
/**
* 上下文持有者
*/
protected ContextHolder ctxHolder = null;
/**
* 状态
*/
protected State state = State.Running;
public void configure(Element _e, Properties _properties) {
Properties p = new XmlElementProperties(_e,_properties);
configure(p);
}
public void report(Element xml) {
if (xml != null){
xml.setAttribute("module", getClass().getName());
xml.setAttribute("id", getId());
xml.setAttribute("state", getState().name());
if (lastDate != null){
xml.setAttribute("lastDate", String.valueOf(lastDate.getTime()));
}
String detail = xml.getAttribute("detail");
if (detail == null || !detail.equals("false")){
Document doc = xml.getOwnerDocument();
if (ctxHolder != null){
Element _ctx = doc.createElement("context");
ctxHolder.report(_ctx);
xml.appendChild(_ctx);
}
if (doer != null){
Element _task = doc.createElement("doer");
doer.report(_task);
xml.appendChild(_task);
}
if (matcher != null){
Element _matcher = doc.createElement("matcher");
matcher.report(_matcher);
xml.appendChild(_matcher);
}
}
}
}
public void report(Map json) {
if (json != null){
json.put("module", getClass().getName());
json.put("id", getId());
json.put("state", getState().name());
boolean detail = JsonTools.getBoolean(json, "detail", true);
if (lastDate != null){
json.put("lastDate",lastDate.getTime());
}
if (detail){
if (ctxHolder != null){
Map _ctx = new HashMap();
ctxHolder.report(_ctx);
json.put("context", _ctx);
}
if (doer != null){
Map _task = new HashMap();
doer.report(_task);
json.put("doer", _task);
}
if (matcher != null){
Map _matcher = new HashMap();
matcher.report(_matcher);
json.put("matcher", _matcher);
}
}
}
}
/**
* 有效期起始时间
*
* 定时器必须在有效期之内才会被调度,可以通过config中fromDate变量进行设置,缺省情况下,取当前时间。
*
* @return 有效期起始时间
*/
abstract public Date fromDate();
/**
* 有效期结束时间
*
* 定时器必须在有效期之内才会被调度,可以通过config中toDate变量进行设置,缺省情况下,取当前时间之后的50年。
*
* @return 有效期结束时间
*/
abstract public Date toDate();
public State getState() {
return state;
}
public boolean isTimeToClear(){return matcher != null && matcher.isTimeToClear();}
public void schedule(DoerCommitter committer) {
synchronized (this) {
if (getState() != State.Running) {
// 当前定时器没有定义为Running
logger.warn("The timer is not running:" + getId());
return;
}
if (doer == null) {
logger.error("The doer is not set:" + getId());
return;
}
if (matcher == null) {
logger.error("The matcher is not set:" + getId());
return;
}
if (committer == null) {
logger.error("The committer is not set:" + getId());
return;
}
Date now = new Date();
Date fromDate = fromDate();
Date toDate = toDate();
if (fromDate != null && toDate != null
&& (now.before(fromDate()) || now.after(toDate()))) {
// 必须在定时器的有效期之内才能调度
return;
}
boolean match = matcher.match(lastDate, now, ctxHolder);
if (match) {
lastDate = now;
//准备执行
doer.setContextHolder(ctxHolder);
// to commit this task
committer.commit(doer, newTask());
}
}
}
public void pause() {
state = State.Paused;
}
public void resume() {
state = State.Running;
}
public void stop(){
state = State.Stopped;
}
public void reload(){
// nothing to do
}
public Date forecastNextDate() {
long current = System.currentTimeMillis();
Date __last = lastDate;
Date __now = null;
int step = 1000*60;
int count = 60*24*31;
for (; count > 0 ; current += step,count--){
__now = new Date(current);
if (matcher.match(__last, __now, ctxHolder)){
return __now;
}
}
return null;
}
/**
* 生成一个任务id
* @return 任务id
*/
protected static String newTaskId(){
return String.format("%d%s",System.currentTimeMillis(),KeyGen.uuid(5, 0, 9));
}
}
/**
* 简单实现
* @author duanyy
*
*/
public static class Simple extends Abstract{
/**
* 定时器ID
*/
protected String id;
public Simple(String _id,Matcher _matcher,Doer _doer){
id = _id;
matcher = _matcher;
doer = _doer;
ctxHolder = new ContextHolder.Default();
}
public Simple(String _id,Matcher _matcher,Runnable runnable){
id = _id;
matcher = _matcher;
doer = new Doer.Wrapper(runnable);
ctxHolder = new ContextHolder.Default();
}
public String getId() {
return id;
}
public void configure(Properties p) {
// nothing to do
}
public Date fromDate() {
return null;
}
public Date toDate() {
return null;
}
public Task newTask() {
return new Task.Default(newTaskId(),"default");
}
}
/**
* 基于XML配置的实现
*
* @author duanyy
* @since 1.6.3.37
*/
public static class XMLed extends Abstract{
/**
* 定时器ID
*/
protected String id;
/**
* 名称
*/
protected String name;
/**
* 说明
*/
protected String note;
/**
* 有效期起始时间
*
* 定时器必须在有效期之内才会被调度,可以通过config中fromDate变量进行设置,缺省情况下,取当前时间。
*/
protected Date fromDate = new Date();
/**
* 有效期结束时间
*
* 定时器必须在有效期之内才会被调度,可以通过config中toDate变量进行设置,缺省情况下,取当前时间之后的50年。
*/
protected Date toDate = new Date(System.currentTimeMillis() + 50 * 365 * 24 * 60 * 60 * 1000L);
/**
* 事件
*/
protected String event = "default";
/**
* 调用参数
*/
protected DefaultProperties parameters;
public String getId() {
return id;
}
public void configure(Properties p){
id = PropertiesConstants.getString(p,"id","",true);
if (id == null || id.length() <= 0){
id = newTimerId();
}
event = PropertiesConstants.getString(p,"event",event,true);
name = PropertiesConstants.getString(p,"name","",true);
note = PropertiesConstants.getString(p,"note","",true);
}
public void report(Element xml) {
super.report(xml);
if (xml != null){
xml.setAttribute("name", name);
xml.setAttribute("note", note);
xml.setAttribute("event", event);
if (fromDate != null){
xml.setAttribute("fromDate", String.valueOf(fromDate.getTime()));
}
if (toDate != null){
xml.setAttribute("toDate", String.valueOf(toDate.getTime()));
}
}
}
public void report(Map json) {
super.report(json);
if (json != null){
json.put("name", name);
json.put("note", note);
json.put("event", event);
if (fromDate != null){
json.put("fromDate", fromDate.getTime());
}
if (toDate != null){
json.put("toDate", toDate.getTime());
}
}
}
@Override
public void configure(Element _e, Properties _properties){
Properties p = new XmlElementProperties(_e,_properties);
configure(p);
Element _matcher = XmlTools.getFirstElementByPath(_e, "matcher");
if (_matcher == null){
logger.error("Can not create matcher : " + getId());
}else{
Factory factory = new Factory(){
public String getClassName(String _module){
if (_module.indexOf(".") >= 0){
return _module;
}
return "com.alogic.timer.matcher." + _module;
}
};
matcher = factory.newInstance(_matcher, p, "module", Crontab.class.getName());
}
Element _task = XmlTools.getFirstElementByPath(_e, "doer");
if (_task == null){
logger.error("Can not create doer : " + getId());
}else{
Factory factory = new Factory();
doer = factory.newInstance(_task, p, "module");
}
Element _context = XmlTools.getFirstElementByPath(_e, "context");
if (_context == null){
ctxHolder = new ContextHolder.Default();
}else{
Factory factory = new Factory();
ctxHolder = factory.newInstance(_context, p, "module", ContextHolder.Default.class.getName());
}
Element _parameters = XmlTools.getFirstElementByPath(_e, "parameters");
if (_parameters != null){
loadParameter(_parameters);
}
}
private void loadParameter(Element root) {
NodeList list = XmlTools.getNodeListByPath(root,"parameter");
if (list.getLength() > 0){
parameters = new DefaultProperties();
for (int i = 0 ;i < list.getLength() ; i ++){
Node n = list.item(i);
if (n.getNodeType() != Node.ELEMENT_NODE){
continue;
}
Element e = (Element)n;
String key = e.getAttribute("id");
String value = e.getAttribute("value");
if (key == null || value == null || key.length() <= 0){
continue;
}
parameters.SetValue(key, value.length() <= 0 ? "true":value);
}
}
}
private static volatile int seed = 10001;
synchronized protected String newTimerId(){
return "timer" + String.valueOf(seed ++);
}
public Date fromDate() {
return fromDate;
}
public Date toDate() {
return toDate;
}
public Task newTask() {
return parameters == null ? new Task.Default(newTaskId(),event)
: new Task.Default(newTaskId(),event,parameters);
}
}
}