This commit is contained in:
bryan.zhang 2017-08-07 14:41:55 +08:00
commit d86369b30c
28 changed files with 1526 additions and 0 deletions

83
.gitignore vendored Normal file
View File

@ -0,0 +1,83 @@
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
*.war
*.del
*.pmd
.tern-project
# Logs and databases #
######################
*.log
*.log.*
# OS generated files #
######################
.DS_Store*
ehthumbs.db
Icon?
Thumbs.db
# Editor Files #
################
*~
*.swp
# Gradle Files #
################
.gradle
# Build output directies
/target
*/target
/build
*/build
# IntelliJ specific files/directories
out
.idea
*.ipr
*.iws
*.iml
atlassian-ide-plugin.xml
# Eclipse specific files/directories
.classpath
.project
.settings
.metadata
.myeclipse
# NetBeans specific files/directories
.nbattrs
*.mymetadata
/logs
*/logs
/payClear-timer/.tern-project

86
pom.xml Normal file
View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<groupId>com.thebeastshop.liteflow</groupId>
<artifactId>liteflow</artifactId>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>
<version>1.0.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
<commons.lang3.version>3.4</commons.lang3.version>
<commons-collections.version>4.1</commons-collections.version>
<spring.version>4.1.7.RELEASE</spring.version>
<org.slf4j.version>1.7.21</org.slf4j.version>
<log4j.version>1.2.17</log4j.version>
<log4j-slf4j.version>1.7.5</log4j-slf4j.version>
<slf4j.version>1.7.13</slf4j.version>
<fastjson.version>1.2.7</fastjson.version>
<classfinder.version>1.0</classfinder.version>
<dom4j.version>1.6.1</dom4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang3.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${log4j-slf4j.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>com.poolik</groupId>
<artifactId>classfinder</artifactId>
<version>${classfinder.version}</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>${dom4j.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,78 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-7-28
* @version 1.0
*/
package com.thebeastshop.liteflow.core;
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.thebeastshop.liteflow.entity.data.DataBus;
import com.thebeastshop.liteflow.entity.data.Slot;
import com.thebeastshop.liteflow.entity.monitor.CompStatistics;
import com.thebeastshop.liteflow.monitor.MonitorBus;
public abstract class Component {
private static final Logger LOG = LoggerFactory.getLogger(Component.class);
private InheritableThreadLocal<Integer> slotIndexTL = new InheritableThreadLocal<Integer>();
private String nodeId;
private boolean continueOnError;
public void execute() throws Exception{
StopWatch stopWatch = new StopWatch();
stopWatch.start();
long initm=Runtime.getRuntime().freeMemory();
process();
stopWatch.stop();
long timeSpent = stopWatch.getTime();
long endm=Runtime.getRuntime().freeMemory();
this.getSlot().addStep(nodeId);
//性能统计
CompStatistics statistics = new CompStatistics();
statistics.setComponentClazzName(this.getClass().getSimpleName());
statistics.setTimeSpent(timeSpent);
statistics.setMemorySpent(initm-endm);
MonitorBus.addStatistics(statistics);
LOG.debug("componnet[{}] finished in {} milliseconds",this.getClass().getSimpleName(),timeSpent);
}
protected abstract void process() throws Exception;
public boolean isContinueOnError() {
return continueOnError;
}
public void setContinueOnError(boolean continueOnError) {
this.continueOnError = continueOnError;
}
public Component setSlotIndex(Integer slotIndex) {
this.slotIndexTL.set(slotIndex);
return this;
}
public Slot getSlot(){
return DataBus.getSlot(this.slotIndexTL.get());
}
public String getNodeId() {
return nodeId;
}
public void setNodeId(String nodeId) {
this.nodeId = nodeId;
}
}

View File

@ -0,0 +1,136 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-7-31
* @version 1.0
*/
package com.thebeastshop.liteflow.core;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.thebeastshop.liteflow.entity.config.Chain;
import com.thebeastshop.liteflow.entity.config.Condition;
import com.thebeastshop.liteflow.entity.config.Node;
import com.thebeastshop.liteflow.entity.config.ThenCondition;
import com.thebeastshop.liteflow.entity.config.WhenCondition;
import com.thebeastshop.liteflow.entity.data.DataBus;
import com.thebeastshop.liteflow.flow.FlowBus;
import com.thebeastshop.liteflow.parser.FlowParser;
public class FlowExecutor {
private static final Logger LOG = LoggerFactory.getLogger(FlowExecutor.class);
private List<String> rulePath;
public void init() {
for(String path : rulePath){
try {
FlowParser.parseLocal(path);
} catch (Exception e) {
LOG.error("init flow executor cause error,cannot parse rule file{}", path, e);
}
}
}
public void reloadRule(){
init();
}
public <T> T execute(String chainId,Object param){
int slotIndex = -1;
try{
Chain chain = FlowBus.getChain(chainId);
if(chain == null){
LOG.error("couldn't find chain with the id[{}]",chainId);
}
slotIndex = DataBus.offerSlot();
LOG.info("slot[{}] offered",slotIndex);
if(slotIndex == -1){
throw new Exception("there is no available slot");
}
DataBus.getSlot(slotIndex).setRequestData(param);
List<Condition> conditionList = chain.getConditionList();
List<Node> nodeList = null;
Component component = null;
for(Condition condition : conditionList){
nodeList = condition.getNodeList();
if(condition instanceof ThenCondition){
for(Node node : nodeList){
component = node.getInstance();
try{
component.setSlotIndex(slotIndex).execute();
}catch(Throwable t){
if(component.isContinueOnError()){
LOG.error("component[{}] cause error,but flow is still go on",t,component.getClass().getSimpleName());
}else{
throw new Exception(t);
}
}
}
}else if(condition instanceof WhenCondition){
final CountDownLatch latch = new CountDownLatch(nodeList.size());
for(Node node : nodeList){
new WhenConditionThread(node,slotIndex,latch).start();
}
latch.await(15, TimeUnit.SECONDS);
}
}
DataBus.getSlot(slotIndex).printStep();
return DataBus.getSlot(slotIndex).getResponseData();
}catch(Exception e){
LOG.error("executor cause error",e);
return null;
}finally{
DataBus.releaseSlot(slotIndex);
}
}
private class WhenConditionThread extends Thread{
private Node node;
private Integer slotIndex;
private CountDownLatch latch;
public WhenConditionThread(Node node,Integer slotIndex,CountDownLatch latch){
this.node = node;
this.slotIndex = slotIndex;
this.latch = latch;
}
@Override
public void run() {
try{
node.getInstance().setSlotIndex(slotIndex).execute();
}catch(Exception e){
LOG.error("component [{}] execute cause error",node.getClazz(),e);
}finally{
latch.countDown();
}
}
}
public List<String> getRulePath() {
return rulePath;
}
public void setRulePath(List<String> rulePath) {
this.rulePath = rulePath;
}
}

View File

@ -0,0 +1,29 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-7-28
* @version 1.0
*/
package com.thebeastshop.liteflow.entity.config;
import java.util.List;
public class Chain {
private List<Condition> conditionList;
public Chain(List<Condition> conditionList) {
this.conditionList = conditionList;
}
public List<Condition> getConditionList() {
return conditionList;
}
public void setConditionList(List<Condition> conditionList) {
this.conditionList = conditionList;
}
}

View File

@ -0,0 +1,29 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-7-28
* @version 1.0
*/
package com.thebeastshop.liteflow.entity.config;
import java.util.List;
public class Condition {
private List<Node> nodeList;
public Condition(List<Node> nodeList) {
this.nodeList = nodeList;
}
public List<Node> getNodeList() {
return nodeList;
}
public void setNodeList(List<Node> nodeList) {
this.nodeList = nodeList;
}
}

View File

@ -0,0 +1,45 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-7-28
* @version 1.0
*/
package com.thebeastshop.liteflow.entity.config;
import com.thebeastshop.liteflow.core.Component;
public class Node {
private String id;
private String clazz;
private Component instance;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public Component getInstance() {
return instance;
}
public void setInstance(Component instance) {
this.instance = instance;
}
}

View File

@ -0,0 +1,20 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-7-28
* @version 1.0
*/
package com.thebeastshop.liteflow.entity.config;
import java.util.List;
public class ThenCondition extends Condition {
public ThenCondition(List<Node> nodeList) {
super(nodeList);
}
}

View File

@ -0,0 +1,20 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-7-28
* @version 1.0
*/
package com.thebeastshop.liteflow.entity.config;
import java.util.List;
public class WhenCondition extends Condition{
public WhenCondition(List<Node> nodeList) {
super(nodeList);
}
}

View File

@ -0,0 +1,50 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-8-1
* @version 1.0
*/
package com.thebeastshop.liteflow.entity.data;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DataBus {
private static final Logger LOG = LoggerFactory.getLogger(DataBus.class);
public static final int SLOT_SIZE = 1024;
public static AtomicInteger OCCUPY_COUNT = new AtomicInteger(0);
private static Slot[] slots = new Slot[SLOT_SIZE];
public synchronized static int offerSlot(){
for(int i = 0; i < slots.length; i++){
if(slots[i] == null){
slots[i] = new Slot();
OCCUPY_COUNT.incrementAndGet();
return i;
}
}
return -1;
}
public static Slot getSlot(int slotIndex){
return slots[slotIndex];
}
public static void releaseSlot(int slotIndex){
if(slots[slotIndex] != null){
slots[slotIndex] = null;
OCCUPY_COUNT.decrementAndGet();
}else{
LOG.warn("the slot[{}] has been released",slotIndex);
}
}
}

View File

@ -0,0 +1,90 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-8-3
* @version 1.0
*/
package com.thebeastshop.liteflow.entity.data;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SuppressWarnings("unchecked")
public class Slot {
private static final Logger LOG = LoggerFactory.getLogger(Slot.class);
private final String REQUEST = "request";
private final String RESPONSE = "response";
private final String NODE_INPUT_PREFIX = "input_";
private final String NODE_OUTPUT_PREFIX = "output_";
private List<String> executeSteps = new ArrayList<String>();
private ConcurrentHashMap<String, Object> dataMap = new ConcurrentHashMap<String, Object>();
public <T> T getInput(String nodeId){
return (T)dataMap.get(NODE_INPUT_PREFIX + nodeId);
}
public <T> T getOutput(String nodeId){
return (T)dataMap.get(NODE_OUTPUT_PREFIX + nodeId);
}
public <T> void setInput(String nodeId,T t){
dataMap.put(NODE_INPUT_PREFIX + nodeId, t);
}
public <T> void setOutput(String nodeId,T t){
dataMap.put(NODE_OUTPUT_PREFIX + nodeId, t);
}
public <T> T getRequestData(){
return (T)dataMap.get(REQUEST);
}
public <T> void setRequestData(T t){
dataMap.put(REQUEST, t);
}
public <T> T getResponseData(){
return (T)dataMap.get(RESPONSE);
}
public <T> void setResponseData(T t){
dataMap.put(RESPONSE, t);
}
public <T> T getData(String key){
return (T)dataMap.get(key);
}
public <T> void setData(String key, T t){
dataMap.put(key, t);
}
public void addStep(String nodeId){
this.executeSteps.add(nodeId);
}
public void printStep(){
StringBuffer str = new StringBuffer();
for(int i = 0; i < this.executeSteps.size(); i++){
str.append(executeSteps.get(i));
if(i < this.executeSteps.size()-1){
str.append("==>");
}
}
LOG.info(str.toString());
}
}

View File

@ -0,0 +1,43 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-8-4
* @version 1.0
*/
package com.thebeastshop.liteflow.entity.monitor;
public class CompStatistics {
private String componentClazzName;
private long timeSpent;
private long memorySpent;
public String getComponentClazzName() {
return componentClazzName;
}
public void setComponentClazzName(String componentClazzName) {
this.componentClazzName = componentClazzName;
}
public long getTimeSpent() {
return timeSpent;
}
public void setTimeSpent(long timeSpent) {
this.timeSpent = timeSpent;
}
public long getMemorySpent() {
return memorySpent;
}
public void setMemorySpent(long memorySpent) {
this.memorySpent = memorySpent;
}
}

View File

@ -0,0 +1,34 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-7-28
* @version 1.0
*/
package com.thebeastshop.liteflow.flow;
import java.util.HashMap;
import java.util.Map;
import com.thebeastshop.liteflow.entity.config.Chain;
public class FlowBus {
private static Map<String, Chain> chainMap;
public static Chain getChain(String id) throws Exception{
if(chainMap == null || chainMap.isEmpty()){
throw new Exception("please config the rule first");
}
return chainMap.get(id);
}
public static void addChain(String name,Chain chain){
if(chainMap == null){
chainMap = new HashMap<String, Chain>();
}
chainMap.put(name, chain);
}
}

View File

@ -0,0 +1,81 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-8-4
* @version 1.0
*/
package com.thebeastshop.liteflow.monitor;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
import java.util.TimerTask;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.thebeastshop.liteflow.entity.data.DataBus;
import com.thebeastshop.liteflow.entity.monitor.CompStatistics;
import com.thebeastshop.liteflow.util.LimitQueue;
public class MonitorBus {
private static final int QUEUE_LIMIT_SIZE = 200;
private static ConcurrentHashMap<String, LimitQueue<CompStatistics>> statisticsMap = new ConcurrentHashMap<String, LimitQueue<CompStatistics>>();
static{
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
MonitorBus.printStatistics();
}
}, 30*1000L, 10*60*1000L);
}
public static void addStatistics(CompStatistics statistics){
if(statisticsMap.containsKey(statistics.getComponentClazzName())){
statisticsMap.get(statistics.getComponentClazzName()).add(statistics);
}else{
LimitQueue<CompStatistics> queue = new LimitQueue<CompStatistics>(QUEUE_LIMIT_SIZE);
queue.add(statistics);
statisticsMap.put(statistics.getComponentClazzName(), queue);
}
}
public static void printStatistics(){
Map<String, Long> compAverageTimeSpent = new HashMap<String, Long>();
Map<String, Long> compAverageMemorySpent = new HashMap<String, Long>();
long totalTimeSpent = 0;
long totalMemorySpent = 0;
for(Entry<String, LimitQueue<CompStatistics>> entry : statisticsMap.entrySet()){
for(CompStatistics statistics : entry.getValue()){
totalTimeSpent += statistics.getTimeSpent();
totalMemorySpent += statistics.getMemorySpent();
}
compAverageTimeSpent.put(entry.getKey(), new BigDecimal(totalTimeSpent).divide(new BigDecimal(entry.getValue().size()), 2, RoundingMode.HALF_UP).longValue());
compAverageMemorySpent.put(entry.getKey(), new BigDecimal(totalMemorySpent).divide(new BigDecimal(entry.getValue().size()), 2, RoundingMode.HALF_UP).longValue());
}
System.out.println("======================================================================================");
System.out.println("===================================SLOT INFO==========================================");
System.out.println("SLOT TOTAL SIZE : "+DataBus.SLOT_SIZE);
System.out.println("SLOT OCCUPY COUNT : "+DataBus.OCCUPY_COUNT);
System.out.println("===============================TIME AVERAGE SPENT=====================================");
for(Entry<String, Long> entry : compAverageTimeSpent.entrySet()){
System.out.println("COMPONENT["+entry.getKey()+"] AVERAGE TIME SPENT : " + entry.getValue());
}
System.out.println("==============================MEMORY AVERAGE SPENT====================================");
for(Entry<String, Long> entry : compAverageMemorySpent.entrySet()){
System.out.println("COMPONENT["+entry.getKey()+"] AVERAGE MEMORY SPENT : "+ new BigDecimal(entry.getValue()).divide(new BigDecimal(1024), 2, RoundingMode.HALF_UP) + "K");
}
System.out.println("======================================================================================");
}
}

View File

@ -0,0 +1,122 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-7-28
* @version 1.0
*/
package com.thebeastshop.liteflow.parser;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.poolik.classfinder.ClassFinder;
import com.poolik.classfinder.filter.Subclass;
import com.poolik.classfinder.info.ClassInfo;
import com.thebeastshop.liteflow.core.Component;
import com.thebeastshop.liteflow.entity.config.Chain;
import com.thebeastshop.liteflow.entity.config.Condition;
import com.thebeastshop.liteflow.entity.config.Node;
import com.thebeastshop.liteflow.entity.config.ThenCondition;
import com.thebeastshop.liteflow.entity.config.WhenCondition;
import com.thebeastshop.liteflow.flow.FlowBus;
import com.thebeastshop.liteflow.util.Dom4JReader;
import com.thebeastshop.liteflow.util.IOUtil;
@SuppressWarnings("unchecked")
public class FlowParser {
private static final Logger LOG = LoggerFactory.getLogger(FlowParser.class);
private static final String ENCODING_FORMAT = "UTF-8";
public static void parseLocal(String rulePath) throws Exception{
String ruleContent = IOUtil.read(rulePath, ENCODING_FORMAT);
parse(ruleContent);
}
public static void parse(String content) throws Exception{
Document document = Dom4JReader.getFormatDocument(content);
parse(document);
}
public static void parse(Document document) throws Exception{
Element rootElement = document.getRootElement();
//find所有的组件实现类并实例化
Map<String, Component> compInstanceMap = new HashMap<String, Component>();
ClassFinder finder = new ClassFinder().addClasspath();
Collection<ClassInfo> classList = finder.findClasses(Subclass.of(Component.class));
Component component = null;
for(ClassInfo classInfo : classList){
LOG.info("component [{}] has been registered to flow parse manager",classInfo.getClassName());
component = (Component)ClassUtils.getClass(classInfo.getClassName()).newInstance();
compInstanceMap.put(classInfo.getClassName(), component);
}
//解析node节点
List<Element> nodeList = rootElement.element("nodes").elements("node");
String id = null;
String clazz = null;
Node node = null;
Map<String, Node> nodeMap = new HashMap<String, Node>();
for(Element e : nodeList){
node = new Node();
id = e.attributeValue("id");
clazz = e.attributeValue("class");
node.setId(id);
node.setClazz(clazz);
if(!compInstanceMap.containsKey(clazz)){
LOG.error("couldn't find [{}] in registered component map",clazz);
}
component = compInstanceMap.get(clazz);
component.setNodeId(id);
node.setInstance(component);
nodeMap.put(id, node);
}
//解析chain节点
String chainName = null;
String condArrayStr = null;
String[] condArray = null;
List<Node> chainNodeList = null;
List<Condition> conditionList = null;
List<Element> chainList = rootElement.elements("chain");
for(Element e : chainList){
chainName = e.attributeValue("name");
conditionList = new ArrayList<Condition>();
for (Iterator<Element> it = e.elementIterator(); it.hasNext();) {
Element condE = it.next();
condArrayStr = condE.attributeValue("value");
if(StringUtils.isBlank(condArrayStr)){
continue;
}
chainNodeList = new ArrayList<Node>();
condArray = condArrayStr.split(",");
for (int i = 0; i < condArray.length; i++) {
chainNodeList.add(nodeMap.get(condArray[i]));
}
if(condE.getName().equals("then")){
conditionList.add(new ThenCondition(chainNodeList));
}else if(condE.getName().equals("when")){
conditionList.add(new WhenCondition(chainNodeList));
}
}
FlowBus.addChain(chainName, new Chain(conditionList));
}
}
}

View File

@ -0,0 +1,117 @@
package com.thebeastshop.liteflow.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;
public class Dom4JReader {
private static final String ENCODING_FORMAT = "UTF-8";
public static Document getDocument(String text) throws DocumentException {
return DocumentHelper.parseText(text);
}
public static Document getFormatDocument(String text) throws DocumentException, UnsupportedEncodingException {
return getFormatDocument(text, ENCODING_FORMAT);
}
public static Document getFormatDocument(String text, String charset) throws DocumentException, UnsupportedEncodingException {
String formatText = new String(text.getBytes("ISO-8859-1"), ENCODING_FORMAT);
return getDocument(formatText);
}
public static Document getDocument(File file) throws DocumentException, IOException {
InputStream inputStream = new FileInputStream(file);
return getDocument(inputStream);
}
public static Document getFormatDocument(File file) throws DocumentException, IOException, UnsupportedEncodingException {
return getFormatDocument(file, ENCODING_FORMAT);
}
public static Document getFormatDocument(File file, String charset) throws DocumentException, IOException, UnsupportedEncodingException {
InputStream inputStream = new FileInputStream(file);
return getFormatDocument(inputStream, charset);
}
public static Document getDocument(InputSource inputSource) throws DocumentException {
SAXReader saxReader = new SAXReader();
return saxReader.read(inputSource);
}
public static Document getFormatDocument(InputSource inputSource) throws DocumentException {
return getFormatDocument(inputSource, ENCODING_FORMAT);
}
public static Document getFormatDocument(InputSource inputSource, String charset) throws DocumentException {
inputSource.setEncoding(charset);
return getDocument(inputSource);
}
public static Document getDocument(InputStream inputStream) throws DocumentException, IOException {
SAXReader saxReader = new SAXReader();
Document document = null;
try {
document = saxReader.read(inputStream);
} catch (DocumentException e) {
throw e;
} finally {
if (inputStream != null) {
inputStream.close();
}
}
return document;
}
public static Document getFormatDocument(InputStream inputStream) throws DocumentException, IOException, UnsupportedEncodingException {
return getFormatDocument(inputStream, ENCODING_FORMAT);
}
public static Document getFormatDocument(InputStream inputStream, String charset) throws DocumentException, IOException, UnsupportedEncodingException {
Reader inputStreamReader = new InputStreamReader(inputStream, charset);
return getDocument(inputStreamReader);
}
public static Document getDocument(Reader reader) throws DocumentException, IOException {
SAXReader saxReader = new SAXReader();
Document document = null;
try {
document = saxReader.read(reader);
} catch (DocumentException e) {
throw e;
} finally {
if (reader != null) {
reader.close();
}
}
return document;
}
public static Document getDocument(URL url) throws DocumentException {
SAXReader saxReader = new SAXReader();
return saxReader.read(url);
}
}

View File

@ -0,0 +1,29 @@
package com.thebeastshop.liteflow.util;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
public class IOUtil {
public static String read(String path, String encoding) throws Exception {
String content = null;
InputStream inputStream = null;
try {
// 从Resource路径获取
inputStream = IOUtil.class.getClassLoader().getResourceAsStream(path);
if (inputStream == null) {
// 从文件路径获取
inputStream = new FileInputStream(path);
}
content = IOUtils.toString(inputStream, encoding);
} finally {
if (inputStream != null) {
IOUtils.closeQuietly(inputStream);
}
}
return content;
}
}

View File

@ -0,0 +1,151 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-8-4
* @version 1.0
*/
package com.thebeastshop.liteflow.util;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
public class LimitQueue<E> implements Queue<E> {
/**
* 队列长度实例化类的时候指定
*/
private int limit;
Queue<E> queue = new LinkedList<E>();
public LimitQueue(int limit) {
this.limit = limit;
}
/**
* 入队
*/
@Override
public boolean offer(E e) {
if (queue.size() >= limit) {
// 如果超出长度,入队时,先出队
queue.poll();
}
return queue.offer(e);
}
/**
* 出队
*/
@Override
public E poll() {
return queue.poll();
}
/**
* 获取队列
*
* @return
* @author SHANHY
* @date 2015年11月9日
*/
public Queue<E> getQueue() {
return queue;
}
/**
* 获取限制大小
*
* @return
* @author SHANHY
* @date 2015年11月9日
*/
public int getLimit() {
return limit;
}
@Override
public boolean add(E e) {
return queue.add(e);
}
@Override
public E element() {
return queue.element();
}
@Override
public E peek() {
return queue.peek();
}
@Override
public boolean isEmpty() {
return queue.size() == 0 ? true : false;
}
@Override
public int size() {
return queue.size();
}
@Override
public E remove() {
return queue.remove();
}
@Override
public boolean addAll(Collection<? extends E> c) {
return queue.addAll(c);
}
@Override
public void clear() {
queue.clear();
}
@Override
public boolean contains(Object o) {
return queue.contains(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return queue.containsAll(c);
}
@Override
public Iterator<E> iterator() {
return queue.iterator();
}
@Override
public boolean remove(Object o) {
return queue.remove(o);
}
@Override
public boolean removeAll(Collection<?> c) {
return queue.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return queue.retainAll(c);
}
@Override
public Object[] toArray() {
return queue.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return queue.toArray(a);
}
}

View File

@ -0,0 +1,32 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-7-27
* @version 1.0
*/
package com.thebeastshop.liteflow.test;
import java.util.Arrays;
import com.thebeastshop.liteflow.core.FlowExecutor;
import com.thebeastshop.liteflow.parser.FlowParser;
public class TestMain {
public static void main(String[] args) throws Exception {
final FlowExecutor executor = new FlowExecutor();
executor.setRulePath(Arrays.asList(new String[]{"flow.xml"}));
executor.init();
for(int i=0;i<200;i++){
String response = executor.execute("chain2", "it's a request");
System.out.println(response);
}
System.in.read();
}
}

View File

@ -0,0 +1,25 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-8-1
* @version 1.0
*/
package com.thebeastshop.liteflow.test.component;
import com.thebeastshop.liteflow.core.Component;
public class AComponent extends Component {
@Override
public void process() {
String str = this.getSlot().getRequestData();
System.out.println(str);
System.out.println("Acomponent executed!");
this.getSlot().setOutput(this.getNodeId(), "A component output");
}
}

View File

@ -0,0 +1,31 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-8-1
* @version 1.0
*/
package com.thebeastshop.liteflow.test.component;
import java.util.ArrayList;
import java.util.List;
import com.thebeastshop.liteflow.core.Component;
public class BComponent extends Component {
@Override
public void process() {
try {
Thread.sleep(400L);
String[] temp = new String[1000];
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Bcomponent executed!");
}
}

View File

@ -0,0 +1,28 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-8-1
* @version 1.0
*/
package com.thebeastshop.liteflow.test.component;
import com.thebeastshop.liteflow.core.Component;
public class CComponent extends Component {
@Override
public void process() {
try {
String[] temp = new String[4000];
Thread.sleep(300L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Ccomponent executed!");
}
}

View File

@ -0,0 +1,36 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-8-1
* @version 1.0
*/
package com.thebeastshop.liteflow.test.component;
import com.thebeastshop.liteflow.core.Component;
import com.thebeastshop.liteflow.entity.data.Slot;
public class DComponent extends Component {
@Override
public void process() {
try {
Slot slot = this.getSlot();
String e = slot.getOutput("e");
if(e == null){
System.out.println(slot);
}
System.out.println("D:" + slot.getOutput("e"));
String[] temp = new String[1400];
Thread.sleep(450L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Dcomponent executed!");
}
}

View File

@ -0,0 +1,29 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-8-1
* @version 1.0
*/
package com.thebeastshop.liteflow.test.component;
import com.thebeastshop.liteflow.core.Component;
public class EComponent extends Component {
@Override
public void process() {
try {
Thread.sleep(120L);
System.out.println("E:" + this.getSlot().getOutput("a"));
this.getSlot().setOutput(this.getNodeId(), "E component output");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Eomponent executed!");
}
}

View File

@ -0,0 +1,28 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-8-1
* @version 1.0
*/
package com.thebeastshop.liteflow.test.component;
import com.thebeastshop.liteflow.core.Component;
public class FComponent extends Component {
@Override
public void process() {
try {
String[] temp = new String[400];
Thread.sleep(40L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Fcomponent executed!");
}
}

View File

@ -0,0 +1,22 @@
/**
* <p>Title: liteFlow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2017-8-1
* @version 1.0
*/
package com.thebeastshop.liteflow.test.component;
import com.thebeastshop.liteflow.core.Component;
public class GComponent extends Component {
@Override
public void process() {
System.out.println("Gcomponent executed!");
this.getSlot().setResponseData("i am a response");
}
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<nodes>
<node id="a" class="com.thebeastshop.liteflow.test.component.AComponent"/>
<node id="b" class="com.thebeastshop.liteflow.test.component.BComponent"/>
<node id="c" class="com.thebeastshop.liteflow.test.component.CComponent"/>
<node id="d" class="com.thebeastshop.liteflow.test.component.DComponent"/>
<node id="e" class="com.thebeastshop.liteflow.test.component.EComponent"/>
<node id="f" class="com.thebeastshop.liteflow.test.component.FComponent"/>
<node id="g" class="com.thebeastshop.liteflow.test.component.GComponent"/>
</nodes>
<chain name="chain1">
<then value="a,c"/>
<when value="b,d"/>
<then value="e,f,g"/>
</chain>
<chain name="chain2">
<then value="a,c,g"/>
<when value="b,e"/>
<then value="d,f"/>
</chain>
</flow>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration>
<appender name="stdout" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} [%p] %m >> %c:%L%n"/>
</layout>
</appender>
<appender name="fileout" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="./logs/commdata.log"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} [%p] %m >> %c:%L%n"/>
</layout>
</appender>
<appender name="asyncStdout" class="org.apache.log4j.AsyncAppender">
<param name="BufferSize" value="8192"/>
<appender-ref ref="stdout"/>
</appender>
<appender name="asyncFileout" class="org.apache.log4j.AsyncAppender">
<param name="BufferSize" value="8192"/>
<appender-ref ref="fileout"/>
</appender>
<root>
<priority value="info" />
<appender-ref ref="asyncStdout"/>
<appender-ref ref="asyncFileout"/>
</root>
</log4j:configuration>