/**
*
* 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.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import org.apache.airavata.common.utils.XMLUtil;
import org.apache.airavata.workflow.model.component.ComponentPort;
import org.apache.airavata.workflow.model.exceptions.WorkflowRuntimeException;
import org.apache.airavata.workflow.model.graph.Edge;
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.xmlpull.infoset.XmlElement;
/**
* The Port class represents a port
*
*/
public abstract class PortImpl implements Port {
/**
* The graph this edge belogs to
*/
private GraphImpl graph;
protected String id;
/**
* The name of this port
*/
private String name;
/**
* The kind of this port, either input port or output port
*/
private Kind kind;
/**
* The node that this port belongs to
*/
private NodeImpl node;
/**
* The Edges that this port is connected to
*/
private List<EdgeImpl> edges;
private ComponentPort componentPort;
/**
* The ID of the node that this port belongs to. This is used only during parsing the XML.
*/
private String nodeID;
/**
* Creates a Port.
*/
protected PortImpl() {
this.edges = new LinkedList<EdgeImpl>();
}
/**
* Constructs a PortImpl.
*
* @param portElement
*/
public PortImpl(XmlElement portElement) {
this();
parse(portElement);
}
public PortImpl(JsonObject portObject) {
this();
parse(portObject);
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getID()
*/
public String getID() {
if (this.id == null) {
// old format
this.id = createID();
}
return this.id;
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getName()
*/
public String getName() {
return this.name;
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#setName(java.lang.String)
*/
public void setName(String name) {
this.name = name;
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getNode()
*/
public NodeImpl getNode() {
return this.node;
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getEdges()
*/
public List<? extends EdgeImpl> getEdges() {
return this.edges;
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getEdge(int)
*/
public Edge getEdge(int index) {
return this.edges.get(index);
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getKind()
*/
public Kind getKind() {
return this.kind;
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getFromPorts()
*/
public List<Port> getFromPorts() {
List<Port> fromPorts = new ArrayList<Port>();
for (EdgeImpl edge : this.edges) {
fromPorts.add(edge.getFromPort());
}
return fromPorts;
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getFromPort()
*/
public Port getFromPort() {
if (this.edges.size() > 0) {
Edge edge = this.edges.get(0);
return edge.getFromPort();
} else {
return null;
}
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getFromNodes()
*/
public List<Node> getFromNodes() {
List<Node> fromNodes = new ArrayList<Node>();
for (Port port : getFromPorts()) {
fromNodes.add(port.getNode());
}
return fromNodes;
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getFromNode()
*/
public Node getFromNode() {
Port fromPort = getFromPort();
if (fromPort == null) {
return null;
} else {
return fromPort.getNode();
}
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getToPorts()
*/
public List<Port> getToPorts() {
List<Port> toPorts = new ArrayList<Port>();
for (Edge edge : this.edges) {
toPorts.add(edge.getToPort());
}
return toPorts;
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getToNodes()
*/
public List<Node> getToNodes() {
List<Node> toNodes = new ArrayList<Node>();
for (Port port : getToPorts()) {
toNodes.add(port.getNode());
}
return toNodes;
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#setComponentPort(org.apache.airavata.workflow.model.component.ComponentPort)
*/
public void setComponentPort(ComponentPort componentPort) {
this.componentPort = componentPort;
}
/**
* @see org.apache.airavata.workflow.model.graph.Port#getComponentPort()
*/
public ComponentPort getComponentPort() {
if (this.componentPort == null) {
int index;
switch (this.kind) {
case DATA_IN:
index = this.node.getInputPorts().indexOf(this);
this.componentPort = this.node.getComponent().getInputPort(index);
break;
case DATA_OUT:
index = this.node.getOutputPorts().indexOf(this);
this.componentPort = this.node.getComponent().getOutputPort(index);
break;
case CONTROL_IN:
this.componentPort = this.node.getComponent().getControlInPort();
break;
case CONTROL_OUT:
index = this.node.getControlOutPorts().indexOf(this);
this.componentPort = this.node.getComponent().getControlOutPort(index);
break;
case EPR:
this.componentPort = this.node.getComponent().getEPRPort();
break;
}
}
return this.componentPort;
}
/**
* Sets the kind of this port.
*
* @param kind
* The kind, either INPUT_PORT or OUTPUT_PORT
*/
protected void setKind(Kind kind) {
this.kind = kind;
}
/**
* Sets a graph this port belogs to.
*
* @param graph
* The graph
*/
protected void setGraph(GraphImpl graph) {
this.graph = graph;
}
public GraphImpl getGraph() {
return graph;
}
/**
* @param node
*/
protected void setNode(NodeImpl node) {
this.node = node;
}
/**
* Adds an Edge.
*
* @param edge
* The edge to add
*/
protected void addEdge(EdgeImpl edge) {
if (this.edges.contains(edge)) {
throw new WorkflowRuntimeException("The edge is already addes");
} else {
this.edges.add(edge);
}
}
/**
* Removes an Edge.
*
* @param edge
* The edge to remove.
*/
protected void removeEdge(Edge edge) {
if (this.edges.contains(edge)) {
this.edges.remove(edge);
// this.node.edgeWasRemoved(edge);
} else {
throw new WorkflowRuntimeException("The edge doesn't exist.");
}
}
/**
* @return The ID of this port
*/
protected String createID() {
String nid = getNode().getID();
String portType;
switch (this.kind) {
case DATA_IN:
portType = "in";
break;
case DATA_OUT:
portType = "out";
break;
case CONTROL_IN:
portType = "ctrl_in";
break;
case CONTROL_OUT:
portType = "ctrl_out";
break;
case EPR:
portType = "epr";
break;
default:
// Should not happen.
throw new WorkflowRuntimeException("Wrong type of the port: " + this.kind);
}
int index = getIndex();
return nid + "_" + portType + "_" + index;
}
/**
* Converts references to indexes.
*
* @throws GraphException
*/
protected void indexToPointer() throws GraphException {
this.node = this.graph.getNode(this.nodeID);
if (this.node == null) {
throw new GraphException("Cannot find a node with the ID, " + this.nodeID + ".");
}
}
/**
* Parses XML
*
* @param portElement
*/
protected void parse(XmlElement portElement) {
XmlElement idElement = portElement.element(GraphSchema.PORT_ID_TAG);
this.id = idElement.requiredText();
XmlElement nameElement = portElement.element(GraphSchema.PORT_NAME_TAG);
if (nameElement != null) {
// TODO control ports might have name?
this.name = nameElement.requiredText();
}
XmlElement nodeElement = portElement.element(GraphSchema.PORT_NODE_TAG);
this.nodeID = nodeElement.requiredText();
}
protected void parse(JsonObject portObject) {
this.id = portObject.getAsJsonPrimitive(GraphSchema.PORT_ID_TAG).getAsString();
JsonPrimitive jPrimitive = portObject.getAsJsonPrimitive(GraphSchema.PORT_NAME_TAG);
if (jPrimitive != null) {
this.name = jPrimitive.getAsString();
}
this.nodeID = portObject.getAsJsonPrimitive(GraphSchema.PORT_NODE_TAG).getAsString();
}
/**
* @return the XML representation of this Port
*/
protected XmlElement toXML() {
XmlElement portElement = XMLUtil.BUILDER.newFragment(GraphSchema.NS, GraphSchema.PORT_TAG);
XmlElement idElement = portElement.addElement(GraphSchema.NS, GraphSchema.PORT_ID_TAG);
idElement.addChild(getID());
if (this.name != null) {
// TODO control ports might have name?
XmlElement nameElement = portElement.addElement(GraphSchema.NS, GraphSchema.PORT_NAME_TAG);
nameElement.addChild(this.name);
}
XmlElement nodeElement = portElement.addElement(GraphSchema.NS, GraphSchema.PORT_NODE_TAG);
nodeElement.addChild(this.node.getID());
return portElement;
}
protected JsonObject toJSON(){
JsonObject portElement = new JsonObject();
portElement.addProperty(GraphSchema.PORT_ID_TAG, getID());
portElement.addProperty(GraphSchema.PORT_NAME_TAG, getName());
portElement.addProperty(GraphSchema.PORT_NODE_TAG, this.node.getID());
return portElement;
}
/**
* Returns the port index within the node that this port belongs to.
*
* @return the port index within the node that this port belongs to
*/
public int getIndex() {
int index;
switch (this.kind) {
case DATA_IN:
index = getNode().getInputPorts().indexOf(this);
break;
case DATA_OUT:
index = getNode().getOutputPorts().indexOf(this);
break;
case CONTROL_IN:
index = 0; // Has only one.
break;
case CONTROL_OUT:
index = getNode().getControlOutPorts().indexOf(this);
break;
case EPR:
index = 0; // Has only one.
break;
default:
// Shoud not happen.
throw new RuntimeException("Wrong type of the port: " + this.kind);
}
return index;
}
public void setID(String id) {
this.id = id;
}
}