1 /*=========================================================================
3 Module: $RCSfile: bbtkConnection.cxx,v $
5 Date: $Date: 2009/03/30 14:42:16 $
6 Version: $Revision: 1.20 $
7 =========================================================================*/
9 /* ---------------------------------------------------------------------
11 * Copyright (c) CREATIS-LRMN (Centre de Recherche en Imagerie Medicale)
12 * Authors : Eduardo Davila, Laurent Guigues, Jean-Pierre Roux
14 * This software is governed by the CeCILL-B license under French law and
15 * abiding by the rules of distribution of free software. You can use,
16 * modify and/ or redistribute the software under the terms of the CeCILL-B
17 * license as circulated by CEA, CNRS and INRIA at the following URL
18 * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
19 * or in the file LICENSE.txt.
21 * As a counterpart to the access to the source code and rights to copy,
22 * modify and redistribute granted by the license, users are provided only
23 * with a limited warranty and the software's author, the holder of the
24 * economic rights, and the successive licensors have only limited
27 * The fact that you are presently reading this means that you have had
28 * knowledge of the CeCILL-B license and that you accept its terms.
29 * ------------------------------------------------------------------------ */
33 *\brief Class bbtk::Connection
36 #include "bbtkConnection.h"
37 #include "bbtkFactory.h"
38 #include "bbtkBlackBox.h"
39 #include "bbtkMessageManager.h"
40 #include "bbtkBlackBoxOutputConnector.h"
44 const std::string IOSTATUS_STRING[3] =
45 {"Up-to-date","Modified","Out-of-date"};
47 const std::string& GetIOStatusString(IOStatus s)
48 { return IOSTATUS_STRING[s]; }
50 //==================================================================
51 Connection::Pointer Connection::New(BlackBox::Pointer from,
52 const std::string& output,
54 const std::string& input ,
55 const Factory::Pointer f )
57 bbtkDebugMessage("object",1,"##> Connection::Connection(\""
58 <<from->bbGetName()<<"\",\""<<output<<"\",\""
59 <<to->bbGetName()<<"\",\""<<input<<"\")"
61 Connection::Pointer p =
62 MakePointer(new Connection(from,output,to,input,f));
63 bbtkDebugMessage("object",1,"<## Connection::Connection(\""
64 <<from->bbGetName()<<"\",\""<<output<<"\",\""
65 <<to->bbGetName()<<"\",\""<<input<<"\")"
69 //==================================================================
71 //==================================================================
72 /// Ctor with the black box from and to and their input and output.
73 /// Check the input and output compatibility
74 Connection::Connection(BlackBox::Pointer from, const std::string& output,
75 BlackBox::Pointer to, const std::string& input ,
76 const Factory::Pointer f )
82 bbtkDebugMessage("object",2,"==> Connection::Connection(\""
83 <<from->bbGetName()<<"\",\""<<output<<"\",\""
84 <<to->bbGetName()<<"\",\""<<input<<"\")"
87 bbtkDebugMessage("connection",1,"==> Connection::Connection(\""
88 <<from->bbGetFullName()<<"\",\""<<output<<"\",\""
89 <<to->bbGetFullName()<<"\",\""<<input<<"\")"
94 if (! from->bbHasOutput(output) )
96 bbtkError("The box \""<<from->bbGetTypeName()<<
97 "\" has no output \""<<output<<"\"");
99 if (! to->bbHasInput(input) )
101 bbtkError("The box \""<<to->bbGetTypeName()<<
102 "\" has no input \""<<input<<"\"");
105 if (to->bbGetInputConnectorMap().find(input)->second->IsConnected())
107 bbtkError("The input \""<<input<<"\" of the box \""<<to->bbGetName()
108 <<"\" is already connected");
111 // std::string t1 ( from->bbGetOutputType(output).name() );
112 // std::string t2 ( to->bbGetInputType(input).name() );
114 if ( from->bbGetOutputType(output) !=
115 to->bbGetInputType(input) )
117 if ( from->bbGetOutputType(output) == typeid(Data) )
119 bbtkWarning("Connection: '"<<from->bbGetName()<<"."<<output
121 <<HumanTypeName<Data>()
122 <<"> : type compatibility with '"
123 <<to->bbGetName()<<"."<<input
124 <<"' will be resolved at run time"
128 else if ( to->bbGetInputType(input) == typeid(Data) )
130 bbtkDebugMessage("Kernel",8," -> '"<<input<<"' type is "
131 <<TypeName<Data>()<<" : can receive any data"
137 // std::cout << "Adaptive connection "<<std::endl;
139 name = from->bbGetName() + "." + output + "-"
140 + to->bbGetName() + "." + input;
141 mAdaptor = mFactory.lock()
142 ->NewAdaptor(from->bbGetOutputType(output),
143 to->bbGetInputType(input),
147 bbtkError("did not find any <"
148 <<TypeName(from->bbGetOutputType(output))
150 <<TypeName(to->bbGetInputType(input))
158 mOriginalFrom = from;
161 mInput = mOriginalInput = input;
162 mOutput = mOriginalOutput = output;
164 // Lock this pointer !!!
165 //Pointer p = MakePointer(this,true);
166 from->bbConnectOutput(output,this);
167 to->bbConnectInput(input,this);
169 from->bbGetOutputConnector(output).AddChangeObserver(boost::bind(&bbtk::Connection::OnOutputChange,this, _1, _2, _3));
172 bbtkDebugMessage("connection",1,"<== Connection::Connection(\""
173 <<from->bbGetFullName()<<"\",\""<<output<<"\",\""
174 <<to->bbGetFullName()<<"\",\""<<input<<"\")"
177 bbtkDebugMessage("object",2,"==> Connection::Connection(\""
178 <<from->bbGetName()<<"\",\""<<output<<"\",\""
179 <<to->bbGetName()<<"\",\""<<input<<"\")"
182 //==================================================================
184 //==================================================================
185 Connection::Pointer Connection::New(BlackBox::Pointer from,
186 const std::string& output,
187 BlackBox::Pointer to,
188 const std::string& input )
190 bbtkDebugMessage("object",1,"##> Connection::Connection(\""
191 <<from->bbGetName()<<"\",\""<<output<<"\",\""
192 <<to->bbGetName()<<"\",\""<<input<<"\")"
194 Connection::Pointer p =
195 MakePointer(new Connection(from,output,to,input));
196 bbtkDebugMessage("object",1,"<## Connection::Connection(\""
197 <<from->bbGetName()<<"\",\""<<output<<"\",\""
198 <<to->bbGetName()<<"\",\""<<input<<"\")"
202 //==================================================================
204 //==================================================================
205 /// Ctor with the black box from and to and their input and output.
206 /// Check the input and output compatibility
207 Connection::Connection(BlackBox::Pointer from, const std::string& output,
208 BlackBox::Pointer to, const std::string& input )
214 bbtkDebugMessage("object",2,"==> Connection::Connection(\""
215 <<from->bbGetName()<<"\",\""<<output<<"\",\""
216 <<to->bbGetName()<<"\",\""<<input<<"\")"
219 bbtkDebugMessage("connection",1,"==> Connection::Connection(\""
220 <<from->bbGetFullName()<<"\",\""<<output<<"\",\""
221 <<to->bbGetFullName()<<"\",\""<<input<<"\")"
226 if (! from->bbHasOutput(output) )
228 bbtkError("The box \""<<from->bbGetTypeName()<<
229 "\" has no output \""<<output<<"\"");
231 if (! to->bbHasInput(input) )
233 bbtkError("The box \""<<to->bbGetTypeName()<<
234 "\" has no input \""<<input<<"\"");
237 if (to->bbGetInputConnectorMap().find(input)->second->IsConnected())
239 bbtkError("The input \""<<input<<"\" of the box \""<<to->bbGetName()
240 <<"\" is already connected");
243 // std::string t1 ( from->bbGetOutputType(output).name() );
244 // std::string t2 ( to->bbGetInputType(input).name() );
246 if ( from->bbGetOutputType(output) !=
247 to->bbGetInputType(input) )
249 if ( from->bbGetOutputType(output) == typeid(Data) )
251 bbtkWarning("Connection '"
253 <<"' : '"<<from->bbGetName()<<"."<<output
255 <<HumanTypeName<Data>()
256 <<"> : type compatibility with '"
257 <<to->bbGetName()<<"."<<input
258 <<"' will be resolved at run time"
262 else if ( to->bbGetInputType(input) == typeid(Data) )
264 bbtkDebugMessage("Kernel",8," -> '"<<input<<"' type is "
265 <<TypeName<Data>()<<" : can receive any data"
271 bbtkError("Connection created between different types without Factory provided");
277 mOriginalFrom = from;
280 mInput = mOriginalInput = input;
281 mOutput = mOriginalOutput = output;
283 // Lock this pointer !!!
284 //Pointer p = MakePointer(this,true);
285 from->bbConnectOutput(output,this);
286 to->bbConnectInput(input,this);
288 from->bbGetOutputConnector(output).AddChangeObserver(boost::bind(&bbtk::Connection::OnOutputChange,this, _1, _2, _3));
290 bbtkDebugMessage("connection",1,"<== Connection::Connection(\""
291 <<from->bbGetFullName()<<"\",\""<<output<<"\",\""
292 <<to->bbGetFullName()<<"\",\""<<input<<"\")"
295 bbtkDebugMessage("object",2,"==> Connection::Connection(\""
296 <<from->bbGetName()<<"\",\""<<output<<"\",\""
297 <<to->bbGetName()<<"\",\""<<input<<"\")"
300 //==================================================================
302 //==================================================================
304 Connection::~Connection()
306 bbtkDebugMessage("object",2,
307 "==> Connection::~Connection() ["
308 <<GetFullName()<<"]"<<std::endl);
310 if (mAdaptor) mAdaptor.reset();
313 mFrom->bbDisconnectOutput(mOutput,this);
314 // GetThisPointer<Connection>());
319 bbtkInternalError("Connection::~Connection() : invalid initial box pointer");
323 mTo->bbDisconnectInput(mInput,this);// GetThisPointer<Connection>());
328 bbtkInternalError("Connection::~Connection() : invalid final box pointer");
332 bbtkDebugMessage("object",2,
333 "<== Connection::~Connection() ["
334 <<GetFullName()<<"]"<<std::endl);
336 //==================================================================
338 //==================================================================
339 /// Recursive execution
340 void Connection::RecursiveExecute()
342 bbtkDebugMessage("process",4,
343 "===> Connection::RecursiveExecute() ["
344 <<GetFullName()<<"]"<<std::endl);
347 // If box from already executing : nothing to do
348 if (mFrom->bbGetExecuting())
350 bbtkDebugMessage("process",3,
351 " -> "<<mFrom->bbGetName()
352 <<" already executing : abort"<<std::endl);
358 mFrom->bbRecursiveExecute(GetThisPointer<Connection>());
363 IOStatus s = MODIFIED;
364 if ( mFrom->bbGetOutputConnector(mOutput).GetStatus() == OUTOFDATE)
368 mTo->bbGetInputConnector(mInput).SetStatus(s);
370 bbtkDebugMessage("process",4,
371 " --> '"<<mTo->bbGetName()<<"."<<mInput
372 <<" ["<<&mTo->bbGetInputConnector(mInput)<<"] "
374 <<GetIOStatusString(s)
378 bbtkDebugMessage("process",4,
379 "<=== Connection::RecursiveExecute() ["
380 <<GetFullName()<<"]"<<std::endl);
383 //==================================================================
387 //==================================================================
388 /// Transfers the data from the source output to the target input
389 /// doing necessary conversions (adaptation or pointer cast)
390 void Connection::TransferData()
392 bbtkDebugMessageInc("data",3,
393 "Connection::TransferData() ["
394 <<GetFullName()<<"]"<<std::endl);
397 // If an adaptor was created we need to adapt the data
400 mAdaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
401 mAdaptor->bbExecute();
402 // LG : Connection Update does not set mTo as modified
403 mTo->bbSetInput(mInput, mAdaptor->bbGetOutput("Out"),false);
406 // If no adaptor but source type is an any and target is not an any
407 else if ( mFromAny && (! mToAny) )
409 bbtkDebugMessage("data",3,
410 " * Source type is an "
411 <<HumanTypeName<Data>()
412 <<" which contains a <"
413 <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
415 bbtkDebugMessage("data",3,
416 " * Target type is <"
417 <<HumanTypeName(mTo->bbGetInputType(mInput))
420 // 0) If from any contents void : nothing to do
421 if (mFrom->bbGetOutput(mOutput).type() == typeid(void))
423 bbtkDebugMessage("data",3,
424 " -> Source is void : nothing to transfer!"<<std::endl);
426 // 1) Test strict type matching between any content and target
427 else if (mFrom->bbGetOutput(mOutput)
428 .contains( mTo->bbGetInputType(mInput) ) )
430 bbtkDebugMessage("data",3,
431 " -> Equal types : transfer ok"<<std::endl);
432 mTo->bbSetInput( mInput,
433 mFrom->bbGetOutput(mOutput),
438 // 2) Look for an adaptor
439 bbtk::BlackBox::Pointer adaptor;
442 adaptor = mFactory.lock()
443 ->NewAdaptor(mFrom->bbGetOutput(mOutput).type(),
444 mTo->bbGetInputType(mInput),
452 bbtkDebugMessage("data",3," -> Adaptor found : using it"
454 adaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
455 adaptor->bbExecute();
456 // LG : Connection Update does not set mTo as modified
457 mTo->bbSetInput(mInput, adaptor->bbGetOutput("Out"),false);
458 // adaptor->bbDelete();
460 // 3) If no adaptor found but the any content is a pointer
461 // and target type is also a pointer : we try run-time cast
462 else if ( (mFrom->bbGetOutput(mOutput).contains_pointer()) &&
463 (mTo->bbGetDescriptor()->GetInputDescriptor(mInput)
466 bbtkDebugMessage("data",3,
467 " -> No adaptor found but source and target types are both pointers : trying up or down cast"<<std::endl);
470 mFrom->bbGetOutput(mOutput)
471 .get_pointer_to(mTo->bbGetInput(mInput).pointed_type());
474 bbtkError("Connection '"
477 <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
479 <<HumanTypeName(mTo->bbGetInputType(mInput))
480 <<"> : no adaptor available and run-time up and down cast failed");
482 mTo->bbBruteForceSetInputPointer(mInput, nptr, false);
484 // 4) Nothing worked : error
487 bbtkError("Connection '"<<GetFullName()<<"' "
488 <<"no adaptor found to convert <"
489 <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
491 <<HumanTypeName(mTo->bbGetInputType(mInput))<<">");
495 // EO : mFromAny && ! mToAny
496 // Default case : types are the same; we use simple get-set
499 // LG : Connection Update does not set mTo as modified
500 mTo->bbSetInput(mInput, mFrom->bbGetOutput(mOutput),false);
504 //==================================================================
506 //==================================================================
507 /// From.Output change propagation
508 void Connection::OnOutputChange(bbtk::BlackBox::Pointer, const std::string&,
511 bbtkDebugMessage("change",2,
512 "==> Connection::OnOutputChange("
513 <<GetIOStatusString(status)<<") ["
514 <<GetFullName()<<"]"<<std::endl);
517 BlackBoxInputConnector* ac = mAdaptor->bbGetInputConnectorMap().find("In")->second;
518 mAdaptor->bbSetStatusAndPropagate(ac,status);
521 mTo->bbSetStatusAndPropagate( mTo->bbGetInputConnectorMap().find(mInput)->second, status);
525 //==================================================================
528 //==================================================================
529 std::string Connection::GetFullName() const {
532 std::string res = mFrom->bbGetName()+"."+mOutput+"--"
533 +mTo->bbGetName()+"."+mInput;
534 if ((!mOriginalFrom.expired()) && (!mOriginalTo.expired()) &&
535 ((mFrom!=mOriginalFrom.lock())||(mTo!=mOriginalTo.lock())))
537 res += "("+mOriginalFrom.lock()->bbGetName()
538 +"."+mOriginalOutput+"--"
539 + mOriginalTo.lock()->bbGetName()+"."+mOriginalInput+")";
543 return "***Invalid Connection***";
545 //==================================================================
547 //==================================================================
548 void Connection::Check() const
550 bbtkMessage("debug",1,"** Checking Connection "<<(void*)this<<" ["<<GetFullName()<<"]"
554 bbtkMessage("debug",2," - From = 0"<<std::endl);
558 bbtkMessage("debug",2," - From : "<<mFrom->bbGetFullName()<<std::endl);
559 if (!mFrom->bbHasOutput(mOutput))
561 bbtkError("** Checking Connection "<<(void*)this
562 <<" ["<<GetFullName()<<"] : "
563 << mFrom->bbGetFullName()<<" does not have output '"
566 bbtkMessage("debug",2," - From : Output '"<<mOutput<<"' exists"<<std::endl);
567 BlackBox::OutputConnectorMapType::const_iterator i
568 = mFrom->bbGetOutputConnectorMap().find(mOutput);
569 if (i== mFrom->bbGetOutputConnectorMap().end())
571 bbtkError("** Checking Connection "<<(void*)this
572 <<" ["<<GetFullName()<<"] : "
573 <<mFrom->bbGetFullName()<<" output '"
574 <<mOutput<<"' is not in OutputConnectorMap");
576 bbtkMessage("debug",2," - From : Output '"<<mOutput
577 <<"' is in OutputConnectorMap"<<std::endl);
579 std::vector< Connection* >::const_iterator j;
581 for (j = i->second->GetConnectionVector().begin();
582 j != i->second->GetConnectionVector().end();
585 if ((*j)==this) break;
588 j = find(i->second->GetConnectionVector().begin(),
589 i->second->GetConnectionVector().end(),
592 if (j==i->second->GetConnectionVector().end())
594 bbtkError("** Checking Connection "<<(void*)this
595 <<" ["<<GetFullName()<<"] : "
596 << "Connection ["<<GetFullName()<<"] : "
597 <<" OutputConnector '"
598 <<mOutput<<"' of "<<mFrom->bbGetFullName()
599 <<" does not point to this connection");
602 bbtkMessage("debug",2," - From : This connection is in OutputConnector connection vector"<<std::endl);
603 bbtkMessage("debug",2," * Box from : Check successfull"<<std::endl);
609 bbtkMessage("debug",2," - To = 0"<<std::endl);
613 bbtkMessage("debug",2," - To : "<<mTo->bbGetName()<<std::endl);
614 // std::cout << mTo << std::endl;
615 // std::cout << mTo->bbGetDescriptor() << std::endl;
616 // std::cout << mTo->bbGetDescriptor()->GetTypeName() << std::endl;
617 // mTo->bbGetFullName();
618 bbtkMessage("debug",2," - To : "<<mTo->bbGetFullName()<<std::endl);
619 if (!mTo->bbHasInput(mInput))
621 bbtkError("** Checking Connection "<<(void*)this
622 <<" ["<<GetFullName()<<"] : "
623 <<mTo->bbGetFullName()<<" does not have input '"
626 bbtkMessage("debug",2," - To : Input '"<<mInput<<"' exists"<<std::endl);
627 BlackBox::InputConnectorMapType::const_iterator i
628 = mTo->bbGetInputConnectorMap().find(mInput);
629 if (i== mTo->bbGetInputConnectorMap().end())
631 bbtkError("** Checking Connection "<<(void*)this
632 <<" ["<<GetFullName()<<"] : "
633 <<mTo->bbGetFullName()<<" input '"
634 <<mInput<<"' is not in InputConnectorMap");
636 bbtkMessage("debug",2," - To : Input '"<<mInput
637 <<"' is in InputConnectorMap"<<std::endl);
639 if (i->second->GetConnection()==0)
641 bbtkError("** Checking Connection "<<(void*)this
642 <<" ["<<GetFullName()<<"] : "
643 <<"Connection "<<GetFullName()<<" : "
644 <<" InputConnector '"
645 <<mInput<<"' of "<<mTo->bbGetFullName()
646 <<" does not point to this connection");
649 bbtkMessage("debug",2," - To : This connection is in InputConnector connection vector"<<std::endl);
650 bbtkMessage("debug",2," * Box to : Check successfull"<<std::endl);
654 //==================================================================
655 //==========================================================================
656 std::string Connection::GetObjectName() const
658 std::string s("Connection '");
663 //==========================================================================
665 //==========================================================================
666 std::string Connection::GetObjectInfo() const
671 //==========================================================================
673 //==========================================================================
674 size_t Connection::GetObjectSize() const
676 size_t s = Superclass::GetObjectSize();
677 s += Connection::GetObjectInternalSize();
680 //==========================================================================
681 //==========================================================================
682 size_t Connection::GetObjectInternalSize() const
684 size_t s = sizeof(Connection);
687 //==========================================================================
688 //==========================================================================
689 size_t Connection::GetObjectRecursiveSize() const
691 size_t s = Superclass::GetObjectRecursiveSize();
692 s += Connection::GetObjectInternalSize();
695 //==========================================================================