All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.anysoft.stream.AbstractHandler Maven / Gradle / Ivy

There is a newer version: 1.6.17
Show newest version
package com.anysoft.stream;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentLinkedQueue;

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 com.anysoft.util.JsonTools;
import com.anysoft.util.Properties;
import com.anysoft.util.PropertiesConstants;
import com.anysoft.util.Reportable;
import com.anysoft.util.XmlElementProperties;
import com.anysoft.util.XmlTools;

/**
 * 数据处理器基类 
 * 
 * @author duanyy
 * @since 1.4.0
 * 
 * @version 1.4.3 [20140903 duanyy] 
* - 增加pause,resume实现
* * @version 1.4.4 [20140917 duanyy]
* - Handler:handle和flush方法增加timestamp参数,以便进行时间同步
* * @version 1.6.0.3 [20141114 duanyy]
* - 修正队列可能为空的异常
* * @version 1.6.4.17 [20151216 duanyy]
* - 根据sonar建议优化代码
* * @version 1.6.4.44 [20160414 duanyy]
* - 修正Report输出的bug,并增加统计数据的分页功能
* - 不再保存全部数据,只保存当前周期数据
* * @version 1.6.7.9 [20170201 duanyy]
* - 采用SLF4j日志框架输出日志
* * @version 1.6.8.1 [20170321 duanyy]
* - 增加配置参数abandonWhenFull,当异步队列满的时候,可选择抛弃后续的数据;
* * @version 1.6.11.3 [20171219 duanyy]
* - 修改异步处理的条件,只有数据和handler同时允许异步处理的时候才异步处理
* * @version 1.6.12.37 [20190626]
* - 修正async变量取值范围的问题
* - 增加资源释放功能
* */ public abstract class AbstractHandler implements Handler { /** * a logger of log4j */ protected static final Logger LOG = LoggerFactory.getLogger(AbstractHandler.class); /** * 当前的时间周期,缺省半个小时 */ protected long currentCycle = 30 * 60 * 1000; /** * 周期时间戳 */ protected long lastVisitedTime; /** * 是否开启Report */ protected boolean enableReport = false; /** * 当前周期之内的Report数据 */ protected Hashtable current_items = null; /** * 异步模式 */ protected boolean async = false; /** * 异步模式下工作线程 */ protected Worker asyncWorker = null; protected String id; public String getId(){ return id; } public void configure(Element _e, Properties _properties) { XmlElementProperties p = new XmlElementProperties(_e,_properties); id = PropertiesConstants.getString(p,"id", "",true); enableReport = PropertiesConstants.getBoolean(p, "report.enable", enableReport,true); if (enableReport){ currentCycle = PropertiesConstants.getLong(p, "report.cycle", currentCycle,true); current_items = new Hashtable(); } async = PropertiesConstants.getBoolean(p,"async",async,true); if (async){ asyncWorker = new Worker(this,p); } onConfigure(_e, p); } public void close() { if (async && asyncWorker != null){ asyncWorker.close(); } } private void stat(String group,Hashtable items,data item){ Measure found = items.get(group); if (found == null){ synchronized (items){ found = items.get(group); if (found == null){ found = new Measure(0); items.put(group, found); } } } found.incr(1); } public void report(Element xml) { if (xml == null) return; xml.setAttribute("module", getClass().getName()); xml.setAttribute("async", Boolean.toString(async)); xml.setAttribute("isRunning", Boolean.toString(isRunning)); if (enableReport){ report(current_items,xml,"stat"); } if (async && asyncWorker != null){ asyncWorker.report(xml); } } private void report(Hashtable _items,Element root,String name){ Document doc = root.getOwnerDocument(); Element child = doc.createElement(name); long total = 0; int current = 0; int offset = XmlTools.getInt(root, "offset", 0); int limit = XmlTools.getInt(root,"limit",30); String keyword = XmlTools.getString(root, "keyword", ""); Iterator> iterator = _items.entrySet().iterator(); while (iterator.hasNext()){ Entry entry = iterator.next(); String dim = entry.getKey(); boolean match = StringUtils.isEmpty(keyword) || dim.contains(keyword); if (match){ if (current >= offset && current < offset + limit){ Element dimElem = doc.createElement("group"); dimElem.setAttribute("dim",dim); dimElem.setAttribute("amount", String.valueOf(entry.getValue().value())); total += entry.getValue().value(); child.appendChild(dimElem); } current ++; } } XmlTools.setLong(child, "times",total); XmlTools.setInt(child, "total", current); XmlTools.setInt(child, "all", _items.size()); XmlTools.setLong(child, "lastVisitedTime", lastVisitedTime); XmlTools.setLong(child, "cycle", currentCycle); root.appendChild(child); } public void report(Map json) { if (json == null) return ; json.put("module", getClass().getName()); json.put("async", async); json.put("isRunning",isRunning); if (enableReport){ report(current_items,json,"stat"); } if (async && asyncWorker != null){ asyncWorker.report(json); } } private void report(Hashtable _items,Map json,String name){ Map child = new HashMap(); long total = 0; int current = 0; int offset = JsonTools.getInt(json, "offset", 0); int limit = JsonTools.getInt(json, "limit", 30); String keyword = JsonTools.getString(json,"keyword",""); List items = new ArrayList(_items.size()); Iterator> iterator = _items.entrySet().iterator(); while (iterator.hasNext()){ Entry entry = iterator.next(); String dim = entry.getKey(); boolean match = StringUtils.isEmpty(keyword) || dim.contains(keyword); if (match){ if (current >= offset && current < offset + limit){ Map itemObj = new HashMap(2); itemObj.put("dim", entry.getKey()); itemObj.put("amount", entry.getValue().value()); items.add(itemObj); total += entry.getValue().value(); } current ++; } } JsonTools.setLong(child, "times",total); JsonTools.setInt(child, "total", current); JsonTools.setInt(child, "all", _items.size()); JsonTools.setLong(child, "lastVisitedTime", lastVisitedTime); JsonTools.setLong(child, "cycle", currentCycle); child.put("item", items); json.put(name, child); } public void handle(data _data,long timestamp) { if (enableReport){ String group = _data.getStatsDimesion(); //当前时间 long current = System.currentTimeMillis(); if (current / currentCycle - lastVisitedTime / currentCycle > 0){ //新的周期 synchronized(current_items){ current_items.clear(); } } stat(group,current_items,_data); lastVisitedTime = current; } if (isRunning){ //只有在running状体下才执行 if (_data.isAsync() && async && asyncWorker != null){ asyncWorker.handle(_data,timestamp); }else{ onHandle(_data,timestamp); } } } public void flush(long timestamp) { if (isRunning){ if (async && asyncWorker != null){ asyncWorker.flush(timestamp); }else{ onFlush(timestamp); } } } public String getHandlerType() { return "handler"; } /** * 暂停 */ public void pause(){ isRunning = false; } /** * 恢复 */ public void resume(){ isRunning = true; } protected boolean isRunning = true; /** * 处理Handle事件 * @param _data */ abstract protected void onHandle(data _data,long timestamp); /** * 处理Flush事件 */ abstract protected void onFlush(long timestamp); abstract protected void onConfigure(Element e, Properties p); public static class Measure { protected long value = 0; public long value(){return value;} public void value(final long _value){value = _value;} public Measure(long _value){ value = _value; } synchronized public void incr(final long increment){ value += increment; } } public static class Worker implements Runnable,Reportable,AutoCloseable{ /** * 异步模式下的时间间隔 */ protected long interval = 1000; /** * 异步模式下的缓冲队列 */ protected ConcurrentLinkedQueue queue = null; /** * 异步模式下的最大队列长度 */ protected volatile int maxQueueLength = 1000; protected AbstractHandler handler = null; /** * 当前队列长度 */ protected volatile int currentQueueLength = 0; private boolean stopped = false; private boolean abandonWhenFull = true; private Thread thread = null; public Worker(AbstractHandler _handler, Properties p){ handler = _handler; interval = PropertiesConstants.getLong(p,"async.interval", interval,true); maxQueueLength = PropertiesConstants.getInt(p,"async.maxQueueLength", maxQueueLength,true); abandonWhenFull = PropertiesConstants.getBoolean(p,"async.abandonWhenFull", abandonWhenFull,true); currentQueueLength = 0; queue = new ConcurrentLinkedQueue(); thread = new Thread(this); thread.start(); } public void run() { while (!stopped){ try { flush(System.currentTimeMillis()); Thread.sleep(interval); }catch (Exception ex){ LOG.error("Thread is interruppted",ex); } } } public void report(Element xml) { if (xml != null){ xml.setAttribute("interval", String.valueOf(interval)); xml.setAttribute("maxQueueLength", String.valueOf(maxQueueLength)); xml.setAttribute("currentQueueLength", String.valueOf(currentQueueLength)); } } public void report(Map json) { if (json != null){ json.put("interval", interval); json.put("maxQueueLength", String.valueOf(maxQueueLength)); json.put("currentQueueLength", String.valueOf(currentQueueLength)); } } public void handle(data _data,long timestamp){ if (abandonWhenFull){ //开启了abandonWhenFull if (currentQueueLength <= maxQueueLength){ if (_data instanceof AutoClear){ //在进入异步队列之前,增加计数器 ((AutoClear)_data).addRef(); } queue.offer(_data); currentQueueLength ++; } //队列满的时候,抛弃掉 }else{ if (currentQueueLength > maxQueueLength){ //当队列已经满的时候,必须先出一个,才能进一个 data item = queue.poll(); if (item != null){ handler.onHandle(item,timestamp); if (item instanceof AutoClear){ //从队列中拉出消费之后,进行release ((AutoClear)item).release(); } currentQueueLength --; } } if (_data instanceof AutoClear){ //在进入异步队列之前,增加计数器 ((AutoClear)_data).addRef(); } queue.offer(_data); currentQueueLength ++; } } public void flush(long timestamp){ if (!queue.isEmpty()){ data item = null; while ((item = queue.poll()) != null){ handler.onHandle(item,timestamp); if (item instanceof AutoClear){ //从队列中拉出消费之后,进行release ((AutoClear)item).release(); } currentQueueLength --; } handler.onFlush(timestamp); } } public void close(){ stopped = true; if (thread != null && thread.isAlive()){ thread.interrupt(); } } } }