1 // =========================================================================
2 // @author Leonardo Florez-Valencia (florez-l@javeriana.edu.co)
3 // =========================================================================
7 #include <cpPlugins/Pipeline.h>
8 #include <boost/property_tree/ptree.hpp>
9 #include <boost/property_tree/xml_parser.hpp>
10 #include <boost/tokenizer.hpp>
12 // -------------------------------------------------------------------------
13 cpPlugins::Pipeline::TAdjMatrix::
18 // -------------------------------------------------------------------------
19 cpPlugins::Pipeline::TAdjMatrix::
24 // -------------------------------------------------------------------------
25 bool cpPlugins::Pipeline::TAdjMatrix::
27 const std::string& oObj, const std::string& dObj,
28 const std::string& oPort, const std::string& dPort
31 TMatrix::const_iterator m = this->m_Matrix.find( oObj );
32 if( m != this->m_Matrix.end( ) )
34 TRow::const_iterator r = m->second.find( dObj );
35 if( r != m->second.end( ) )
36 return( r->second.find( TEdge( oPort, dPort ) ) != r->second.end( ) );
44 // -------------------------------------------------------------------------
45 cpPlugins::Pipeline::TAdjMatrix::
46 TEdges& cpPlugins::Pipeline::TAdjMatrix::
47 operator()( const std::string& o, const std::string& d )
49 TMatrix::iterator m = this->m_Matrix.find( o );
50 if( m != this->m_Matrix.end( ) )
52 TRow::iterator r = m->second.find( d );
53 if( r != m->second.end( ) )
58 this->m_Matrix[ o ][ d ] = TEdges( );
59 return( this->operator()( o, d ) );
62 // -------------------------------------------------------------------------
63 const cpPlugins::Pipeline::TAdjMatrix::
64 TEdges& cpPlugins::Pipeline::TAdjMatrix::
65 operator()( const std::string& o, const std::string& d ) const
67 TMatrix::const_iterator m = this->m_Matrix.find( o );
68 if( m != this->m_Matrix.end( ) )
70 TRow::const_iterator r = m->second.find( d );
71 if( r != m->second.end( ) )
76 cpPluginsErrorMacro( << "Connection not found." );
79 // -------------------------------------------------------------------------
81 void cpPlugins::Pipeline::TAdjMatrix::
82 SaveXML( boost::property_tree::ptree* node ) const
84 TMatrix::const_iterator m = this->m_Matrix.begin( );
85 for( ; m != this->m_Matrix.end( ); ++m )
87 TRow::const_iterator r = m->second.begin( );
88 for( ; r != m->second.end( ); r++ )
90 for( const TEdge& e: r->second )
92 boost::property_tree::ptree c;
93 c.put( "<xmlattr>.from", e.first + "@" + m->first );
94 c.put( "<xmlattr>.to", e.second + "@" + r->first );
95 node->add_child( "pipeline.connection", c );
102 // -------------------------------------------------------------------------
103 void cpPlugins::Pipeline::
109 // -------------------------------------------------------------------------
110 cpPlugins::ProcessObject* cpPlugins::Pipeline::
111 CreateNode( const std::string& class_name, const std::string& node_name )
114 cpPlugins::ProcessObject::SharedPtr p = this->m_Mgr.Create( class_name );
117 << "Something went wrong creating an object of type \""
118 << class_name << "\""
121 // Assign an unique name to it
122 std::string u = ( node_name == "" )? class_name: node_name;
123 while( !( this->m_Nodes.insert( TNodes::value_type( u, p ) ).second ) )
126 p->SetPipeline( this );
127 p->SetExecutionDebug( this->GetExecutionDebug( ) );
129 // Connect parameters
130 std::set< std::string > names;
132 names = p->Get{{t}}ValueNames( );
133 for( const std::string& n: names )
134 this->Configure{{t}}Value( n + "@" + u, p->Get{{t}}ValueTemplate( n ) );
138 // TODO: connect set/sequences
143 // -------------------------------------------------------------------------
144 cpPlugins::ProcessObject* cpPlugins::Pipeline::
145 GetNode( const std::string& name )
147 TNodes::iterator i = this->m_Nodes.find( name );
148 if( i != this->m_Nodes.end( ) )
149 return( i->second.get( ) );
154 // -------------------------------------------------------------------------
155 const cpPlugins::ProcessObject* cpPlugins::Pipeline::
156 GetNode( const std::string& name ) const
158 TNodes::const_iterator i = this->m_Nodes.find( name );
159 if( i != this->m_Nodes.end( ) )
160 return( i->second.get( ) );
165 // -------------------------------------------------------------------------
166 void cpPlugins::Pipeline::
168 const std::string& oObj, const std::string& dObj,
169 const std::string& oPort, const std::string& dPort
172 TNodes::iterator oIt = this->m_Nodes.find( oObj );
173 TNodes::iterator dIt = this->m_Nodes.find( dObj );
174 TNodes::iterator eIt = this->m_Nodes.end( );
175 if( oIt == eIt || dIt == eIt )
176 cpPluginsErrorMacro( this, << "Connection not possible." );
177 if( this->m_AdjMatrix.HasConnection( oObj, dObj, oPort, dPort ) )
180 // Check destination node
181 cpPlugins::ProcessObject::SharedPtr dest = dIt->second;
184 this, << "Invalid destination \"" << dObj << "\"."
187 // Process source node
188 cpPlugins::Filter* src = oIt->second->Cast< cpPlugins::Filter >( );
191 oIt->second->Cast< cpPlugins::Functor >( ), oPort, dest.get( ), dPort
194 this->_Connect( src, oPort, dest.get( ), dPort );
196 // Update adjacency matrix
197 this->m_AdjMatrix( oObj, dObj ).insert( TEdge( oPort, dPort ) );
200 // -------------------------------------------------------------------------
201 void cpPlugins::Pipeline::
202 Connect( const std::string& src, const std::string& dest )
204 std::string oObj, dObj, oPort, dPort;
205 Self::_ParseComponentName( src, oObj, oPort );
206 Self::_ParseComponentName( dest, dObj, dPort );
207 this->Connect( oObj, dObj, oPort, dPort );
210 // -------------------------------------------------------------------------
211 void cpPlugins::Pipeline::
212 LoadXML( const std::string& fname )
214 boost::property_tree::ptree xml;
215 boost::property_tree::read_xml( fname, xml );
217 // Check for a single pipeline
218 const boost::property_tree::ptree* pipeline = NULL;
219 for( const boost::property_tree::ptree::value_type& v: xml )
221 if( v.first == "pipeline" )
223 if( pipeline != NULL )
224 cpPluginsErrorMacro( << "Multiple pipelines are not supported." );
225 pipeline = &( v.second );
230 // Ok, seems ok to reset current pipeline
234 boost::optional< std::string > desc =
235 pipeline->get_optional< std::string >( "<xmlattr>.desc" );
237 this->m_Description = desc.get( );
240 for( const boost::property_tree::ptree::value_type& node: *pipeline )
242 if( node.first == "node" )
244 std::string name = node.second.get< std::string >( "<xmlattr>.name" );
245 std::string cname = node.second.get< std::string >( "<xmlattr>.class" );
246 cpPlugins::ProcessObject* n = this->CreateNode( cname, name );
253 for( const boost::property_tree::ptree::value_type& c: *pipeline )
254 if( c.first == "connection" )
256 c.second.get< std::string >( "<xmlattr>.from" ),
257 c.second.get< std::string >( "<xmlattr>.to" )
261 // -------------------------------------------------------------------------
262 void cpPlugins::Pipeline::
263 SaveXML( const std::string& fname ) const
265 boost::property_tree::ptree d;
266 if( this->m_Description != "" )
267 d.put( "pipeline.<xmlattr>.desc", this->m_Description );
270 TNodes::const_iterator n = this->m_Nodes.begin( );
271 for( ; n != this->m_Nodes.end( ); ++n )
272 n->second->SaveXML( &d );
275 this->m_AdjMatrix.SaveXML( &d );
278 boost::property_tree::xml_writer_settings< std::string > s( ' ', 2 );
279 boost::property_tree::write_xml( fname, d, std::locale( ), s );
282 // -------------------------------------------------------------------------
283 bool cpPlugins::Pipeline::
284 GetExecutionDebug( ) const
286 return( this->m_PipelineExecutionDebug );
289 // -------------------------------------------------------------------------
290 void cpPlugins::Pipeline::
291 SetExecutionDebug( bool d )
293 this->m_PipelineExecutionDebug = d;
294 for( TNodes::value_type& n: this->m_Nodes )
295 n.second->SetExecutionDebug( d );
298 // -------------------------------------------------------------------------
300 void cpPlugins::Pipeline::
301 Modified{{t}}Value( const std::string& name )
305 Self::_ParseComponentName( name, n, v );
308 TNodes::iterator node = this->m_Nodes.find( n );
309 if( node == this->m_Nodes.end( ) )
311 this, << "Unknown node \"" << n << "\"."
314 // Get configured value and continue
315 node->second->Set{{t}}Value( v, this->Get{{t}}Value( name ) );
316 this->Superclass::Modified{{t}}Value( name );
319 // -------------------------------------------------------------------------
320 void cpPlugins::Pipeline::
321 Modified{{t}}Set( const std::string& name )
323 std::cout << "Modified{{t}}Set: " << name << std::endl;
324 this->Superclass::Modified{{t}}Set( name );
327 // -------------------------------------------------------------------------
328 void cpPlugins::Pipeline::
329 Modified{{t}}Sequence( const std::string& name )
331 std::cout << "Modified{{t}}Sequence: " << name << std::endl;
332 this->Superclass::Modified{{t}}Sequence( name );
336 // -------------------------------------------------------------------------
337 void cpPlugins::Pipeline::
338 ModifiedChoice( const std::string& name )
340 std::cout << "ModifiedChoice: " << name << std::endl;
341 this->Superclass::ModifiedChoice( name );
344 // -------------------------------------------------------------------------
345 void cpPlugins::Pipeline::
347 const std::string& input, const std::string& node, const std::string& port
351 this->m_InputRelations.insert(
352 TPortRelations::value_type( input, TEdge( node, port ) )
358 // -------------------------------------------------------------------------
359 void cpPlugins::Pipeline::
360 SetInput( const std::string& name, cpPlugins::DataObject* data )
364 TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
365 if( rIt != this->m_InputRelations.end( ) )
367 n = rIt->second.first;
368 o = rIt->second.second;
371 Self::_ParseComponentName( name, n, o );
374 TNodes::iterator node = this->m_Nodes.find( n );
375 if( node == this->m_Nodes.end( ) )
377 this, << "Unknown node \"" << n << "\"."
379 node->second->SetInput( o, data );
382 // -------------------------------------------------------------------------
383 cpPlugins::DataObject* cpPlugins::Pipeline::
384 GetInput( const std::string& name, const unsigned int id )
388 TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
389 if( rIt != this->m_InputRelations.end( ) )
391 n = rIt->second.first;
392 o = rIt->second.second;
395 Self::_ParseComponentName( name, n, o );
398 TNodes::iterator node = this->m_Nodes.find( n );
399 if( node == this->m_Nodes.end( ) )
401 this, << "Unknown node \"" << n << "\"."
403 return( node->second->GetInput( o, id ) );
406 // -------------------------------------------------------------------------
407 const cpPlugins::DataObject* cpPlugins::Pipeline::
408 GetInput( const std::string& name, const unsigned int id ) const
412 TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
413 if( rIt != this->m_InputRelations.end( ) )
415 n = rIt->second.first;
416 o = rIt->second.second;
419 Self::_ParseComponentName( name, n, o );
422 TNodes::const_iterator node = this->m_Nodes.find( n );
423 if( node == this->m_Nodes.end( ) )
425 this, << "Unknown node \"" << n << "\"."
427 return( node->second->GetInput( o, id ) );
430 // -------------------------------------------------------------------------
431 bool cpPlugins::Pipeline::
432 HasInput( const std::string& name ) const
436 TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
437 if( rIt != this->m_InputRelations.end( ) )
439 n = rIt->second.first;
440 o = rIt->second.second;
443 Self::_ParseComponentName( name, n, o );
446 TNodes::const_iterator node = this->m_Nodes.find( n );
447 if( node == this->m_Nodes.end( ) )
449 this, << "Unknown node \"" << n << "\"."
451 return( node->second->HasInput( n ) );
454 // -------------------------------------------------------------------------
455 void cpPlugins::Pipeline::
457 const std::string& output, const std::string& node, const std::string& port
461 this->m_OutputRelations.insert(
462 TPortRelations::value_type( output, TEdge( node, port ) )
468 // -------------------------------------------------------------------------
469 cpPlugins::DataObject* cpPlugins::Pipeline::
470 GetOutput( const std::string& name )
474 TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
475 if( rIt != this->m_OutputRelations.end( ) )
477 n = rIt->second.first;
478 o = rIt->second.second;
481 Self::_ParseComponentName( name, n, o );
484 TNodes::iterator node = this->m_Nodes.find( n );
485 if( node == this->m_Nodes.end( ) )
487 this, << "Unknown node \"" << n << "\"."
489 cpPlugins::Filter* f = node->second->Cast< cpPlugins::Filter >( );
491 return( f->GetOutput( o ) );
494 this, << "Node \"" << n << "\" does not have outputs."
498 // -------------------------------------------------------------------------
499 const cpPlugins::DataObject* cpPlugins::Pipeline::
500 GetOutput( const std::string& name ) const
504 TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
505 if( rIt != this->m_OutputRelations.end( ) )
507 n = rIt->second.first;
508 o = rIt->second.second;
511 Self::_ParseComponentName( name, n, o );
514 TNodes::const_iterator node = this->m_Nodes.find( n );
515 if( node == this->m_Nodes.end( ) )
517 this, << "Unknown node \"" << n << "\"."
519 const cpPlugins::Filter* f = node->second->Cast< cpPlugins::Filter >( );
521 return( f->GetOutput( o ) );
524 this, << "Node \"" << n << "\" does not have outputs."
528 // -------------------------------------------------------------------------
529 cpPlugins::Pipeline::
533 m_PipelineExecutionDebug( false )
535 this->m_Mgr.Configure( );
538 // -------------------------------------------------------------------------
539 cpPlugins::Pipeline::
544 // -------------------------------------------------------------------------
545 void cpPlugins::Pipeline::
548 for( TNodes::value_type& v: this->m_Nodes )
549 v.second->Cast< cpPlugins::ProcessObject >( )->Update( );
552 // -------------------------------------------------------------------------
553 void cpPlugins::Pipeline::
555 Filter* src, const std::string& srcPort,
556 ProcessObject* dest, const std::string& destPort
559 if( src->HasOutValue( srcPort ) && dest->HasInValue( destPort ) )
562 else if( src->HasOutput( srcPort ) && dest->HasInput( destPort ) )
563 dest->SetInput( destPort, src->GetOutput( srcPort ) );
567 << "Invalid connection from \"" << src->GetName( ) << "\" to \""
568 << dest->GetName( ) << " (" << srcPort << "->" << destPort << ")"
572 // -------------------------------------------------------------------------
573 void cpPlugins::Pipeline::
575 Functor* functor, const std::string& functorValue,
576 ProcessObject* dest, const std::string& destValue
579 if( functorValue == "Functor" )
581 Filter* filter = dynamic_cast< Filter* >( dest );
583 filter->SetFunctor( destValue, functor );
585 cpPluginsErrorMacro( this, << "Invalid functor connection." );
590 functor->HasOutValue( functorValue ) && dest->HasInValue( destValue )
593 destValue, functor->GetOutValuePtr( functorValue )
598 << "Invalid connection from \"" << functor->GetName( ) << "\" to \""
599 << dest->GetName( ) << " (" << functorValue << "->"
605 // -------------------------------------------------------------------------
606 void cpPlugins::Pipeline::
608 const std::string& name,
610 std::string& component
613 typedef boost::char_separator< char > _TSep;
614 typedef boost::tokenizer< _TSep > _TTok;
616 // Get parameter info
617 _TTok tok( name, _TSep( "@" ) );
618 std::vector< std::string > tokens;
619 for( _TTok::const_iterator tIt = tok.begin( ); tIt != tok.end( ); ++tIt )
620 tokens.push_back( *tIt );
622 // Try another distribution
623 if( tokens.size( ) != 2 )
627 // Nothing else to do?
628 if( tokens.size( ) != 2 )
630 << "Unknown input value parameter \"" << name << "\"."
634 component = tokens[ 0 ];