org.apache.airavata.workflow.model.graph.impl.NodeImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.airavata.workflow.model.graph.impl.NodeImpl.java

Source

/*
 *
 * 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.model.graph.impl;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import org.apache.airavata.common.utils.StringUtil;
import org.apache.airavata.common.utils.XMLUtil;
import org.apache.airavata.workflow.model.component.Component;
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.Edge;
import org.apache.airavata.workflow.model.graph.Graph;
import org.apache.airavata.workflow.model.graph.GraphException;
import org.apache.airavata.workflow.model.graph.GraphSchema;
import org.apache.airavata.workflow.model.graph.Node;
import org.apache.airavata.workflow.model.graph.Port;
import org.apache.airavata.workflow.model.graph.Port.Kind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmlpull.infoset.XmlElement;

/**
 * The abstract implementation of the Node interface. This class should be hidden from the outsize of the package.
 * 
 */
public abstract class NodeImpl implements Node {

    private static final Logger logger = LoggerFactory.getLogger(NodeImpl.class);

    protected String id;

    /**
     * A name of the node.
     */
    private String name = "";

    private Component component;

    private List<DataPort> outputPorts;

    private List<DataPort> inputPorts;

    private ControlPort controlInPort;

    private List<ControlPort> controlOutPorts;

    private PortImpl eprPort;

    private GraphImpl graph;

    private Point position;

    // The followings are used only during parsing the XML.

    private List<String> inputPortIDs;

    private List<String> outputPortIDs;

    private String controlInPortID;

    private List<String> controlOutPortIDs;

    private String eprPortID;

    private boolean breakOnExecution = false;

    protected String label;

    protected transient boolean requireJoin = false;

    private NodeExecutionState state = NodeExecutionState.WAITING;

    private List<NodeObserver> observers;

    /**
     * Creates a Node.
     */
    protected NodeImpl() {

        // Iinitialized to the empty string to avoid NullPointerException.
        this.name = "";

        this.position = new Point();
        this.inputPorts = new ArrayList<DataPort>();
        this.outputPorts = new ArrayList<DataPort>();
        this.controlOutPorts = new ArrayList<ControlPort>();

        this.inputPortIDs = new ArrayList<String>();
        this.outputPortIDs = new ArrayList<String>();
        this.controlOutPortIDs = new ArrayList<String>();

        observers = new ArrayList<Node.NodeObserver>();
    }

    protected NodeImpl(Graph graph) {
        this();
        this.graph = (GraphImpl) graph;
        this.graph.addNode(this);
    }

    /**
     * Constructs a NodeImpl.
     * 
     * @param nodeElement
     * @throws GraphException
     */
    public NodeImpl(XmlElement nodeElement) throws GraphException {
        this();
        parse(nodeElement);
    }

    public NodeImpl(JsonObject nodeObject) throws GraphException {
        this();
        parse(nodeObject);
    }

    /**
     * @return the ID of the node
     */
    public String getID() {
        return this.id;
    }

    /**
     * Creates unique node ID in the graph that this node belongs to.
     */
    public void createID() {
        String candidateID = StringUtil.convertToJavaIdentifier(this.name);
        Node node = this.graph.getNode(candidateID);
        while (node != null && node != this) {
            candidateID = StringUtil.incrementName(candidateID);
            node = this.graph.getNode(candidateID);
        }
        this.id = candidateID;

        for (PortImpl port : getAllPorts()) {
            port.createID();
        }
    }

    /**
     * Returns the name.
     * 
     * @return The name
     */
    public String getName() {
        return this.name;
    }

    /**
     * Sets the name.
     * 
     * @param name
     *            The name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Returns the component.
     * 
     * @return The component
     */
    public Component getComponent() {
        return this.component;
    }

    /**
     * Sets the component.
     * 
     * @param component
     *            The component to set.
     */
    public void setComponent(Component component) {
        this.component = component;
    }

    /**
     * @see org.apache.airavata.workflow.model.graph.Node#getGraph()
     */
    public Graph getGraph() {
        return this.graph;
    }

    /**
     * @param port
     */
    public void addOutputPort(DataPort port) {
        port.setKind(PortImpl.Kind.DATA_OUT);
        this.outputPorts.add(port);
        addPort(port);
    }

    /**
     * @param port
     * @throws GraphException
     */
    public void removeOutputPort(PortImpl port) throws GraphException {
        this.graph.removePort(port);
        this.outputPorts.remove(port);
    }

    /**
     * @param port
     */
    public void addInputPort(DataPort port) {
        port.setKind(PortImpl.Kind.DATA_IN);
        this.inputPorts.add(port);
        addPort(port);
    }

    /**
     * @param port
     * @throws GraphException
     */
    public void removeInputPort(PortImpl port) throws GraphException {
        this.graph.removePort(port);
        this.inputPorts.remove(port);
    }

    /**
     * Sets the location of the node.
     * 
     * @param point
     *            The location
     */
    public void setPosition(Point point) {
        this.position.x = point.x;
        this.position.y = point.y;
    }

    /**
     * @see org.apache.airavata.workflow.model.graph.Node#getPosition()
     */
    public Point getPosition() {
        return this.position;
    }

    /**
     * Returns the List of output ports.
     * 
     * @return the List of output ports
     */
    public List<DataPort> getOutputPorts() {
        return this.outputPorts;
    }

    /**
     * Returns the List of input ports.
     * 
     * @return the List of input ports
     */
    public List<DataPort> getInputPorts() {
        return this.inputPorts;
    }

    /**
     * Returns the output port of the specified index.
     * 
     * @param index
     *            The specified index
     * @return the uses port of the specified index
     */
    public DataPort getOutputPort(int index) {
        if (index < 0 || index >= this.outputPorts.size()) {
            String message = "index has to be possitive and less than " + this.outputPorts.size();
            throw new IllegalArgumentException(message);
        }
        return this.outputPorts.get(index);
    }

    /**
     * Returns the input port of the specified index.
     * 
     * @param index
     *            The specified index
     * @return the input port of the specified index
     */
    public DataPort getInputPort(int index) {
        if (index < 0 || index >= this.inputPorts.size()) {
            throw new IllegalArgumentException();
        }
        return this.inputPorts.get(index);
    }

    /**
     * @return The controlInPort.
     */
    public ControlPort getControlInPort() {
        return this.controlInPort;
    }

    /**
     * @see org.apache.airavata.workflow.model.graph.Node#getControlOutPorts()
     */
    public List<ControlPort> getControlOutPorts() {
        return this.controlOutPorts;
    }

    /**
     * @see org.apache.airavata.workflow.model.graph.Node#getEPRPort()
     */
    public PortImpl getEPRPort() {
        return this.eprPort;
    }

    /**
     * Returns all ports that belong to this node.
     * 
     * @return All ports that belong to this node.
     */
    public Collection<PortImpl> getAllPorts() {
        ArrayList<PortImpl> ports = new ArrayList<PortImpl>();
        ports.addAll(this.inputPorts);
        ports.addAll(this.outputPorts);
        if (this.controlInPort != null) {
            ports.add(this.controlInPort);
        }
        ports.addAll(this.controlOutPorts);
        if (this.eprPort != null) {
            ports.add(this.eprPort);
        }
        return ports;
    }

    /**
     * Checks if this node contains a specified port.
     * 
     * @param port
     *            The specified port
     * @return true if this node contains port; false otherwise
     */
    public boolean containsPort(Port port) {
        boolean contain = this.inputPorts.contains(port) || this.outputPorts.contains(port);
        return contain;
    }

    /**
     * @param controlInPort
     */
    public void setControlInPort(ControlPort controlInPort) {
        controlInPort.setKind(Kind.CONTROL_IN);
        this.controlInPort = controlInPort;
        addPort(this.controlInPort);
    }

    /**
     * @param controlOutPort
     */
    public void addControlOutPort(ControlPort controlOutPort) {
        controlOutPort.setKind(Kind.CONTROL_OUT);
        this.controlOutPorts.add(controlOutPort);
        addPort(controlOutPort);
    }

    /**
     * @param eprPort
     */
    public void setEPRPort(PortImpl eprPort) {
        eprPort.setKind(Kind.EPR);
        this.eprPort = eprPort;
        addPort(eprPort);
    }

    /**
     * Sets a graph this node belogs to.
     * 
     * @param graph
     *            The graph
     */
    protected void setGraph(GraphImpl graph) {
        this.graph = graph;
    }

    protected void indexToPointer() throws GraphException {
        for (String portID : this.inputPortIDs) {
            PortImpl port = this.graph.getPort(portID);
            if (port == null) {
                throw new GraphException("Port, " + portID + ", does not exist.");
            }
            port.setKind(PortImpl.Kind.DATA_IN);
            port.setNode(this);
            this.inputPorts.add((DataPort) port);
        }

        for (String portID : this.outputPortIDs) {
            PortImpl port = this.graph.getPort(portID);
            if (port == null) {
                throw new GraphException("Port, " + portID + ", does not exist.");
            }
            port.setKind(PortImpl.Kind.DATA_OUT);
            port.setNode(this);
            this.outputPorts.add((DataPort) port);
        }

        if (this.controlInPortID != null) {
            PortImpl port = this.graph.getPort(this.controlInPortID);
            if (port == null) {
                throw new GraphException("Port, " + this.controlInPortID + ", does not exist.");
            }
            port.setKind(PortImpl.Kind.CONTROL_IN);
            port.setNode(this);
            this.controlInPort = (ControlPort) port;
        }

        for (String portID : this.controlOutPortIDs) {
            PortImpl port = this.graph.getPort(portID);
            if (port == null) {
                throw new GraphException("Port, " + portID + ", does not exist.");
            }
            port.setKind(PortImpl.Kind.CONTROL_OUT);
            port.setNode(this);
            this.controlOutPorts.add((ControlPort) port);
        }

        if (this.eprPortID != null) {
            PortImpl port = this.graph.getPort(this.eprPortID);
            if (port == null) {
                throw new GraphException("Port, " + this.eprPortID + ", does not exist.");
            }
            port.setKind(PortImpl.Kind.EPR);
            port.setNode(this);
            this.eprPort = port;
        }
    }

    /**
     * @param nodeElement
     * @throws GraphException
     */
    protected void parse(XmlElement nodeElement) throws GraphException {
        XmlElement idElement = nodeElement.element(GraphSchema.NODE_ID_TAG);
        this.id = idElement.requiredText();

        XmlElement nameElement = nodeElement.element(GraphSchema.NODE_NAME_TAG);
        this.name = nameElement.requiredText();

        // XmlElement labelElement = nodeElement
        // .element(GraphSchema.NODE_STREAM_LABEL_TAG);
        // if (null != labelElement) {
        // this.label = labelElement.requiredText();
        // }

        Iterable<XmlElement> inputPortElements = nodeElement.elements(null, GraphSchema.NODE_INPUT_PORT_TAG);
        for (XmlElement inputPort : inputPortElements) {
            this.inputPortIDs.add(inputPort.requiredText());
        }

        Iterable<XmlElement> outputPortElements = nodeElement.elements(null, GraphSchema.NODE_OUTPUT_PORT_TAG);
        for (XmlElement outputPort : outputPortElements) {
            this.outputPortIDs.add(outputPort.requiredText());
        }

        XmlElement controlInPortElement = nodeElement.element(GraphSchema.NODE_CONTROL_IN_PORT_TAG);
        if (controlInPortElement != null) {
            this.controlInPortID = controlInPortElement.requiredText();
        }

        Iterable<XmlElement> controlOutPortElements = nodeElement.elements(null,
                GraphSchema.NODE_CONTROL_OUT_PORT_TAG);
        for (XmlElement controlOutPort : controlOutPortElements) {
            this.controlOutPortIDs.add(controlOutPort.requiredText());
        }

        XmlElement eprPortElement = nodeElement.element(GraphSchema.NODE_EPR_PORT_TAG);
        if (eprPortElement != null) {
            this.eprPortID = eprPortElement.requiredText();
        }

        XmlElement xElement = nodeElement.element(GraphSchema.NODE_X_LOCATION_TAG);
        this.position.x = (int) Double.parseDouble(xElement.requiredText());

        XmlElement yElement = nodeElement.element(GraphSchema.NODE_Y_LOCATION_TAG);
        this.position.y = (int) Double.parseDouble(yElement.requiredText());

        XmlElement configElement = nodeElement.element(GraphSchema.NODE_CONFIG_TAG);
        if (configElement != null) {
            parseConfiguration(configElement);
        }

        XmlElement componentElement = nodeElement.element(GraphSchema.NODE_COMPONENT_TAG);
        if (componentElement != null) {
            // XXX Not used since the introduction of .xwf
            parseComponent(componentElement);
        }
    }

    protected void parse(JsonObject nodeObject) {
        this.id = nodeObject.getAsJsonPrimitive(GraphSchema.NODE_ID_TAG).getAsString();
        this.name = nodeObject.getAsJsonPrimitive(GraphSchema.NODE_NAME_TAG).getAsString();

        JsonArray jArray;
        if (nodeObject.get(GraphSchema.NODE_INPUT_PORT_TAG) != null) {
            jArray = nodeObject.getAsJsonArray(GraphSchema.NODE_INPUT_PORT_TAG);
            for (JsonElement jsonElement : jArray) {
                this.inputPortIDs.add(jsonElement.getAsString());
            }

        }

        if (nodeObject.get(GraphSchema.NODE_OUTPUT_PORT_TAG) != null) {
            jArray = nodeObject.getAsJsonArray(GraphSchema.NODE_OUTPUT_PORT_TAG);
            for (JsonElement jsonElement : jArray) {
                this.outputPortIDs.add(jsonElement.getAsString());
            }

        }

        JsonElement jElement = nodeObject.get(GraphSchema.NODE_CONTROL_IN_PORT_TAG);
        if (jElement != null) {
            this.controlInPortID = jElement.getAsString();
        }

        if (nodeObject.get(GraphSchema.NODE_CONTROL_OUT_PORT_TAG) != null) {
            jArray = nodeObject.getAsJsonArray(GraphSchema.NODE_CONTROL_OUT_PORT_TAG);
            for (JsonElement jsonElement : jArray) {
                this.controlOutPortIDs.add(jsonElement.getAsString());
            }
        }

        jElement = nodeObject.get(GraphSchema.NODE_EPR_PORT_TAG);
        if (jElement != null) {
            this.eprPortID = jElement.getAsString();
        }

        this.position.x = nodeObject.get(GraphSchema.NODE_X_LOCATION_TAG).getAsInt();
        this.position.y = nodeObject.get(GraphSchema.NODE_Y_LOCATION_TAG).getAsInt();

        // Parse config element not sure why we used it.
        // Parse component element.
        JsonObject configObject = nodeObject.getAsJsonObject(GraphSchema.NODE_CONFIG_TAG);
        if (configObject != null) {
            parseConfiguration(configObject);
        }

    }

    /**
     * @param componentElement
     * @throws GraphException
     *             When the component is in wrong format. This might be thrown by the sub classes.
     */
    @SuppressWarnings("unused")
    @Deprecated
    protected void parseComponent(XmlElement componentElement) throws GraphException {
        logger.debug("Entering:" + componentElement);
        // Do nothing by default.
    }

    protected void parseConfiguration(XmlElement configElement) {
        logger.debug("Entering:" + configElement);
        // Do nothing by default.
    }

    protected void parseConfiguration(JsonObject configObject) {
        logger.debug("Entering:" + new Gson().toJson(configObject));
    }

    /**
     * @return the node xml
     */
    protected XmlElement toXML() {
        XmlElement nodeElement = XMLUtil.BUILDER.newFragment(GraphSchema.NS, GraphSchema.NODE_TAG);

        XmlElement idElement = nodeElement.addElement(GraphSchema.NS, GraphSchema.NODE_ID_TAG);
        idElement.addChild(this.id);

        XmlElement nameElement = nodeElement.addElement(GraphSchema.NS, GraphSchema.NODE_NAME_TAG);
        nameElement.addChild(this.name);

        // if (null != this.label) {
        // XmlElement labelElement = nodeElement.addElement(GraphSchema.NS,
        // GraphSchema.NODE_STREAM_LABEL_TAG);
        //
        // labelElement.addChild(this.label);
        // }
        // Output ports
        for (PortImpl port : this.outputPorts) {
            XmlElement portElement = nodeElement.addElement(GraphSchema.NS, GraphSchema.NODE_OUTPUT_PORT_TAG);
            portElement.addChild(port.getID());
        }

        // Input ports
        for (PortImpl port : this.inputPorts) {
            XmlElement portElement = nodeElement.addElement(GraphSchema.NS, GraphSchema.NODE_INPUT_PORT_TAG);
            portElement.addChild(port.getID());
        }

        // Control-in port
        if (this.controlInPort != null) {
            XmlElement portElement = nodeElement.addElement(GraphSchema.NS, GraphSchema.NODE_CONTROL_IN_PORT_TAG);
            portElement.addChild(this.controlInPort.getID());
        }

        // EPR Port
        if (this.eprPort != null) {
            XmlElement portElement = nodeElement.addElement(GraphSchema.NS, GraphSchema.NODE_EPR_PORT_TAG);
            portElement.addChild(this.eprPort.getID());
        }

        // Control-out ports
        for (PortImpl port : this.controlOutPorts) {
            XmlElement portElement = nodeElement.addElement(GraphSchema.NS, GraphSchema.NODE_CONTROL_OUT_PORT_TAG);
            portElement.addChild(port.getID());
        }

        XmlElement xElement = nodeElement.addElement(GraphSchema.NS, GraphSchema.NODE_X_LOCATION_TAG);
        xElement.addChild(Integer.toString(this.position.x));

        XmlElement yElement = nodeElement.addElement(GraphSchema.NS, GraphSchema.NODE_Y_LOCATION_TAG);
        yElement.addChild(Integer.toString(this.position.y));

        addConfigurationElement(nodeElement);

        return nodeElement;
    }

    protected JsonObject toJSON() {
        JsonObject nodeObject = new JsonObject();
        nodeObject.addProperty(GraphSchema.NODE_ID_TAG, getID());
        nodeObject.addProperty(GraphSchema.NODE_NAME_TAG, getName());

        if (this.inputPorts.size() > 0) {
            JsonArray inputPortsArray = new JsonArray();
            for (PortImpl inputPort : this.inputPorts) {
                inputPortsArray.add(new JsonPrimitive(inputPort.getID()));
            }
            nodeObject.add(GraphSchema.NODE_INPUT_PORT_TAG, inputPortsArray);
        }

        if (this.outputPorts.size() > 0) {
            JsonArray outputPortsArray = new JsonArray();
            for (PortImpl outputPort : this.outputPorts) {
                outputPortsArray.add(new JsonPrimitive(outputPort.getID()));
            }
            nodeObject.add(GraphSchema.NODE_OUTPUT_PORT_TAG, outputPortsArray);
        }

        if (this.controlInPort != null) {
            nodeObject.addProperty(GraphSchema.NODE_CONTROL_IN_PORT_TAG, this.controlInPort.getID());
        }

        if (this.controlOutPorts.size() > 0) {
            JsonArray controlOutPortArray = new JsonArray();
            for (PortImpl controlOutPort : this.controlOutPorts) {
                controlOutPortArray.add(new JsonPrimitive(controlOutPort.getID()));
            }
            nodeObject.add(GraphSchema.NODE_CONTROL_OUT_PORT_TAG, controlOutPortArray);
        }

        nodeObject.addProperty(GraphSchema.NODE_X_LOCATION_TAG, Integer.toString(this.position.x));
        nodeObject.addProperty(GraphSchema.NODE_Y_LOCATION_TAG, Integer.toString(this.position.y));

        addConfigurationElement(nodeObject);

        return nodeObject;
    }

    /**
     * Adds a configuration element to a specified node element.
     * 
     * @param nodeElement
     *            The specified node element
     * @return The configuration element added
     */
    @SuppressWarnings("unused")
    protected XmlElement addConfigurationElement(XmlElement nodeElement) {
        // Do nothing by default.
        return null;
    }

    protected JsonObject addConfigurationElement(JsonObject nodeObject) {
        // Do nothing by default.
        return null;
    }

    /**
    * Called when an Edge was added. It doesn't do anything by default.
    * 
    * @param edge
    * @throws GraphException
    *             When the added edge is not allowed. This might be thrown by subclasses.
    */
    @SuppressWarnings("unused")
    protected void edgeWasAdded(Edge edge) throws GraphException {
        // Do nothing
    }

    /**
     * Called when an Edge was removed. It doesn't do anything by default.
     * 
     * @param edge
     */
    @SuppressWarnings("unused")
    protected void edgeWasRemoved(Edge edge) {
        // Do nothing
    }

    private void addPort(PortImpl port) {
        port.setNode(this);
        this.graph.addPort(port);
    }

    public boolean isBreak() {
        return this.breakOnExecution;
    }

    public void setBreak(boolean breakVal) {
        this.breakOnExecution = breakVal;
    }

    /**
    * 
    */
    public boolean isAllInPortsConnected() {
        for (Iterator<DataPort> iterator = this.inputPorts.iterator(); iterator.hasNext();) {
            DataPort port = iterator.next();
            if (port.getFromNode() == null) {
                return false;
            }

        }
        return true;

    }

    public DataPort getOutputPort(String fromPortID) {
        for (DataPort port : this.outputPorts) {
            if (port.getID().equals(fromPortID)) {
                return port;
            }
        }
        throw new WorkflowRuntimeException("Port with id not found :" + fromPortID);
    }

    public DataPort getInputPort(String id) {
        for (DataPort port : this.inputPorts) {
            if (port.getID().equals(id)) {
                return port;
            }
        }
        throw new WorkflowRuntimeException("Port with id not found :" + id);
    }

    /**
     * @return
     */
    public String getLabel() {
        return this.label;
    }

    public void setRequireJoin(boolean join) {
        this.requireJoin = join;
    }

    public boolean getRequireJoin() {
        return this.requireJoin;
    }

    @Override
    public NodeExecutionState getState() {
        return state;
    }

    @Override
    public void setState(NodeExecutionState state) {
        this.state = state;
        triggerNodeObservers(NodeUpdateType.STATE_CHANGED);
    }

    @Override
    public void registerObserver(NodeObserver o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(NodeObserver o) {
        if (observers.contains(o)) {
            observers.remove(o);
        }
    }

    private void triggerNodeObservers(NodeUpdateType type) {
        for (NodeObserver o : observers) {
            try {
                o.nodeUpdated(type);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
    }
}