/**
* Copyright 2010 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.jpdl;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.drools.definition.process.Connection;
import org.drools.definition.process.Node;
import org.drools.jpdl.core.JpdlProcess;
import org.drools.workflow.core.Constraint;
import org.drools.workflow.core.impl.ConnectionImpl;
import org.drools.workflow.core.impl.ConnectionRef;
import org.drools.workflow.core.impl.NodeImpl;
import org.drools.workflow.core.node.StateNode;
import org.jbpm.graph.def.Action;
import org.jbpm.instantiation.Delegation;
/**
*
* @author salaboy
*/
public class EpdlWriter {
private static int suggestedNodeId = 99;
public static void write(JpdlProcess process) {
Node[] nodes = process.getNodes();
int id = 0;
System.out.println("<process xmlns=\"http://drools.org/drools-5.0/process\""+
" xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\" "+
"xs:schemaLocation=\"http://drools.org/drools-5.0/process drools-processes-5.0.xsd\" " +
"type=\"RuleFlow\" name=\"flow\" id=\""+process.getName()+"\" package-name=\"org.drools.examples\" >");
System.out.println("<header>");
System.out.println("</header>");
//Print nodes and Connections
printNodesAndConnections(nodes);
System.out.println("</process>");
}
private static void printNodesAndConnections(Node[] nodes) {
String generatedConnections = "";
System.out.println("<nodes>");
for (Node node : nodes) {
//System.out.println("Node Type: "+node.getClass()+" - Name"+node.getName());
if (node instanceof org.drools.jpdl.core.node.StartState) {
System.out.println("<start id=\"" + node.getId() + "\" name=\"" + node.getName() + "\" />");
} else if (node instanceof org.drools.jpdl.core.node.Fork) {
System.out.println("<split id=\"" + node.getId() + "\" name=\"" + node.getName() + "\" type=\"1\" />");
} else if (node instanceof org.drools.jpdl.core.node.Join) {
System.out.println("<join id=\"" + node.getId() + "\" name=\"" + node.getName() + "\" type=\"1\" />");
} else if (node instanceof org.drools.jpdl.core.node.SuperState) {
generatedConnections += suggestSplitNode(node);
generatedConnections += suggestJoinNode(node);
System.out.println("<composite id=\""+ node.getId() +"\" name=\""+ node.getName() +"\">");
List<org.drools.jpdl.core.node.JpdlNode> nodesList = ((org.drools.jpdl.core.node.SuperState)node).getNodes();
printNodesAndConnections(nodesList.toArray(new Node[nodesList.size()]));
printInPortsAndOutPorts(nodesList.toArray(new Node[nodesList.size()]));
System.out.println("</composite>");
} else if (node instanceof org.drools.jpdl.core.node.State) {
generatedConnections += suggestJoinNode(node);
System.out.println("<state id=\"" + node.getId() + "\" name=\"" + node.getName() + "\" >");
System.out.println(" <constraints>");
Set<String> keys = node.getOutgoingConnections().keySet();
for (String key : keys) {
for (Connection connection : node.getOutgoingConnections(key)) {
System.out.println(" <constraint toNodeId=\"" + connection.getTo().getId() + "\" name=\"signalTo" + connection.getTo().getName() + "\" />");
}
}
System.out.println(" </constraints>");
System.out.println("</state>");
} else if (node instanceof org.drools.jpdl.core.node.Decision) {
System.out.println("<split id=\"" + node.getId() + "\" name=\"" + node.getName() + "\" type=\"2\" >");
System.out.println(" <constraints>");
Set<String> keys = node.getOutgoingConnections().keySet();
for (String key : keys) {
for (Connection connection : node.getOutgoingConnections(key)) {
System.out.println(" <constraint toNodeId=\"" + connection.getTo().getId() + "\" name=\"signalTo" + connection.getTo().getName() + "\" toType=\"DROOLS_DEFAULT\" type=\"rule\" dialect=\"java\" >");
//System.out.println(" "+"There is no way to get the conditions in each leavingTransition (depracated since 3.2 - http://docs.jboss.com/jbpm/v3.2/userguide/html_single/#condition.element)");
//System.out.println(" "+"There is no way to access the decision expresion or the decision delegation class through the APIs");
System.out.println(" </constraint>");
}
}
System.out.println(" </constraints>");
System.out.println("</split>");
} else if (node instanceof org.drools.jpdl.core.node.EndState) {
generatedConnections += suggestJoinNode(node);
System.out.println("<end id=\"" + node.getId() + "\" name=\"" + node.getName() + "\" />");
} else if (node instanceof org.drools.jpdl.core.node.JpdlNode) {
generatedConnections += suggestSplitNode(node);
generatedConnections += suggestJoinNode(node);
System.out.println("<actionNode id=\"" + node.getId() + "\" name=\"" + node.getName() + "\">");
System.out.println(" <action type=\"expression\" dialect=\"java\" >");
Action action = ((org.drools.jpdl.core.node.JpdlNode) node).getAction();
if (action != null) {
Delegation delegation = action.getActionDelegation();
if (delegation != null) {
// System.out.println("Introspect = "+delegation.getClassName());
// System.out.println("replaced"+delegation.getClassName().replace(".","/"));
// Resource resource = ResourceFactory.newInputStreamResource(EpdlWriter.class.getResourceAsStream(delegation.getClassName().replace(".","/")));
// System.out.println(""+resource);
// System.out.println("Paste the content of the execute() method of the class"+delegation.getClassName());
}
}
System.out.println(" </action>");
System.out.println("</actionNode>");
}
}
System.out.println("</nodes>");
System.out.println("<connections>");
for (Node node : nodes) {
Map<String, List<Connection>> outConnections = node.getOutgoingConnections();
Set<String> keys = outConnections.keySet();
if(keys.size() == 0){
break;
}
for (String key : keys) {
List<Connection> connections = outConnections.get(key);
for (Connection connection : connections) {
System.out.println(" <connection from=\"" + node.getId() + "\" to=\"" + connection.getTo().getId() + "\" />");
}
}
}
if(!generatedConnections.equals("")){
System.out.println("<!-- Generated Connection for suggested nodes -->");
System.out.println(generatedConnections);
System.out.println("<!-- END - Generated Connection for suggested nodes -->");
}
System.out.println("</connections>");
}
private static String suggestJoinNode(Node node) {
String resultGeneratedConnection = "";
Set<String> incomingConnectionsTypes = node.getIncomingConnections().keySet();
//Probably we are inside a composite node or in a disconected node (??)
if(incomingConnectionsTypes.size()== 0){
return "";
}
String firstKey = incomingConnectionsTypes.iterator().next();
boolean suggestJoinNode = false;
if (incomingConnectionsTypes.size() > 1) {
suggestJoinNode = true;
} else if (incomingConnectionsTypes.size() == 1 && node.getIncomingConnections().get(firstKey).size() > 1) {
suggestJoinNode = true;
}
if (suggestJoinNode) {
System.out.println("<!-- This is a suggested Join Node -->");
System.out.println("<join id=\"" + (suggestedNodeId) + "\" name=\"Join XOR - "+suggestedNodeId+"\" type=\"2\" />");
for (String key : incomingConnectionsTypes) {
Iterator<Connection> itConnections = node.getIncomingConnections(key).iterator();
long fromNodeId = 0;
while (itConnections.hasNext()) {
Connection connection = itConnections.next();
Node fromNode = connection.getFrom();
fromNodeId = connection.getTo().getId();
if(fromNode instanceof org.drools.jpdl.core.node.State){
System.out.println("<!-- Take a look at the State Node that is pointing here, " +
"you will need to change the constraint for signal it to the new JoinNode id -->");
System.out.println("<!-- in node id: "+fromNode.getId()+ " / name: "+fromNode.getName()+" -->");
System.out.println("<!-- you should change the fromId ("+fromNodeId+") attribute to: "+suggestedNodeId+"-->");
System.out.println("<!-- you can also change the name for something that reference the JoinNode -->");
}
fromNode.getOutgoingConnections(key).remove(connection);
resultGeneratedConnection += " <connection from=\"" + fromNode.getId() + "\" to=\"" + suggestedNodeId + "\" />\n";
}
resultGeneratedConnection += " <connection from=\"" + suggestedNodeId + "\" to=\"" + fromNodeId + "\" />\n";
}
System.out.println("<!-- END - This is a suggested Join Node -->");
suggestedNodeId++;
}
return resultGeneratedConnection;
}
private static String suggestSplitNode(Node node) {
String resultGeneratedConnection = "";
Set<String> outgoingConnectionsTypes = node.getOutgoingConnections().keySet();
//Probably we are inside a composite node or in a disconected node (??)
if(outgoingConnectionsTypes.size()== 0){
return "";
}
String firstKey = outgoingConnectionsTypes.iterator().next();
boolean suggestSplitNode = false;
if (outgoingConnectionsTypes.size() > 1) {
suggestSplitNode = true;
} else if (outgoingConnectionsTypes.size() == 1 && node.getOutgoingConnections().get(firstKey).size() > 1) {
suggestSplitNode = true;
}
if(suggestSplitNode){
System.out.println("<!-- This is a suggested Split Node -->");
System.out.println("<split id=\"" + (suggestedNodeId) + "\" name=\"Split XOR - "+suggestedNodeId+"\" type=\"2\" >");
System.out.println(" <constraints>");
Set<String> keys = node.getOutgoingConnections().keySet();
for(String key: keys){
for (Connection connection: node.getOutgoingConnections(key)) {
System.out.println(" <constraint toNodeId=\""+connection.getTo().getId()+"\" name=\"signalTo"+connection.getTo().getName()+
"\" toType=\"DROOLS_DEFAULT\" type=\"rule\" dialect=\"java\" >");
//System.out.println(" "+"There is no way to get the conditions in each leavingTransition (depracated since 3.2 - http://docs.jboss.com/jbpm/v3.2/userguide/html_single/#condition.element)");
//System.out.println(" "+"There is no way to access the decision expresion or the decision delegation class through the APIs");
System.out.println(" </constraint>");
}
}
System.out.println(" </constraints>");
System.out.println("</split>");
System.out.println("<!-- END - This is a suggested Split Node -->");
List<Connection> removeConnections = new ArrayList<Connection>();
for (String key : outgoingConnectionsTypes) {
Iterator<Connection> itConnections = node.getOutgoingConnections(key).iterator();
while (itConnections.hasNext()) {
Connection connection = itConnections.next();
Node toNode = connection.getTo();
removeConnections.add(connection);
resultGeneratedConnection += " <connection from=\"" + suggestedNodeId + "\" to=\"" + toNode.getId() + "\" />\n";
}
}
resultGeneratedConnection += " <connection from=\"" + node.getId() + "\" to=\"" + suggestedNodeId + "\" />\n";
suggestedNodeId++;
for(Connection conn : removeConnections){
node.getOutgoingConnections(conn.getFromType()).remove(conn);
}
}
return resultGeneratedConnection;
}
private static void printInPortsAndOutPorts(Node[] toArray) {
int lastNode = 0;
if(toArray.length > 1){
lastNode = toArray.length -1;
}
System.out.println("<in-ports>");
System.out.println(" <in-port type=\"DROOLS_DEFAULT\" nodeId=\""+toArray[0].getId()+"\" nodeInType=\"DROOLS_DEFAULT\" />");
System.out.println("</in-ports>");
System.out.println("<out-ports>");
System.out.println(" <out-port type=\"DROOLS_DEFAULT\" nodeId=\""+toArray[lastNode].getId()+"\" nodeOutType=\"DROOLS_DEFAULT\" />");
System.out.println("</out-ports>");
}
}