org.jbpt.pm.ProcessModel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jbpt-bpm Show documentation
Show all versions of jbpt-bpm Show documentation
The jBPT code library is a compendium of technologies that support research on design, execution, and evaluation of business processes.
package org.jbpt.pm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jbpt.algo.graph.DirectedGraphAlgorithms;
import org.jbpt.algo.graph.GraphAlgorithms;
import org.jbpt.graph.abs.AbstractDirectedGraph;
import org.jbpt.hypergraph.abs.IVertex;
import org.jbpt.hypergraph.abs.Vertex;
import org.jbpt.petri.PetriNet;
import org.jbpt.petri.Place;
import org.jbpt.petri.Transition;
/**
* Basic process model implementation
*
* @author Artem Polyvyanyy, Tobias Hoppe, Cindy F?hnrich, Andreas Meyer
*/
public class ProcessModel extends AbstractDirectedGraph, FlowNode> implements IProcessModel, FlowNode, NonFlowNode> {
private DirectedGraphAlgorithms, FlowNode> directedGraphAlgorithms = new DirectedGraphAlgorithms, FlowNode>();
private GraphAlgorithms, FlowNode> graphAlgorithms = new GraphAlgorithms, FlowNode>();
protected Set nonFlowNodes = new HashSet();
/**
* Construct an empty process
*/
public ProcessModel() {
}
/**
* Construct an empty process with the given name
* @param name of the process
*/
public ProcessModel(String name) {
setName(name);
}
@Override
public ControlFlow addControlFlow(FlowNode from, FlowNode to) {
return addControlFlow(from, to, 1f);
}
@Override
public ControlFlow addControlFlow(FlowNode from, FlowNode to, float probability) {
if (from == null || to == null) {
return null;
}
from.setModel(this);
to.setModel(this);
Collection ss = new ArrayList();
ss.add(from);
Collection ts = new ArrayList();
ts.add(to);
if (!this.checkEdge(ss, ts)) return null;
return new ControlFlow(this, from, to, probability);
}
@Override
public ControlFlow addEdge(FlowNode from, FlowNode to) {
return addControlFlow(from, to);
}
@Override
public FlowNode addFlowNode(FlowNode obj) {
obj.setModel(this);
return super.addVertex(obj);
}
@Override
@Deprecated
public Gateway addGateway(Gateway gateway) {
return (Gateway) this.addFlowNode(gateway);
}
@Override
public NonFlowNode addNonFlowNode(NonFlowNode obj) {
return (this.nonFlowNodes.add(obj)) ? obj : null;
}
/**
* Add activity to the process
* @param task {@link Activity} to add
* @return {@link Activity} that was added to the process, null
upon failure
*/
@Deprecated
public Activity addTask(Activity task) {
return (Activity) this.addFlowNode(task);
}
@Override
public ProcessModel clone(){
ProcessModel clone = (ProcessModel) super.clone();
// clear algorithm class
clone.clearMembers();
// workaround since abstract graph notifier is not cloned
clone.removeVertices(clone.getVertices());
clone.removeEdges(clone.getEdges());
Map nodeCopies = new HashMap();
for (FlowNode n : this.getVertices()) {
FlowNode c = n.clone();
clone.addFlowNode(c);
nodeCopies.put(n, c);
}
for (ControlFlow f : this.getControlFlow()) {
FlowNode from = nodeCopies.get(f.getSource());
FlowNode to = nodeCopies.get(f.getTarget());
clone.addControlFlow(from, to);
}
clone.nonFlowNodes = new HashSet();
for (NonFlowNode node : this.nonFlowNodes){
clone.nonFlowNodes.add((NonFlowNode) node.clone());
}
return clone;
}
@Override
public boolean contains(Vertex modelElement){
return this.vertices.containsKey(modelElement) || this.nonFlowNodes.contains(modelElement);
}
@Override
public boolean containsAllTypes(Collection> classes) {
if (classes == null) {
return false;
}
for (Class> clazz : classes) {
boolean result = containsType(clazz);
if (!result) {
return false;
}
}
return true;
}
@Override
public boolean containsType(Class> clazz) {
if (clazz == null) {
return false;
}
for (IVertex flowNode : this.vertices.keySet()) {
if (clazz.isInstance(flowNode)) {
return true;
}
}
for (IVertex nonFlowNode : this.nonFlowNodes) {
if (clazz.isInstance(nonFlowNode)) {
return true;
}
}
return false;
}
@Override
public Collection extends IVertex> filter(Class> clazz) {
Collection result = new ArrayList();
for (IVertex flowNode : this.vertices.keySet()){
if (clazz.isInstance(flowNode)){
result.add((Vertex) flowNode);
}
}
for (IVertex nonFlowNode : this.nonFlowNodes){
if (clazz.isInstance(nonFlowNode)){
result.add((Vertex) nonFlowNode);
}
}
return result;
}
@SuppressWarnings("unchecked")
@Override
public Collection getActivities() {
return (Collection) this.filter(Activity.class);
}
@Override
public Collection> getControlFlow() {
return this.getEdges();
}
@Override
public Collection getDataNodes() {
Collection dataNodes = new ArrayList();
for (NonFlowNode node : this.nonFlowNodes){
if (node instanceof DataNode){
dataNodes.add((DataNode) node);
}
}
return dataNodes;
}
@Override
public Collection getEntries() {
return (Collection) directedGraphAlgorithms.getSources(this);
}
@SuppressWarnings("unchecked")
@Override
public Collection getEvents() {
return (Collection) this.filter(Event.class);
}
@Override
public Collection getExits() {
return (Collection) directedGraphAlgorithms.getSinks(this);
}
@Override
public Collection getFlowNodes() {
return (Collection) super.getVertices();
}
@Override
public Collection getFlowNodes(NonFlowNode obj) {
Set result = new HashSet();
result.addAll(this.getInputFlowNodes(obj));
result.addAll(this.getOutputFlowNodes(obj));
return new ArrayList(result);
}
@SuppressWarnings("unchecked")
@Override
public Collection getGateways() {
return (Collection) this.filter(Gateway.class);
}
@SuppressWarnings("unchecked")
@Override
public Collection getGateways(Class> type) {
return (Collection) this.filter(type);
}
@Override
public Collection> getIncomingControlFlow(FlowNode obj) {
return super.getIncomingEdges(obj);
}
@SuppressWarnings("unchecked")
@Override
public Collection getInputFlowNodes(NonFlowNode obj) {
Set result = new HashSet();
//given node is part of this graph
if (this.nonFlowNodes.contains(obj)){
if (obj instanceof IDataNode){
//31.07.2012 Temporary Remove
//result.addAll((Collection extends FlowNode>) ((IDataNode) obj).getWritingFlowNodes());
//result.addAll((Collection extends FlowNode>) ((IDataNode) obj).getUnspecifiedFlowNodes());
}
}
return result;
}
@SuppressWarnings("unchecked")
@Override
public Collection getInputNonFlowNodes(FlowNode obj) {
Set result = new HashSet();
//31.07.2012 Temporary Remove
//result.addAll((Collection extends NonFlowNode>) obj.getReadDocuments());
//result.addAll((Collection extends NonFlowNode>) obj.getUnspecifiedDocuments());
//result.addAll((Collection extends NonFlowNode>) obj.getResources());
return result;
}
@Override
public Collection getNonFlowNodes() {
return new ArrayList(this.nonFlowNodes);
}
@Override
public Collection getNonFlowNodes(FlowNode obj) {
Set result = new HashSet();
result.addAll(this.getInputNonFlowNodes(obj));
result.addAll(this.getOutputNonFlowNodes(obj));
return new ArrayList(result);
}
@Override
public Collection> getOutgoingControlFlow(FlowNode obj) {
return this.getOutgoingEdges(obj);
}
@SuppressWarnings("unchecked")
@Override
public Collection getOutputFlowNodes(NonFlowNode obj) {
Set result = new HashSet();
//given node part of this graph?
//31.07.2012 Temporary Remove
// if (this.nonFlowNodes.contains(obj)){
// if (obj instanceof IDataNode){
// result.addAll((Collection extends FlowNode>) ((IDataNode) obj).getReadingFlowNodes());
// result.addAll((Collection extends FlowNode>) ((IDataNode) obj).getUnspecifiedFlowNodes());
// }
// }
return result;
}
@SuppressWarnings("unchecked")
@Override
public Collection getOutputNonFlowNodes(FlowNode obj) {
Set result = new HashSet();
//31.07.2012 Temporary Remove
//result.addAll((Collection extends NonFlowNode>) obj.getWriteDocuments());
//result.addAll((Collection extends NonFlowNode>) obj.getUnspecifiedDocuments());
//result.addAll((Collection extends NonFlowNode>) obj.getResources());
return result;
}
@Override
public boolean isConnected(){
return graphAlgorithms.isConnected(this);
}
@Override
public ControlFlow removeControlFlow(ControlFlow flow) {
return this.removeEdge(flow)!=null ? flow : null;
}
@Override
public Collection> removeControlFlows(Collection> flows) {
return this.removeEdges(flows);
}
@Override
public FlowNode removeFlowNode(FlowNode obj) {
return super.removeVertex(obj);
}
@Override
@Deprecated
public Gateway removeGateway(Gateway gateway) {
return (Gateway) this.removeFlowNode(gateway);
}
@Override
public NonFlowNode removeNonFlowNode(NonFlowNode obj) {
return this.nonFlowNodes.remove(obj) ? obj : null;
}
@Override
@Deprecated
public Activity removeTask(Activity task) {
return (Activity) this.removeFlowNode(task);
}
@Override
public String toDOT() {
String result = "";
if (this == null) {
return result;
}
result += "digraph G {\n";
result += "rankdir=LR \n"; //rankdir=LR for left to right graph; rankdir=TD for top to down graph
for (Event e : this.getEvents()) {
result += String.format(" n%s[shape=ellipse,label=\"%s\"];\n", e.getId().replace("-", ""), e.getName());
}
result+="\n";
for (Activity a : this.getActivities()) {
result += String.format(" n%s[shape=box,label=\"%s\"];\n", a.getId().replace("-", ""), a.getName());
}
result+="\n";
for (Gateway g : this.getGateways(AndGateway.class)) {
result += String.format(" n%s[shape=diamond,label=\"%s\"];\n", g.getId().replace("-", ""), "AND");
}
for (Gateway g : this.getGateways(XorGateway.class)) {
result += String.format(" n%s[shape=diamond,label=\"%s\"];\n", g.getId().replace("-", ""), "XOR");
}
for (Gateway g : this.getGateways(OrGateway.class)) {
result += String.format(" n%s[shape=diamond,label=\"%s\"];\n", g.getId().replace("-", ""), "OR");
}
for (Gateway g : this.getGateways(AlternativGateway.class))
result += String.format(" n%s[shape=diamond,label=\"%s\"];\n", g.getId().replace("-", ""), "?");
result+="\n";
for (DataNode d : this.getDataNodes()) {
result += String.format(" n%s[shape=note,label=\"%s\"];\n", d.getId().replace("-", ""), d.getName().concat(" [" + d.getState() + "]"));
}
result+="\n";
for (ControlFlow cf: this.getControlFlow()) {
if (cf.getLabel()!=null && cf.getLabel()!="")
result += String.format(" n%s->n%s[label=\"%s\"];\n", cf.getSource().getId().replace("-", ""), cf.getTarget().getId().replace("-", ""), cf.getLabel());
else
result += String.format(" n%s->n%s;\n", cf.getSource().getId().replace("-", ""), cf.getTarget().getId().replace("-", ""));
}
result+="\n";
for (Activity a : this.getActivities()) {
for (IDataNode d : a.getReadDocuments()) {
result += String.format(" n%s->n%s;\n", d.getId().replace("-", ""), a.getId().replace("-", ""));
}
for (IDataNode d : a.getWriteDocuments()) {
result += String.format(" n%s->n%s;\n", a.getId().replace("-", ""), d.getId().replace("-", ""));
}
}
result += "}";
return result;
}
@Override
public Collection getAllPredecessors(FlowNode fn) {
Set result = new HashSet();
Set temp = new HashSet();
temp.addAll(getDirectPredecessors(fn));
result.addAll(temp);
while(!(temp.isEmpty())) {
Set temp2 = new HashSet();
for (FlowNode flowNode : temp) {
temp2.addAll(getDirectPredecessors(flowNode));
}
temp = temp2;
Set temp3 = new HashSet();
for (FlowNode flowNode : temp) {
if(!(result.contains(flowNode))) {
result.add(flowNode);
} else {
temp3.add(flowNode);
}
}
for (FlowNode flowNode : temp3) {
temp.remove(flowNode);
}
}
return result;
}
@Override
public Collection getAllSuccessors(FlowNode fn) {
Set result = new HashSet();
Set temp = new HashSet();
temp.addAll(getDirectSuccessors(fn));
result.addAll(temp);
while(!(temp.isEmpty())) {
Set temp2 = new HashSet();
for (FlowNode flowNode : temp) {
temp2.addAll(getDirectSuccessors(flowNode));
}
temp = temp2;
Set temp3 = new HashSet();
for (FlowNode flowNode : temp) {
if(!(result.contains(flowNode))) {
result.add(flowNode);
} else {
temp3.add(flowNode);
}
}
for (FlowNode flowNode : temp3) {
temp.remove(flowNode);
}
}
return result;
}
/**
* assumptions:
* single entry node - single start node
* start with (i) activity or (ii) event followed by activity or and/ xor gateway
* every activity has at most one incoming and at most one outgoing edge
* unique labeling of activities
* control flow nodes: start event, end event, activity, gateway
*/
@Override
public PetriNet toPetriNet() {
PetriNet pn = new PetriNet();
List nodes1 = new ArrayList();
List nodes2 = new ArrayList();
List nodes3 = new ArrayList();
for (FlowNode fn : this.getEntries()) {
if(fn instanceof Activity) {
pn.addFlow(new Place(), new Transition(fn.getName()));
nodes1.add(fn);
} else if(fn instanceof Event) {
fn = this.getFirstDirectSuccessor(fn);
if(fn instanceof Activity) {
pn.addFlow(new Place(), new Transition(fn.getName()));
nodes1.add(fn);
} else if(fn instanceof AndGateway) {
for (FlowNode flowNode : this.getDirectSuccessors(fn)) {
pn.addFlow(new Place(), new Transition(flowNode.getName()));
nodes1.add(flowNode);
}
} else if(fn instanceof XorGateway) {
Place p = new Place();
for (FlowNode flowNode : this.getDirectSuccessors(fn)) {
pn.addFlow(p, new Transition(flowNode.getName()));
nodes1.add(flowNode);
}
} else {
//not possible
}
} else {
//not possible
}
} //initial transition
while(!(nodes1.isEmpty())) {
for (FlowNode flowNode : nodes1) {
if(flowNode instanceof Activity) {
while(this.getFirstDirectSuccessor(flowNode) instanceof Activity) {
for (Transition transition : pn.getSinkTransitions()) {
if (transition.getName().equalsIgnoreCase(flowNode.getName())) {
Place p = new Place();
pn.addFlow(transition, p);
pn.addFlow(p, new Transition(this.getFirstDirectSuccessor(flowNode).getName()));
}
}
flowNode = this.getFirstDirectSuccessor(flowNode);
}
nodes2.add(flowNode);
} else if(flowNode instanceof Gateway) {
nodes2.add(flowNode);
} else {
//not possible
}
} //gateway reached for each path
nodes1.clear();
nodes1.addAll(nodes2);
nodes2.clear();
//handle gateways
while(!(nodes1.isEmpty())) {
FlowNode currentFlowNode = nodes1.get(0);
for (FlowNode node : this.getDirectSuccessors(currentFlowNode)) {
if(node instanceof Event) {
break;
}
Gateway gw = (Gateway) node;
for (FlowNode flowNode : nodes1) {
for (FlowNode flowNode2 : this.getDirectSuccessors(flowNode)) {
if(flowNode2.equals(gw)) {
nodes2.add(flowNode);
}
}
}
if(this.getIncomingEdges(gw).size() == 1 && this.getOutgoingEdges(gw).size() > 1) { //split
if(gw instanceof AndGateway) { //and split
for (Transition transition : pn.getSinkTransitions()) {
for (FlowNode flowNode : nodes2) {
if(flowNode instanceof Activity) {
if (transition.getName().equalsIgnoreCase(flowNode.getName())) {
for (FlowNode flowNode2 : this.getDirectSuccessors(gw)) {
Place p = new Place();
pn.addFlow(transition, p);
if(flowNode2 instanceof Activity) {
pn.addFlow(p, new Transition(flowNode2.getName()));
nodes3.add(flowNode2);
} else if(flowNode2 instanceof Gateway) {
Transition t = new Transition();
t.setDescription(flowNode2.getName());
pn.addFlow(p, t);
if(!(nodes3.contains(gw))) {
nodes3.add(gw);
}
} else {
//not possible
}
}
}
} else if(flowNode instanceof Gateway) {
if(transition.getDescription().equalsIgnoreCase(node.getName())) {
for (FlowNode flowNode2 : this.getDirectSuccessors(gw)) {
Place p = new Place();
pn.addFlow(transition, p);
if(flowNode2 instanceof Activity) {
pn.addFlow(p, new Transition(flowNode2.getName()));
nodes3.add(flowNode2);
} else if(flowNode2 instanceof Gateway) {
Transition t = new Transition();
t.setDescription(flowNode2.getName());
pn.addFlow(p, t);
if(!(nodes3.contains(gw))) {
nodes3.add(gw);
}
} else {
//not possible
}
}
}
} else {
//not possible
}
}
}
} else if(gw instanceof XorGateway) { //xor split
for (Transition transition : pn.getSinkTransitions()) {
for (FlowNode flowNode : nodes2) {
if(flowNode instanceof Activity) {
if (transition.getName().equalsIgnoreCase(flowNode.getName())) {
Place p = new Place();
for (FlowNode flowNode2 : this.getDirectSuccessors(gw)) {
pn.addFlow(transition, p);
if(flowNode2 instanceof Activity) {
pn.addFlow(p, new Transition(flowNode2.getName()));
nodes3.add(flowNode2);
} else if(flowNode2 instanceof Gateway) {
Transition t = new Transition();
t.setDescription(flowNode2.getName());
pn.addFlow(p, t);
if(!(nodes3.contains(gw))) {
nodes3.add(gw);
}
} else {
//not possible
}
}
}
} else if(flowNode instanceof Gateway) {
if(transition.getDescription().equalsIgnoreCase(node.getName())) {
Place p = new Place();
for (FlowNode flowNode2 : this.getDirectSuccessors(gw)) {
pn.addFlow(transition, p);
if(flowNode2 instanceof Activity) {
pn.addFlow(p, new Transition(flowNode2.getName()));
nodes3.add(flowNode2);
} else if(flowNode2 instanceof Gateway) {
Transition t = new Transition();
t.setDescription(flowNode2.getName());
pn.addFlow(p, t);
if(!(nodes3.contains(gw))) {
nodes3.add(gw);
}
} else {
//not possible
}
}
}
} else {
//not possible
}
}
}
} else {
//not possible
}
} else if(this.getIncomingEdges(gw).size() > 1 && this.getOutgoingEdges(gw).size() == 1) { //join
if(nodes1.containsAll(this.getDirectPredecessors(gw))) {
if(gw instanceof AndGateway) { //and join
Transition t1 = new Transition(this.getFirstDirectSuccessor(gw).getName());
Transition t2 = new Transition();
t2.setDescription(gw.getName());
for (Transition transition : pn.getSinkTransitions()) {
if(this.getFirstDirectSuccessor(gw) instanceof Activity) {
for (FlowNode flowNode : nodes2) {
if(flowNode instanceof Activity) {
if (transition.getName().equalsIgnoreCase(flowNode.getName())) {
Place p = new Place();
pn.addFlow(transition, p);
pn.addFlow(p, t1);
if(!(nodes3.contains(getFirstDirectSuccessor(gw)))) {
nodes3.add(getFirstDirectSuccessor(gw));
}
}
} else if(flowNode instanceof Gateway) {
for (FlowNode flowNode2 : this.getDirectSuccessors(flowNode)) {
if (transition.getDescription().equalsIgnoreCase(flowNode2.getName())) {
Place p = new Place();
pn.addFlow(transition, p);
pn.addFlow(p, t1);
if(!(nodes3.contains(getFirstDirectSuccessor(gw)))) {
nodes3.add(getFirstDirectSuccessor(gw));
}
}
}
}
}
} else if(this.getFirstDirectSuccessor(gw) instanceof Gateway) {
for (FlowNode flowNode : nodes2) {
if(flowNode instanceof Activity) {
if (transition.getName().equalsIgnoreCase(flowNode.getName())) {
Place p = new Place();
pn.addFlow(transition, p);
pn.addFlow(p, t2);
if(!(nodes3.contains(gw))) {
nodes3.add(gw);
}
}
} else if(flowNode instanceof Gateway) {
if (transition.getDescription().equalsIgnoreCase(flowNode.getName())) {
Place p = new Place();
pn.addFlow(transition, p);
pn.addFlow(p, t2);
if(!(nodes3.contains(gw))) {
nodes3.add(gw);
}
}
}
}
}
}
for (FlowNode flowNode : nodes2) {
nodes1.remove(flowNode);
}
} else if(gw instanceof XorGateway) { //xor join
Transition t1 = new Transition(this.getFirstDirectSuccessor(gw).getName());
Transition t2 = new Transition();
t2.setDescription(gw.getName());
Place p = new Place();
for (Transition transition : pn.getSinkTransitions()) {
if(this.getFirstDirectSuccessor(gw) instanceof Activity) {
for (FlowNode flowNode : nodes2) {
if(flowNode instanceof Activity) {
if (transition.getName().equalsIgnoreCase(flowNode.getName())) {
pn.addFlow(transition, p);
pn.addFlow(p, t1);
if(!(nodes3.contains(getFirstDirectSuccessor(gw)))) {
nodes3.add(getFirstDirectSuccessor(gw));
}
}
} else if(flowNode instanceof Gateway) {
for (FlowNode flowNode2 : this.getDirectSuccessors(flowNode)) {
if (transition.getDescription().equalsIgnoreCase(flowNode2.getName())) {
pn.addFlow(transition, p);
pn.addFlow(p, t1);
if(!(nodes3.contains(getFirstDirectSuccessor(gw)))) {
nodes3.add(getFirstDirectSuccessor(gw));
}
}
}
}
}
} else if(this.getFirstDirectSuccessor(gw) instanceof Gateway) {
for (FlowNode flowNode : nodes2) {
if(flowNode instanceof Activity) {
if (transition.getName().equalsIgnoreCase(flowNode.getName())) {
pn.addFlow(transition, p);
pn.addFlow(p, t2);
if(!(nodes3.contains(gw))) {
nodes3.add(gw);
}
}
} else if(flowNode instanceof Gateway) {
if (transition.getDescription().equalsIgnoreCase(flowNode.getName())) {
pn.addFlow(transition, p);
pn.addFlow(p, t2);
if(!(nodes3.contains(gw))) {
nodes3.add(gw);
}
}
}
}
}
}
for (FlowNode flowNode : nodes2) {
nodes1.remove(flowNode);
}
}
} else {
nodes3.add(currentFlowNode);
}
} else if(this.getIncomingEdges(gw).size() > 1 && this.getOutgoingEdges(gw).size() > 1) { //split and join
//TODO
} else {
//at most one inc and one out
}
nodes2.clear();
}
if(nodes1.contains(currentFlowNode)) {
nodes1.remove(currentFlowNode);
}
}
nodes1.clear();
nodes2.clear();
nodes1.addAll(nodes3);
nodes3.clear();
}
for (Transition t : pn.getSinkTransitions()) {
pn.addFlow(t, new Place());
}
return pn;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy