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.load.Loader 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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
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.Settings;
import com.anysoft.util.XmlElementProperties;
import com.anysoft.util.Reportable;
import com.anysoft.util.Watcher;
import com.anysoft.util.XMLConfigurable;
import com.anysoft.util.XmlTools;
import com.anysoft.util.resource.ResourceFactory;
/**
* 通用装载框架
*
* @author duanyy
* @version 1.6.5.13 [20160612 duanyy]
* - 增加对象过期判断功能
*
* @version 1.6.7.9 [20170201 duanyy]
* - 采用SLF4j日志框架输出日志
*
* @version 1.6.10.6 [20171114 duanyy]
* - 优化日志输出
*
* @version 1.6.11.4 [20171222 duanyy]
* - 增加Hot实现
*
* @version 1.6.11.15 [20180206 duanyy]
* - 加载sink时增加scope支持
*
* @version 1.6.11.45 [duanyy 20180722]
* - Sinkable实现增加nocache模式;
*/
public interface Loader extends Configurable,XMLConfigurable,Reportable{
/**
* 按照id装载指定的对象
*
* @param id 对象id
* @param cacheAllowed 是否允许缓存
* @return 对象实例
*/
public O load(String id,boolean cacheAllowed);
/**
* 注册监听器
*
* @param watcher 监听器
*/
public void addWatcher(Watcher watcher);
/**
* 注销监听器
* @param watcher 监听器
*/
public void removeWatcher(Watcher watcher);
/**
* 虚基类
*
* @author duanyy
*
* @param
*/
public abstract static class Abstract implements Loader{
/**
* a logger of log4j
*/
protected static final Logger LOG = LoggerFactory.getLogger(Loader.class);
/**
* 对象有效期
*/
protected long ttl = 0;
/**
* 获取对象有效期
* @return ttl
*/
public long getTTL(){
return ttl;
}
@Override
public void configure(Properties p) {
ttl = PropertiesConstants.getLong(p,"ttl", ttl);
}
@Override
public void configure(Element e, Properties p) {
Properties props = new XmlElementProperties(e,p);
configure(props);
}
@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());
}
}
@Override
public void addWatcher(Watcher watcher) {
// nothing to do
}
@Override
public void removeWatcher(Watcher watcher) {
// nothing to do
}
/**
* 指定的Loadable对象是否过期
* @param o 对象
* @return 是否过期
*/
protected boolean isExpired(O o){
if (ttl > 0){
return o != null && System.currentTimeMillis() - o.getTimestamp() > ttl;
}else{
return o != null && o.isExpired();
}
}
}
/**
* Sinkable
* @author duanyy
*
*/
public abstract static class Sinkable extends Abstract {
protected List> loaders = new ArrayList>();
/**
* 本身不缓存
*/
private boolean noCache = false;
/**
* 是否本身不缓存数据
* @return 如果为true,则本身不缓存数据
*/
protected boolean noCache(){
return noCache;
}
@Override
public void configure(Properties p){
super.configure(p);
noCache = PropertiesConstants.getBoolean(p,"noCache", noCache);
}
@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 {
Loader loader = factory.newInstance(elem, props, "module");
if (loader != null){
loaders.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 O load(String id, boolean cacheAllowed) {
O found = noCache()? null:loadFromSelf(id,cacheAllowed);
if (found == null){
found = loadFromSink(id,cacheAllowed);
}
return found;
}
protected O loadFromSink(String id,boolean cacheAllowed){
for (Loader l:loaders){
O found = l.load(id, cacheAllowed);
if (found != null){
return found;
}
}
return null;
}
@Override
public void report(Element xml) {
if (xml != null){
super.report(xml);
if (!loaders.isEmpty()){
Document doc = xml.getOwnerDocument();
for (Loader l:loaders){
Element elem = doc.createElement("sink");
l.report(elem);
xml.appendChild(elem);
}
}
}
}
@Override
public void report(Map json) {
if (json != null){
super.report(json);
if (!loaders.isEmpty()){
List list = new ArrayList();
for (Loader l:loaders){
Map map = new HashMap();
l.report(map);
list.add(map);
}
json.put("sink", list);
}
}
}
@Override
public void addWatcher(Watcher watcher) {
for (Loader l:loaders){
l.addWatcher(watcher);
}
}
@Override
public void removeWatcher(Watcher watcher) {
for (Loader l:loaders){
l.removeWatcher(watcher);
}
}
protected abstract O loadFromSelf(String id,boolean cacheAllowed);
}
/**
* 缓存过的
* @author duanyy
*
* @param
*/
public static class Cached extends Sinkable implements Watcher{
/**
* 缓存的对象
*/
private Map cachedObjects = new ConcurrentHashMap();
/**
* 监听器
*/
private List> watchers = new ArrayList>();
@Override
public void configure(Element e, Properties p) {
super.configure(e, p);
for (Loader l:loaders){
l.addWatcher(this);
}
}
@Override
public O load(String id, boolean cacheAllowed) {
if (noCache()){
return loadFromSink(id,cacheAllowed);
}else{
O found = loadFromSelf(id,cacheAllowed);
if (found == null){
synchronized (this){
found = loadFromSelf(id,cacheAllowed);
if (found == null){
found = loadFromSink(id,cacheAllowed);
if (found != null){
cachedObjects.put(id, found);
}
}
}
}
return found;
}
}
@Override
protected O loadFromSelf(String id, boolean cacheAllowed) {
O found = null;
if (cacheAllowed){
found = cachedObjects.get(id);
if (isExpired(found)){
cachedObjects.remove(id);
found = null;
}
}
return found;
}
@Override
public void addWatcher(Watcher watcher) {
for (Loader l:loaders){
l.addWatcher(watcher);
}
watchers.add(watcher);
}
@Override
public void removeWatcher(Watcher watcher) {
for (Loader l:loaders){
l.removeWatcher(watcher);
}
watchers.remove(watcher);
}
@Override
public void added(String id, O data) {
cachedObjects.remove(id);
for (Watcher w:watchers){
w.added(id, data);
}
}
@Override
public void removed(String id, O data) {
cachedObjects.remove(id);
for (Watcher w:watchers){
w.removed(id, data);
}
}
@Override
public void changed(String id, O data) {
cachedObjects.remove(id);
for (Watcher w:watchers){
w.changed(id, data);
}
}
@Override
public void allChanged() {
cachedObjects.clear();
for (Watcher w:watchers){
w.allChanged();
}
}
}
/**
* 容器
*
* @author duanyy
*
* @param
*/
public static class Container extends Sinkable{
private Map objects = new ConcurrentHashMap();
/**
* 向缓存加入对象
* @param id 对象id
* @param o 对象
*/
public void add(String id,O o){
objects.put(id, o);
}
/**
* 从缓存中删除对象
* @param id 对象
*/
public void remove(String id){
objects.remove(id);
}
/**
* 清楚缓存所有对象
*/
public void clear(){
objects.clear();
}
/**
* 获取缓存中的对象
* @param id 对象id
* @return 对象实例
*/
public O get(String id){
return objects.get(id);
}
@Override
protected O loadFromSelf(String id, boolean cacheAllowed) {
return objects.get(id);
}
}
/**
* 基于XML配置的容器
*
* @author duanyy
*
* @param
*/
public abstract static class XmlResource extends Container{
protected abstract String getObjectXmlTag();
protected abstract String getObjectDftClass();
@Override
public void configure(Element root, Properties p) {
super.configure(root, p);
Properties props = new XmlElementProperties(root,p);
loadFromElement(root,props);
}
protected void loadFromElement(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());
if (StringUtils.isNotEmpty(instance.getId())){
add(instance.getId(), instance);
}
}
}
}
/**
* 基于外部XML配置的容器
*
* @author duanyy
*
* @param
*
* @since 1.6.12.33 [20190505]
*/
public abstract static class OutterXmlResource extends Container{
protected abstract String getObjectXmlTag();
protected abstract String getObjectDftClass();
@Override
public void configure(Properties p) {
super.configure(p);
String path = PropertiesConstants.getString(p, "path", "");
if (StringUtils.isNotEmpty(path)){
loadFromPath(path,p);
}
}
protected void loadFromPath(String path, Properties p) {
ResourceFactory rf = Settings.getResourceFactory();
InputStream in = null;
try {
in = rf.load(path, null, null);
Document doc = XmlTools.loadFromInputStream(in);
if (doc != null){
loadFromElement(doc.getDocumentElement(),p);
}
} catch (Exception ex) {
LOG.error("Error occurs when load xml file,source=" + path);
LOG.error(ExceptionUtils.getStackTrace(ex));
} finally {
IOTools.closeStream(in);
}
}
protected void loadFromElement(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());
if (StringUtils.isNotEmpty(instance.getId())){
add(instance.getId(), instance);
}
}
}
}
/**
* 管理器
*
* @author duanyy
*
* @param
*/
public abstract static class Manager{
/**
* a logger of log4j
*/
protected static final Logger LOG = LoggerFactory.getLogger(Manager.class);
/**
* 获取缺省的实现类名
* @return 实现类名
*/
protected abstract String getDefaultClass();
/**
* 从xml配置节点上装入Loader
*
* @param root xml配置节点
* @param moduleAttr 类名的字段名
* @param p 环境变量
* @return Loader实例
*/
public Loader loadFrom(Element root,String moduleAttr,Properties p) {
Loader loader = null;
try {
Factory> f = new Factory>();
loader = f.newInstance(root, p, moduleAttr, getDefaultClass());
}catch (Exception ex){
LOG.error(String.format("Can not create loader with %s", XmlTools.node2String(root)));
}
return loader;
}
/**
* 从xml配置节点上装入Loader
*
* @param root xml配置节点
* @param p 环境变量集
* @return Loader实例
*/
public Loader loadFrom(Element root,Properties p){
return loadFrom(root,"module",p);
}
/**
* 从xml文档的根节点装入loader
* @param doc xml文档
* @param p 环境变量集
* @return Loader实例
*/
public Loader loadFrom(Document doc,Properties p){
return loadFrom(doc.getDocumentElement(),p);
}
/**
* 从配置文件的路径中装入
* @param master 主路径
* @param secondary 备用路径
* @return Loader实例
*/
public Loader loadFrom(String master,String secondary){
Loader loader = null;
ResourceFactory rf = Settings.getResourceFactory();
InputStream in = null;
try {
in = rf.load(master, secondary, null);
Document doc = XmlTools.loadFromInputStream(in);
loader = loadFrom(doc,Settings.get());
} catch (Exception ex) {
LOG.error("Error occurs when load xml file,source=" + master);
LOG.error(ExceptionUtils.getStackTrace(ex));
} finally {
IOTools.closeStream(in);
}
return loader;
}
/**
* 从配置文件的路径中装入
* @param src 主路径
* @return Loader实例
*/
public Loader loadFrom(String src){
Loader loader = null;
ResourceFactory rf = Settings.getResourceFactory();
InputStream in = null;
try {
in = rf.load(src, null, null);
Document doc = XmlTools.loadFromInputStream(in);
loader = loadFrom(doc,Settings.get());
} catch (Exception ex) {
LOG.error("Error occurs when load xml file,source=" + src);
LOG.error(ExceptionUtils.getStackTrace(ex));
} finally {
IOTools.closeStream(in);
}
return loader;
}
}
/**
* 热部署Loader
* @author yyduan
*
* @param
*
* @version 1.6.12.17 [20181226 duanyy]
* - interval参数可以配置;
*/
public static abstract class Hot extends Loader.Abstract implements Runnable{
/**
* 监听器
*/
private List> watchers = new ArrayList>();
/**
* 扫描线程池
*/
private ScheduledThreadPoolExecutor threadPool = new ScheduledThreadPoolExecutor(1);
/**
* 扫描间隔,缺省:60s
*/
private long interval = 60;
/**
* 线程启动延迟,缺省:60s
*/
private long delay = 60;
/**
* 是否已经进行了第一次加载
*/
private boolean firstLoad = false;
/**
* 缓存的对象
*/
private Map objects = new ConcurrentHashMap();
/**
* 向缓存加入对象
* @param id 对象id
* @param o 对象
*/
protected void add(String id,O o){
objects.put(id, o);
}
/**
* 从缓存中删除对象
* @param id 对象
*/
protected void remove(String id){
objects.remove(id);
}
/**
* 清楚缓存所有对象
*/
protected void clear(){
objects.clear();
}
/**
* 获取缓存中的对象
* @param id 对象id
* @return 对象实例
*/
protected O get(String id){
return objects.get(id);
}
/**
* 缓存中是否包含指定id的对象
* @param id 对象id
* @return 是否包含指定id的对象
*/
protected boolean contain(String id){
return objects.containsKey(id);
}
@Override
public void addWatcher(Watcher watcher) {
super.addWatcher(watcher);
watchers.add(watcher);
}
@Override
public void removeWatcher(Watcher watcher) {
super.removeWatcher(watcher);
watchers.remove(watcher);
}
@Override
public void configure(Properties p) {
super.configure(p);
interval = PropertiesConstants.getLong(p,"interval",interval);
boolean preload = PropertiesConstants.getBoolean(p,"preload",true);
if (preload){
//进行预加载
//初次加载
doLoad(true);
//启动扫描线程
threadPool.scheduleAtFixedRate(this, delay, interval, TimeUnit.SECONDS);
//已经进行了一次加载
firstLoad = true;
}
}
/**
* 执行扫描加载过程
* @param first 是否第一次加载
*/
protected abstract void doLoad(boolean first);
@Override
public void run(){
doLoad(false);
}
@Override
public O load(String id, boolean cacheAllowed) {
if (!firstLoad){
//还没有加载
synchronized(this){
if (!firstLoad){
//初次加载
doLoad(true);
//启动扫描线程
threadPool.scheduleAtFixedRate(this, delay, interval, TimeUnit.SECONDS);
//已经进行了一次加载
firstLoad = true;
}
}
}
return get(id);
}
/**
* 触发对象增加事件
* @param id 对象id
* @param o 对象实例
*/
protected void fireAdded(String id,O o){
for (Watcher w:watchers){
w.added(id, o);
}
}
/**
* 触发对象被删除事件
* @param id 对象id
* @param o 对象实例
*/
protected void fireRemove(String id,O o){
for (Watcher w:watchers){
w.removed(id, o);
}
}
/**
* 触发对象变更事件
* @param id 对象id
* @param o 对象实例
*/
protected void fireChanged(String id,O o){
for (Watcher w:watchers){
w.changed(id, o);
}
}
/**
* 触发所有对象变更事件
*/
protected void fireAllChanged(){
for (Watcher w:watchers){
w.allChanged();
}
}
}
/**
* 热部署文件
*
* @author yyduan
*
*/
public static abstract class HotFile extends Loader.Abstract implements Runnable{
protected String digest = "";
protected String filePath;
protected ScheduledThreadPoolExecutor threadPool = new ScheduledThreadPoolExecutor(1);
protected long interval = 10;
protected long delay = 10;
private Map objects = new ConcurrentHashMap();
/**
* 监听器
*/
private List> watchers = 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(objects,filePath);
threadPool.scheduleAtFixedRate(this, delay, interval, TimeUnit.SECONDS);
}
@Override
public O load(String id, boolean cacheAllowed) {
return objects.get(id);
}
/**
* 从指定路径装入信息
*
* @param path
*/
protected void loadFromPath(final Map 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 Map 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 Map 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());
if (StringUtils.isNotEmpty(instance.getId())){
container.put(instance.getId(), instance);
}
}
}
protected String getObjectXmlTag() {
return "model";
}
protected abstract String getObjectDftClass();
@Override
public void addWatcher(Watcher watcher) {
super.addWatcher(watcher);
watchers.add(watcher);
}
@Override
public void removeWatcher(Watcher watcher) {
super.removeWatcher(watcher);
watchers.remove(watcher);
}
@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);
Map temp = new ConcurrentHashMap();
loadFromFile(temp,file);
objects = temp;
for (Watcher w:watchers){
w.allChanged();
}
}
}
}
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;
}
}
}