INET Framework for OMNeT++/OMNEST
|
#include <Blackboard.h>
Classes | |
class | BBItem |
class | iterator |
Public Types | |
typedef std::vector < BlackboardAccess * > | SubscriberVector |
typedef BBItem * | BBItemRef |
Public Member Functions | |
Blackboard () | |
virtual | ~Blackboard () |
Methods for publishers | |
virtual BBItemRef | publish (const char *label, cPolymorphic *item) |
virtual void | withdraw (BBItemRef bbItem) |
virtual void | changed (BBItemRef bbItem, cPolymorphic *item=NULL) |
Methods for subscribers | |
virtual BBItemRef | subscribe (BlackboardAccess *bbClient, const char *label) |
virtual BBItemRef | find (const char *label) |
virtual BBItemRef | subscribe (BlackboardAccess *bbClient, BBItemRef bbItem) |
virtual void | unsubscribe (BlackboardAccess *bbClient, BBItemRef bbItem) |
virtual void | registerClient (BlackboardAccess *bbClient) |
virtual void | removeClient (BlackboardAccess *bbClient) |
virtual void | getBlackboardContent (BlackboardAccess *bbClient) |
iterator | begin () |
iterator | end () |
Protected Types | |
typedef std::map< std::string, BBItem * > | ContentsMap |
Protected Member Functions | |
virtual void | initialize () |
virtual void | handleMessage (cMessage *msg) |
Protected Attributes | |
bool | coreDebug |
Set debugging for the basic module. | |
ContentsMap | contents |
SubscriberVector | registeredClients |
Friends | |
class | Iterator |
The Blackboard works as entity to enable inter-layer/inter-process communication.
NOTE: BLACKBOARD IS NO LONGER USED BY THE INET FRAMEWORK -- SUCCESSOR IS NotificationBoard.
Blackboard makes it possible for several modules (representing e.g. protocol layers) to share information, in a publish-subscribe fashion. Participating modules or classes have to implement the BlackboardAccess interface (=have this abstract class as base class).
Anyone can publish data items on the blackboard. In order to allow for some type safety via dynamic_cast, items have to be subclassed from cPolymorphic.
Every item is published with a unique string label. The Blackboard makes no assumption about the format of the label, but it's generally a good idea to make it structured, e.g. with a dotted format ("nic1.linkstatus"). The label can be used by subscribers to identify an item ("I want to subscribe to nic1.linkstatus"). There are other ways to subscribe too, not only by label, e.g. one can browse through all Blackboard items, examine each (its label, C++ class, actual contents etc.) and decide individually whether to subscribe to it or not.
Labels are only used when publishing or subscribing to items. After that, items can be referred to using BBItemRefs. (BBItemRefs are sort of "handles" to blackboard items; think of file handles (fd's) or FILE* variables in Unix and C programming, or window handles (HWND) in the Windows API.) BBItemRefs allow very efficient (constant-time) access to Blackboard items.
Clients may browse blackboard contents and subscribe to items. After subscription, clients will receive notifications via BlackboardAccess callbacks whenever the subscribed item changes. Clients may also subscribe to get notified whenever items are published to or withdrawn from the blackboard.
Notifications are done with callback-like mechanism. Participating modules or classes have to subclass from the abstract base class BlackboardAccess and implement its methods (in Java, one would say clients should implement the BlackboardAccess interface.) This usually means multiple inheritance, but without the problems of multiple inheritance (Multiple inheritance is sometimes considered "evil", but never if used to do "mixins" as here.)
Some examples for usage. The first one, Foo demonstrates subscribe-by-name, the second one, Bar shows subscribe-when-published, and the third one, Zak does subscribe-by-browse.
// subscribe-by-name class Foo : public cSimpleModule, public BlackboardAccess { protected: BBItemRef ref; ... };
void Foo::initialize(int stage) { // to avoid a subscribe-BEFORE-publish a two stage // initialization should be used and all publish calls should // go into the first stage (stage 0) whereas you should subscribe // in the second stage (stage 1) if(stage==0) { ... } else if(stage==1) { ref = getBlackboard()->subscribe(this,"routingTable"); ... } }
void Foo::blackboardItemChanged(BBItemRef item) { if (item==ref) { IRoutingTable *rt = check_and_cast<IRoutingTable *>(ref->getData()); ... } else ... }
// subscribe-when-published class Bar : public cSimpleModule, public BlackboardAccess { ... };
void Bar::initialize(int stage) { if(stage==0) { getBlackboard()->registerClient(this); // make sure we get what's already on the blackboard getBlackboard()->getBlackboardContent(this); } }
void Bar::blackboardItemPublished(BBItemRef item) { // if label begins with "nic." and it's a NetworkInterfaceData, subscribe if (!strncmp(item->getLabel(),"nic.",4) && dynamic_cast<NetworkInterfaceData *>(item->getData())) { // new network interface appeared, subscribe to it and do whatever // other actions are necessary getBlackboard()->subscribe(this, item); ... } }
// subscribe-by-browse class Zak : public cSimpleModule, public BlackboardAccess { ... };
void Zak::letsCheckWhatIsOnTheBlackboard() { // subscribe to all NetworkInterfaceData Blackboard *bb = getBlackboard(); for (Blackboard::iterator i=bb->begin(); i!=bb->end(); ++i) if (dynamic_cast<NetworkInterfaceData *>((*i)->getData())) bb->subscribe(this, *i); }
typedef BBItem* Blackboard::BBItemRef |
"Handle" to blackboard items. To get the data or the label, write bbref->getData() and bbref->getLabel(), respectively. BBItemRefs become stale when the item gets withdrawn (unpublished) from the blackboard.
typedef std::map<std::string, BBItem*> Blackboard::ContentsMap [protected] |
typedef std::vector<BlackboardAccess *> Blackboard::SubscriberVector |
Blackboard::Blackboard | ( | ) |
{ }
Blackboard::~Blackboard | ( | ) | [virtual] |
iterator Blackboard::begin | ( | ) | [inline] |
As with standard C++ classes.
{return iterator(contents.begin());}
void Blackboard::changed | ( | BBItemRef | bbItem, |
cPolymorphic * | item = NULL |
||
) | [virtual] |
Tell BB that an item has changed (typically called by publisher). When item pointer is omitted, it is assumed that the item object was updated "in place" (as opposed to being replaced by another object).
{ coreEV <<"enter changed; item: "<<bbItem->getLabel()<<" changed -> notify subscribers\n"; Enter_Method("changed(\"%s\", %s *ptr)", bbItem->getLabel(), item->getClassName()); // update data pointer if (item) bbItem->_item = item; // notify subscribers SubscriberVector& vec = bbItem->subscribers; for (SubscriberVector::iterator i=vec.begin(); i!=vec.end(); ++i){ (*i)->blackboardItemChanged(bbItem); } }
iterator Blackboard::end | ( | ) | [inline] |
As with standard C++ classes.
{return iterator(contents.end());}
BBItemRef Blackboard::find | ( | const char * | label | ) | [virtual] |
Find item with given label on the BB
Referenced by removeClient(), subscribe(), and unsubscribe().
void Blackboard::getBlackboardContent | ( | BlackboardAccess * | bbClient | ) | [virtual] |
Utility function: the client gets immediate notification with all items currently on clipboard (as if they were added just now). This may simplify initialization code in a subscribe-when-published style client.
{ Enter_Method("getBlackboardContent(this)"); for (ContentsMap::iterator i=contents.begin(); i!=contents.end(); ++i) bbClient->blackboardItemPublished((*i).second); }
void Blackboard::handleMessage | ( | cMessage * | msg | ) | [protected, virtual] |
Does nothing.
{
error("Blackboard doesn't handle messages, it can be accessed via direct method calls");
}
void Blackboard::initialize | ( | ) | [protected, virtual] |
BBItemRef Blackboard::publish | ( | const char * | label, |
cPolymorphic * | item | ||
) | [virtual] |
Publish new item on the BB, with the given label.
{ Enter_Method("publish(\"%s\", %s *ptr)", label, item->getClassName()); // check uniqueness of label ContentsMap::iterator k = contents.find(std::string(label)); if (k!=contents.end()) error("publish(): blackboard already contains an item with label `%s'", label); // add to BB contents BBItem *bbitem = new BBItem(); bbitem->_item = item; bbitem->_label = label; contents[bbitem->_label] = bbitem; coreEV <<"publish "<<label<<" on bb\n"; coreEV <<"bbItem->label: "<<bbitem->getLabel()<<endl; // notify SubscriberVector& vec = registeredClients; for (SubscriberVector::iterator i=vec.begin(); i!=vec.end(); ++i){ (*i)->blackboardItemPublished(bbitem); } return bbitem; }
void Blackboard::registerClient | ( | BlackboardAccess * | bbClient | ) | [virtual] |
Generally subscribe to notifications about items being published to/withdrawn from BB.
{ Enter_Method("registerClient(this)"); // check if already subscribed SubscriberVector& vec = registeredClients; if (std::find(vec.begin(), vec.end(), bbClient)!=vec.end()) return; // ok, already subscribed // add subscriber vec.push_back(bbClient); }
void Blackboard::removeClient | ( | BlackboardAccess * | bbClient | ) | [virtual] |
Cancel subscription initiated by registerClient().
{ Enter_Method("removeClient(this)"); // check if subscribed SubscriberVector& vec = registeredClients; SubscriberVector::iterator k = std::find(vec.begin(), vec.end(), bbClient); if (k==vec.end()) return; // ok, not subscribed // remove subscriber vec.erase(k); }
BBItemRef Blackboard::subscribe | ( | BlackboardAccess * | bbClient, |
BBItemRef | bbItem | ||
) | [virtual] |
Subscribe to a BB item identified by item reference
{ Enter_Method("subscribe(this,\"%s\")", bbItem->getLabel()); // check if already subscribed SubscriberVector& vec = bbItem->subscribers; if (std::find(vec.begin(), vec.end(), bbClient)!=vec.end()) return bbItem; // already subscribed // add subscriber vec.push_back(bbClient); coreEV <<"sucessfully subscribed for item: "<<bbItem->getLabel()<<endl; return bbItem; }
BBItemRef Blackboard::subscribe | ( | BlackboardAccess * | bbClient, |
const char * | label | ||
) | [virtual] |
Subscribe to a BB item identified by a label
void Blackboard::unsubscribe | ( | BlackboardAccess * | bbClient, |
BBItemRef | bbItem | ||
) | [virtual] |
Unsubcribe module from change notifications
{ Enter_Method("unsubscribe(this,\"%s\")", bbItem->getLabel()); // check if already subscribed SubscriberVector& vec = bbItem->subscribers; SubscriberVector::iterator k = std::find(vec.begin(), vec.end(), bbClient); if (k==vec.end()) return; // ok, not subscribed // remove subscriber vec.erase(k); }
void Blackboard::withdraw | ( | BBItemRef | bbItem | ) | [virtual] |
Withdraw (unpublish) item from the BB (typically called by publisher).
{ Enter_Method("withdraw(\"%s\")", bbItem->getLabel()); // find on BB ContentsMap::iterator k = contents.find(bbItem->_label); if (k==contents.end()) error("withdraw(): item labelled `%s' is not on clipboard (BBItemRef stale?)", bbItem->_label.c_str()); // notify subscribers SubscriberVector& vec = bbItem->subscribers; for (SubscriberVector::iterator i=vec.begin(); i!=vec.end(); ++i) (*i)->blackboardItemWithdrawn(bbItem); // remove contents.erase(k); bbItem->_item = NULL; // may make bogus code crash sooner delete bbItem; }
friend class Iterator [friend] |
ContentsMap Blackboard::contents [protected] |
Referenced by find(), getBlackboardContent(), initialize(), publish(), withdraw(), and ~Blackboard().
bool Blackboard::coreDebug [protected] |
Set debugging for the basic module.
Referenced by initialize().
SubscriberVector Blackboard::registeredClients [protected] |
Referenced by publish(), registerClient(), and removeClient().