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");
124 //EED2021-09-06 dlopen flags for == != -> bbtkDynamicLibraryHandling.h
126 // std::string t1 ( from->bbGetOutputType(output).name() );
127 // std::string t2 ( to->bbGetInputType(input).name() );
129 if ( from->bbGetOutputType(output) != to->bbGetInputType(input) )
131 if ( from->bbGetOutputType(output) == typeid(Data) )
133 bbtkWarning("Connection: '"<<from->bbGetName()<<"."<<output
135 <<HumanTypeName<Data>()
136 <<"> : type compatibility with '"
137 <<to->bbGetName()<<"."<<input
138 <<"' will be resolved at run time"
141 } else if ( to->bbGetInputType(input) == typeid(Data) ) {
142 bbtkDebugMessage("kernel",8," -> '"<<input<<"' type is "
143 <<TypeName<Data>()<<" : can receive any data"
147 // std::cout << "Adaptive connection "<<std::endl;
149 name = from->bbGetName() + "." + output + "-"
150 + to->bbGetName() + "." + input;
151 mAdaptor = mFactory.lock()
152 ->NewAdaptor(from->bbGetOutputType(output),
153 to->bbGetInputType(input),
157 bbtkError("did not find any <"
158 <<TypeName(from->bbGetOutputType(output))
160 <<TypeName(to->bbGetInputType(input))
168 mOriginalFrom = from;
171 mInput = mOriginalInput = input;
172 mOutput = mOriginalOutput = output;
174 // Lock this pointer !!!
175 //Pointer p = MakePointer(this,true);
176 from->bbConnectOutput(output,this);
177 to->bbConnectInput(input,this);
179 from->bbGetOutputConnector(output).AddChangeObserver(boost::bind(&bbtk::Connection::OnOutputChange,this, _1, _2, _3));
182 bbtkDebugMessage("connection",1,"<== Connection(\""
183 <<from->bbGetName()<<"\",\""<<output<<"\",\""
184 <<to->bbGetName()<<"\",\""<<input<<"\")"
187 bbtkDebugMessage("object",2,"<== Connection(\""
188 <<from->bbGetName()<<"\",\""<<output<<"\",\""
189 <<to->bbGetName()<<"\",\""<<input<<"\")"
192 //==================================================================
194 //==================================================================
195 Connection::Pointer Connection::New(BlackBox::Pointer from,
196 const std::string& output,
197 BlackBox::Pointer to,
198 const std::string& input )
200 bbtkDebugMessage("object",1,"##> Connection(\""
201 <<from->bbGetName()<<"\",\""<<output<<"\",\""
202 <<to->bbGetName()<<"\",\""<<input<<"\")"
204 Connection::Pointer p =
205 MakePointer(new Connection(from,output,to,input));
206 bbtkDebugMessage("object",1,"<## Connection(\""
207 <<from->bbGetName()<<"\",\""<<output<<"\",\""
208 <<to->bbGetName()<<"\",\""<<input<<"\")"
212 //==================================================================
214 //==================================================================
215 /// Ctor with the black box from and to and their input and output.
216 /// Check the input and output compatibility
217 Connection::Connection(BlackBox::Pointer from, const std::string& output,
218 BlackBox::Pointer to, const std::string& input )
224 bbtkDebugMessage("object",2,"==> Connection(\""
225 <<from->bbGetName()<<"\",\""<<output<<"\",\""
226 <<to->bbGetName()<<"\",\""<<input<<"\")"
229 bbtkDebugMessage("connection",1,"==> Connection(\""
230 <<from->bbGetName()<<"\",\""<<output<<"\",\""
231 <<to->bbGetName()<<"\",\""<<input<<"\")"
236 if (! from->bbHasOutput(output) )
238 bbtkError("The box \""<<from->bbGetTypeName()<<
239 "\" has no output \""<<output<<"\"");
241 if (! to->bbHasInput(input) )
243 bbtkError("The box \""<<to->bbGetTypeName()<<
244 "\" has no input \""<<input<<"\"");
247 if (to->bbGetInputConnectorMap().find(input)->second->IsConnected())
249 bbtkError("The input \""<<input<<"\" of the box \""<<to->bbGetName()
250 <<"\" is already connected");
253 // std::string t1 ( from->bbGetOutputType(output).name() );
254 // std::string t2 ( to->bbGetInputType(input).name() );
256 if ( from->bbGetOutputType(output) !=
257 to->bbGetInputType(input) )
259 if ( from->bbGetOutputType(output) == typeid(Data) )
261 bbtkWarning("Connection '"
263 <<"' : '"<<from->bbGetName()<<"."<<output
265 <<HumanTypeName<Data>()
266 <<"> : type compatibility with '"
267 <<to->bbGetName()<<"."<<input
268 <<"' will be resolved at run time"
272 else if ( to->bbGetInputType(input) == typeid(Data) )
274 bbtkDebugMessage("kernel",8," -> '"<<input<<"' type is "
275 <<TypeName<Data>()<<" : can receive any data"
281 bbtkError("Connection created between different types without Factory provided");
287 mOriginalFrom = from;
290 mInput = mOriginalInput = input;
291 mOutput = mOriginalOutput = output;
293 // Lock this pointer !!!
294 //Pointer p = MakePointer(this,true);
295 from->bbConnectOutput(output,this);
296 to->bbConnectInput(input,this);
298 from->bbGetOutputConnector(output).AddChangeObserver(boost::bind(&bbtk::Connection::OnOutputChange,this, _1, _2, _3));
300 bbtkDebugMessage("connection",1,"<== Connection(\""
301 <<from->bbGetName()<<"\",\""<<output<<"\",\""
302 <<to->bbGetName()<<"\",\""<<input<<"\")"
305 bbtkDebugMessage("object",2,"==> Connection(\""
306 <<from->bbGetName()<<"\",\""<<output<<"\",\""
307 <<to->bbGetName()<<"\",\""<<input<<"\")"
310 //==================================================================
312 //==================================================================
314 Connection::~Connection()
316 bbtkCDebugMessage("object",4,
320 if (mAdaptor) mAdaptor.reset();
323 mFrom->bbDisconnectOutput(mOutput,this);
324 // GetThisPointer<Connection>());
329 bbtkInternalError("~Connection() : invalid initial box pointer");
333 mTo->bbDisconnectInput(mInput,this);// GetThisPointer<Connection>());
338 bbtkInternalError("~Connection() : invalid final box pointer");
342 bbtkCDebugMessage("object",4,
346 //==================================================================
348 //==================================================================
349 /// Recursive execution
350 void Connection::RecursiveExecute()
352 bbtkCDebugMessage("process",4,
353 "===> Connection::RecursiveExecute()"
357 // If box from already executing : nothing to do
358 if (mFrom->bbGetExecuting())
360 bbtkDebugMessage("process",3,
361 " -> "<<mFrom->bbGetName()
362 <<" already executing : abort"<<std::endl);
368 mFrom->bbRecursiveExecute(GetThisPointer<Connection>());
373 IOStatus s = MODIFIED;
374 if ( mFrom->bbGetOutputConnector(mOutput).GetStatus() == OUTOFDATE)
378 mTo->bbGetInputConnector(mInput).SetStatus(s);
380 bbtkCDebugMessage("process",4,
381 " --> '"<<mTo->bbGetName()<<"."<<mInput
382 <<" ["<<&mTo->bbGetInputConnector(mInput)<<"] "
384 <<GetIOStatusString(s)
388 bbtkCDebugMessage("process",4,
389 "<=== Connection::RecursiveExecute()"
393 //==================================================================
397 //==================================================================
398 /// Transfers the data from the source output to the target input
399 /// doing necessary conversions (adaptation or pointer cast)
400 void Connection::TransferData()
402 bbtkCDebugMessage("data",3,
403 "Connection::TransferData()"
407 // If an adaptor was created we need to adapt the data
410 mAdaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
411 mAdaptor->bbExecute();
412 // LG : Connection Update does not set mTo as modified
413 mTo->bbSetInput(mInput, mAdaptor->bbGetOutput("Out"),false);
416 // If no adaptor but source type is an any and target is not an any
417 else if ( mFromAny && (! mToAny) )
419 bbtkCDebugMessage("data",3,
420 " * Source type is an "
421 <<HumanTypeName<Data>()
422 <<" which contains a <"
423 <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
425 bbtkCDebugMessage("data",3,
426 " * Target type is <"
427 <<HumanTypeName(mTo->bbGetInputType(mInput))
430 // 0) If from any contents void : nothing to do
431 if (mFrom->bbGetOutput(mOutput).type() == typeid(void))
433 bbtkCDebugMessage("data",3,
434 " -> Source is void : nothing to transfer!"<<std::endl);
436 // 1) Test strict type matching between any content and target
437 else if (mFrom->bbGetOutput(mOutput)
438 .contains( mTo->bbGetInputType(mInput) ) )
440 bbtkCDebugMessage("data",3,
441 " -> Equal types : transfer ok"<<std::endl);
442 mTo->bbSetInput( mInput,
443 mFrom->bbGetOutput(mOutput),
448 // 2) Look for an adaptor
449 bbtk::BlackBox::Pointer adaptor;
452 adaptor = mFactory.lock()
453 ->NewAdaptor(mFrom->bbGetOutput(mOutput).type(),
454 mTo->bbGetInputType(mInput),
462 bbtkCDebugMessage("data",3," -> Adaptor found : using it"
464 adaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
465 adaptor->bbExecute();
466 // LG : Connection Update does not set mTo as modified
467 mTo->bbSetInput(mInput, adaptor->bbGetOutput("Out"),false);
468 // adaptor->bbDelete();
470 // 3) If no adaptor found but the any content is a pointer
471 // and target type is also a pointer : we try run-time cast
472 else if ( (mFrom->bbGetOutput(mOutput).contains_pointer()) &&
473 (mTo->bbGetDescriptor()->GetInputDescriptor(mInput)
476 bbtkCDebugMessage("data",3,
477 " -> No adaptor found but source and target types are both pointers : trying up or down cast"<<std::endl);
480 mFrom->bbGetOutput(mOutput)
481 .get_pointer_to(mTo->bbGetInput(mInput).pointed_type());
484 bbtkError("Connection '"
487 <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
489 <<HumanTypeName(mTo->bbGetInputType(mInput))
490 <<"> : no adaptor available and run-time up and down cast failed");
492 mTo->bbBruteForceSetInputPointer(mInput, nptr, false);
494 // 4) Nothing worked : error
497 bbtkError("Connection '"<<GetFullName()<<"' "
498 <<"no adaptor found to convert <"
499 <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
501 <<HumanTypeName(mTo->bbGetInputType(mInput))<<">");
505 // EO : mFromAny && ! mToAny
506 // Default case : types are the same; we use simple get-set
509 // LG : Connection Update does not set mTo as modified
510 mTo->bbSetInput(mInput, mFrom->bbGetOutput(mOutput),false);
513 //==================================================================
515 //==================================================================
516 /// From.Output change propagation
517 void Connection::OnOutputChange(bbtk::BlackBox::Pointer, const std::string&,
520 bbtkCDebugMessage("change",2,
521 "==> Connection::OnOutputChange("
522 <<GetIOStatusString(status)<<")"
526 BlackBoxInputConnector* ac = mAdaptor->bbGetInputConnectorMap().find("In")->second;
527 mAdaptor->bbSetStatusAndPropagate(ac,status);
530 mTo->bbSetStatusAndPropagate( mTo->bbGetInputConnectorMap().find(mInput)->second, status);
534 //==================================================================
537 //==================================================================
538 std::string Connection::GetFullName() const {
541 std::string res = mFrom->bbGetName()+"."+mOutput+"--"
542 +mTo->bbGetName()+"."+mInput;
543 if ((!mOriginalFrom.expired()) && (!mOriginalTo.expired()) &&
544 ((mFrom!=mOriginalFrom.lock())||(mTo!=mOriginalTo.lock())))
546 res += "("+mOriginalFrom.lock()->bbGetName()
547 +"."+mOriginalOutput+"--"
548 + mOriginalTo.lock()->bbGetName()+"."+mOriginalInput+")";
552 return "***Invalid Connection***";
554 //==================================================================
556 //==================================================================
557 void Connection::Check() const
559 bbtkMessage("debug",1,"** Checking Connection "<<(void*)this<<" ["
564 bbtkMessage("debug",2," - From = 0"<<std::endl);
568 bbtkMessage("debug",2," - From : "<<mFrom->bbGetName()<<std::endl);
569 if (!mFrom->bbHasOutput(mOutput))
571 bbtkError("** Checking Connection "<<(void*)this
572 <<" ["<<GetFullName()<<"] : "
573 << mFrom->bbGetName()<<" does not have output '"
576 bbtkMessage("debug",2," - From : Output '"<<mOutput<<"' exists"<<std::endl);
577 BlackBox::OutputConnectorMapType::const_iterator i
578 = mFrom->bbGetOutputConnectorMap().find(mOutput);
579 if (i== mFrom->bbGetOutputConnectorMap().end())
581 bbtkError("** Checking Connection "<<(void*)this
582 <<" ["<<GetFullName()<<"] : "
583 <<mFrom->bbGetName()<<" output '"
584 <<mOutput<<"' is not in OutputConnectorMap");
586 bbtkMessage("debug",2," - From : Output '"<<mOutput
587 <<"' is in OutputConnectorMap"<<std::endl);
589 std::vector< Connection* >::const_iterator j;
591 for (j = i->second->GetConnectionVector().begin();
592 j != i->second->GetConnectionVector().end();
595 if ((*j)==this) break;
598 j = find(i->second->GetConnectionVector().begin(),
599 i->second->GetConnectionVector().end(),
602 if (j==i->second->GetConnectionVector().end())
604 bbtkError("** Checking Connection "<<(void*)this
605 <<" ["<<GetFullName()<<"] : "
606 <<" OutputConnector '"
607 <<mOutput<<"' of "<<mFrom->bbGetName()
608 <<" does not point to this connection");
611 bbtkMessage("debug",2," - From : This connection is in OutputConnector connection vector"<<std::endl);
612 bbtkMessage("debug",2," * Box from : Check successfull"<<std::endl);
618 bbtkMessage("debug",2," - To = 0"<<std::endl);
622 bbtkMessage("debug",2," - To : "<<mTo->bbGetName()<<std::endl);
623 // std::cout << mTo << std::endl;
624 // std::cout << mTo->bbGetDescriptor() << std::endl;
625 // std::cout << mTo->bbGetDescriptor()->GetTypeName() << std::endl;
627 bbtkMessage("debug",2," - To : "<<mTo->bbGetName()<<std::endl);
628 if (!mTo->bbHasInput(mInput))
630 bbtkError("** Checking Connection "<<(void*)this
631 <<" ["<<GetFullName()<<"] : "
632 <<mTo->bbGetName()<<" does not have input '"
635 bbtkMessage("debug",2," - To : Input '"<<mInput<<"' exists"<<std::endl);
636 BlackBox::InputConnectorMapType::const_iterator i
637 = mTo->bbGetInputConnectorMap().find(mInput);
638 if (i== mTo->bbGetInputConnectorMap().end())
640 bbtkError("** Checking Connection "<<(void*)this
641 <<" ["<<GetFullName()<<"] : "
642 <<mTo->bbGetName()<<" input '"
643 <<mInput<<"' is not in InputConnectorMap");
645 bbtkMessage("debug",2," - To : Input '"<<mInput
646 <<"' is in InputConnectorMap"<<std::endl);
648 if (i->second->GetConnection()==0)
650 bbtkError("** Checking Connection "<<(void*)this
651 <<" ["<<GetFullName()<<"] : "
652 <<" InputConnector '"
653 <<mInput<<"' of "<<mTo->bbGetName()
654 <<" does not point to this connection");
657 bbtkMessage("debug",2," - To : This connection is in InputConnector connection vector"<<std::endl);
658 bbtkMessage("debug",2," * Box to : Check successfull"<<std::endl);
662 //==================================================================
663 //==========================================================================
664 std::string Connection::GetObjectName() const
666 std::string s("Connection '");
671 //==========================================================================
673 //==========================================================================
674 std::string Connection::GetObjectInfo() const
679 //==========================================================================
681 //==========================================================================
682 size_t Connection::GetObjectSize() const
684 size_t s = Superclass::GetObjectSize();
685 s += Connection::GetObjectInternalSize();
688 //==========================================================================
689 //==========================================================================
690 size_t Connection::GetObjectInternalSize() const
692 size_t s = sizeof(Connection);
695 //==========================================================================
696 //==========================================================================
697 size_t Connection::GetObjectRecursiveSize() const
699 size_t s = Superclass::GetObjectRecursiveSize();
700 s += Connection::GetObjectInternalSize();
703 //==========================================================================