1 /*=========================================================================
3 Module: $RCSfile: bbtkConnection.cxx,v $
5 Date: $Date: 2009/05/28 08:12:05 $
6 Version: $Revision: 1.21 $
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"
42 #define bbtkCMessage(key,level,mess) \
43 bbtkMessage(key,level,"["<<GetFullName()<<"] "<<mess)
44 #define bbtkCDebugMessage(key,level,mess) \
45 bbtkDebugMessage(key,level,"["<<GetFullName()<<"] "<<mess)
49 const std::string IOSTATUS_STRING[3] =
50 {"Up-to-date","Modified","Out-of-date"};
52 const std::string& GetIOStatusString(IOStatus s)
53 { return IOSTATUS_STRING[s]; }
55 //==================================================================
56 Connection::Pointer Connection::New(BlackBox::Pointer from,
57 const std::string& output,
59 const std::string& input ,
60 const Factory::Pointer f )
62 bbtkDebugMessage("object",1,"##> Connection(\""
63 <<from->bbGetName()<<"\",\""<<output<<"\",\""
64 <<to->bbGetName()<<"\",\""<<input<<"\")"
66 Connection::Pointer p =
67 MakePointer(new Connection(from,output,to,input,f));
68 bbtkDebugMessage("object",1,"<## Connection(\""
69 <<from->bbGetName()<<"\",\""<<output<<"\",\""
70 <<to->bbGetName()<<"\",\""<<input<<"\")"
74 //==================================================================
76 //==================================================================
77 /// Ctor with the black box from and to and their input and output.
78 /// Check the input and output compatibility
79 Connection::Connection(BlackBox::Pointer from, const std::string& output,
80 BlackBox::Pointer to, const std::string& input ,
81 const Factory::Pointer f )
87 bbtkDebugMessage("object",2,"==> Connection(\""
88 <<from->bbGetName()<<"\",\""<<output<<"\",\""
89 <<to->bbGetName()<<"\",\""<<input<<"\")"
92 bbtkDebugMessage("connection",1,"==> Connection(\""
93 <<from->bbGetName()<<"\",\""<<output<<"\",\""
94 <<to->bbGetName()<<"\",\""<<input<<"\")"
99 if (! from->bbHasOutput(output) )
101 bbtkError("The box \""<<from->bbGetTypeName()<<
102 "\" has no output \""<<output<<"\"");
104 if (! to->bbHasInput(input) )
106 bbtkError("The box \""<<to->bbGetTypeName()<<
107 "\" has no input \""<<input<<"\"");
110 if (to->bbGetInputConnectorMap().find(input)->second->IsConnected())
112 bbtkError("The input \""<<input<<"\" of the box \""<<to->bbGetName()
113 <<"\" is already connected");
116 // std::string t1 ( from->bbGetOutputType(output).name() );
117 // std::string t2 ( to->bbGetInputType(input).name() );
119 if ( from->bbGetOutputType(output) !=
120 to->bbGetInputType(input) )
122 if ( from->bbGetOutputType(output) == typeid(Data) )
124 bbtkWarning("Connection: '"<<from->bbGetName()<<"."<<output
126 <<HumanTypeName<Data>()
127 <<"> : type compatibility with '"
128 <<to->bbGetName()<<"."<<input
129 <<"' will be resolved at run time"
133 else if ( to->bbGetInputType(input) == typeid(Data) )
135 bbtkDebugMessage("kernel",8," -> '"<<input<<"' type is "
136 <<TypeName<Data>()<<" : can receive any data"
142 // std::cout << "Adaptive connection "<<std::endl;
144 name = from->bbGetName() + "." + output + "-"
145 + to->bbGetName() + "." + input;
146 mAdaptor = mFactory.lock()
147 ->NewAdaptor(from->bbGetOutputType(output),
148 to->bbGetInputType(input),
152 bbtkError("did not find any <"
153 <<TypeName(from->bbGetOutputType(output))
155 <<TypeName(to->bbGetInputType(input))
163 mOriginalFrom = from;
166 mInput = mOriginalInput = input;
167 mOutput = mOriginalOutput = output;
169 // Lock this pointer !!!
170 //Pointer p = MakePointer(this,true);
171 from->bbConnectOutput(output,this);
172 to->bbConnectInput(input,this);
174 from->bbGetOutputConnector(output).AddChangeObserver(boost::bind(&bbtk::Connection::OnOutputChange,this, _1, _2, _3));
177 bbtkDebugMessage("connection",1,"<== Connection(\""
178 <<from->bbGetName()<<"\",\""<<output<<"\",\""
179 <<to->bbGetName()<<"\",\""<<input<<"\")"
182 bbtkDebugMessage("object",2,"<== Connection(\""
183 <<from->bbGetName()<<"\",\""<<output<<"\",\""
184 <<to->bbGetName()<<"\",\""<<input<<"\")"
187 //==================================================================
189 //==================================================================
190 Connection::Pointer Connection::New(BlackBox::Pointer from,
191 const std::string& output,
192 BlackBox::Pointer to,
193 const std::string& input )
195 bbtkDebugMessage("object",1,"##> Connection(\""
196 <<from->bbGetName()<<"\",\""<<output<<"\",\""
197 <<to->bbGetName()<<"\",\""<<input<<"\")"
199 Connection::Pointer p =
200 MakePointer(new Connection(from,output,to,input));
201 bbtkDebugMessage("object",1,"<## Connection(\""
202 <<from->bbGetName()<<"\",\""<<output<<"\",\""
203 <<to->bbGetName()<<"\",\""<<input<<"\")"
207 //==================================================================
209 //==================================================================
210 /// Ctor with the black box from and to and their input and output.
211 /// Check the input and output compatibility
212 Connection::Connection(BlackBox::Pointer from, const std::string& output,
213 BlackBox::Pointer to, const std::string& input )
219 bbtkDebugMessage("object",2,"==> Connection(\""
220 <<from->bbGetName()<<"\",\""<<output<<"\",\""
221 <<to->bbGetName()<<"\",\""<<input<<"\")"
224 bbtkDebugMessage("connection",1,"==> Connection(\""
225 <<from->bbGetName()<<"\",\""<<output<<"\",\""
226 <<to->bbGetName()<<"\",\""<<input<<"\")"
231 if (! from->bbHasOutput(output) )
233 bbtkError("The box \""<<from->bbGetTypeName()<<
234 "\" has no output \""<<output<<"\"");
236 if (! to->bbHasInput(input) )
238 bbtkError("The box \""<<to->bbGetTypeName()<<
239 "\" has no input \""<<input<<"\"");
242 if (to->bbGetInputConnectorMap().find(input)->second->IsConnected())
244 bbtkError("The input \""<<input<<"\" of the box \""<<to->bbGetName()
245 <<"\" is already connected");
248 // std::string t1 ( from->bbGetOutputType(output).name() );
249 // std::string t2 ( to->bbGetInputType(input).name() );
251 if ( from->bbGetOutputType(output) !=
252 to->bbGetInputType(input) )
254 if ( from->bbGetOutputType(output) == typeid(Data) )
256 bbtkWarning("Connection '"
258 <<"' : '"<<from->bbGetName()<<"."<<output
260 <<HumanTypeName<Data>()
261 <<"> : type compatibility with '"
262 <<to->bbGetName()<<"."<<input
263 <<"' will be resolved at run time"
267 else if ( to->bbGetInputType(input) == typeid(Data) )
269 bbtkDebugMessage("kernel",8," -> '"<<input<<"' type is "
270 <<TypeName<Data>()<<" : can receive any data"
276 bbtkError("Connection created between different types without Factory provided");
282 mOriginalFrom = from;
285 mInput = mOriginalInput = input;
286 mOutput = mOriginalOutput = output;
288 // Lock this pointer !!!
289 //Pointer p = MakePointer(this,true);
290 from->bbConnectOutput(output,this);
291 to->bbConnectInput(input,this);
293 from->bbGetOutputConnector(output).AddChangeObserver(boost::bind(&bbtk::Connection::OnOutputChange,this, _1, _2, _3));
295 bbtkDebugMessage("connection",1,"<== Connection(\""
296 <<from->bbGetName()<<"\",\""<<output<<"\",\""
297 <<to->bbGetName()<<"\",\""<<input<<"\")"
300 bbtkDebugMessage("object",2,"==> Connection(\""
301 <<from->bbGetName()<<"\",\""<<output<<"\",\""
302 <<to->bbGetName()<<"\",\""<<input<<"\")"
305 //==================================================================
307 //==================================================================
309 Connection::~Connection()
311 bbtkCDebugMessage("object",4,
315 if (mAdaptor) mAdaptor.reset();
318 mFrom->bbDisconnectOutput(mOutput,this);
319 // GetThisPointer<Connection>());
324 bbtkInternalError("~Connection() : invalid initial box pointer");
328 mTo->bbDisconnectInput(mInput,this);// GetThisPointer<Connection>());
333 bbtkInternalError("~Connection() : invalid final box pointer");
337 bbtkCDebugMessage("object",4,
341 //==================================================================
343 //==================================================================
344 /// Recursive execution
345 void Connection::RecursiveExecute()
347 bbtkCDebugMessage("process",4,
348 "===> Connection::RecursiveExecute()"
352 // If box from already executing : nothing to do
353 if (mFrom->bbGetExecuting())
355 bbtkDebugMessage("process",3,
356 " -> "<<mFrom->bbGetName()
357 <<" already executing : abort"<<std::endl);
363 mFrom->bbRecursiveExecute(GetThisPointer<Connection>());
368 IOStatus s = MODIFIED;
369 if ( mFrom->bbGetOutputConnector(mOutput).GetStatus() == OUTOFDATE)
373 mTo->bbGetInputConnector(mInput).SetStatus(s);
375 bbtkCDebugMessage("process",4,
376 " --> '"<<mTo->bbGetName()<<"."<<mInput
377 <<" ["<<&mTo->bbGetInputConnector(mInput)<<"] "
379 <<GetIOStatusString(s)
383 bbtkCDebugMessage("process",4,
384 "<=== Connection::RecursiveExecute()"
388 //==================================================================
392 //==================================================================
393 /// Transfers the data from the source output to the target input
394 /// doing necessary conversions (adaptation or pointer cast)
395 void Connection::TransferData()
397 bbtkCDebugMessage("data",3,
398 "Connection::TransferData()"
402 // If an adaptor was created we need to adapt the data
405 mAdaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
406 mAdaptor->bbExecute();
407 // LG : Connection Update does not set mTo as modified
408 mTo->bbSetInput(mInput, mAdaptor->bbGetOutput("Out"),false);
411 // If no adaptor but source type is an any and target is not an any
412 else if ( mFromAny && (! mToAny) )
414 bbtkCDebugMessage("data",3,
415 " * Source type is an "
416 <<HumanTypeName<Data>()
417 <<" which contains a <"
418 <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
420 bbtkCDebugMessage("data",3,
421 " * Target type is <"
422 <<HumanTypeName(mTo->bbGetInputType(mInput))
425 // 0) If from any contents void : nothing to do
426 if (mFrom->bbGetOutput(mOutput).type() == typeid(void))
428 bbtkCDebugMessage("data",3,
429 " -> Source is void : nothing to transfer!"<<std::endl);
431 // 1) Test strict type matching between any content and target
432 else if (mFrom->bbGetOutput(mOutput)
433 .contains( mTo->bbGetInputType(mInput) ) )
435 bbtkCDebugMessage("data",3,
436 " -> Equal types : transfer ok"<<std::endl);
437 mTo->bbSetInput( mInput,
438 mFrom->bbGetOutput(mOutput),
443 // 2) Look for an adaptor
444 bbtk::BlackBox::Pointer adaptor;
447 adaptor = mFactory.lock()
448 ->NewAdaptor(mFrom->bbGetOutput(mOutput).type(),
449 mTo->bbGetInputType(mInput),
457 bbtkCDebugMessage("data",3," -> Adaptor found : using it"
459 adaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
460 adaptor->bbExecute();
461 // LG : Connection Update does not set mTo as modified
462 mTo->bbSetInput(mInput, adaptor->bbGetOutput("Out"),false);
463 // adaptor->bbDelete();
465 // 3) If no adaptor found but the any content is a pointer
466 // and target type is also a pointer : we try run-time cast
467 else if ( (mFrom->bbGetOutput(mOutput).contains_pointer()) &&
468 (mTo->bbGetDescriptor()->GetInputDescriptor(mInput)
471 bbtkCDebugMessage("data",3,
472 " -> No adaptor found but source and target types are both pointers : trying up or down cast"<<std::endl);
475 mFrom->bbGetOutput(mOutput)
476 .get_pointer_to(mTo->bbGetInput(mInput).pointed_type());
479 bbtkError("Connection '"
482 <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
484 <<HumanTypeName(mTo->bbGetInputType(mInput))
485 <<"> : no adaptor available and run-time up and down cast failed");
487 mTo->bbBruteForceSetInputPointer(mInput, nptr, false);
489 // 4) Nothing worked : error
492 bbtkError("Connection '"<<GetFullName()<<"' "
493 <<"no adaptor found to convert <"
494 <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
496 <<HumanTypeName(mTo->bbGetInputType(mInput))<<">");
500 // EO : mFromAny && ! mToAny
501 // Default case : types are the same; we use simple get-set
504 // LG : Connection Update does not set mTo as modified
505 mTo->bbSetInput(mInput, mFrom->bbGetOutput(mOutput),false);
509 //==================================================================
511 //==================================================================
512 /// From.Output change propagation
513 void Connection::OnOutputChange(bbtk::BlackBox::Pointer, const std::string&,
516 bbtkCDebugMessage("change",2,
517 "==> Connection::OnOutputChange("
518 <<GetIOStatusString(status)<<")"
522 BlackBoxInputConnector* ac = mAdaptor->bbGetInputConnectorMap().find("In")->second;
523 mAdaptor->bbSetStatusAndPropagate(ac,status);
526 mTo->bbSetStatusAndPropagate( mTo->bbGetInputConnectorMap().find(mInput)->second, status);
530 //==================================================================
533 //==================================================================
534 std::string Connection::GetFullName() const {
537 std::string res = mFrom->bbGetName()+"."+mOutput+"--"
538 +mTo->bbGetName()+"."+mInput;
539 if ((!mOriginalFrom.expired()) && (!mOriginalTo.expired()) &&
540 ((mFrom!=mOriginalFrom.lock())||(mTo!=mOriginalTo.lock())))
542 res += "("+mOriginalFrom.lock()->bbGetName()
543 +"."+mOriginalOutput+"--"
544 + mOriginalTo.lock()->bbGetName()+"."+mOriginalInput+")";
548 return "***Invalid Connection***";
550 //==================================================================
552 //==================================================================
553 void Connection::Check() const
555 bbtkMessage("debug",1,"** Checking Connection "<<(void*)this<<" ["
560 bbtkMessage("debug",2," - From = 0"<<std::endl);
564 bbtkMessage("debug",2," - From : "<<mFrom->bbGetName()<<std::endl);
565 if (!mFrom->bbHasOutput(mOutput))
567 bbtkError("** Checking Connection "<<(void*)this
568 <<" ["<<GetFullName()<<"] : "
569 << mFrom->bbGetName()<<" does not have output '"
572 bbtkMessage("debug",2," - From : Output '"<<mOutput<<"' exists"<<std::endl);
573 BlackBox::OutputConnectorMapType::const_iterator i
574 = mFrom->bbGetOutputConnectorMap().find(mOutput);
575 if (i== mFrom->bbGetOutputConnectorMap().end())
577 bbtkError("** Checking Connection "<<(void*)this
578 <<" ["<<GetFullName()<<"] : "
579 <<mFrom->bbGetName()<<" output '"
580 <<mOutput<<"' is not in OutputConnectorMap");
582 bbtkMessage("debug",2," - From : Output '"<<mOutput
583 <<"' is in OutputConnectorMap"<<std::endl);
585 std::vector< Connection* >::const_iterator j;
587 for (j = i->second->GetConnectionVector().begin();
588 j != i->second->GetConnectionVector().end();
591 if ((*j)==this) break;
594 j = find(i->second->GetConnectionVector().begin(),
595 i->second->GetConnectionVector().end(),
598 if (j==i->second->GetConnectionVector().end())
600 bbtkError("** Checking Connection "<<(void*)this
601 <<" ["<<GetFullName()<<"] : "
602 <<" OutputConnector '"
603 <<mOutput<<"' of "<<mFrom->bbGetName()
604 <<" does not point to this connection");
607 bbtkMessage("debug",2," - From : This connection is in OutputConnector connection vector"<<std::endl);
608 bbtkMessage("debug",2," * Box from : Check successfull"<<std::endl);
614 bbtkMessage("debug",2," - To = 0"<<std::endl);
618 bbtkMessage("debug",2," - To : "<<mTo->bbGetName()<<std::endl);
619 // std::cout << mTo << std::endl;
620 // std::cout << mTo->bbGetDescriptor() << std::endl;
621 // std::cout << mTo->bbGetDescriptor()->GetTypeName() << std::endl;
623 bbtkMessage("debug",2," - To : "<<mTo->bbGetName()<<std::endl);
624 if (!mTo->bbHasInput(mInput))
626 bbtkError("** Checking Connection "<<(void*)this
627 <<" ["<<GetFullName()<<"] : "
628 <<mTo->bbGetName()<<" does not have input '"
631 bbtkMessage("debug",2," - To : Input '"<<mInput<<"' exists"<<std::endl);
632 BlackBox::InputConnectorMapType::const_iterator i
633 = mTo->bbGetInputConnectorMap().find(mInput);
634 if (i== mTo->bbGetInputConnectorMap().end())
636 bbtkError("** Checking Connection "<<(void*)this
637 <<" ["<<GetFullName()<<"] : "
638 <<mTo->bbGetName()<<" input '"
639 <<mInput<<"' is not in InputConnectorMap");
641 bbtkMessage("debug",2," - To : Input '"<<mInput
642 <<"' is in InputConnectorMap"<<std::endl);
644 if (i->second->GetConnection()==0)
646 bbtkError("** Checking Connection "<<(void*)this
647 <<" ["<<GetFullName()<<"] : "
648 <<" InputConnector '"
649 <<mInput<<"' of "<<mTo->bbGetName()
650 <<" does not point to this connection");
653 bbtkMessage("debug",2," - To : This connection is in InputConnector connection vector"<<std::endl);
654 bbtkMessage("debug",2," * Box to : Check successfull"<<std::endl);
658 //==================================================================
659 //==========================================================================
660 std::string Connection::GetObjectName() const
662 std::string s("Connection '");
667 //==========================================================================
669 //==========================================================================
670 std::string Connection::GetObjectInfo() const
675 //==========================================================================
677 //==========================================================================
678 size_t Connection::GetObjectSize() const
680 size_t s = Superclass::GetObjectSize();
681 s += Connection::GetObjectInternalSize();
684 //==========================================================================
685 //==========================================================================
686 size_t Connection::GetObjectInternalSize() const
688 size_t s = sizeof(Connection);
691 //==========================================================================
692 //==========================================================================
693 size_t Connection::GetObjectRecursiveSize() const
695 size_t s = Superclass::GetObjectRecursiveSize();
696 s += Connection::GetObjectInternalSize();
699 //==========================================================================