/*========================================================================= Program: bbtk Module: $RCSfile: bbtkBlackBox.cxx,v $ Language: C++ Date: $Date: 2008/12/10 09:33:18 $ Version: $Revision: 1.36 $ =========================================================================*/ /* --------------------------------------------------------------------- * Copyright (c) CREATIS-LRMN (Centre de Recherche en Imagerie Medicale) * Authors : Eduardo Davila, Laurent Guigues, Jean-Pierre Roux * * This software is governed by the CeCILL-B license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/ or redistribute the software under the terms of the CeCILL-B * license as circulated by CEA, CNRS and INRIA at the following URL * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html * or in the file LICENSE.txt. * * As a counterpart to the access to the source code and rights to copy, * modify and redistribute granted by the license, users are provided only * with a limited warranty and the software's author, the holder of the * economic rights, and the successive licensors have only limited * liability. * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-B license and that you accept its terms. * ------------------------------------------------------------------------ */ /** * \file * \brief Class bbtk::BlackBox : abstract black-box interface. */ #include "bbtkBlackBox.h" #include "bbtkPackage.h" #include "bbtkMessageManager.h" #include "bbtkFactory.h" #include "bbtkBlackBoxOutputConnector.h" #include "bbtkConfigurationFile.h" #include "bbtkWxBlackBox.h" #include //#include namespace bbtk { static bool bbmgSomeBoxExecuting = false; static bool bbmgFreezeExecution = false; static std::set bbmgExecutionList; //========================================================================= BlackBox::Deleter::Deleter() { } //========================================================================= //========================================================================= void BlackBox::Deleter::Delete(Object* p) { BlackBox* b = dynamic_cast(p); if (!b) { bbtkInternalError("BlackBox::Deleter::Delete("<GetObjectName() <<"["<GetObjectName();//b->bbGetNameWithParent(); bbtkDebugMessage("object",2,"##> BlackBox::Deleter(\""<bbGetDescriptor(); bbtkDebugMessage("object",2,"##> BlackBox::Deleter(\""<bbDelete(); bbtkDebugMessage("object",2,"##> BlackBox::Deleter(\""<GetPackage(); if (!pack.expired()) { Package::ReleaseBlackBoxDescriptor(pack,desc); } else { bbtkDebugMessage("object",2,"##> BlackBox::Deleter(\""< BlackBox::Deleter(\""< BlackBox::BlackBox(\"" < BlackBox::BlackBox(" < BlackBox::~BlackBox() ["<bbDesallocateConnectors(); bbtkDebugMessage("object",4,"<== BlackBox::~BlackBox() ["< BlackBox::bbExecute("<<(int)force<<") [" < already executing : bailing out"< FreezeExecution global flag is 'true' : abort execution"<bbGetNameWithParent()+"<"+this->bbGetDescriptor()->GetTypeName()+">"; } //========================================================================= //========================================================================= /// Returns the name with the name of the parent prepended if any std::string BlackBox::bbGetNameWithParent() const { if (bbmParent.lock()) { return bbmParent.lock()->bbGetNameWithParent() + ":" + bbmName; } else { return bbmName; } } //========================================================================= //========================================================================= /// Prints the Help on the BlackBox type void BlackBox::bbGetHelp(bool full) const { bbGetDescriptor()->GetHelp(full); } //========================================================================= //========================================================================= /// Returns true if the UserBlackBox has an input of name name bool BlackBox::bbHasInput(const std::string& name) const { bbtkDebugMessageInc("Kernel",8, "BlackBox::bbHasInput(\"" <GetInputDescriptorMap().find(name) != bbGetDescriptor()->GetInputDescriptorMap().end()); bbtkDebugDecTab("Kernel",8); return r; } //========================================================================= //========================================================================= /// Returns true if the UserBlackBox has an output of name name bool BlackBox::bbHasOutput(const std::string& name) const { bbtkDebugMessageInc("Kernel",8,"BlackBox::bbHasOutput(\"" <GetOutputDescriptorMap().find(name) != bbGetDescriptor()->GetOutputDescriptorMap().end()); bbtkDebugDecTab("Kernel",8); return r; } //========================================================================= //========================================================================= /// Gets the output type of a given name TypeInfo BlackBox::bbGetOutputType( const std::string &name ) const { bbtkDebugMessageInc("Kernel",8, "BlackBox::bbGetOutputType(\"" <GetOutputDescriptor(name)->GetTypeInfo(); bbtkDebugDecTab("Kernel",8); return r; } //========================================================================= //========================================================================= /// Gets the input type of a given name TypeInfo BlackBox::bbGetInputType( const std::string &name ) const { bbtkDebugMessageInc("Kernel",8, "BlackBox::bbGetInputType(\"" <GetInputDescriptor(name)->GetTypeInfo(); bbtkDebugDecTab("Kernel",8); return r; } //========================================================================= //========================================================================= /// Allocates the i/o connectors of the black box void BlackBox::bbAllocateConnectors() { bbtkDebugMessageInc("Kernel",8, "BlackBox::bbAllocateConnectors() [" <GetInputDescriptorMap(); BlackBoxDescriptor::InputDescriptorMapType::const_iterator i; for ( i = imap.begin(); i != imap.end(); ++i ) { bbtkDebugMessage("Kernel",8,"* Allocate \""<first<<"\""<second->GetName()] = new BlackBoxInputConnector(GetThisPointer()); } const BlackBoxDescriptor::OutputDescriptorMapType& omap = bbGetDescriptor()->GetOutputDescriptorMap(); BlackBoxDescriptor::OutputDescriptorMapType::const_iterator o; for ( o = omap.begin(); o != omap.end(); ++o ) { bbtkDebugMessage("Kernel",8,"* Allocate \""<first<<"\""<second->GetName()] = new BlackBoxOutputConnector(); } bbtkDebugDecTab("Kernel",8); } //========================================================================= //========================================================================= /// Desallocates the i/o connectors of the black box void BlackBox::bbDesallocateConnectors() { bbtkDebugMessageInc("Kernel",8, "BlackBox::bbDesallocateConnectors()" <first<<"\""<second); } OutputConnectorMapType::const_iterator o; for ( o = bbGetOutputConnectorMap().begin(); o != bbGetOutputConnectorMap().end(); ++o ) { bbtkDebugMessage("Kernel",8,"* Delete \""<first<<"\""<second); } bbtkDebugDecTab("Kernel",8); } //========================================================================= //========================================================================= /// Copies the input / output values from another box void BlackBox::bbCopyIOValues(BlackBox& from) { bbtkDebugMessageInc("Kernel",1, "BlackBox::bbCopyIOValues(" <GetInputDescriptorMap(); BlackBoxDescriptor::InputDescriptorMapType::const_iterator i; for ( i = imap.begin(); i != imap.end(); ++i ) { if (! i->second->GetCopyConstruct() ) continue; std::string input = i->second->GetName(); bbtkDebugMessage("Kernel",2,"* Copying input "<bbSetInput(input, from.bbGetInput(input) ); } // copies the output values const BlackBoxDescriptor::OutputDescriptorMapType& omap = bbGetDescriptor()->GetOutputDescriptorMap(); BlackBoxDescriptor::OutputDescriptorMapType::const_iterator o; for ( o = omap.begin(); o != omap.end(); ++o ) { if (! o->second->GetCopyConstruct() ) continue; std::string output = o->second->GetName(); bbtkDebugMessage("Kernel",2,"* Copying output "<bbSetOutput(output, from.bbGetOutput(output) ); } bbtkDebugDecTab("Kernel",9); } //========================================================================= //========================================================================= bool BlackBox::bbCanReact() const { return ( bbGlobalGetSomeBoxExecuting() #ifdef _USE_WXWIDGETS_ || Wx::IsSomeWindowAlive() #endif ); } //========================================================================= //========================================================================= /// User overloadable destruction method of a black box void BlackBox::bbUserDelete() { bbtkDebugMessage("process",5, "=> BlackBox::bbUserDelete() [" < BlackBox::bbSetInputChangeTime("<SetChangeTime(t) ) { bool was_up_to_date = bbIsUpToDate(); // If new time is greater than the old max time of inputs if ( mMaxInputChangeTime.Set(t) ) { // If the box turned out-of-date if ( was_up_to_date && bbIsOutOfDate() ) { // if ( ( bbBoxProcessModeIsReactive() || (c==bbGetInputConnectorMap().find("BoxExecute")->second)) && (bbCanReact() ) ) { bbtkDebugMessage("change",2, "an input of " <() ); } // Have to propagate the modification to aval boxes OutputConnectorMapType::iterator i; for (i = bbGetOutputConnectorMap().begin(); i != bbGetOutputConnectorMap().end(); ++i) { i->second->SetChangeTime(t); } // update the MinOutputChangeTime mMinOutputChangeTime.Set(t); } } } } //========================================================================= //========================================================================= /// Sets the ChangeTime of output void BlackBox::bbSetOutputChangeTime(BlackBoxOutputConnector* c, const ChangeTime& t) { bbtkDebugMessage("change",1, "==> BlackBox::bbSetOutputChangeTime("<SetChangeTime(t); // c->GetChangeTime() = t; // bbUpdateMinOutputChangeTime(t); // propagate } //========================================================================= */ /* //========================================================================= void BlackBox::bbUpdateMaxInputChangeTime(const ChangeTime& t) { if ( t > mMaxInputChangeTime ) { mMaxInputChangeTime = t; if ( mMinOutputChangeTime > mMaxInputChangeTime ) { } } } //========================================================================= //========================================================================= void bbUpdateMinOutputChangeTime(const ChangeTime& t) { ChangeTime old = mMinOutputChangeTime; mMinOutputChangeTime = MAXLONG; OutputConnectorMapType::iterator i; for (i = bbGetOutputConnectorMap.begin(); i != bbGetOutputConnectorMap.end(); ++i) { if (i->second->GetChangeTime() < mMinOutputChangeTime) mMinOutputChangeTime = i->second->GetChangeTime(); } if ( mMinOutputChangeTime < old ) { } } //========================================================================= */ //========================================================================= /// Signals that the BlackBox has been modified through /// the input connector c /// and propagates it downward /// ** NOT USER INTENDED ** void BlackBox::bbSetStatusAndPropagate(BlackBoxInputConnector* c, IOStatus s) { bbtkDebugMessageInc("change",5, "=> BlackBox::bbSetStatusAndPropagate(input," <SetStatus(s); OutputConnectorMapType::const_iterator o; for ( o = bbGetOutputConnectorMap().begin(); o != bbGetOutputConnectorMap().end(); ++o ) { if (o->second->GetStatus()==UPTODATE) { o->second->SetStatus(OUTOFDATE); o->second->SignalChange(GetThisPointer(),o->first); } } if ( ( bbBoxProcessModeIsReactive() || (c==bbGetInputConnectorMap().find("BoxExecute")->second)) && (bbCanReact() ) ) { bbtkDebugMessage("change",2, "-> Execution triggered by Reactive mode or BoxExecute input change"<() ); } bbtkDebugMessageInc("change",5, "<= BlackBox::bbSetStatusAndPropagate(input) [" < BlackBox::bbSignalOutputModification(" < BlackBox::bbSignalOutputModification(" <second->GetStatus()==UPTODATE) // { i->second->SignalChange(GetThisPointer(),i->first); // Has to notify the output "BoxChange" also if (output != "BoxChange") { i = bbGetOutputConnectorMap().find("BoxChange"); if ( i != bbGetOutputConnectorMap().end() ) { i->second->SignalChange(GetThisPointer(),i->first); } } if (reaction) bbGlobalProcessExecutionList(); // } bbtkDebugMessageDec("change",5, "<= BlackBox::bbSignalOutputModification(" <& output, bool reaction) { bbtkDebugMessageInc("change",5, "=> BlackBox::bbSignalOutputModification(vector of outputs) [" <::const_iterator o; bool changed = false; for (o=output.begin();o!=output.end();++o) { // the output "BoxChange" must be signaled **AFTER** all others if (*o == "BoxChange") continue; // Look for the connector i = bbGetOutputConnectorMap().find(*o); if ( i == bbGetOutputConnectorMap().end() ) { bbtkError("BlackBox["<second->GetStatus()==UPTODATE) // { i->second->SignalChange(GetThisPointer(),i->first); changed = true; // } } // Has to notify the output "BoxChange" also i = bbGetOutputConnectorMap().find("BoxChange"); if ( changed && (i != bbGetOutputConnectorMap().end())) { // if (i->second->GetStatus()==UPTODATE) // { i->second->SignalChange(GetThisPointer(),i->first); if (reaction) bbGlobalProcessExecutionList(); // } } bbtkDebugMessageDec("change",5, "<= BlackBox::bbSignalOutputModification(vector of outputs) [" < BlackBox::bbUpdateInputs() [" <first=="WinHide") continue; // If input type is Void : no recurse //if ( bbGetDescriptor()->GetInputDescriptor(i->first)->GetTypeInfo() // == typeid(Void) ) // continue; bbtkDebugMessageDec("change",2, bbGetName()<<"."<first <<" ["<second<<"] " <<" status before update = '" <second->GetStatus()) <<"'"<second->BackwardUpdate(); IOStatus t = i->second->GetStatus(); if (t > s) s = t; bbtkDebugMessageDec("change",2, bbGetName()<<"."<first <<" ["<second<<"] " <<" status before process = '" <second->GetStatus()) <<"'"< BlackBox::bbComputePostProcessStatus() [" <second->GetStatus(); if (t == OUTOFDATE) new_output_status = OUTOFDATE; // A previously MODIFIED status turns to UPTODATE if (t==MODIFIED) i->second->SetStatus(UPTODATE); bbtkDebugMessage("change",2, bbGetName()<<"."<first<<" : " << GetIOStatusString(t) << " -> " << GetIOStatusString(i->second->GetStatus()) << std::endl); } bbtkDebugMessage("change",2, bbGetName()<<" new output status : " << GetIOStatusString(new_output_status) <second->SetStatus(new_output_status); } bbtkDebugMessageInc("process",4, "<= BlackBox::bbComputePostProcessStatus() [" < to the connection c void BlackBox::bbConnectInput( const std::string& name, Connection* c) { bbtkDebugMessage("connection",2, "==> BlackBox::bbConnectInput(\"" <GetFullName()<<") [" <second->SetConnection(c); // The input *MUST* be set OUTOFDATE to update its input on next execution bbSetStatusAndPropagate(i->second,OUTOFDATE); bbtkDebugMessage("connection",2, "<== BlackBox::bbConnectInput(\"" <GetFullName()<<") [" < to the connection c void BlackBox::bbConnectOutput( const std::string& name, Connection* c) { bbtkDebugMessage("connection",2, "==> BlackBox::bbConnectOutput(\""<GetFullName()<<") [" <second->SetConnection(c); bbtkDebugMessage("connection",2, "<== BlackBox::bbConnectOutput(\""<GetFullName()<<") [" < from the connection c void BlackBox::bbDisconnectInput( const std::string& name, Connection* c) { bbtkDebugMessage("connection",2, "==> BlackBox::bbDisconnectInput(\""<GetFullName()<<") [" <second->UnsetConnection(c); bbtkDebugMessage("connection",2, "<== BlackBox::bbDisconnectInput(\""<GetFullName()<<") [" < from the connection c void BlackBox::bbDisconnectOutput( const std::string& name, Connection* c) { bbtkDebugMessage("connection",2, "==> BlackBox::bbDisconnectOutput(\""<GetFullName()<<") [" <second->UnsetConnection(c); bbtkDebugMessage("connection",2, "<== BlackBox::bbDisconnectOutput(\""<GetFullName()<<") [" <GetPackage(); if ((p != 0) && ( ! p->GetFactorySet().empty() ) ) { Factory::Pointer f = p->GetFactorySet().begin()->lock(); BlackBox::Pointer a; try { a = f->NewAdaptor( bbGetOutputType(output), typeid(std::string), ""); } catch (bbtk::Exception e) { } if (a){ // bbUpdate(); a->bbSetInput("In",bbGetOutput(output)); a->bbExecute(); v = a->bbGetOutput("Out").unsafe_get() ; } else { v="? (no adaptor found)"; } } else { v="? (no factory found)"; } } else { // bbUpdate(); v = bbGetOutput(output).unsafe_get() ; } return v; } //========================================================================= //========================================================================= std::string BlackBox::bbGetInputAsString( const std::string &input ) { std::string v; // Looks for the adaptor if (bbGetInputType(input) != typeid(std::string)) { // Look for factory Package::Pointer p = bbGetDescriptor()->GetPackage(); if ((p != 0) && ( ! p->GetFactorySet().empty() ) ) { Factory::Pointer f = p->GetFactorySet().begin()->lock(); BlackBox::Pointer a; try { a = f->NewAdaptor( bbGetInputType(input), typeid(std::string), ""); }catch (bbtk::Exception e) { } if (a) { // bbUpdate(); a->bbSetInput("In",bbGetInput(input)); a->bbExecute(); v = a->bbGetOutput("Out").unsafe_get() ; } else { v="? (no adaptor found)"; } } else { v="? (no factory found)"; } } else { v = bbGetInput(input).unsafe_get() ; } return v; } //======================================================================= //======================================================================= // Replaces substrings "<" by "[" void SubsBrackets ( std::string& s ) { // std::cout << "BEFORE=["<bbGetDescriptor()->GetPackage()->GetName()+"::"+ bbGetTypeName() + "]"; } else { labelStr = bbGetName(); labelStr = labelStr + " [" +this->bbGetDescriptor()->GetPackage()->GetName()+"::"+ bbGetTypeName() + "] "; } SubsBrackets(labelStr); if (detail==1) { labelStr = labelStr + " | {{ "; std::string tempStrTypeName; bool tmp; tmp=false; for ( i = mInputConnectorMap.begin(); i != mInputConnectorMap.end(); ++i ) { if (tmp==true) { labelStr=labelStr+" | "; } tmp=true; if (instanceOrtype==true) { valueStr = this->bbGetInputAsString(i->first) + " = "; } const BlackBoxInputDescriptor* id = bbGetDescriptor()->GetInputDescriptor(i->first); tempStrTypeName=id->GetTypeName(); SubsBrackets(tempStrTypeName); std::string Name(i->first); SubsBrackets(Name); labelStr=labelStr + "<"+i->first.c_str()+"> " + valueStr + Name.c_str() + " [" + tempStrTypeName.c_str() + "]"; } labelStr=labelStr+ " } | {"; tmp = false; OutputConnectorMapType::iterator ii; for ( ii = mOutputConnectorMap.begin(); ii != mOutputConnectorMap.end(); ++ii ) { if (tmp==true) { labelStr=labelStr+" | "; } tmp = true; if (instanceOrtype==true) { valueStr = this->bbGetOutputAsString(ii->first) + " = "; } const BlackBoxOutputDescriptor* id = bbGetDescriptor()->GetOutputDescriptor(ii->first); tempStrTypeName=id->GetTypeName(); SubsBrackets(tempStrTypeName); std::string Name(ii->first); SubsBrackets(Name); labelStr=labelStr+"<"+ii->first.c_str()+"> " + valueStr + Name.c_str() + " ["+tempStrTypeName+"]"; } labelStr = labelStr+ " } }" ; } // detail fprintf(ff," " ); bbWriteDotInputOutputName(ff,true,detail,level); std::string tmp ( bbGetTypeName() ); SubsBrackets(tmp); std::string url; if (relative_link) url = this->bbGetDescriptor()->GetPackage()->GetDocRelativeURL() + "#" + tmp; else url = this->bbGetDescriptor()->GetPackage()->GetDocURL() + "#" + tmp; fprintf( ff , " [shape=record, URL=\"%s\",label=\"%s\"]%s\n",url.c_str(),labelStr.c_str(),";" ); // std::cout << labelStr << std::endl; // Relation Input if (GetThisPointer()!=parentblackbox){ for ( i = mInputConnectorMap.begin(); i != mInputConnectorMap.end(); ++i ) { if (i->second) { Connection* con = i->second->GetConnection(); if (con!=NULL){ BlackBox::Pointer a=con->GetOriginalBlackBoxFrom(); BlackBox::Pointer b=con->GetOriginalBlackBoxTo(); fprintf(ff," "); a->bbWriteDotInputOutputName(ff,false,detail,level); if (detail==1) { fprintf(ff,":%s",con->GetOriginalBlackBoxFromOutput().c_str()); } fprintf(ff,"->"); b->bbWriteDotInputOutputName(ff,true,detail,level); if (detail==1) { fprintf(ff,":%s",con->GetOriginalBlackBoxToInput().c_str()); } fprintf(ff,"%s\n",";"); } // if con } // if second } // for } // if parentblackbox } //========================================================================= //========================================================================= void BlackBox::bbShowRelations(BlackBox::Pointer parentblackbox, int detail, int level /*,Factory *factory*/ ) { if (this->bbGetDescriptor()->GetPackage()) { bbtkMessage("Help",1,"Black Box '"<bbGetDescriptor()->GetPackage()->GetName() <<"::"<bbGetDescriptor()->GetTypeName()<<">"<bbGetDescriptor()->GetTypeName()<<">"< iname; std::vector ivalue; std::vector iconn; std::vector istatus; InputConnectorMapType::iterator i; unsigned int namelmax = 0; unsigned int valuelmax = 0; // unsigned int connlmax = 0; for ( i = mInputConnectorMap.begin(); i != mInputConnectorMap.end(); ++i ) { iname.push_back(i->first); if (iname.back().size()>namelmax) namelmax = iname.back().size(); ivalue.push_back(bbGetInputAsString(i->first)); if (ivalue.back().size()>valuelmax) valuelmax = ivalue.back().size(); std::string s(""); Connection* con = i->second->GetConnection(); if (con!=0){ s = con->GetOriginalBlackBoxFrom()->bbGetName(); s += "."; s += con->GetOriginalBlackBoxFromOutput(); } // if con iconn.push_back(s); istatus.push_back(GetIOStatusString(i->second->GetStatus())); } OutputConnectorMapType::iterator o; std::vector oname; std::vector ovalue; std::vector > oconn; std::vector ostatus; for ( o = mOutputConnectorMap.begin(); o != mOutputConnectorMap.end(); ++o ) { oname.push_back(o->first); if (oname.back().size()>namelmax) namelmax = oname.back().size(); ovalue.push_back(bbGetOutputAsString(o->first)); if (ovalue.back().size()>valuelmax) valuelmax = ovalue.back().size(); std::vector ss; const std::vector& con = o->second->GetConnectionVector(); std::vector::const_iterator c; for (c=con.begin();c!=con.end();++c) { std::string s; s = (*c)->GetOriginalBlackBoxTo()->bbGetName(); s += "."; s += (*c)->GetOriginalBlackBoxToInput(); ss.push_back(s); } // if con oconn.push_back(ss); ostatus.push_back(GetIOStatusString(o->second->GetStatus())); } if (iname.size()) bbtkMessage("Help",1," * Inputs : "<::iterator i1,i2,i3,i4; for (i1=iname.begin(),i2=ivalue.begin(),i3=iconn.begin(),i4=istatus.begin(); i1!=iname.end(),i2!=ivalue.end(),i3!=iconn.end(),i4!=istatus.end(); ++i1,++i2,++i3,++i4) { std::string name(*i1); name += "'"; name.append(1+namelmax-name.size(),' '); std::string value(*i2); value += "'"; value.append(1+valuelmax-value.size(),' '); if (i3->size()) bbtkMessage("Help",1," '"< BlackBox::bbGlobalProcessExecutionList()" <::iterator i; while (bbmgExecutionList.size()>0) { i = bbmgExecutionList.begin(); BlackBox::WeakPointer p = *i; bbmgExecutionList.erase(i); if (p.lock()) { bbtkDebugMessage("process",4, " -> Executing "<< p.lock()->bbGetFullName()<bbExecute(true); } else { bbtkGlobalError("Strange error in BlackBox::bbGlobalProcessExecutionList() : Weak bb pointer in bbmgExecutionList is no more valid..."); } } bbmgExecutionList.clear(); bbtkDebugMessageDec("process",3, "<= BlackBox::bbGlobalProcessExecutionList()" <bbGetFullName()<<")"<bbGetInputConnectorMap().find( nameInput.c_str() )->second; if (cc->GetConnection()!=NULL) { cc->GetConnection()->GetBlackBoxFrom()->bbUserOnShow(); } } } // EO namespace bbtk // EOF