/* * 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.operator; import de.unihalle.informatik.Alida.dataio.ALDDataIOManagerCmdline; import de.unihalle.informatik.Alida.dataio.provider.ALDDataIOCmdline; import de.unihalle.informatik.Alida.operator.ALDOperator.HidingMode; import java.util.*; import java.io.*; import org.apache.xmlbeans.*; /** Each instance of this class represents an operator invocation for the * implicit processing graph. * It holds input and output ports used to link the objects according to the data flow, * as well as the parameter's values upon invocation in a parameter hash. */ public class ALDOpNode { // IMPORTANT NOTE: the reference to the operator object needs to be // remove upon return of the operate method for the VM to be able to garbage // collect the operator object and its references ALDOperator op; /** the input ports of this opNode. */ private ALDInputPort[] inputPorts; /** the output ports of this opNode. */ private ALDOutputPort[] outputPorts; /** name of the operator for which an invocations is represented by this opNode */ final private String name; /** version of the operator for which an invocations is represented by this opNode */ final private String version; /** class of the operator for which an invocations is represented by this opNode */ final private Class<? extends ALDOperator> operatorClass; /** Hiding mode of this opnode in the processing history. */ HidingMode hidingMode; /** This opnode prefers a complete DAG to constructed for its invocation. */ final boolean completeDAG; /** This hash contains the values of all parameters as return by the <code>toString()</code> * method of the parameters at the time of invocation of the operator using <code>runOp()</code>. */ private Hashtable<String, String> parameterHash; /** parameteHash as an XmlObject */ private XmlObject parameterHashAsXml; /** parent of this opNode, will be set during back tracing */ private ALDOpNode parent; /** children of this opNode, will be set during back tracing */ private Vector<ALDOpNode> children; /** children of this opNode, set when the <code> operate()</code> * represented by this <code>opNode</code> calls nested operators. */ private Vector<ALDOpNode> directlyRegisteredChildren; /** depth in calling stack of Operators, set when back tracing */ private int depth; /** ALDDataPorts created within this opNode, set during back tracing */ private Vector<ALDDataPort> includedData; /** Construct an <code>ALDOpNode</code> for the operator <code>op</code> and <code>hidingMode</code> * * @param op Operator to instatiate an opnode for * @param hidingMode hiding mode within processing history */ public ALDOpNode( ALDOperator op, HidingMode hidingMode) { //Experimental if ( collectInstances ) { allInstances.add( this ); } //END Experimental this.completeDAG = op.completeDAG; this.depth = Integer.MAX_VALUE; this.hidingMode = hidingMode; this.op = op; this.name = op.getName(); this.operatorClass = op.getClass(); this.version = op.getVersion(); try { Collection<String> inInoutNames = op.getInInoutNames(); inputPorts = new ALDInputPort[ inInoutNames.size()]; int i = -1; for ( String inputName : inInoutNames ) { i++; inputPorts[i] = new ALDInputPort( this, i, inputName); } Collection<String> outInoutNames = op.getOutInoutNames(); outputPorts = new ALDOutputPort[ outInoutNames.size()]; i = -1; for ( String outputName : outInoutNames ) { i++; outputPorts[i] = new ALDOutputPort( this, i, outputName); } parameterHash = new Hashtable<String, String>(); children = new Vector<ALDOpNode>(); directlyRegisteredChildren = new Vector<ALDOpNode>(); includedData = new Vector<ALDDataPort>(); // copy IN and INOUT parameters of the descriptor to a private hash // this is necessary, as the descriptor may be reused lateron with different // values of its parameters (or the values changes for another purpose) for ( String pName : op.getInInoutNames() ) { if ( op.getParameter( pName) != null ) { Object value = op.getParameter( pName); if ( value.getClass().isArray()) { try { ALDDataIOCmdline provider = (ALDDataIOCmdline)ALDDataIOManagerCmdline.getInstance().getProvider(value.getClass(), ALDDataIOCmdline.class); String valueString = provider.writeData( value, ""); parameterHash.put( op.getParameterDescriptor( pName).name, valueString); } catch (Exception ex) { parameterHash.put( op.getParameterDescriptor( pName).name, value.toString()); } } else { parameterHash.put( op.getParameterDescriptor( pName).name, value.toString()); } } } //parameterHashAsXml = op.parametersToXmlObject(); } catch (Exception e) { e.printStackTrace(); } } /** Get the name of the operator represented by this opNode. */ public String getName() { return name; } /** Get the software version. */ public String getVersion() { return version; } /** Get the class object of the operator represented by this opNode. */ public Class<? extends ALDOperator> getOperatorClass() { return operatorClass; } /** Set depth. */ void setDepth( int depth) { this.depth = depth; } /** Get depth. */ public int getDepth() { return depth; } /** Add a child found during back tracing. * @param opNode child to add */ void addChild( ALDOpNode opNode) { children.add( opNode); } /** Add a directly registered child during invocation. * @param opNode child to add */ void addDirectChild( ALDOpNode opNode) { directlyRegisteredChildren.add( opNode); } /** Add a data port found during back tracing. */ void addData( ALDDataPort data) { includedData.add( data); } /** Get input port with index i of this opNode. */ public ALDPort getInputPort( int i) { return inputPorts[i]; } /** Get output port with index i of this opNode. */ public ALDOutputPort getOutputPort( int i) { return outputPorts[i]; } /** Set the origin of the input port with index i. * This sets the origin of the associated input port as well * as its canoncial classname. The explanation is usually to * be copied from the argument descriptor of this input port. * * @param i index of the input port * @param obj object to assiciate with the port * @param explanation explnatory string of port **/ void setInOrigin( int i, Object obj, String explanation) { if ( obj != null ) { inputPorts[i].setOrigin(ALDOperator.getALDPortHashAccessKey().getHistoryLink(obj)); if ( obj.getClass().getPackage() == null ) inputPorts[i].setClassname( obj.getClass().getName()); else inputPorts[i].setClassname( obj.getClass().getPackage()+"."+obj.getClass().getName()); } inputPorts[i].setExplanation( explanation); } /** Set the origin of the output port with index i. * This sets the origin of the accociated output port as well * as its canoncial classname. The explanation is usually to * be copied from the argument descriptor of this output port. * * @param i index of the input port * @param obj object to assiciate with the port * @param explanation explnatory string of port **/ void setOutOrigin( int i, Object obj, String explanation) { if ( obj != null ) { outputPorts[i].setOrigin( ALDOperator.getALDPortHashAccessKey().getHistoryLink(obj) ); if ( obj.getClass().getPackage() == null ) { outputPorts[i].setClassname( obj.getClass().getName()); } else { outputPorts[i].setClassname( obj.getClass().getPackage()+"."+obj.getClass().getName()); } } outputPorts[i].setExplanation( explanation); } /** Set the parent opNode. */ public void setParent( ALDOpNode parent) { this.parent = parent; } /** Get the parent opNode. */ public ALDOpNode getParent() { return parent; } /** Get the all opNode children found during back tracing. */ protected Vector<ALDOpNode> getChildren() { return children; } /** Get the all <code>opNode</code> children directly registered during invocation. */ protected Vector<ALDOpNode> getDirectlyRegisteredChildern() { return directlyRegisteredChildren; } /** Get all included data ports found during back tracing. */ protected Vector<ALDDataPort> getIncludedData() { return includedData; } /** Get all input ports of this opNode. */ protected ALDInputPort[] getInputPorts() { return inputPorts; } /** Get all output ports of this opNode. */ protected ALDOutputPort[] getOutputPorts() { return outputPorts; } /** Get all keys of the parameter hash. */ public Enumeration<String> getParameterKeys() { return this.parameterHash.keys(); } /** Get value of parameter for given key. */ public String getParameter( String key) { return this.parameterHash.get( key); } /** Set hidden flag of this opNode. * This prevents this <code>opNode</code> to be included into a processing * history as explicitly constructed. */ public void setHidden( HidingMode hidingMode) { this.hidingMode = hidingMode; } /** Get hiding mode of this opNode. */ public HidingMode getHidingMode() { return this.hidingMode; } /** Get the parameter hash where values of parameters. * are represented as xml objects. */ public XmlObject getParameterHashAsXml() { return this.parameterHashAsXml; } /** Print information if this opNode to standard output. */ public void print() { System.out.println( "ALDOpNode ( with " + inputPorts.length + "/" + outputPorts.length + " ports for operator " + name + " at depth " + depth + ", completeDAG " + completeDAG + ")" ); System.out.println( " >>>>> children: "); Iterator<ALDOpNode> oItr = children.iterator(); while ( oItr.hasNext() ) { System.out.println( " " + oItr.next().getName()); } System.out.println( " <<<<< children: "); System.out.println( " >>>>> direct children: "); oItr = directlyRegisteredChildren.iterator(); while ( oItr.hasNext() ) { System.out.println( " " + oItr.next().getName()); } System.out.println( " <<<<< direct children: "); } // Experimental /** if true all instances of ALDOpNode will be collected in a * static Vector. * WARNING: no instance of ALDOpNode will ever be freed currently in this case */ private static boolean collectInstances = false; // Maybe we should use weak references to allow instances of opNode to be freed private static Vector<ALDOpNode> allInstances = new Vector<ALDOpNode>(); static synchronized Vector<ALDOpNode> getAllInstances() { return( (Vector<ALDOpNode>)allInstances.clone() ); } public static synchronized void printInstanceStatistics() { printInstanceStatistics( System.out); } public static synchronized void printInstanceStatistics( PrintStream stream) { stream.println( "Currently there are " + allInstances.size() + " instances of ALDOpNode"); int numberParameters = 0; int charsInParameters = 0; int charsInValues = 0; for ( int i = 0 ; i < allInstances.size() ; i++ ) { Enumeration<String> keys = allInstances.elementAt( i).getParameterKeys(); while(keys.hasMoreElements()) { numberParameters++; String key = keys.nextElement(); charsInParameters += key.length(); charsInValues += allInstances.elementAt( i).getParameter( key).length(); } } stream.println( " with a total of " + numberParameters + " parameters with " + + charsInParameters + " characters in the keys and " + + charsInValues + " characters in the values"); } // END Experimental }