2 # ---------------------------------------------------------------------
4 # Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image
6 # Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton
7 # Previous Authors : Laurent Guigues, Jean-Pierre Roux
8 # CreaTools website : www.creatis.insa-lyon.fr/site/fr/creatools_accueil
10 # This software is governed by the CeCILL-B license under French law and
11 # abiding by the rules of distribution of free software. You can use,
12 # modify and/ or redistribute the software under the terms of the CeCILL-B
13 # license as circulated by CEA, CNRS and INRIA at the following URL
14 # http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
15 # or in the file LICENSE.txt.
17 # As a counterpart to the access to the source code and rights to copy,
18 # modify and redistribute granted by the license, users are provided only
19 # with a limited warranty and the software's author, the holder of the
20 # economic rights, and the successive licensors have only limited
23 # The fact that you are presently reading this means that you have had
24 # knowledge of the CeCILL-B license and that you accept its terms.
25 # ------------------------------------------------------------------------ */
28 /*=========================================================================
30 Module: $RCSfile: bbtkConnection.cxx,v $
32 Date: $Date: 2012/11/16 08:49:01 $
33 Version: $Revision: 1.22 $
34 =========================================================================*/
40 *\brief Class bbtk::Connection
43 #include "bbtkConnection.h"
44 #include "bbtkFactory.h"
45 #include "bbtkBlackBox.h"
46 #include "bbtkMessageManager.h"
47 #include "bbtkBlackBoxOutputConnector.h"
49 #define bbtkCMessage(key,level,mess) \
50 bbtkMessage(key,level,"["<<GetFullName()<<"] "<<mess)
51 #define bbtkCDebugMessage(key,level,mess) \
52 bbtkDebugMessage(key,level,"["<<GetFullName()<<"] "<<mess)
56 const std::string IOSTATUS_STRING[3] =
57 {"Up-to-date","Modified","Out-of-date"};
59 const std::string& GetIOStatusString(IOStatus s)
60 { return IOSTATUS_STRING[s]; }
62 //==================================================================
63 Connection::Pointer Connection::New(BlackBox::Pointer from,
64 const std::string& output,
66 const std::string& input ,
67 const Factory::Pointer f )
69 bbtkDebugMessage("object",1,"##> Connection(\""
70 <<from->bbGetName()<<"\",\""<<output<<"\",\""
71 <<to->bbGetName()<<"\",\""<<input<<"\")"
73 Connection::Pointer p =
74 MakePointer(new Connection(from,output,to,input,f));
75 bbtkDebugMessage("object",1,"<## Connection(\""
76 <<from->bbGetName()<<"\",\""<<output<<"\",\""
77 <<to->bbGetName()<<"\",\""<<input<<"\")"
81 //==================================================================
83 //==================================================================
84 /// Ctor with the black box from and to and their input and output.
85 /// Check the input and output compatibility
86 Connection::Connection(BlackBox::Pointer from, const std::string& output,
87 BlackBox::Pointer to, const std::string& input ,
88 const Factory::Pointer f )
94 bbtkDebugMessage("object",2,"==> Connection(\""
95 <<from->bbGetName()<<"\",\""<<output<<"\",\""
96 <<to->bbGetName()<<"\",\""<<input<<"\")"
99 bbtkDebugMessage("connection",1,"==> Connection(\""
100 <<from->bbGetName()<<"\",\""<<output<<"\",\""
101 <<to->bbGetName()<<"\",\""<<input<<"\")"
106 if (! from->bbHasOutput(output) )
108 bbtkError("The box \""<<from->bbGetTypeName()<<
109 "\" has no output \""<<output<<"\"");
111 if (! to->bbHasInput(input) )
113 bbtkError("The box \""<<to->bbGetTypeName()<<
114 "\" has no input \""<<input<<"\"");
117 if (to->bbGetInputConnectorMap().find(input)->second->IsConnected())
119 bbtkError("The input \""<<input<<"\" of the box \""<<to->bbGetName()
120 <<"\" is already connected");
123 // std::string t1 ( from->bbGetOutputType(output).name() );
124 // std::string t2 ( to->bbGetInputType(input).name() );
126 if ( from->bbGetOutputType(output) !=
127 to->bbGetInputType(input) )
129 if ( from->bbGetOutputType(output) == typeid(Data) )
131 bbtkWarning("Connection: '"<<from->bbGetName()<<"."<<output
133 <<HumanTypeName<Data>()
134 <<"> : type compatibility with '"
135 <<to->bbGetName()<<"."<<input
136 <<"' will be resolved at run time"
140 else if ( to->bbGetInputType(input) == typeid(Data) )
142 bbtkDebugMessage("kernel",8," -> '"<<input<<"' type is "
143 <<TypeName<Data>()<<" : can receive any data"
149 // std::cout << "Adaptive connection "<<std::endl;
151 name = from->bbGetName() + "." + output + "-"
152 + to->bbGetName() + "." + input;
153 mAdaptor = mFactory.lock()
154 ->NewAdaptor(from->bbGetOutputType(output),
155 to->bbGetInputType(input),
159 bbtkError("did not find any <"
160 <<TypeName(from->bbGetOutputType(output))
162 <<TypeName(to->bbGetInputType(input))
170 mOriginalFrom = from;
173 mInput = mOriginalInput = input;
174 mOutput = mOriginalOutput = output;
176 // Lock this pointer !!!
177 //Pointer p = MakePointer(this,true);
178 from->bbConnectOutput(output,this);
179 to->bbConnectInput(input,this);
181 from->bbGetOutputConnector(output).AddChangeObserver(boost::bind(&bbtk::Connection::OnOutputChange,this, _1, _2, _3));
184 bbtkDebugMessage("connection",1,"<== Connection(\""
185 <<from->bbGetName()<<"\",\""<<output<<"\",\""
186 <<to->bbGetName()<<"\",\""<<input<<"\")"
189 bbtkDebugMessage("object",2,"<== Connection(\""
190 <<from->bbGetName()<<"\",\""<<output<<"\",\""
191 <<to->bbGetName()<<"\",\""<<input<<"\")"
194 //==================================================================
196 //==================================================================
197 Connection::Pointer Connection::New(BlackBox::Pointer from,
198 const std::string& output,
199 BlackBox::Pointer to,
200 const std::string& input )
202 bbtkDebugMessage("object",1,"##> Connection(\""
203 <<from->bbGetName()<<"\",\""<<output<<"\",\""
204 <<to->bbGetName()<<"\",\""<<input<<"\")"
206 Connection::Pointer p =
207 MakePointer(new Connection(from,output,to,input));
208 bbtkDebugMessage("object",1,"<## Connection(\""
209 <<from->bbGetName()<<"\",\""<<output<<"\",\""
210 <<to->bbGetName()<<"\",\""<<input<<"\")"
214 //==================================================================
216 //==================================================================
217 /// Ctor with the black box from and to and their input and output.
218 /// Check the input and output compatibility
219 Connection::Connection(BlackBox::Pointer from, const std::string& output,
220 BlackBox::Pointer to, const std::string& input )
226 bbtkDebugMessage("object",2,"==> Connection(\""
227 <<from->bbGetName()<<"\",\""<<output<<"\",\""
228 <<to->bbGetName()<<"\",\""<<input<<"\")"
231 bbtkDebugMessage("connection",1,"==> Connection(\""
232 <<from->bbGetName()<<"\",\""<<output<<"\",\""
233 <<to->bbGetName()<<"\",\""<<input<<"\")"
238 if (! from->bbHasOutput(output) )
240 bbtkError("The box \""<<from->bbGetTypeName()<<
241 "\" has no output \""<<output<<"\"");
243 if (! to->bbHasInput(input) )
245 bbtkError("The box \""<<to->bbGetTypeName()<<
246 "\" has no input \""<<input<<"\"");
249 if (to->bbGetInputConnectorMap().find(input)->second->IsConnected())
251 bbtkError("The input \""<<input<<"\" of the box \""<<to->bbGetName()
252 <<"\" is already connected");
255 // std::string t1 ( from->bbGetOutputType(output).name() );
256 // std::string t2 ( to->bbGetInputType(input).name() );
258 if ( from->bbGetOutputType(output) !=
259 to->bbGetInputType(input) )
261 if ( from->bbGetOutputType(output) == typeid(Data) )
263 bbtkWarning("Connection '"
265 <<"' : '"<<from->bbGetName()<<"."<<output
267 <<HumanTypeName<Data>()
268 <<"> : type compatibility with '"
269 <<to->bbGetName()<<"."<<input
270 <<"' will be resolved at run time"
274 else if ( to->bbGetInputType(input) == typeid(Data) )
276 bbtkDebugMessage("kernel",8," -> '"<<input<<"' type is "
277 <<TypeName<Data>()<<" : can receive any data"
283 bbtkError("Connection created between different types without Factory provided");
289 mOriginalFrom = from;
292 mInput = mOriginalInput = input;
293 mOutput = mOriginalOutput = output;
295 // Lock this pointer !!!
296 //Pointer p = MakePointer(this,true);
297 from->bbConnectOutput(output,this);
298 to->bbConnectInput(input,this);
300 from->bbGetOutputConnector(output).AddChangeObserver(boost::bind(&bbtk::Connection::OnOutputChange,this, _1, _2, _3));
302 bbtkDebugMessage("connection",1,"<== Connection(\""
303 <<from->bbGetName()<<"\",\""<<output<<"\",\""
304 <<to->bbGetName()<<"\",\""<<input<<"\")"
307 bbtkDebugMessage("object",2,"==> Connection(\""
308 <<from->bbGetName()<<"\",\""<<output<<"\",\""
309 <<to->bbGetName()<<"\",\""<<input<<"\")"
312 //==================================================================
314 //==================================================================
316 Connection::~Connection()
318 bbtkCDebugMessage("object",4,
322 if (mAdaptor) mAdaptor.reset();
325 mFrom->bbDisconnectOutput(mOutput,this);
326 // GetThisPointer<Connection>());
331 bbtkInternalError("~Connection() : invalid initial box pointer");
335 mTo->bbDisconnectInput(mInput,this);// GetThisPointer<Connection>());
340 bbtkInternalError("~Connection() : invalid final box pointer");
344 bbtkCDebugMessage("object",4,
348 //==================================================================
350 //==================================================================
351 /// Recursive execution
352 void Connection::RecursiveExecute()
354 bbtkCDebugMessage("process",4,
355 "===> Connection::RecursiveExecute()"
359 // If box from already executing : nothing to do
360 if (mFrom->bbGetExecuting())
362 bbtkDebugMessage("process",3,
363 " -> "<<mFrom->bbGetName()
364 <<" already executing : abort"<<std::endl);
370 mFrom->bbRecursiveExecute(GetThisPointer<Connection>());
375 IOStatus s = MODIFIED;
376 if ( mFrom->bbGetOutputConnector(mOutput).GetStatus() == OUTOFDATE)
380 mTo->bbGetInputConnector(mInput).SetStatus(s);
382 bbtkCDebugMessage("process",4,
383 " --> '"<<mTo->bbGetName()<<"."<<mInput
384 <<" ["<<&mTo->bbGetInputConnector(mInput)<<"] "
386 <<GetIOStatusString(s)
390 bbtkCDebugMessage("process",4,
391 "<=== Connection::RecursiveExecute()"
395 //==================================================================
399 //==================================================================
400 /// Transfers the data from the source output to the target input
401 /// doing necessary conversions (adaptation or pointer cast)
402 void Connection::TransferData()
404 bbtkCDebugMessage("data",3,
405 "Connection::TransferData()"
409 // If an adaptor was created we need to adapt the data
412 mAdaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
413 mAdaptor->bbExecute();
414 // LG : Connection Update does not set mTo as modified
415 mTo->bbSetInput(mInput, mAdaptor->bbGetOutput("Out"),false);
418 // If no adaptor but source type is an any and target is not an any
419 else if ( mFromAny && (! mToAny) )
421 bbtkCDebugMessage("data",3,
422 " * Source type is an "
423 <<HumanTypeName<Data>()
424 <<" which contains a <"
425 <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
427 bbtkCDebugMessage("data",3,
428 " * Target type is <"
429 <<HumanTypeName(mTo->bbGetInputType(mInput))
432 // 0) If from any contents void : nothing to do
433 if (mFrom->bbGetOutput(mOutput).type() == typeid(void))
435 bbtkCDebugMessage("data",3,
436 " -> Source is void : nothing to transfer!"<<std::endl);
438 // 1) Test strict type matching between any content and target
439 else if (mFrom->bbGetOutput(mOutput)
440 .contains( mTo->bbGetInputType(mInput) ) )
442 bbtkCDebugMessage("data",3,
443 " -> Equal types : transfer ok"<<std::endl);
444 mTo->bbSetInput( mInput,
445 mFrom->bbGetOutput(mOutput),
450 // 2) Look for an adaptor
451 bbtk::BlackBox::Pointer adaptor;
454 adaptor = mFactory.lock()
455 ->NewAdaptor(mFrom->bbGetOutput(mOutput).type(),
456 mTo->bbGetInputType(mInput),
464 bbtkCDebugMessage("data",3," -> Adaptor found : using it"
466 adaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
467 adaptor->bbExecute();
468 // LG : Connection Update does not set mTo as modified
469 mTo->bbSetInput(mInput, adaptor->bbGetOutput("Out"),false);
470 // adaptor->bbDelete();
472 // 3) If no adaptor found but the any content is a pointer
473 // and target type is also a pointer : we try run-time cast
474 else if ( (mFrom->bbGetOutput(mOutput).contains_pointer()) &&
475 (mTo->bbGetDescriptor()->GetInputDescriptor(mInput)
478 bbtkCDebugMessage("data",3,
479 " -> No adaptor found but source and target types are both pointers : trying up or down cast"<<std::endl);
482 mFrom->bbGetOutput(mOutput)
483 .get_pointer_to(mTo->bbGetInput(mInput).pointed_type());
486 bbtkError("Connection '"
489 <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
491 <<HumanTypeName(mTo->bbGetInputType(mInput))
492 <<"> : no adaptor available and run-time up and down cast failed");
494 mTo->bbBruteForceSetInputPointer(mInput, nptr, false);
496 // 4) Nothing worked : error
499 bbtkError("Connection '"<<GetFullName()<<"' "
500 <<"no adaptor found to convert <"
501 <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
503 <<HumanTypeName(mTo->bbGetInputType(mInput))<<">");
507 // EO : mFromAny && ! mToAny
508 // Default case : types are the same; we use simple get-set
511 // LG : Connection Update does not set mTo as modified
512 mTo->bbSetInput(mInput, mFrom->bbGetOutput(mOutput),false);
516 //==================================================================
518 //==================================================================
519 /// From.Output change propagation
520 void Connection::OnOutputChange(bbtk::BlackBox::Pointer, const std::string&,
523 bbtkCDebugMessage("change",2,
524 "==> Connection::OnOutputChange("
525 <<GetIOStatusString(status)<<")"
529 BlackBoxInputConnector* ac = mAdaptor->bbGetInputConnectorMap().find("In")->second;
530 mAdaptor->bbSetStatusAndPropagate(ac,status);
533 mTo->bbSetStatusAndPropagate( mTo->bbGetInputConnectorMap().find(mInput)->second, status);
537 //==================================================================
540 //==================================================================
541 std::string Connection::GetFullName() const {
544 std::string res = mFrom->bbGetName()+"."+mOutput+"--"
545 +mTo->bbGetName()+"."+mInput;
546 if ((!mOriginalFrom.expired()) && (!mOriginalTo.expired()) &&
547 ((mFrom!=mOriginalFrom.lock())||(mTo!=mOriginalTo.lock())))
549 res += "("+mOriginalFrom.lock()->bbGetName()
550 +"."+mOriginalOutput+"--"
551 + mOriginalTo.lock()->bbGetName()+"."+mOriginalInput+")";
555 return "***Invalid Connection***";
557 //==================================================================
559 //==================================================================
560 void Connection::Check() const
562 bbtkMessage("debug",1,"** Checking Connection "<<(void*)this<<" ["
567 bbtkMessage("debug",2," - From = 0"<<std::endl);
571 bbtkMessage("debug",2," - From : "<<mFrom->bbGetName()<<std::endl);
572 if (!mFrom->bbHasOutput(mOutput))
574 bbtkError("** Checking Connection "<<(void*)this
575 <<" ["<<GetFullName()<<"] : "
576 << mFrom->bbGetName()<<" does not have output '"
579 bbtkMessage("debug",2," - From : Output '"<<mOutput<<"' exists"<<std::endl);
580 BlackBox::OutputConnectorMapType::const_iterator i
581 = mFrom->bbGetOutputConnectorMap().find(mOutput);
582 if (i== mFrom->bbGetOutputConnectorMap().end())
584 bbtkError("** Checking Connection "<<(void*)this
585 <<" ["<<GetFullName()<<"] : "
586 <<mFrom->bbGetName()<<" output '"
587 <<mOutput<<"' is not in OutputConnectorMap");
589 bbtkMessage("debug",2," - From : Output '"<<mOutput
590 <<"' is in OutputConnectorMap"<<std::endl);
592 std::vector< Connection* >::const_iterator j;
594 for (j = i->second->GetConnectionVector().begin();
595 j != i->second->GetConnectionVector().end();
598 if ((*j)==this) break;
601 j = find(i->second->GetConnectionVector().begin(),
602 i->second->GetConnectionVector().end(),
605 if (j==i->second->GetConnectionVector().end())
607 bbtkError("** Checking Connection "<<(void*)this
608 <<" ["<<GetFullName()<<"] : "
609 <<" OutputConnector '"
610 <<mOutput<<"' of "<<mFrom->bbGetName()
611 <<" does not point to this connection");
614 bbtkMessage("debug",2," - From : This connection is in OutputConnector connection vector"<<std::endl);
615 bbtkMessage("debug",2," * Box from : Check successfull"<<std::endl);
621 bbtkMessage("debug",2," - To = 0"<<std::endl);
625 bbtkMessage("debug",2," - To : "<<mTo->bbGetName()<<std::endl);
626 // std::cout << mTo << std::endl;
627 // std::cout << mTo->bbGetDescriptor() << std::endl;
628 // std::cout << mTo->bbGetDescriptor()->GetTypeName() << std::endl;
630 bbtkMessage("debug",2," - To : "<<mTo->bbGetName()<<std::endl);
631 if (!mTo->bbHasInput(mInput))
633 bbtkError("** Checking Connection "<<(void*)this
634 <<" ["<<GetFullName()<<"] : "
635 <<mTo->bbGetName()<<" does not have input '"
638 bbtkMessage("debug",2," - To : Input '"<<mInput<<"' exists"<<std::endl);
639 BlackBox::InputConnectorMapType::const_iterator i
640 = mTo->bbGetInputConnectorMap().find(mInput);
641 if (i== mTo->bbGetInputConnectorMap().end())
643 bbtkError("** Checking Connection "<<(void*)this
644 <<" ["<<GetFullName()<<"] : "
645 <<mTo->bbGetName()<<" input '"
646 <<mInput<<"' is not in InputConnectorMap");
648 bbtkMessage("debug",2," - To : Input '"<<mInput
649 <<"' is in InputConnectorMap"<<std::endl);
651 if (i->second->GetConnection()==0)
653 bbtkError("** Checking Connection "<<(void*)this
654 <<" ["<<GetFullName()<<"] : "
655 <<" InputConnector '"
656 <<mInput<<"' of "<<mTo->bbGetName()
657 <<" does not point to this connection");
660 bbtkMessage("debug",2," - To : This connection is in InputConnector connection vector"<<std::endl);
661 bbtkMessage("debug",2," * Box to : Check successfull"<<std::endl);
665 //==================================================================
666 //==========================================================================
667 std::string Connection::GetObjectName() const
669 std::string s("Connection '");
674 //==========================================================================
676 //==========================================================================
677 std::string Connection::GetObjectInfo() const
682 //==========================================================================
684 //==========================================================================
685 size_t Connection::GetObjectSize() const
687 size_t s = Superclass::GetObjectSize();
688 s += Connection::GetObjectInternalSize();
691 //==========================================================================
692 //==========================================================================
693 size_t Connection::GetObjectInternalSize() const
695 size_t s = sizeof(Connection);
698 //==========================================================================
699 //==========================================================================
700 size_t Connection::GetObjectRecursiveSize() const
702 size_t s = Superclass::GetObjectRecursiveSize();
703 s += Connection::GetObjectInternalSize();
706 //==========================================================================