/machinelearning/5.0.x/drools-core/src/main/java/org/drools/workflow/core/node/CompositeNode.java

https://github.com/etirelli/droolsjbpm-contributed-experiments · Java · 456 lines · 386 code · 60 blank · 10 comment · 100 complexity · 0fcfa5ab7d957a628a1a2f58b065706c MD5 · raw file

  1. package org.drools.workflow.core.node;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.List;
  5. import java.util.Map;
  6. import org.drools.definition.process.Connection;
  7. import org.drools.definition.process.Node;
  8. import org.drools.workflow.core.NodeContainer;
  9. import org.drools.workflow.core.impl.ConnectionImpl;
  10. import org.drools.workflow.core.impl.NodeContainerImpl;
  11. import org.drools.workflow.core.impl.NodeImpl;
  12. /**
  13. *
  14. * @author <a href="mailto:kris_verlaenen@hotmail.com">Kris Verlaenen</a>
  15. */
  16. public class CompositeNode extends NodeImpl implements NodeContainer, EventNodeInterface {
  17. private static final long serialVersionUID = 400L;
  18. private org.drools.workflow.core.NodeContainer nodeContainer;
  19. private Map<String, CompositeNode.NodeAndType> inConnectionMap = new HashMap<String, CompositeNode.NodeAndType>();
  20. private Map<String, CompositeNode.NodeAndType> outConnectionMap = new HashMap<String, CompositeNode.NodeAndType>();
  21. public CompositeNode() {
  22. this.nodeContainer = new NodeContainerImpl();
  23. }
  24. public Node getNode(long id) {
  25. return nodeContainer.getNode(id);
  26. }
  27. public Node internalGetNode(long id) {
  28. return getNode(id);
  29. }
  30. public Node[] getNodes() {
  31. List<Node> subNodes = new ArrayList<Node>();
  32. for (Node node: nodeContainer.getNodes()) {
  33. if (!(node instanceof CompositeNode.CompositeNodeStart) &&
  34. !(node instanceof CompositeNode.CompositeNodeEnd)) {
  35. subNodes.add(node);
  36. }
  37. }
  38. return subNodes.toArray(new Node[subNodes.size()]);
  39. }
  40. public void addNode(Node node) {
  41. // TODO find a more elegant solution for this
  42. // preferrable remove id setting from this class
  43. // and delegate to GUI command that drops node
  44. if (node.getId() <= 0) {
  45. long id = 0;
  46. for (Node n: nodeContainer.getNodes()) {
  47. if (n.getId() > id) {
  48. id = n.getId();
  49. }
  50. }
  51. ((org.drools.workflow.core.Node) node).setId(++id);
  52. }
  53. nodeContainer.addNode(node);
  54. ((org.drools.workflow.core.Node) node).setNodeContainer(this);
  55. }
  56. protected void internalAddNode(Node node) {
  57. addNode(node);
  58. }
  59. public void removeNode(Node node) {
  60. nodeContainer.removeNode(node);
  61. ((org.drools.workflow.core.Node) node).setNodeContainer(null);
  62. }
  63. protected void internalRemoveNode(Node node) {
  64. removeNode(node);
  65. }
  66. public boolean acceptsEvent(String type, Object event) {
  67. for (Node node: getNodes()) {
  68. if (node instanceof EventNodeInterface) {
  69. if (((EventNodeInterface) node).acceptsEvent(type, event)) {
  70. return true;
  71. }
  72. }
  73. }
  74. return false;
  75. }
  76. public void linkIncomingConnections(String inType, long inNodeId, String inNodeType) {
  77. linkIncomingConnections(inType, new NodeAndType(inNodeId, inNodeType));
  78. }
  79. public void linkIncomingConnections(String inType, CompositeNode.NodeAndType inNode) {
  80. CompositeNode.NodeAndType oldNodeAndType = inConnectionMap.get(inType);
  81. if (oldNodeAndType != null) {
  82. if (oldNodeAndType.equals(inNode)) {
  83. return;
  84. } else {
  85. // remove old start nodes + connections
  86. List<Connection> oldInConnections =
  87. oldNodeAndType.getNode().getIncomingConnections(oldNodeAndType.getType());
  88. if (oldInConnections != null) {
  89. for (Connection connection: new ArrayList<Connection>(oldInConnections)) {
  90. if (connection.getFrom() instanceof CompositeNodeStart) {
  91. removeNode(connection.getFrom());
  92. ((ConnectionImpl) connection).terminate();
  93. }
  94. }
  95. }
  96. }
  97. }
  98. inConnectionMap.put(inType, inNode);
  99. if (inNode != null) {
  100. List<Connection> connections = getIncomingConnections(inType);
  101. for (Connection connection: connections) {
  102. CompositeNodeStart start = new CompositeNodeStart(connection.getFrom(), inType);
  103. internalAddNode(start);
  104. if (inNode.getNode() != null) {
  105. new ConnectionImpl(
  106. start, org.drools.workflow.core.Node.CONNECTION_DEFAULT_TYPE,
  107. inNode.getNode(), inNode.getType());
  108. }
  109. }
  110. }
  111. }
  112. public void linkOutgoingConnections(long outNodeId, String outNodeType, String outType) {
  113. linkOutgoingConnections(new NodeAndType(outNodeId, outNodeType), outType);
  114. }
  115. public void linkOutgoingConnections(CompositeNode.NodeAndType outNode, String outType) {
  116. CompositeNode.NodeAndType oldNodeAndType = outConnectionMap.get(outType);
  117. if (oldNodeAndType != null) {
  118. if (oldNodeAndType.equals(outNode)) {
  119. return;
  120. } else {
  121. // remove old end nodes + connections
  122. List<Connection> oldOutConnections =
  123. oldNodeAndType.getNode().getOutgoingConnections(oldNodeAndType.getType());
  124. for (Connection connection: new ArrayList<Connection>(oldOutConnections)) {
  125. if (connection.getTo() instanceof CompositeNodeEnd) {
  126. removeNode(connection.getTo());
  127. ((ConnectionImpl) connection).terminate();
  128. }
  129. }
  130. }
  131. }
  132. outConnectionMap.put(outType, outNode);
  133. if (outNode != null) {
  134. List<Connection> connections = getOutgoingConnections(outType);
  135. for (Connection connection: connections) {
  136. CompositeNodeEnd end = new CompositeNodeEnd(connection.getTo(), outType);
  137. internalAddNode(end);
  138. if (outNode.getNode() != null) {
  139. new ConnectionImpl(
  140. outNode.getNode(), outNode.getType(),
  141. end, org.drools.workflow.core.Node.CONNECTION_DEFAULT_TYPE);
  142. }
  143. }
  144. }
  145. }
  146. public CompositeNode.NodeAndType getLinkedIncomingNode(String inType) {
  147. return inConnectionMap.get(inType);
  148. }
  149. public CompositeNode.NodeAndType internalGetLinkedIncomingNode(String inType) {
  150. return inConnectionMap.get(inType);
  151. }
  152. public CompositeNode.NodeAndType getLinkedOutgoingNode(String outType) {
  153. return outConnectionMap.get(outType);
  154. }
  155. public CompositeNode.NodeAndType internalGetLinkedOutgoingNode(String outType) {
  156. return outConnectionMap.get(outType);
  157. }
  158. public Map<String, CompositeNode.NodeAndType> getLinkedIncomingNodes() {
  159. return inConnectionMap;
  160. }
  161. public Map<String, CompositeNode.NodeAndType> getLinkedOutgoingNodes() {
  162. return outConnectionMap;
  163. }
  164. public void validateAddIncomingConnection(final String type, final Connection connection) {
  165. CompositeNode.NodeAndType nodeAndType = internalGetLinkedIncomingNode(type);
  166. if (connection.getFrom().getNodeContainer() == this) {
  167. if (nodeAndType != null) {
  168. throw new IllegalArgumentException("Cannot link incoming connection type more than once: " + type);
  169. }
  170. } else {
  171. if (nodeAndType != null) {
  172. NodeImpl node = (NodeImpl) nodeAndType.getNode();
  173. if (node != null) {
  174. node.validateAddIncomingConnection(nodeAndType.getType(), connection);
  175. }
  176. }
  177. }
  178. }
  179. public void addIncomingConnection(String type, Connection connection) {
  180. if (connection.getFrom().getNodeContainer() == this) {
  181. linkOutgoingConnections(connection.getFrom().getId(), connection.getFromType(), org.drools.workflow.core.Node.CONNECTION_DEFAULT_TYPE);
  182. } else {
  183. super.addIncomingConnection(type, connection);
  184. CompositeNode.NodeAndType inNode = internalGetLinkedIncomingNode(type);
  185. if (inNode != null) {
  186. CompositeNodeStart start = new CompositeNodeStart(connection.getFrom(), type);
  187. internalAddNode(start);
  188. NodeImpl node = (NodeImpl) inNode.getNode();
  189. if (node != null) {
  190. new ConnectionImpl(
  191. start, org.drools.workflow.core.Node.CONNECTION_DEFAULT_TYPE,
  192. inNode.getNode(), inNode.getType());
  193. }
  194. }
  195. }
  196. }
  197. public void validateAddOutgoingConnection(final String type, final Connection connection) {
  198. CompositeNode.NodeAndType nodeAndType = internalGetLinkedOutgoingNode(type);
  199. if (connection.getTo().getNodeContainer() == this) {
  200. if (nodeAndType != null) {
  201. throw new IllegalArgumentException("Cannot link outgoing connection type more than once: " + type);
  202. }
  203. } else {
  204. if (nodeAndType != null) {
  205. NodeImpl node = (NodeImpl) nodeAndType.getNode();
  206. if (node != null) {
  207. ((NodeImpl) nodeAndType.getNode()).validateAddOutgoingConnection(nodeAndType.getType(), connection);
  208. }
  209. }
  210. }
  211. }
  212. public void addOutgoingConnection(String type, Connection connection) {
  213. if (connection.getTo().getNodeContainer() == this) {
  214. linkIncomingConnections(
  215. org.drools.workflow.core.Node.CONNECTION_DEFAULT_TYPE,
  216. connection.getTo().getId(), connection.getToType());
  217. } else {
  218. super.addOutgoingConnection(type, connection);
  219. CompositeNode.NodeAndType outNode = internalGetLinkedOutgoingNode(type);
  220. if (outNode != null) {
  221. CompositeNodeEnd end = new CompositeNodeEnd(connection.getTo(), type);
  222. internalAddNode(end);
  223. NodeImpl node = (NodeImpl) outNode.getNode();
  224. if (node != null) {
  225. new ConnectionImpl(
  226. outNode.getNode(), outNode.getType(),
  227. end, org.drools.workflow.core.Node.CONNECTION_DEFAULT_TYPE);
  228. }
  229. }
  230. }
  231. }
  232. public void validateRemoveIncomingConnection(final String type, final Connection connection) {
  233. CompositeNode.NodeAndType nodeAndType = internalGetLinkedIncomingNode(type);
  234. if (nodeAndType != null) {
  235. for (Connection inConnection: nodeAndType.getNode().getIncomingConnections(nodeAndType.getType())) {
  236. if (((CompositeNodeStart) inConnection.getFrom()).getInNodeId() == connection.getFrom().getId()) {
  237. ((NodeImpl) nodeAndType.getNode()).validateRemoveIncomingConnection(nodeAndType.getType(), inConnection);
  238. return;
  239. }
  240. }
  241. throw new IllegalArgumentException(
  242. "Could not find internal incoming connection for node");
  243. }
  244. }
  245. public void removeIncomingConnection(String type, Connection connection) {
  246. super.removeIncomingConnection(type, connection);
  247. CompositeNode.NodeAndType nodeAndType = internalGetLinkedIncomingNode(type);
  248. if (nodeAndType != null) {
  249. for (Connection inConnection: nodeAndType.getNode().getIncomingConnections(nodeAndType.getType())) {
  250. if (((CompositeNodeStart) inConnection.getFrom()).getInNodeId() == connection.getFrom().getId()) {
  251. Node compositeNodeStart = inConnection.getFrom();
  252. ((ConnectionImpl) inConnection).terminate();
  253. internalRemoveNode(compositeNodeStart);
  254. return;
  255. }
  256. }
  257. throw new IllegalArgumentException(
  258. "Could not find internal incoming connection for node");
  259. }
  260. }
  261. public void validateRemoveOutgoingConnection(final String type, final Connection connection) {
  262. CompositeNode.NodeAndType nodeAndType = internalGetLinkedOutgoingNode(type);
  263. if (nodeAndType != null) {
  264. for (Connection outConnection: nodeAndType.getNode().getOutgoingConnections(nodeAndType.getType())) {
  265. if (((CompositeNodeEnd) outConnection.getTo()).getOutNodeId() == connection.getTo().getId()) {
  266. ((NodeImpl) nodeAndType.getNode()).validateRemoveOutgoingConnection(nodeAndType.getType(), outConnection);
  267. return;
  268. }
  269. }
  270. throw new IllegalArgumentException(
  271. "Could not find internal outgoing connection for node");
  272. }
  273. }
  274. public void removeOutgoingConnection(String type, Connection connection) {
  275. super.removeOutgoingConnection(type, connection);
  276. CompositeNode.NodeAndType nodeAndType = internalGetLinkedOutgoingNode(type);
  277. if (nodeAndType != null) {
  278. for (Connection outConnection: nodeAndType.getNode().getOutgoingConnections(nodeAndType.getType())) {
  279. if (((CompositeNodeEnd) outConnection.getTo()).getOutNodeId() == connection.getTo().getId()) {
  280. Node compositeNodeEnd = outConnection.getTo();
  281. ((ConnectionImpl) outConnection).terminate();
  282. internalRemoveNode(compositeNodeEnd);
  283. return;
  284. }
  285. }
  286. throw new IllegalArgumentException(
  287. "Could not find internal outgoing connection for node");
  288. }
  289. }
  290. public class NodeAndType {
  291. private long nodeId;
  292. private String type;
  293. private transient Node node;
  294. public NodeAndType(long nodeId, String type) {
  295. if (type == null) {
  296. throw new IllegalArgumentException(
  297. "Node or type may not be null!");
  298. }
  299. this.nodeId = nodeId;
  300. this.type = type;
  301. }
  302. public NodeAndType(Node node, String type) {
  303. if (node == null || type == null) {
  304. throw new IllegalArgumentException(
  305. "Node or type may not be null!");
  306. }
  307. this.nodeId = node.getId();
  308. this.node = node;
  309. this.type = type;
  310. }
  311. public Node getNode() {
  312. if (node == null) {
  313. try {
  314. node = nodeContainer.getNode(nodeId);
  315. } catch (IllegalArgumentException e) {
  316. // unknown node id, returning null
  317. }
  318. }
  319. return node;
  320. }
  321. public long getNodeId() {
  322. return nodeId;
  323. }
  324. public String getType() {
  325. return type;
  326. }
  327. public boolean equals(Object o) {
  328. if (o instanceof NodeAndType) {
  329. return nodeId == ((NodeAndType) o).nodeId
  330. && type.equals(((NodeAndType) o).type);
  331. }
  332. return false;
  333. }
  334. public int hashCode() {
  335. return 7*(int)nodeId + 13*type.hashCode();
  336. }
  337. }
  338. public class CompositeNodeStart extends NodeImpl {
  339. private static final long serialVersionUID = 400L;
  340. private long inNodeId;
  341. private transient Node inNode;
  342. private String inType;
  343. public CompositeNodeStart(Node outNode, String outType) {
  344. setName("Composite node start");
  345. this.inNodeId = outNode.getId();
  346. this.inNode = outNode;
  347. this.inType = outType;
  348. setMetaData("hidden", true);
  349. }
  350. public Node getInNode() {
  351. if (inNode == null) {
  352. inNode = getNodeContainer().getNode(inNodeId);
  353. }
  354. return inNode;
  355. }
  356. public long getInNodeId() {
  357. return inNodeId;
  358. }
  359. public String getInType() {
  360. return inType;
  361. }
  362. public Connection getTo() {
  363. final List<Connection> list =
  364. getOutgoingConnections(org.drools.workflow.core.Node.CONNECTION_DEFAULT_TYPE);
  365. if (list.size() > 0) {
  366. return (Connection) list.get(0);
  367. }
  368. return null;
  369. }
  370. }
  371. public class CompositeNodeEnd extends NodeImpl {
  372. private static final long serialVersionUID = 400L;
  373. private long outNodeId;
  374. private transient Node outNode;
  375. private String outType;
  376. public CompositeNodeEnd(Node outNode, String outType) {
  377. setName("Composite node end");
  378. this.outNodeId = outNode.getId();
  379. this.outNode = outNode;
  380. this.outType = outType;
  381. setMetaData("hidden", true);
  382. }
  383. public Node getOutNode() {
  384. if (outNode == null) {
  385. outNode = getNodeContainer().getNode(outNodeId);
  386. }
  387. return outNode;
  388. }
  389. public long getOutNodeId() {
  390. return outNodeId;
  391. }
  392. public String getOutType() {
  393. return outType;
  394. }
  395. }
  396. }