
com.alogic.load.Scanner Maven / Gradle / Ivy
package com.alogic.load;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
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.anysoft.util.Configurable;
import com.anysoft.util.Factory;
import com.anysoft.util.IOTools;
import com.anysoft.util.JsonTools;
import com.anysoft.util.Properties;
import com.anysoft.util.PropertiesConstants;
import com.anysoft.util.Reportable;
import com.anysoft.util.Settings;
import com.anysoft.util.XMLConfigurable;
import com.anysoft.util.XmlElementProperties;
import com.anysoft.util.XmlTools;
/**
* 扫描器,用于列表性数据的加载
*
* @author duanyy
* @since 1.6.12.30 [20190425 duanyy]
*/
public interface Scanner extends Configurable,XMLConfigurable,Reportable{
/**
* 获取id
* @return id
*/
public String getId();
/**
* 开始扫描
* @param listener
*/
public void scan(Listener listener);
/**
* 虚基类
*
* @author duanyy
*
* @param 数据对象
*/
public abstract static class Abstract implements Scanner{
/**
* a logger of log4j
*/
protected static final Logger LOG = LoggerFactory.getLogger(Loader.class);
protected String id = "default";
@Override
public void configure(Element e, Properties p) {
Properties props = new XmlElementProperties(e,p);
configure(props);
}
@Override
public void configure(Properties p) {
id = PropertiesConstants.getString(p,"id",id,true);
}
@Override
public String getId() {
return null;
}
@Override
public void report(Element xml) {
if (xml != null){
XmlTools.setString(xml,"module",getClass().getName());
}
}
@Override
public void report(Map json) {
if (json != null){
JsonTools.setString(json,"module",getClass().getName());
}
}
}
/**
* Sinkable
* @author duanyy
*
* @param 数据对象
*/
public static class Sinkable extends Abstract {
/**
* 子scanner
*/
protected List> scanners = new ArrayList>();
@Override
public void configure(Element e, Properties p) {
Properties props = new XmlElementProperties(e,p);
configure(props);
NodeList nodeList = XmlTools.getNodeListByPath(e, getSinkTag());
Factory> factory = new Factory>();
String scope = PropertiesConstants.getString(p, "ketty.scope", "runtime");
for (int i = 0 ;i < nodeList.getLength() ; i ++){
Node n = nodeList.item(i);
if (Node.ELEMENT_NODE != n.getNodeType()){
continue;
}
Element elem = (Element)n;
String itemScope = XmlTools.getString(elem, "scope", "");
if (StringUtils.isNotEmpty(itemScope) && !itemScope.equals(scope)){
continue;
}
try {
Scanner loader = factory.newInstance(elem, props, "module");
if (loader != null){
scanners.add(loader);
}
}catch (Exception ex){
LOG.error("Can not create loader from element:" + XmlTools.node2String(elem));
LOG.error(ExceptionUtils.getStackTrace(ex));
}
}
}
/**
* 获取Sink的tag名
* @return tag名
*/
protected String getSinkTag(){
return "sink";
}
@Override
public void scan(Listener listener) {
if (listener != null){
Object cookie = listener.begin(this.getId());
scanSelf(cookie,listener);
scanSinks(cookie,listener);
listener.end(cookie, this.getId());
}
}
protected void scanSelf(Object cookie,Listener listener){
}
protected void scanSinks(Object cookie,Listener listener){
for (Scanner scanner:scanners){
try {
scanner.scan(listener);
}catch (Exception ex){
LOG.error(String.format("Failed to scan scanner:%s",scanner.getId()));
LOG.error(ExceptionUtils.getStackTrace(ex));
}
}
}
}
/**
* Cached
* @author duanyy
*
* @param 数据对象
*/
public static class Cached extends Sinkable implements Listener{
/**
* 子scanner
*/
protected List> scanners = new ArrayList>();
protected List cached = new ArrayList();
protected long ttl = 60 * 10000;
protected long lastTimestamp = 0;
@Override
public void configure(Properties p) {
super.configure(p);
ttl = (PropertiesConstants.getLong(p, "ttl", 60))*1000;
}
protected boolean isExpired(long now){
return now - this.lastTimestamp > ttl;
}
@Override
protected void scanSelf(Object cookie,Listener listener){
long now = System.currentTimeMillis();
if (isExpired(now)){
//缓存数据过期,重新加载
synchronized(this){
cached.clear();
scanSinks(cookie,this);
this.lastTimestamp = now;
}
}
for (O data:cached){
listener.found(cookie, data);
}
}
@Override
public void scan(Listener listener) {
if (listener != null){
Object cookie = listener.begin(this.getId());
scanSelf(cookie,listener);
listener.end(cookie, this.getId());
}
}
@Override
public Object begin(String scannerId) {
return this;
}
@Override
public void found(Object cookie, O data) {
cached.add(data);
}
@Override
public void end(Object cookie, String scannerId) {
}
}
/**
* 热部署文件
*
* @author yyduan
*
*/
public static abstract class HotFile extends Abstract implements Runnable{
protected String digest = "";
protected String filePath;
protected ScheduledThreadPoolExecutor threadPool = new ScheduledThreadPoolExecutor(1);
protected long interval = 10;
protected long delay = 10;
protected List cached = new ArrayList();
@Override
public void configure(Properties p){
super.configure(p);
filePath = PropertiesConstants.getString(p, "path", "");
interval = PropertiesConstants.getLong(p,"interval",interval);
delay = PropertiesConstants.getLong(p,"delay",delay);
loadFromPath(cached,filePath);
threadPool.scheduleAtFixedRate(this, delay, interval, TimeUnit.SECONDS);
}
@Override
public void scan(Listener listener) {
if (listener != null){
Object cookie = listener.begin(this.getId());
for (O data:cached){
listener.found(cookie, data);
}
listener.end(cookie, this.getId());
}
}
/**
* 从指定路径装入信息
*
* @param path
*/
protected void loadFromPath(final List container,final String path){
File file = new File(path);
if (file.exists() && file.isFile()){
digest = getFileDigest(file);
loadFromFile(container,file);
}else{
LOG.warn("File does not exist :" + path);
}
}
protected synchronized void loadFromFile(final List container,final File file){
InputStream in = null;
try {
in = new FileInputStream(file);
Document doc = XmlTools.loadFromInputStream(in);
if (doc != null){
loadFromElement(container,doc.getDocumentElement(),Settings.get());
}
} catch (Exception e) {
LOG.error("Can not open file : " + file.getPath());
LOG.error(ExceptionUtils.getStackTrace(e));
} finally{
IOTools.close(in);
}
}
protected void loadFromElement(final List container,Element root,Properties p){
NodeList nodeList = XmlTools.getNodeListByPath(root, getObjectXmlTag());
Factory factory = new Factory();
for (int i = 0 ;i < nodeList.getLength() ; i ++){
Node n = nodeList.item(i);
if (Node.ELEMENT_NODE != n.getNodeType()){
continue;
}
Element e = (Element)n;
O instance = factory.newInstance(e, p, "module", getObjectDftClass());
objectFound(container,instance);
}
}
protected void objectFound(final List container,O instance){
if (StringUtils.isNotEmpty(instance.getId())){
container.add(instance);
}
}
protected String getObjectXmlTag() {
return "model";
}
protected abstract String getObjectDftClass();
@Override
public void run() {
File file = new File(filePath);
if (file.exists() && file.isFile()){
String md5 = getFileDigest(file);
if (md5 != null && ! md5.equals(digest)){
digest = md5;
LOG.info("File has been changed:" + filePath);
List temp = new ArrayList();
loadFromFile(temp,file);
cached = temp;
}
}
}
protected synchronized String getFileDigest(File file){
String digest = null;
InputStream in;
try {
in = new FileInputStream(file);
digest = DigestUtils.md5Hex(in);
} catch (Exception e) {
LOG.error("Can not open file : " + file.getPath());
LOG.error(ExceptionUtils.getStackTrace(e));
}
return digest;
}
}
/**
* 扫描监听器
* @author duanyy
*
* @param 数据对象
*/
public static interface Listener {
public Object begin(String scannerId);
public void found(Object cookie,O data);
public void end(Object cookie,String scannerId);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy