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.anysoft.stream.AbstractHandler Maven / Gradle / Ivy
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();
}
}
}
}