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.Scheduler Maven / Gradle / Ivy
package com.alogic.timer.core;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
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.ha.FailoverController;
import com.alogic.ha.FailoverListener;
import com.anysoft.util.BaseException;
import com.anysoft.util.Factory;
import com.anysoft.util.IOTools;
import com.anysoft.util.Properties;
import com.anysoft.util.PropertiesConstants;
import com.anysoft.util.Settings;
import com.anysoft.util.XmlElementProperties;
import com.anysoft.util.XmlTools;
import com.anysoft.util.resource.ResourceFactory;
/**
* 调度者
*
* @author duanyy
* @since 1.6.3.37
*
* @version 1.6.3.38 [duanyy 20150812]
* - 增加集群功能
*
* @version 1.6.4.37 [duanyy 20160321]
* - 优化锁被打断的时的处理
*
* @version 1.6.4.39 [duanyy 20160325]
* - 采用concurrent包来调度定时器
* - scheduler可以作为一个一次性的timer运行
*
* @version 1.6.4.42 [duanyy 20160407]
* - 增加Linked实现
*
* @version 1.6.7.9 [20170201 duanyy]
* - 采用SLF4j日志框架输出日志
*
* @version 1.6.8.3 [20170328 duanyy]
* - 采用新的ha框架来进行分布式全局锁控制
*/
public interface Scheduler extends Timer,Runnable {
/**
* 获取所管理的Timer列表
* @return Timer列表
*/
public Timer [] getTimers();
/**
* 获取指定ID的timer
* @param id ID
* @return Timer
*/
public Timer get(String id);
/**
* 将指定的Timer加入调度列表
* @param timer 定时器
*/
public void schedule(Timer timer);
/**
* 按照指定的匹配规则调度指定的任务
* @param id 定时器的ID
* @param matcher 匹配器
* @param task 任务
*/
public void schedule(String id,Matcher matcher,Doer task);
/**
* 按照指定的匹配规则调度指定的Runnable
* @param id 定时器的ID
* @param matcher 匹配器
* @param runnable 任务
*/
public void schedule(String id,Matcher matcher,Runnable runnable);
/**
* 设置任务提交者
* @param committer 任务提交者
*/
public void setTaskCommitter(DoerCommitter committer);
/**
* 删除指定ID的timer
* @param id ID
*/
public void remove(String id);
/**
* 开始调度
*/
public void start();
/**
* 停止调度
*/
public void stop();
/**
* 等待线程结束直到超时
*/
public void join(long timeout);
/**
* Abstract
* @author duanyy
*
*/
abstract public static class Abstract implements Scheduler,FailoverListener{
protected static final Logger logger = LoggerFactory.getLogger(Timer.class);
protected State state = State.Init;
protected DoerCommitter comitter = null;
protected long interval = 1000;
protected FailoverController fc = null;
protected Future> future = null;
protected String id = "root";
public void setTaskCommitter(DoerCommitter _committer){
comitter = _committer;
}
public void configure(Properties p){
interval = PropertiesConstants.getLong(p,"interval",interval,true);
id = PropertiesConstants.getString(p, "id", "root");
fc = getFailoverController(p);
if (fc != null){
fc.start(this);
}
}
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("id", getId());
xml.setAttribute("type", "Scheduler");
xml.setAttribute("module", getClass().getName());
Timer[] timers = getTimers();
if (timers.length > 0){
Document doc = xml.getOwnerDocument();
for (int i = 0 ; i < timers.length ; i ++){
Timer t = timers[i];
Element _timer = doc.createElement("timer");
_timer.setAttribute("detail", "false");
t.report(_timer);
xml.appendChild(_timer);
}
}
if (comitter != null){
Document doc = xml.getOwnerDocument();
Element _committer = doc.createElement("committer");
comitter.report(_committer);
xml.appendChild(_committer);
}
}
}
public void report(Map json) {
if (json != null){
json.put("module", getClass().getName());
json.put("id",getId());
json.put("type","Scheduler");
Timer[] timers = getTimers();
if (timers.length > 0){
List _timer = new ArrayList();
for (int i = 0 ; i < timers.length ; i ++){
Timer t = timers[i];
Map _map = new HashMap();
_map.put("detail", "false");
t.report(_map);
_timer.add(_map);
}
json.put("timer", _timer);
}
if (comitter != null){
Map _comitter = new HashMap();
comitter.report(_comitter);
json.put("comitter", _comitter);
}
}
}
public void schedule(String id, Matcher matcher, Doer task) {
schedule(new Timer.Simple(id, matcher, task));
}
public void schedule(String id, Matcher matcher, Runnable runnable) {
schedule(new Timer.Simple(id, matcher, runnable));
}
public String getId() {
return id;
}
public State getState() {
return state;
}
public void pause() {
if (state != State.Running){
throw new BaseException("core.incorrect_state","The current state is not Running,Can not pause.");
}
state = State.Paused;
}
public void resume() {
if (state != State.Paused){
throw new BaseException("core.incorrect_state","The current state is not Paused,Can not resume.");
}
state = State.Running;
}
public void schedule(DoerCommitter committer) {
//scheduler只能启动一次,所以只能状态为Init时启动
if (state == State.Init){
setTaskCommitter(committer);
start();
}
}
public void start() {
final ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
final Runnable self = this;
service.schedule(
new Runnable(){
@Override
public void run() {
logger.info(String.format("Start scheduler[%s]....",getId()));
state = State.Idle;
future = service.scheduleAtFixedRate(self, 5000, interval, TimeUnit.MILLISECONDS);
}},
0, TimeUnit.MILLISECONDS);
}
@Override
public void reload(){
Timer[] all = getTimers();
for (Timer t:all){
t.reload();
}
}
public void stop(){
state = State.Stopping;
if (fc != null){
fc.stop();
}
logger.info(String.format("Try to stop the scheduler[%s]....[%s]",getId(),state.toString()));
if (future != null){
//等待2秒钟,再打断线程
try {
Thread.sleep(2*interval);
} catch (InterruptedException e) {
}
future.cancel(true);
}
Timer [] timers = getTimers();
for (Timer timer:timers){
timer.stop();
}
}
public void run(){
if (state == State.Idle){
state = State.Running;
try {
if (fc != null){
if (fc.isActive()){
scheduleOnce();
}
}else{
scheduleOnce();
}
}finally{
state = State.Idle;
}
}
}
abstract protected void scheduleOnce();
public void join(long timeout){
if (future != null){
try {
future.get(timeout, TimeUnit.MILLISECONDS);
} catch (Exception e) {
// nothing to do
}
}
}
public Date forecastNextDate() {
return new Date();
}
public boolean isTimeToClear(){return true;}
private FailoverController getFailoverController(Properties p) {
FailoverController controller = null;
String module = PropertiesConstants.getString(p,"failover","",true);
if (StringUtils.isNotEmpty(module)){
Factory factory = new Factory();
try {
controller = factory.newInstance(module, p);
}catch (Exception ex){
logger.error("Can not create FailoverController instance:" + module);
}
}
return controller;
}
@Override
public void becomeActive() {
logger.info("Scheduler is active now.");
}
@Override
public void becomeStandby() {
logger.info("Scheduler is standby now.");
}
}
/**
* 简单实现
* @author duanyy
*
*/
public static class Simple extends Abstract{
protected Hashtable timers = new Hashtable();
protected boolean async = true;
public void configure(Properties p) throws BaseException {
super.configure(p);
async = PropertiesConstants.getBoolean(p,"async",async,true);
}
public Timer[] getTimers() {
return timers.values().toArray(new Timer[0]);
}
public Timer get(String id) {
return timers.get(id);
}
public void schedule(Timer timer) {
timers.put(timer.getId(), timer);
}
public void remove(String id) {
timers.remove(id);
}
protected void scheduleOnce() {
if (state != State.Running){
//not running
return ;
}
try {
Iterator iter = timers.values().iterator();
final List toBeClear = new ArrayList();
while (iter.hasNext()){
final Timer timer = iter.next();
if (async){
Thread thread = new Thread(){
public void run(){
timer.schedule(comitter);
if (timer.isTimeToClear()){
toBeClear.add(timer.getId());
}
}
};
thread.setDaemon(true);
thread.start();
}else{
timer.schedule(comitter);
if (timer.isTimeToClear()){
toBeClear.add(timer.getId());
}
}
}
for (String id:toBeClear){
timers.remove(id);
}
}catch (Exception ex){
logger.error("Erro when scheduling..",ex);
}
}
public Task newTask() {
//never used
return null;
}
}
/**
* 基于XML配置的实现
*
* @author duanyy
*
*/
public static class XMLed extends Simple{
/**
* 缺省的Timer实现
*/
protected String dftTimer = Timer.XMLed.class.getName();
public void configure(Element _e, Properties _properties)
throws BaseException {
Properties p = new XmlElementProperties(_e,_properties);
dftTimer = PropertiesConstants.getString(p,"dftTimerClass",dftTimer,true);
configure(p);
Element _committer = XmlTools.getFirstElementByPath(_e, "committer");
if (_committer != null){
Factory factory = new Factory();
comitter = factory.newInstance(_committer, p, "module", ThreadPoolTaskCommitter.class.getName());
}
loadTimerFromElement(_e,p);
}
protected void loadTimerFromElement(Element root,Properties p){
loadIncludeFiles(root,p);
NodeList timerList = XmlTools.getNodeListByPath(root, "timer");
Factory factory = new Factory();
for (int i = 0 ;i < timerList.getLength(); i ++){
Node n = timerList.item(i);
if (n.getNodeType() != Node.ELEMENT_NODE){
continue;
}
Element e = (Element)n;
try {
Timer timer = factory.newInstance(e, p, "module", dftTimer);
if (timer != null){
schedule(timer);
}
}catch (Exception ex){
logger.error("Can not create timer",ex);
}
}
}
protected void loadIncludeFiles(Element root,Properties p){
NodeList includes = XmlTools.getNodeListByPath(root, "include");
for (int i = 0 ;i < includes.getLength() ; i++){
Node n = includes.item(i);
if (n.getNodeType() != Node.ELEMENT_NODE){
continue;
}
Element e = (Element)n;
String src = e.getAttribute("src");
if (src == null || src.length() <= 0){
continue;
}
Document doc = loadDocument(p.transform(src),null);
if (doc == null){
continue;
}
loadTimerFromElement(doc.getDocumentElement(),p);
}
}
/**
* 从主/备地址中装入文档
*
* @param master 主地址
* @param secondary 备用地址
* @return XML文档
*/
protected static Document loadDocument(String master,String secondary){
ResourceFactory rm = Settings.getResourceFactory();
if (null == rm){
rm = new ResourceFactory();
}
Document ret = null;
InputStream in = null;
try {
in = rm.load(master,secondary, null);
ret = XmlTools.loadFromInputStream(in);
} catch (Exception ex){
logger.error("Error occurs when load xml file,source=" + master, ex);
}finally {
IOTools.closeStream(in);
}
return ret;
}
}
/**
* 外部连接配置文件
*
* @author duanyy
*
*/
public static class Linked extends XMLed{
public void configure(Element _e, Properties _properties){
Properties p = new XmlElementProperties(_e,_properties);
String src = PropertiesConstants.getString(p,"src","");
if (StringUtils.isNotEmpty(src)){
Document doc = loadDocument(src,null);
if (doc != null){
super.configure(doc.getDocumentElement(),p);
}else{
super.configure(_e, _properties);
}
}else{
logger.error("Can not find src attr in Linked module");
super.configure(_e, _properties);
}
}
}
}