--- /dev/null
+// =========================================================================
+// @author Leonardo Florez-Valencia (florez-l@javeriana.edu.co)
+// =========================================================================
+
+$include "Value.e"
+
+#include <cpPlugins/Pipeline.h>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+#include <boost/tokenizer.hpp>
+
+// -------------------------------------------------------------------------
+cpPlugins::Pipeline::TAdjMatrix::
+TAdjMatrix( )
+{
+}
+
+// -------------------------------------------------------------------------
+cpPlugins::Pipeline::TAdjMatrix::
+~TAdjMatrix( )
+{
+}
+
+// -------------------------------------------------------------------------
+bool cpPlugins::Pipeline::TAdjMatrix::
+HasConnection(
+ const std::string& oObj, const std::string& dObj,
+ const std::string& oPort, const std::string& dPort
+ ) const
+{
+ TMatrix::const_iterator m = this->m_Matrix.find( oObj );
+ if( m != this->m_Matrix.end( ) )
+ {
+ TRow::const_iterator r = m->second.find( dObj );
+ if( r != m->second.end( ) )
+ return( r->second.find( TEdge( oPort, dPort ) ) != r->second.end( ) );
+ else
+ return( false );
+ }
+ else
+ return( false );
+}
+
+// -------------------------------------------------------------------------
+cpPlugins::Pipeline::TAdjMatrix::
+TEdges& cpPlugins::Pipeline::TAdjMatrix::
+operator()( const std::string& o, const std::string& d )
+{
+ TMatrix::iterator m = this->m_Matrix.find( o );
+ if( m != this->m_Matrix.end( ) )
+ {
+ TRow::iterator r = m->second.find( d );
+ if( r != m->second.end( ) )
+ return( r->second );
+ } // end if
+
+ // If not found...
+ this->m_Matrix[ o ][ d ] = TEdges( );
+ return( this->operator()( o, d ) );
+}
+
+// -------------------------------------------------------------------------
+const cpPlugins::Pipeline::TAdjMatrix::
+TEdges& cpPlugins::Pipeline::TAdjMatrix::
+operator()( const std::string& o, const std::string& d ) const
+{
+ TMatrix::const_iterator m = this->m_Matrix.find( o );
+ if( m != this->m_Matrix.end( ) )
+ {
+ TRow::const_iterator r = m->second.find( d );
+ if( r != m->second.end( ) )
+ return( r->second );
+ } // end if
+
+ // If not found...
+ cpPluginsErrorMacro( << "Connection not found." );
+}
+
+// -------------------------------------------------------------------------
+template< >
+void cpPlugins::Pipeline::TAdjMatrix::
+SaveXML( boost::property_tree::ptree* node ) const
+{
+ TMatrix::const_iterator m = this->m_Matrix.begin( );
+ for( ; m != this->m_Matrix.end( ); ++m )
+ {
+ TRow::const_iterator r = m->second.begin( );
+ for( ; r != m->second.end( ); r++ )
+ {
+ for( const TEdge& e: r->second )
+ {
+ boost::property_tree::ptree c;
+ c.put( "<xmlattr>.from", e.first + "@" + m->first );
+ c.put( "<xmlattr>.to", e.second + "@" + r->first );
+ node->add_child( "pipeline.connection", c );
+
+ } // end for
+ } // end for
+ } // end for
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+Clear( )
+{
+ // TODO
+}
+
+// -------------------------------------------------------------------------
+cpPlugins::ProcessObject* cpPlugins::Pipeline::
+CreateNode( const std::string& class_name, const std::string& node_name )
+{
+ // Create object
+ cpPlugins::ProcessObject::SharedPtr p = this->m_Mgr.Create( class_name );
+ if( !p )
+ cpPluginsErrorMacro(
+ << "Something went wrong creating an object of type \""
+ << class_name << "\""
+ );
+
+ // Assign an unique name to it
+ std::string u = ( node_name == "" )? class_name: node_name;
+ while( !( this->m_Nodes.insert( TNodes::value_type( u, p ) ).second ) )
+ u += "_";
+ p->SetName( u );
+ p->SetPipeline( this );
+ p->SetExecutionDebug( this->GetExecutionDebug( ) );
+
+ // Connect parameters
+ std::set< std::string > names;
+ {{#t}}
+ names = p->Get{{t}}ValueNames( );
+ for( const std::string& n: names )
+ this->Configure{{t}}Value( n + "@" + u, p->Get{{t}}ValueTemplate( n ) );
+ names.clear( );
+ {{/t}}
+
+ // TODO: connect set/sequences
+
+ return( p.get( ) );
+}
+
+// -------------------------------------------------------------------------
+cpPlugins::ProcessObject* cpPlugins::Pipeline::
+GetNode( const std::string& name )
+{
+ TNodes::iterator i = this->m_Nodes.find( name );
+ if( i != this->m_Nodes.end( ) )
+ return( i->second.get( ) );
+ else
+ return( NULL );
+}
+
+// -------------------------------------------------------------------------
+const cpPlugins::ProcessObject* cpPlugins::Pipeline::
+GetNode( const std::string& name ) const
+{
+ TNodes::const_iterator i = this->m_Nodes.find( name );
+ if( i != this->m_Nodes.end( ) )
+ return( i->second.get( ) );
+ else
+ return( NULL );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+Connect(
+ const std::string& oObj, const std::string& dObj,
+ const std::string& oPort, const std::string& dPort
+ )
+{
+ TNodes::iterator oIt = this->m_Nodes.find( oObj );
+ TNodes::iterator dIt = this->m_Nodes.find( dObj );
+ TNodes::iterator eIt = this->m_Nodes.end( );
+ if( oIt == eIt || dIt == eIt )
+ cpPluginsErrorMacro( this, << "Connection not possible." );
+ if( this->m_AdjMatrix.HasConnection( oObj, dObj, oPort, dPort ) )
+ return;
+
+ // Check destination node
+ cpPlugins::ProcessObject::SharedPtr dest = dIt->second;
+ if( !dest )
+ cpPluginsErrorMacro(
+ this, << "Invalid destination \"" << dObj << "\"."
+ );
+
+ // Process source node
+ cpPlugins::Filter* src = oIt->second->Cast< cpPlugins::Filter >( );
+ if( src == NULL )
+ this->_Connect(
+ oIt->second->Cast< cpPlugins::Functor >( ), oPort, dest.get( ), dPort
+ );
+ else
+ this->_Connect( src, oPort, dest.get( ), dPort );
+
+ // Update adjacency matrix
+ this->m_AdjMatrix( oObj, dObj ).insert( TEdge( oPort, dPort ) );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+Connect( const std::string& src, const std::string& dest )
+{
+ std::string oObj, dObj, oPort, dPort;
+ Self::_ParseComponentName( src, oObj, oPort );
+ Self::_ParseComponentName( dest, dObj, dPort );
+ this->Connect( oObj, dObj, oPort, dPort );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+LoadXML( const std::string& fname )
+{
+ boost::property_tree::ptree xml;
+ boost::property_tree::read_xml( fname, xml );
+
+ // Check for a single pipeline
+ const boost::property_tree::ptree* pipeline = NULL;
+ for( const boost::property_tree::ptree::value_type& v: xml )
+ {
+ if( v.first == "pipeline" )
+ {
+ if( pipeline != NULL )
+ cpPluginsErrorMacro( << "Multiple pipelines are not supported." );
+ pipeline = &( v.second );
+
+ } // end if
+ } // end for
+
+ // Ok, seems ok to reset current pipeline
+ this->Clear( );
+
+ // Get description
+ boost::optional< std::string > desc =
+ pipeline->get_optional< std::string >( "<xmlattr>.desc" );
+ if( desc )
+ this->m_Description = desc.get( );
+
+ // Load nodes
+ for( const boost::property_tree::ptree::value_type& node: *pipeline )
+ {
+ if( node.first == "node" )
+ {
+ std::string name = node.second.get< std::string >( "<xmlattr>.name" );
+ std::string cname = node.second.get< std::string >( "<xmlattr>.class" );
+ cpPlugins::ProcessObject* n = this->CreateNode( cname, name );
+ n->LoadXML( node );
+
+ } // end if
+ } // end for
+
+ // Load connections
+ for( const boost::property_tree::ptree::value_type& c: *pipeline )
+ if( c.first == "connection" )
+ this->Connect(
+ c.second.get< std::string >( "<xmlattr>.from" ),
+ c.second.get< std::string >( "<xmlattr>.to" )
+ );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+SaveXML( const std::string& fname ) const
+{
+ boost::property_tree::ptree d;
+ if( this->m_Description != "" )
+ d.put( "pipeline.<xmlattr>.desc", this->m_Description );
+
+ // Save nodes
+ TNodes::const_iterator n = this->m_Nodes.begin( );
+ for( ; n != this->m_Nodes.end( ); ++n )
+ n->second->SaveXML( &d );
+
+ // Save connections
+ this->m_AdjMatrix.SaveXML( &d );
+
+ // Real write
+ boost::property_tree::xml_writer_settings< std::string > s( ' ', 2 );
+ boost::property_tree::write_xml( fname, d, std::locale( ), s );
+}
+
+// -------------------------------------------------------------------------
+bool cpPlugins::Pipeline::
+GetExecutionDebug( ) const
+{
+ return( this->m_PipelineExecutionDebug );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+SetExecutionDebug( bool d )
+{
+ this->m_PipelineExecutionDebug = d;
+ for( TNodes::value_type& n: this->m_Nodes )
+ n.second->SetExecutionDebug( d );
+}
+
+// -------------------------------------------------------------------------
+{{#t}}
+void cpPlugins::Pipeline::
+Modified{{t}}Value( const std::string& name )
+{
+ // Guess information
+ std::string n, v;
+ Self::_ParseComponentName( name, n, v );
+
+ // Find node
+ TNodes::iterator node = this->m_Nodes.find( n );
+ if( node == this->m_Nodes.end( ) )
+ cpPluginsErrorMacro(
+ this, << "Unknown node \"" << n << "\"."
+ );
+
+ // Get configured value and continue
+ node->second->Set{{t}}Value( v, this->Get{{t}}Value( name ) );
+ this->Superclass::Modified{{t}}Value( name );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+Modified{{t}}Set( const std::string& name )
+{
+ std::cout << "Modified{{t}}Set: " << name << std::endl;
+ this->Superclass::Modified{{t}}Set( name );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+Modified{{t}}Sequence( const std::string& name )
+{
+ std::cout << "Modified{{t}}Sequence: " << name << std::endl;
+ this->Superclass::Modified{{t}}Sequence( name );
+}
+{{/t}}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+ModifiedChoice( const std::string& name )
+{
+ std::cout << "ModifiedChoice: " << name << std::endl;
+ this->Superclass::ModifiedChoice( name );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+DefineInput(
+ const std::string& input, const std::string& node, const std::string& port
+ )
+{
+ if(
+ this->m_InputRelations.insert(
+ TPortRelations::value_type( input, TEdge( node, port ) )
+ ).second
+ )
+ this->Modified( );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+SetInput( const std::string& name, cpPlugins::DataObject* data )
+{
+ // Guess information
+ std::string n, o;
+ TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
+ if( rIt != this->m_InputRelations.end( ) )
+ {
+ n = rIt->second.first;
+ o = rIt->second.second;
+ }
+ else
+ Self::_ParseComponentName( name, n, o );
+
+ // Find node
+ TNodes::iterator node = this->m_Nodes.find( n );
+ if( node == this->m_Nodes.end( ) )
+ cpPluginsErrorMacro(
+ this, << "Unknown node \"" << n << "\"."
+ );
+ node->second->SetInput( o, data );
+}
+
+// -------------------------------------------------------------------------
+cpPlugins::DataObject* cpPlugins::Pipeline::
+GetInput( const std::string& name, const unsigned int id )
+{
+ // Guess information
+ std::string n, o;
+ TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
+ if( rIt != this->m_InputRelations.end( ) )
+ {
+ n = rIt->second.first;
+ o = rIt->second.second;
+ }
+ else
+ Self::_ParseComponentName( name, n, o );
+
+ // Find node
+ TNodes::iterator node = this->m_Nodes.find( n );
+ if( node == this->m_Nodes.end( ) )
+ cpPluginsErrorMacro(
+ this, << "Unknown node \"" << n << "\"."
+ );
+ return( node->second->GetInput( o, id ) );
+}
+
+// -------------------------------------------------------------------------
+const cpPlugins::DataObject* cpPlugins::Pipeline::
+GetInput( const std::string& name, const unsigned int id ) const
+{
+ // Guess information
+ std::string n, o;
+ TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
+ if( rIt != this->m_InputRelations.end( ) )
+ {
+ n = rIt->second.first;
+ o = rIt->second.second;
+ }
+ else
+ Self::_ParseComponentName( name, n, o );
+
+ // Find node
+ TNodes::const_iterator node = this->m_Nodes.find( n );
+ if( node == this->m_Nodes.end( ) )
+ cpPluginsErrorMacro(
+ this, << "Unknown node \"" << n << "\"."
+ );
+ return( node->second->GetInput( o, id ) );
+}
+
+// -------------------------------------------------------------------------
+bool cpPlugins::Pipeline::
+HasInput( const std::string& name ) const
+{
+ // Guess information
+ std::string n, o;
+ TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
+ if( rIt != this->m_InputRelations.end( ) )
+ {
+ n = rIt->second.first;
+ o = rIt->second.second;
+ }
+ else
+ Self::_ParseComponentName( name, n, o );
+
+ // Find node
+ TNodes::const_iterator node = this->m_Nodes.find( n );
+ if( node == this->m_Nodes.end( ) )
+ cpPluginsErrorMacro(
+ this, << "Unknown node \"" << n << "\"."
+ );
+ return( node->second->HasInput( n ) );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+DefineOutput(
+ const std::string& output, const std::string& node, const std::string& port
+ )
+{
+ if(
+ this->m_OutputRelations.insert(
+ TPortRelations::value_type( output, TEdge( node, port ) )
+ ).second
+ )
+ this->Modified( );
+}
+
+// -------------------------------------------------------------------------
+cpPlugins::DataObject* cpPlugins::Pipeline::
+GetOutput( const std::string& name )
+{
+ // Guess information
+ std::string n, o;
+ TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
+ if( rIt != this->m_OutputRelations.end( ) )
+ {
+ n = rIt->second.first;
+ o = rIt->second.second;
+ }
+ else
+ Self::_ParseComponentName( name, n, o );
+
+ // Find node
+ TNodes::iterator node = this->m_Nodes.find( n );
+ if( node == this->m_Nodes.end( ) )
+ cpPluginsErrorMacro(
+ this, << "Unknown node \"" << n << "\"."
+ );
+ cpPlugins::Filter* f = node->second->Cast< cpPlugins::Filter >( );
+ if( f != NULL )
+ return( f->GetOutput( o ) );
+ else
+ cpPluginsErrorMacro(
+ this, << "Node \"" << n << "\" does not have outputs."
+ );
+}
+
+// -------------------------------------------------------------------------
+const cpPlugins::DataObject* cpPlugins::Pipeline::
+GetOutput( const std::string& name ) const
+{
+ // Guess information
+ std::string n, o;
+ TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
+ if( rIt != this->m_OutputRelations.end( ) )
+ {
+ n = rIt->second.first;
+ o = rIt->second.second;
+ }
+ else
+ Self::_ParseComponentName( name, n, o );
+
+ // Find node
+ TNodes::const_iterator node = this->m_Nodes.find( n );
+ if( node == this->m_Nodes.end( ) )
+ cpPluginsErrorMacro(
+ this, << "Unknown node \"" << n << "\"."
+ );
+ const cpPlugins::Filter* f = node->second->Cast< cpPlugins::Filter >( );
+ if( f != NULL )
+ return( f->GetOutput( o ) );
+ else
+ cpPluginsErrorMacro(
+ this, << "Node \"" << n << "\" does not have outputs."
+ );
+}
+
+// -------------------------------------------------------------------------
+cpPlugins::Pipeline::
+Pipeline( )
+ : Superclass( ),
+ m_Description( "" ),
+ m_PipelineExecutionDebug( false )
+{
+ this->m_Mgr.Configure( );
+}
+
+// -------------------------------------------------------------------------
+cpPlugins::Pipeline::
+~Pipeline( )
+{
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+_GenerateData( )
+{
+ for( TNodes::value_type& v: this->m_Nodes )
+ v.second->Cast< cpPlugins::ProcessObject >( )->Update( );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+_Connect(
+ Filter* src, const std::string& srcPort,
+ ProcessObject* dest, const std::string& destPort
+ )
+{
+ if( src->HasOutValue( srcPort ) && dest->HasInValue( destPort ) )
+ {
+ }
+ else if( src->HasOutput( srcPort ) && dest->HasInput( destPort ) )
+ dest->SetInput( destPort, src->GetOutput( srcPort ) );
+ else
+ cpPluginsErrorMacro(
+ this,
+ << "Invalid connection from \"" << src->GetName( ) << "\" to \""
+ << dest->GetName( ) << " (" << srcPort << "->" << destPort << ")"
+ );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+_Connect(
+ Functor* functor, const std::string& functorValue,
+ ProcessObject* dest, const std::string& destValue
+ )
+{
+ if( functorValue == "Functor" )
+ {
+ Filter* filter = dynamic_cast< Filter* >( dest );
+ if( filter != NULL )
+ filter->SetFunctor( destValue, functor );
+ else
+ cpPluginsErrorMacro( this, << "Invalid functor connection." );
+ }
+ else
+ {
+ if(
+ functor->HasOutValue( functorValue ) && dest->HasInValue( destValue )
+ )
+ dest->SetInValuePtr(
+ destValue, functor->GetOutValuePtr( functorValue )
+ );
+ else
+ cpPluginsErrorMacro(
+ this,
+ << "Invalid connection from \"" << functor->GetName( ) << "\" to \""
+ << dest->GetName( ) << " (" << functorValue << "->"
+ << destValue << ")"
+ );
+ } // end if
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Pipeline::
+_ParseComponentName(
+ const std::string& name,
+ std::string& node,
+ std::string& component
+ )
+{
+ typedef boost::char_separator< char > _TSep;
+ typedef boost::tokenizer< _TSep > _TTok;
+
+ // Get parameter info
+ _TTok tok( name, _TSep( "@" ) );
+ std::vector< std::string > tokens;
+ for( _TTok::const_iterator tIt = tok.begin( ); tIt != tok.end( ); ++tIt )
+ tokens.push_back( *tIt );
+
+ // Try another distribution
+ if( tokens.size( ) != 2 )
+ {
+ } // end if
+
+ // Nothing else to do?
+ if( tokens.size( ) != 2 )
+ cpPluginsErrorMacro(
+ << "Unknown input value parameter \"" << name << "\"."
+ );
+
+ // Names
+ component = tokens[ 0 ];
+ node = tokens[ 1 ];
+}
+
+// eof - $RCSfile$