/* * This file is part of Alida, a Java library for * Advanced Library for Integrated Development of Data Analysis Applications. * * Copyright (C) 2010 - @YEAR@ * * This program 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. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. * * Fore more information on Alida, visit * * http://www.informatik.uni-halle.de/alida/ * */ /* * Most recent change(s): * * $Rev$ * $Date$ * $Author$ * */ package de.unihalle.informatik.Alida.workflows; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.Vector; import de.unihalle.informatik.Alida.exceptions.ALDOperatorException; import de.unihalle.informatik.Alida.exceptions.ALDWorkflowException; import de.unihalle.informatik.Alida.exceptions.ALDWorkflowException.WorkflowExceptionType; import de.unihalle.informatik.Alida.operator.ALDOperator; /** * This class represents a node in an Alida work flow. * Essentially it holds an {@link de.unihalle.informatik.Alida.annotations.ALDAOperator} object * and edges connecting parameters of this operator. * @author posch * */ public class ALDWorkflowNode { public static enum ALDWorkflowNodeState { UNCONFIGURED, CONFIGURED, RUNNABLE, RUNNING, READY } /** * The operator object associated with this node. */ private ALDOperator op; /** * Is true it his node is used as an interior shadow (or substitute) for the * node holding this work flow {see {@link ALDWorkflow}. */ public final boolean isInteriorShadowNode; /** * The state of the node */ private transient ALDWorkflowNodeState state; /** * The execution progress of the operator associated with this node */ private transient String operatorExecutionProgressDescr = null; /** * This is the enclosing work flow. */ private ALDWorkflow parentWorkflow; /** * all incoming edges. */ Vector<ALDWorkflowEdge> inEdges; /** * outgoing edges. */ Vector<ALDWorkflowEdge> outEdges; /** * Create a node * @param parentWorkflow TODO * @param op * @param id */ public ALDWorkflowNode(ALDWorkflow parentWorkflow, ALDOperator op) { this(parentWorkflow, op,false); } /** * Create a node * @param parentWorkflow TODO * @param op * @param id */ public ALDWorkflowNode(ALDWorkflow parentWorkflow, ALDOperator op, boolean isInteriorShadowNode) { this.setParentWorkflow(parentWorkflow); this.op = op; this.isInteriorShadowNode = isInteriorShadowNode; if ( op.getMissingRequiredInputs().size() == 0 ) { this.state = ALDWorkflowNodeState.CONFIGURED; } else { this.state = ALDWorkflowNodeState.UNCONFIGURED; } inEdges = new Vector<ALDWorkflowEdge>(); outEdges = new Vector<ALDWorkflowEdge>(); } /** * @return the parentWorkflow */ public ALDWorkflow getParentWorkflow() { return parentWorkflow; } /** * @param parentWorkflow the parentWorkflow to set */ protected void setParentWorkflow(ALDWorkflow parentWorkflow) { this.parentWorkflow = parentWorkflow; } /** Returns the operator associated with this node. * * @return */ public ALDOperator getOperator() { return op; } /** Sets the operator associated with this node. * The new operator instance needs to be of the same class as the current operator instance. * * @throws ALDWorkflowException if the new operator instance is of wrong type */ protected void setOperator( ALDOperator newOp) throws ALDWorkflowException { if ( newOp.getClass() != this.getOperator().getClass() ) { throw new ALDWorkflowException(WorkflowExceptionType.INVALID_OPERATOR, "ALDWorkflowNode::setOperator wrong class of operator"); } this.op = newOp; } /** * Returns the current state of this node * @return */ public ALDWorkflowNodeState getState() { return state; } /** * Sets the state of this node * * @param state New state */ protected void setState( ALDWorkflowNodeState state) { this.state = state; } /** * Return the Id associated with this node. * @return */ public Integer getId() { return ALDWorkflow.mapNodeToNodeId(this).id; } /** * Return true if the state of this node is greater equal the * <code>compareState</code> * @param compareState * @return */ public boolean stateGreaterEqual( ALDWorkflowNodeState compareState) { return this.state.compareTo(compareState) >= 0; } /** Returns all incoming edges. * * @return */ protected Vector<ALDWorkflowEdge> getInEdges() { return inEdges; } /** * Returns all outgoing edges. * * @return */ protected Vector<ALDWorkflowEdge> getOutEdges() { return outEdges; } /** * @return the operatorExecutionProgressDescr */ public String getOperatorExecutionProgressDescr() { return operatorExecutionProgressDescr; } /** * @param operatorExecutionProgressDescr the operatorExecutionProgressDescr to set */ public void setOperatorExecutionProgressDescr( String operatorExecutionProgressDescr) { this.operatorExecutionProgressDescr = operatorExecutionProgressDescr; } /** Return all parents of this node. * Parents are define to be nodes with at least one edge connecting * a output parameter of this source node to the node considered. * The interior shadow node is define to have no parents (inside this work flow). * * @return all parents */ public Set<ALDWorkflowNode> getParents() { HashSet<ALDWorkflowNode> indices = new HashSet<ALDWorkflowNode>(); if ( this.isInteriorShadowNode) return indices; for ( ALDWorkflowEdge edge : this.inEdges ) { indices.add( edge.getSourceNode()); } return indices; } /** Return all children nodes of this node. * Children are define to be nodes with at least one edge connecting * a input parameter of this child node to the node considered. * The interior shadow considered not to be a child of any node (inside this work flow). * * @return indices of all child nodes */ public Set<ALDWorkflowNode> getChildren() { HashSet<ALDWorkflowNode> indices = new HashSet<ALDWorkflowNode>(); for ( ALDWorkflowEdge edge : this.outEdges ) { if ( ! edge.getTargetNode().isInteriorShadowNode ) indices.add( edge.getTargetNode()); } return indices; } /** * Return the nodeIds of all descendants of the given node. * * @param nodeId * @return nodeIds of all descendants */ public Set<ALDWorkflowNode> getDescendants() { HashSet<ALDWorkflowNode> descendants = new HashSet<ALDWorkflowNode>(this.getChildren()); for ( ALDWorkflowNode descendant : this.getChildren() ) { descendants.addAll( descendant.getDescendants()); } return descendants; } /** * Return all ancestors of this node. * * @return all descendants */ public Set<ALDWorkflowNode> getAncestors() { HashSet<ALDWorkflowNode> ancestors = new HashSet<ALDWorkflowNode>(this.getParents()); for ( ALDWorkflowNode ancestor : this.getParents() ) { ancestors.addAll( ancestor.getAncestors()); } return ancestors; } /** Return all incoming edges for this node which * have their target at <code>parameterName</code>. * * @param parameterName * @return indices of all incoming edges which have their target at <code>parameterName</code> */ public Collection<ALDWorkflowEdge> getInEdgesForParameter( String parameterName) { Vector<ALDWorkflowEdge> edges = new Vector<ALDWorkflowEdge>(); for ( ALDWorkflowEdge edge : this.getInEdges() ) { if ( parameterName.equals( edge.getTargetParameterName()) ) { edges.add( edge); } } if ( ALDWorkflow.debug >= 2) { System.out.println( "ALDWorkflowNode::getInEdgesForParameter for node <" + ALDWorkflow.mapNodeToNodeId(this) + "> and parameter " + parameterName + ": " + ALDWorkflow.edgeIdsToString(edges)); } return edges; } /** Return outgoing edges for this node which * have their source at <code>parameterName</code>. * * @param parameterName * @return indices of all outgoing edges which have their source at <code>parameterName</code> */ public Collection<ALDWorkflowEdge> getOutEdgesForParameter( String parameterName) { Vector<ALDWorkflowEdge> edges = new Vector<ALDWorkflowEdge>(); for ( ALDWorkflowEdge edge : this.outEdges ) { if ( parameterName.equals( edge.getSourceParameterName()) ) { edges.add( edge); } } if ( ALDWorkflow.debug >= 2) { System.out.println( "ALDWorkflowNode::getOutEdgesForParameter for node <" + ALDWorkflow.mapNodeToNodeId(this) + "> and parameter " + parameterName + ": " + edges); } return edges; } /** * Checks if this node is configured. * A node is configured if all required input parameters have a non-null value * in the operator object associated with the node or gave an incoming * edge in the work flow. * * @return */ public boolean isConfigured() { if ( this.getMissingRequiredInputs().size() == 0) { return true; } else { return false; } } /** * Returns the names of all required input parameters of the operator object associated with the node * which are not linked and have a value of null * * @return */ public Collection<String> getMissingRequiredInputs() { List<String> missingInputs = this.getOperator().getMissingRequiredInputs(); if ( ALDWorkflow.debug >= 2 ) { System.out.println(" ALDWorkflowNode::getMissingRequiredInputs missing in operator" + missingInputs); } LinkedList<String> missing = new LinkedList<String>( missingInputs); for ( String paramName : missingInputs) { if ( this.getInEdgesForParameter( paramName).size() != 0 ) { missing.remove( paramName); } } if ( ALDWorkflow.debug >= 2 ) { System.out.println(" ALDWorkflowNode::getMissingRequiredInputs missing considering also edges" + missingInputs); } return missing; } /** * Reset the parameter <code>parameterName</code> in the operator associated to * this node. * Currently this sets the parameters value to null. * * @param parameterName * @throws ALDWorkflowException if the parameter does not exists */ void resetParameter( String parameterName) throws ALDWorkflowException { try { this.getOperator().setParameter( parameterName, null); } catch (ALDOperatorException e) { throw( new ALDWorkflowException( WorkflowExceptionType.FATAL_INTERNAL_ERROR, "Cannot reset parameter <" + parameterName + "> in operator <" + this.getOperator().getName() + ">")); } } /** * Print information of this node to standard out. */ public void print() { System.out.println( "ALDWorkflowNode <" + ALDWorkflow.mapNodeToNodeId(this) + "> for operator " + op.getName()); try { System.out.println( " verbose = " + op.getVerbose()); } catch (ALDOperatorException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println( " incoming edges"); for ( ALDWorkflowEdge edge : inEdges) { edge.print(); } System.out.println( " out going edges"); for ( ALDWorkflowEdge edge : outEdges) { edge.print(); } } }