/** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.airavata.workflow.engine.interpretor; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.apache.airavata.workflow.engine.invoker.Invoker; import org.apache.airavata.workflow.engine.util.InterpreterUtil; import org.apache.airavata.workflow.model.component.Component; import org.apache.airavata.workflow.model.component.ws.WSComponent; import org.apache.airavata.workflow.model.exceptions.WorkflowException; import org.apache.airavata.workflow.model.exceptions.WorkflowRuntimeException; import org.apache.airavata.workflow.model.graph.ControlPort; import org.apache.airavata.workflow.model.graph.DataPort; import org.apache.airavata.workflow.model.graph.Node; import org.apache.airavata.workflow.model.graph.Node.NodeExecutionState; import org.apache.airavata.workflow.model.graph.impl.EdgeImpl; import org.apache.airavata.workflow.model.graph.system.DoWhileNode; import org.apache.airavata.workflow.model.graph.system.EndDoWhileNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DoWhileHandler implements Callable<Boolean> { private static Logger log = LoggerFactory.getLogger(DoWhileHandler.class); private DoWhileNode dowhilenode; private Map<Node, Invoker> invokerMap; private ArrayList<Node> waitingNode; private ArrayList<Node> finishedNodes; private WorkflowInterpreter interpreter; private ExecutorService threadExecutor; /** * * Constructs a DoWhileHandler. * * @param node * @param invokerMap * @param waitingNode * @param finishedNodes * @param interpreter */ public DoWhileHandler(DoWhileNode node, Map<Node, Invoker> invokerMap, ArrayList<Node> waitingNode, ArrayList<Node> finishedNodes, WorkflowInterpreter interpreter, ExecutorService threadExecutor) { this.dowhilenode = node; this.invokerMap = invokerMap; this.waitingNode = waitingNode; this.finishedNodes = finishedNodes; this.interpreter = interpreter; this.threadExecutor = threadExecutor; } /** * To evaluate dowhile condition with the input values * * @param doWhileNode * @param inputPorts * @param invokerMap * @return boolean value * @throws WorkFlowInterpreterException * @throws XBayaException */ private boolean evaluate(DoWhileNode doWhileNode, List<DataPort> inputPorts, Map<Node, Invoker> invokerMap) throws WorkFlowInterpreterException, WorkflowException { String booleanExpression = doWhileNode.getXpath(); if (booleanExpression == null) { throw new WorkFlowInterpreterException("XPath for if cannot be null"); } int i = 0; for (DataPort port : inputPorts) { Object inputVal1 = InterpreterUtil.findInputFromPort(port, invokerMap); if (null == inputVal1) { throw new WorkFlowInterpreterException("Unable to find inputs for the node:" + doWhileNode.getID()); } booleanExpression = booleanExpression.replaceAll("\\$" + i, "'" + inputVal1 + "'"); i++; } Boolean result = new Boolean(false); // Now the XPath expression try { XPathFactory xpathFact = XPathFactory.newInstance(); XPath xpath = xpathFact.newXPath(); result = (Boolean) xpath.evaluate(booleanExpression, booleanExpression, XPathConstants.BOOLEAN); } catch (XPathExpressionException e) { throw new WorkFlowInterpreterException("Cannot evaluate XPath in If Condition: " + booleanExpression); } return result.booleanValue(); } /** * To get only web service components attached to dowhile * * @param waitingNode * @return list */ private ArrayList<Node> handleDowhile(ArrayList<Node> waitingNode, ArrayList<Node> finishedNodes) { ArrayList<Node> list = new ArrayList<Node>(); for (Node node : waitingNode) { Component component = node.getComponent(); if (component instanceof WSComponent) { ControlPort control = node.getControlInPort(); boolean controlDone = true; if (control != null) { for (EdgeImpl edge : control.getEdges()) { controlDone = controlDone && (finishedNodes.contains(edge.getFromPort().getNode()) || ((ControlPort) edge.getFromPort()).isConditionMet()); } } /* * Check for input ports */ List<DataPort> inputPorts = node.getInputPorts(); boolean inputsDone = true; for (DataPort dataPort : inputPorts) { inputsDone = inputsDone && finishedNodes.contains(dataPort.getFromNode()); } if (inputsDone && controlDone) { list.add(node); } } } return list; } /** * @see java.util.concurrent.Callable#call() */ @Override public Boolean call() throws Exception { log.debug("Invoked Dowhile node"); SystemComponentInvoker dowhileinvoker = new SystemComponentInvoker(); // TODO check for multiple input case Object inputVal1 = InterpreterUtil.findInputFromPort(this.dowhilenode.getInputPort(0), this.invokerMap); dowhileinvoker.addOutput(this.dowhilenode.getOutputPort(0).getID(), inputVal1); this.invokerMap.put(this.dowhilenode, dowhileinvoker); this.finishedNodes.add(this.dowhilenode); ArrayList<Node> readyNodes = this.handleDowhile(this.waitingNode, this.finishedNodes); // When you are starting 1st time its getting input from 1st node and // invoking all the webservice components if (readyNodes.size() != 1) { throw new WorkflowRuntimeException("More than one dowhile execution not supported"); } Node donode = readyNodes.get(0); this.interpreter.handleWSComponent(donode); log.debug("Invoked service " + donode.getName()); List<DataPort> inputPorts = this.dowhilenode.getInputPorts(); boolean runflag = true; while (runflag) { // while (true) { // if (NodeController.isRunning(donode) || NodeController.isWaiting(donode)) { // Thread.sleep(500); // log.debug("Service " + donode.getName() + " waiting"); // } else if (NodeController.isFinished(donode)) { // log.debug("Service " + donode.getName() + " Finished"); // List<DataPort> ports = this.dowhilenode.getOutputPorts(); // for (int outputPortIndex = 0, inputPortIndex = 1; outputPortIndex < ports.size(); outputPortIndex++) { // Object inputValue = InterpreterUtil.findInputFromPort(this.dowhilenode.getInputPort(inputPortIndex), this.invokerMap); // dowhileinvoker.addOutput(this.dowhilenode.getOutputPort(outputPortIndex).getID(), inputValue); // } // break; // } else if (NodeController.isFailed(donode)) { // log.debug("Service " + donode.getName() + " Failed"); // runflag = false; // dowhilenode.setState(NodeExecutionState.FAILED); // this.threadExecutor.shutdown(); // return false; // } else if (donode.isBreak()) { // log.debug("Service " + donode.getName() + " set to break"); // runflag = false; // break; // } else { // log.error("Service " + donode.getName() + " have unknow status"); // throw new WorkFlowInterpreterException("Unknow status of the node"); // } // } // this.invokerMap.put(this.dowhilenode, dowhileinvoker); log.debug("Going to evaluate do while expression for " + donode.getName()); if (!evaluate(this.dowhilenode, inputPorts, this.invokerMap)) { log.debug("Expression evaluation is false so calling EndDoWhile"); runflag = false; } else { if (readyNodes.size() != 1) { throw new WorkFlowInterpreterException("More than one dowhile execution not supported"); } Node whileNode = readyNodes.get(0); log.debug("Expression evaluation is true so invoking service again " + whileNode.getName()); this.interpreter.handleWSComponent(whileNode); } } // WS node should be done dowhilenode.setState(NodeExecutionState.FINISHED); EndDoWhileNode endDoWhileNode = this.dowhilenode.getEndDoWhileNode(); // ///////////////////////////////////////////////////////// // // Do WHile finished execution thus we can set the ////// // //inputs to the EndDOWHile and resume the executions///// SystemComponentInvoker invoker = new SystemComponentInvoker(); List<DataPort> inputports = endDoWhileNode.getInputPorts(); for (int inputPortIndex = 0; inputPortIndex < inputports.size(); inputPortIndex++) { Object inputVal = dowhileinvoker.getOutput(inputports.get(inputPortIndex).getFromPort().getID()); invoker.addOutput(endDoWhileNode.getOutputPort(inputPortIndex).getID(), inputVal); } this.invokerMap.put(endDoWhileNode, invoker); // TODO send mail once the iterations have converged endDoWhileNode.setState(NodeExecutionState.FINISHED); this.threadExecutor.shutdown(); return true; } }