/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.foundation.bpel; import java.util.Vector; import org.openflexo.antar.Assignment; import org.openflexo.antar.Conditional; import org.openflexo.antar.ControlGraph; import org.openflexo.antar.Flow; import org.openflexo.antar.Nop; import org.openflexo.antar.Sequence; import org.openflexo.antar.expr.DefaultExpressionParser; import org.openflexo.antar.expr.Expression; import org.openflexo.antar.expr.Variable; import org.openflexo.foundation.bindings.AbstractBinding; import org.openflexo.foundation.bindings.BindingAssignment; import org.openflexo.foundation.bindings.BindingExpression; import org.openflexo.foundation.bindings.BindingValue; import org.openflexo.foundation.bindings.StaticBinding; import org.openflexo.foundation.exec.ControlGraphBuilder; import org.openflexo.foundation.exec.InvalidModelException; import org.openflexo.foundation.exec.NotSupportedException; import org.openflexo.foundation.wkf.edge.FlexoPostCondition; import org.openflexo.foundation.wkf.node.ANDOperator; import org.openflexo.foundation.wkf.node.AbstractNode; import org.openflexo.foundation.wkf.node.ActivityNode; import org.openflexo.foundation.wkf.node.FlexoNode; import org.openflexo.foundation.wkf.node.IFOperator; import org.openflexo.foundation.wkf.node.OperatorNode; import org.openflexo.foundation.wkf.node.SelfExecutableActivityNode; import org.openflexo.foundation.wkf.ws.AbstractInPort; import org.openflexo.foundation.wkf.ws.FlexoPort; import org.openflexo.foundation.wkf.ws.FlexoPortMap; import org.openflexo.foundation.wkf.ws.OutputPort; public class BPELControlGraphBuilder extends ControlGraphBuilder { AbstractInPort operationPortIN; OutputPort operationPortOUT; boolean portReached = false; boolean debug = true; public BPELControlGraphBuilder(AbstractInPort pIN, OutputPort pOUT) { operationPortIN = pIN; operationPortOUT = pOUT; } @Override protected String getProcedureName() { // TODO Auto-generated method stub return null; } @Override public ControlGraph makeControlGraph(boolean interprocedural) throws InvalidModelException, NotSupportedException { // start with the Port if (operationPortIN == null) { throw new BPELInvalidModelException("No port defined for Flexo Process"); } BPELNodeAccu acc = new BPELNodeAccu(); ControlGraph toReturn = handleNode(operationPortIN, acc); return toReturn; } protected ControlGraph handleSequence(AbstractNode n, BPELNodeAccu acc) throws NotSupportedException, BPELInvalidModelException { Sequence toReturn = new Sequence(); AbstractNode currentNode = n; System.out.println("Handling sequence starting at : " + currentNode.getName()); /* a sequence stops when * - The outport is reached * - A AND node is reached * - several edges enter the same node (case of a if) */ while (!(currentNode instanceof FlexoPort) && !(acc.lookingForAnd() && currentNode instanceof ANDOperator) && !(acc.lookingForIf() && getIncomingEdges(currentNode) != 1)) { ControlGraph toAdd = handleNode(currentNode, acc); if (toAdd != null) { toReturn.addToStatements(toAdd); } if (acc.getNodes().size() > 1) { toReturn.addToStatements(handleFlow(acc)); } currentNode = acc.getNodes().get(0); if (acc.hasBeenHandled(currentNode)) { throw new BPELInvalidModelException("A cycle has been detected in your Flexo Model"); } } if (debug) { System.out.println("SEQUENCE RETURNING"); } return toReturn; } protected ControlGraph handleFlow(BPELNodeAccu acc) throws BPELInvalidModelException, NotSupportedException { Flow toReturn = new Flow(); acc.setLookingForAnd(true); for (AbstractNode n : acc.getNodes()) { toReturn.addToStatements(handleSequence(n, acc)); } acc.setLookingForAnd(false); if (debug) { System.out.println("FLOW RETURNING ON NODE"); } return toReturn; } protected Vector<AbstractNode> getNextNodes(AbstractNode n) throws BPELInvalidModelException { Vector<AbstractNode> toReturn = new Vector<AbstractNode>(); for (FlexoPostCondition p : n.getOutgoingPostConditions()) { toReturn.add(p.getNextNode()); } if (toReturn.size() == 0) { throw new BPELInvalidModelException("Every possible path in the Workflow must lean to the IN/OUT port; Node " + n.getName() + " has no outgoing edge"); } return toReturn; } protected int getIncomingEdges(AbstractNode n) throws BPELInvalidModelException { if (n instanceof ActivityNode) { if (((ActivityNode) n).getPreConditions().size() != 1) { throw new BPELInvalidModelException("Every ActivityNode must have only one precondition"); } return ((ActivityNode) n).getPreConditions().get(0).getIncomingPostConditions().size(); } else { System.out.println("incoming edges of " + n.getName() + " : " + n.getIncomingPostConditions().size()); return n.getIncomingPostConditions().size(); } } protected ControlGraph handleNode(FlexoPort port, BPELNodeAccu acc) throws BPELInvalidModelException, NotSupportedException { if (portReached) { return null; } portReached = true; // A port can be seen as a single instruction that does stuff // like an API... BPELWSAPI toReturn = new BPELWSAPI(port); Vector<FlexoPostCondition<AbstractNode, AbstractNode>> postConditions = port.getOutgoingPostConditions(); if (postConditions.size() != 1) { throw new BPELInvalidModelException("There must be one and only one edge coming out of a port."); } if (postConditions.get(0).getEndNode() == null || postConditions.get(0).getNextNode() == null) { throw new BPELInvalidModelException("Every edge leaving a port must be connected"); } AbstractNode nodeInSequence = postConditions.get(0).getNextNode(); toReturn.setControlGraph(handleSequence(nodeInSequence, new BPELNodeAccu())); return toReturn; } protected ControlGraph handleNode(SelfExecutableActivityNode n, BPELNodeAccu acc) throws BPELInvalidModelException { acc.setNodes(getNextNodes(n)); Vector<BindingAssignment> assignments = n.getAssignments(); if (assignments == null || assignments.size() == 0) { return new Nop(); } if (assignments.size() == 1) { Assignment toReturn = getAssignment(assignments.get(0)); return toReturn; } else { Sequence toReturn = new Sequence(); for (int i = 0; i < assignments.size(); i++) { Assignment currentAssignment = getAssignment(assignments.get(i)); toReturn.addToStatements(currentAssignment); } return toReturn; } } private Assignment getAssignment(BindingAssignment a) { BindingValue target = a.getReceiver(); Variable receiver = new Variable(BPELPrettyPrinter.getInstance().makeStringRepresentation(target)); AbstractBinding value = a.getValue(); Expression expr = null; if (value instanceof BindingExpression) { expr = ((BindingExpression) value).getExpression(); } if (value instanceof BindingValue) { Variable var = new Variable(BPELPrettyPrinter.getInstance().makeStringRepresentation((BindingValue) value)); expr = var; } else if (value instanceof StaticBinding) { expr = new Variable((String) ((StaticBinding) value).getValue()); } else { try { expr = new DefaultExpressionParser().parse(value.toString(), null); } catch (Exception e) { System.out.println("Could not parse expression... " + value.toString()); e.printStackTrace(); } } return new Assignment(receiver, expr); // a.getValue().g /* System.out.println("String rep of target : "+target.getStringRepresentation()); String sTarget="processInstance"; for (BindingPathElement el: target.getBindingPath()) { sTarget+=".{"+el.getEntity().getFullQualifiedName()+"}"+el.getSerializationRepresentation(); } System.out.println("sTarget : "+sTarget); */ /* System.out.println("Entity : "+ ent.getFullQualifiedName()+ " "+ent.getFullyQualifiedName()); System.out.println("parent entity :"+ent.getParentBaseEntity().getFullQualifiedName()); */ } protected ControlGraph handleNode(OperatorNode n, BPELNodeAccu acc) throws NotSupportedException, BPELInvalidModelException { if (n instanceof IFOperator) { IFOperator ifOp = (IFOperator) n; // need a condition // a then statement // and a else statement Expression condition = null; ControlGraph thenClause = null; ControlGraph elseClause = null; if (ifOp.getPositiveEvaluationPostConditions().size() != 1 || ifOp.getNegativeEvaluationPostConditions().size() != 1) { throw new BPELInvalidModelException("If operator should have 2 outgoing edges: 1 true and 1 false"); } FlexoPostCondition trueCond = ifOp.getPositiveEvaluationPostConditions().firstElement(); FlexoPostCondition falseCond = ifOp.getNegativeEvaluationPostConditions().firstElement(); acc.setLookingForIf(true); thenClause = handleSequence(trueCond.getNextNode(), acc); elseClause = handleSequence(falseCond.getNextNode(), acc); acc.setLookingForIf(false); if (ifOp.getConditionPrimitive() instanceof BindingExpression) { BindingExpression expression = (BindingExpression) ifOp.getConditionPrimitive(); condition = expression.getExpression(); } Conditional toReturn = new Conditional(condition, thenClause, elseClause); return toReturn; } else if (n instanceof ANDOperator) { acc.setNodes(getNextNodes(n)); return null; } else { throw new NotSupportedException("Operator " + n.getClass().getName() + " is not supported..."); } } protected ControlGraph handleNode(FlexoPortMap n, BPELNodeAccu acc) throws BPELInvalidModelException { acc.setNodes(getNextNodes(n)); BPELWSInvocation invoc = new BPELWSInvocation(n.getSubProcessNode()); System.out.println("added service invocation"); if (n.getSubProcessNode().getActivationAssignments() != null && n.getSubProcessNode().getActivationAssignments().size() > 0 || n.getSubProcessNode().getDesactivationAssignments() != null && n.getSubProcessNode().getDesactivationAssignments().size() > 0) { Sequence seq = new Sequence(); if (n.getSubProcessNode().getActivationAssignments() != null) { for (BindingAssignment ba : n.getSubProcessNode().getActivationAssignments()) { Assignment a = getAssignment(ba); seq.addToStatements(a); } } seq.addToStatements(invoc); if (n.getSubProcessNode().getActivationAssignments() != null) { for (BindingAssignment ba : n.getSubProcessNode().getDesactivationAssignments()) { Assignment a = getAssignment(ba); seq.addToStatements(a); } } return seq; } else { return invoc; } } protected ControlGraph handleNode(ActivityNode n, BPELNodeAccu acc) throws BPELInvalidModelException, NotSupportedException { // we should create here an invocation object... which we will leave empty, but to show that the user has to do something here. System.out.println("Handling activity : " + n.getName()); Vector<FlexoNode> endNodes = n.getOperationPetriGraph().getAllEndNodes(); if (endNodes.size() == 1) { acc.setNodes(getNextNodes(endNodes.get(0))); return new BPELWSInvocation(); } if (endNodes.size() == 2) { Sequence toReturn = new Sequence(); toReturn.addToStatements(new BPELWSInvocation()); // in this case, we will create a if with no condition for now. acc.setLookingForIf(true); System.out.println("2 edges at Activity :" + endNodes.get(0).getName() + " " + endNodes.get(1).getName()); System.out.println(" End Nodes :" + getNextNodes(endNodes.get(0)).get(0).getClass().getName() + " " + getNextNodes(endNodes.get(1)).get(0).getClass().getName()); ControlGraph firstCase = handleSequence(getNextNodes(endNodes.get(0)).get(0), acc); ControlGraph secondCase = handleSequence(getNextNodes(endNodes.get(1)).get(0), acc); acc.setLookingForIf(false); Conditional cond = new Conditional(null, firstCase, secondCase); toReturn.addToStatements(cond); return toReturn; } else { throw new BPELInvalidModelException("When generating BPEL, there can be only one or two endNodes inside an Activity"); } } protected ControlGraph handleNode(AbstractNode n, BPELNodeAccu acc) throws BPELInvalidModelException, NotSupportedException { if (n instanceof FlexoPort) { return handleNode((FlexoPort) n, acc); } acc.nodeIsHandled(n); if (n instanceof SelfExecutableActivityNode) { return handleNode((SelfExecutableActivityNode) n, acc); } if (n instanceof OperatorNode) { return handleNode((OperatorNode) n, acc); } if (n instanceof FlexoPortMap) { return handleNode((FlexoPortMap) n, acc); } if (n instanceof ActivityNode) { return handleNode((ActivityNode) n, acc); } throw new NotSupportedException("The FlexoNode " + n.getClass().getName() + " is not supported for BPEL generation"); } }