/** * * 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.xbaya.modifier; import java.awt.Color; import java.awt.Point; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.airavata.workflow.model.component.system.InputComponent; import org.apache.airavata.workflow.model.component.ws.WSComponent; import org.apache.airavata.workflow.model.exceptions.WorkflowRuntimeException; import org.apache.airavata.workflow.model.graph.GraphException; import org.apache.airavata.workflow.model.graph.Node; import org.apache.airavata.workflow.model.graph.Port; import org.apache.airavata.workflow.model.graph.impl.PortImpl; import org.apache.airavata.workflow.model.graph.system.InputNode; import org.apache.airavata.workflow.model.graph.util.GraphUtil; import org.apache.airavata.workflow.model.graph.ws.WSGraph; import org.apache.airavata.workflow.model.graph.ws.WSNode; import org.apache.airavata.workflow.model.graph.ws.WSPort; import org.apache.airavata.workflow.model.wf.Workflow; import org.apache.airavata.xbaya.graph.controller.NodeController; import org.apache.airavata.xbaya.messaging.EventData; import org.apache.airavata.xbaya.messaging.EventDataRepository; import org.apache.airavata.xbaya.messaging.MonitorException; import org.apache.airavata.xbaya.ui.monitor.MonitorEventHandler.NodeState; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class WorkflowModifier { private static final Logger logger = LoggerFactory.getLogger(WorkflowModifier.class); private Workflow modifiedWorkflow; private EventDataRepository eventData; /** * Constructs a WorkflowModifier. * * @param modifiedWorkflow * @param eventData */ public WorkflowModifier(Workflow modifiedWorkflow, EventDataRepository eventData) { this.modifiedWorkflow = modifiedWorkflow; this.eventData = eventData; } /** * @return The workflow that needs to be executed. * @throws GraphException * @throws MonitorException */ public Workflow createDifference() throws GraphException, MonitorException { WSGraph originalGraph = this.modifiedWorkflow.getGraph(); Workflow workflow = this.modifiedWorkflow.clone(); String name = workflow.getName(); name += " (diff)"; workflow.setName(name); WSGraph graph = workflow.getGraph(); // Remove the finished node. removeFinishedNodes(originalGraph, graph); Set<WSPort> originalFromPorts = getFinalOutputPorts(originalGraph, graph); // Create input nodes for unconnected input ports. createInputNodes(graph, originalFromPorts); // Set default values. for (WSPort originalFromPort : originalFromPorts) { // TODO handle the case that node is not WSNode. Node originalFromNode = originalFromPort.getNode(); String fromNodeID = originalFromNode.getID(); String output; if (originalFromNode instanceof InputNode) { // notification that includes the input of the workflow. output = getWorkflowInput(fromNodeID); } else if (originalFromNode instanceof WSNode) { // Retrieve input value from notification. WSComponent component = ((WSNode) originalFromNode).getComponent(); String messageName = component.getOutputTypeName(); String parameterName = originalFromPort.getComponentPort().getName(); output = getOutput(fromNodeID, messageName, parameterName); } else { // This should not happen. throw new WorkflowRuntimeException(originalFromNode.getClass().getName()); } Port originalToPort = originalFromPort.getToPorts().get(0); PortImpl toPort = graph.getPort(originalToPort.getID()); InputNode inputNode = (InputNode) toPort.getFromNode(); inputNode.setDefaultValue(output); } return workflow; } /** * @param originalGraph * @param graph * @throws GraphException */ private void removeFinishedNodes(WSGraph originalGraph, WSGraph graph) throws GraphException { ArrayList<Node> finishedNodes = new ArrayList<Node>(); for (Node node : originalGraph.getNodes()) { Color color = NodeController.getGUI(node).getBodyColor(); if (NodeState.FINISHED.color.equals(color)) { finishedNodes.add(node); } } for (Node finishedNode : finishedNodes) { Node node = graph.getNode(finishedNode.getID()); graph.removeNode(node); } } /** * @param originalGraph * @param graph * @return The final output ports. */ private Set<WSPort> getFinalOutputPorts(WSGraph originalGraph, WSGraph graph) { Collection<Port> inputPorts = GraphUtil.getPorts(graph, Port.Kind.DATA_IN); Set<WSPort> originalFromPorts = new HashSet<WSPort>(); for (Port inputPort : inputPorts) { Port fromPort = inputPort.getFromPort(); if (fromPort == null) { // This input port is not connected. String inputPortID = inputPort.getID(); logger.debug("id: " + inputPortID); Port originalInputPort = originalGraph.getPort(inputPortID); // No duplicate in set. Port originalFromPort = originalInputPort.getFromPort(); originalFromPorts.add((WSPort) originalFromPort); } } return originalFromPorts; } /** * @param graph * @param originalFromPorts * @throws GraphException */ private void createInputNodes(WSGraph graph, Set<WSPort> originalFromPorts) throws GraphException { InputComponent inputComponent = new InputComponent(); for (WSPort originalFromPort : originalFromPorts) { InputNode inputNode = inputComponent.createNode(graph); List<Port> originalToPorts = originalFromPort.getToPorts(); boolean first = true; for (Port originalToPort : originalToPorts) { String toPortID = originalToPort.getID(); Port toPort = graph.getPort(toPortID); graph.addEdge(inputNode.getPort(), toPort); if (first) { first = false; Point position = NodeController.getGUI(originalToPort).getPosition(); Point inputNodePosition = new Point(0, position.y); inputNode.setPosition(inputNodePosition); } } } } private String getWorkflowInput(String nodeID) throws MonitorException { logger.debug("Node:" + nodeID); List<EventData> events = this.eventData.getEvents(); for (EventData event : events) { // EventType type = event.getType(); // // TODO change this to read from the notification from GPEL. // if (type != EventType.INVOKING_SERVICE) { // continue; // } // String id = event.getNodeID(); // if (!"".equals(id)) { // continue; // } // // TODO null check // XmlElement eventElement = event.getEvent(); // XmlElement result = eventElement.element(MonitorUtil.REQUEST); // XmlElement body = result.element(MonitorUtil.BODY); // XmlElement soapBody = body.element(XmlConstants.S_BODY); // WsdlPortTypeOperation wsdlPortTypeOperation; // try { // wsdlPortTypeOperation = WSDLUtil.getFirstOperation(this.modifiedWorkflow.getWorkflowWSDL()); // } catch (UtilsException e) { // throw new MonitorException(e); // } // XmlElement part = soapBody.element(wsdlPortTypeOperation.getName()); // XmlElement parameter = part.element(nodeID); // // TODO support complex type. // String value = parameter.requiredText(); return event.getMessage(); } // TODO String message = "Couldn't find a notification of about the input with nodeID, " + nodeID; throw new MonitorException(message); } private String getOutput(String nodeID, String messageName, String parameterName) throws MonitorException { List<EventData> events = this.eventData.getEvents(); for (EventData event : events) { // // We need to find the notification that contains the output of the // // service invocation. // EventType type = event.getType(); // if (!(type == EventType.SENDING_RESULT || type == EventType.RECEIVED_RESULT)) { // continue; // } // String id = event.getNodeID(); // if (!nodeID.equals(id)) { // continue; // } // // TODO null check // XmlElement eventElement = event.getEvent(); // XmlElement result = eventElement.element(MonitorUtil.RESULT); // XmlElement body = result.element(MonitorUtil.BODY); // XmlElement soapBody = body.element(XmlConstants.S_BODY); // XmlElement part = soapBody.element(messageName); // XmlElement parameter = part.element(parameterName); // // TODO support complex type. // String value = parameter.requiredText(); return event.getMessage(); } // TODO String message = "Couldn't find a notification of the output from the service with nodeID, " + nodeID; throw new MonitorException(message); } }