Provides a blackboard like information distribution. More...
#include <Blackboard.h>
Inherited by BaseUtility, and BaseWorldUtility.
Classes | |
class | Subscriber |
Internal class to store subscriber data. More... | |
Public Member Functions | |
void | handleMessage (cMessage *msg) |
This modules shouldn't receive any messages. | |
virtual void | initialize (int) |
Initializes blackboard. | |
virtual int | numInitStages () const |
We define two initialization stages. | |
Methods for consumers of change notifications | |
int | subscribe (ImNotifiable *client, const BBItem *category, int scopeModuleId=-1) |
int | subscribe (ImNotifiable *client, int category, int scopeModuleId=-1) |
void | unsubscribe (ImNotifiable *client, int category) |
Methods for producers of change notifications | |
void | publishBBItem (int category, const BBItem *details, int scopeModuleId) |
int | getCategory (const BBItem *details) |
Protected Types | |
Typedefs for container shortcuts. | |
typedef std::vector< Subscriber > | SubscriberVector |
typedef std::vector < SubscriberVector > | ClientVector |
typedef std::vector< const char * > | CategoryDescriptions |
typedef std::vector< int > | ParentVector |
typedef ClientVector::iterator | ClientVectorIter |
typedef CategoryDescriptions::iterator | DescriptionsIter |
typedef ParentVector::iterator | ParentVectorIter |
Protected Member Functions | |
const char * | categoryName (int category) |
int | findAndCreateDescription (bool *isNewEntry, const BBItem *category) |
void | fillParentVector (const BBItem *category, int cat) |
Protected Attributes | |
ClientVector | clientVector |
CategoryDescriptions | categoryDescriptions |
ParentVector | parentVector |
int | nextCategory |
bool | coreDebug |
Friends | |
std::ostream & | operator<< (std::ostream &, const SubscriberVector &) |
Provides a blackboard like information distribution.
In protocol simulations, one often has to evaluate the performance of a protocol. This implies that not only the protocol has to be developed, but also the code used for the performance evaluation. Often, this leads to ugly implementations: real protocol code is mixed with debug and performance evaluation code. This mix becomes annoying if the code is made public to the community.
Another, somewhat similar, problem appears if programmers want to implement new protocols that integrate information from other protocol layers. Usually, researchers have to re-implement at least parts of the protocol to expose the necessary information -- making it less useful for other researchers as this usually increases the coupling of the protocols.
One way around both problems is a black board. On the black board, protocols publish their state and possible state changes. It is now possible to separate performance monitors from the protocol code. Also, cross-layer information exchange also boils down to publishing and subscribing information -- without introducing tight coupling. The only commonly known entity is the blackboard.
The interaction with the blackboard is simple:
publisher -publish(BBItem)-> Blackboard -notify(BBItem)--> subscriber
The publisher can be anything that knows how to call a Blackboard and how to construct a proper BBItem. It remains the logical owner of the published item. The BB neither stores it, nor keeps any reference to it.
The subscriber must implement the ImNotifiable interface. It can keep a copy of the published item (cache it), but it should not keep a reference to it. Otherwise, things become really messy. (Some code written for older versions of the BB speaks for itself).
Definition at line 60 of file Blackboard.h.
const char * Blackboard::categoryName | ( | int | category | ) | [protected] |
find the description of a category
Definition at line 52 of file Blackboard.cc.
Referenced by publishBBItem(), subscribe(), and unsubscribe().
{ if(categoryDescriptions.size() < static_cast<unsigned>(category)) { error("BlackBoard::categoryName called with unknown category (%i)", category); } return categoryDescriptions[category]; }
void Blackboard::fillParentVector | ( | const BBItem * | category, | |
int | cat | |||
) | [protected] |
traverse inheritance diagramm and make sure that children of category are also delivered to modules that susbcribed to one of its parent classes.
Definition at line 90 of file Blackboard.cc.
References findAndCreateDescription(), and BBItem::parentObject().
Referenced by getCategory(), and subscribe().
{ bool isNewEntry = true; int it; BBItem *parentObject; BBItem base; parentObject = category->parentObject(); if(typeid(*parentObject) != typeid(base)) { it = findAndCreateDescription(&isNewEntry, parentObject); parentVector[cat] = it; fillParentVector(parentObject, it); } delete parentObject; }
int Blackboard::findAndCreateDescription | ( | bool * | isNewEntry, | |
const BBItem * | category | |||
) | [protected] |
find or create a category, returns iterator in map and sets isNewEntry to true if the entry was created new.
Definition at line 60 of file Blackboard.cc.
Referenced by fillParentVector(), getCategory(), and subscribe().
{ CategoryDescriptions::size_type it; std::string desc = category->getClassName(); std::string cName; for(it = 0; it < categoryDescriptions.size(); ++it) { cName = categoryDescriptions[it]; if(cName == desc) { (*isNewEntry) = false; break; } } if(it == categoryDescriptions.size()) { (*isNewEntry) = true; categoryDescriptions.push_back(category->getClassName()); it = categoryDescriptions.size() - 1; clientVector.push_back(SubscriberVector()); if(it != clientVector.size()-1) error("BlackBoard::findAndCreateDescription SubscriberVector creation failed"); parentVector.push_back(-1); if(it != parentVector.size()-1) error("BlackBoard::findAndCreateDescription ParentVector creation failed"); nextCategory = categoryDescriptions.size(); } return static_cast<int>(it); }
int Blackboard::getCategory | ( | const BBItem * | details | ) |
Get the category from the BB -- if you don't want to subscribe but rather publish
Definition at line 208 of file Blackboard.cc.
References fillParentVector(), and findAndCreateDescription().
Referenced by SimpleBattery::initialize(), UWBIRMac::initialize(), csma::initialize(), TrafficGen::initialize(), SensorApplLayer::initialize(), NetworkStackTrafficGen::initialize(), BaseMobility::initialize(), BaseLayer::initialize(), and MoBANCoordinator::publishToNodes().
{ if(coreDebug) { Enter_Method("getCategory(%s)", details?details->getClassName():"n/a"); } else { Enter_Method_Silent(); } int category = -1; bool isNewEntry; if(details) { category = findAndCreateDescription(&isNewEntry, details); if(isNewEntry) fillParentVector(details, category); } else { error("BlackBoard::getCategory called without category item"); } return category; }
void Blackboard::publishBBItem | ( | int | category, | |
const BBItem * | details, | |||
int | scopeModuleId | |||
) |
Tells Blackboard that a change of the given category has taken place. The optional details object (
This function is very central once you start working with the blackboard. You should heed the following advices:
Definition at line 184 of file Blackboard.cc.
References categoryName().
Referenced by BMacLayer::addToQueue(), TrafficGen::handleLowerMsg(), SensorApplLayer::handleLowerMsg(), NetworkStackTrafficGen::handleLowerMsg(), LMacLayer::handleUpperMsg(), SimpleBattery::initialize(), MoBANCoordinator::publishToNodes(), NetworkStackTrafficGen::sendBroadcast(), SensorApplLayer::sendData(), BaseModule::switchHostState(), and BaseMobility::updatePosition().
{ if(coreDebug) { Enter_Method("publish(%s, %s, %i)", categoryName(category), details?details->info().c_str() : "n/a", scopeModuleId); } else { Enter_Method_Silent(); } int pCat; if(clientVector.size() > 0) { SubscriberVector::const_iterator j; for (j=clientVector[category].begin(); j!=clientVector[category].end(); ++j) { if(((*j).scopeModuleId == -1) || ((*j).scopeModuleId == scopeModuleId)) { (*j).client->receiveBBItem(category, details, scopeModuleId); } } pCat = parentVector[category]; if(pCat >= 0) publishBBItem(pCat, details, scopeModuleId); } }
int Blackboard::subscribe | ( | ImNotifiable * | client, | |
int | category, | |||
int | scopeModuleId = -1 | |||
) |
Subscribe to changes of a specific category. This time using the numeric id. This implies that you have previously called subscribe with the appropriate category class.
Both subscribe functions subscribe also to children of this category class.
Subscribe in stage 0 of initialize -- this way you get all publishes that happen at stage 1.
Definition at line 110 of file Blackboard.cc.
References categoryName().
{ if(coreDebug) { Enter_Method("subscribe(%s, %i)", categoryName(category), scopeModuleId); } else { Enter_Method_Silent(); } // find or create entry for this category SubscriberVector& clients = clientVector[category]; SubscriberVector::const_iterator it; for(it = clients.begin(); it != clients.end(); ++it) { if((*it).client == client) { std::string cname("unkown"); cModule *cm = dynamic_cast<cModule *>(client); if(cm) cname = cm->getFullPath(); error("BlackBoard::subscribe called twice for item %s, by client %s. \nThis probably means that a class from which you derived yours has \nalready subscribed to this item. This may result in conflicts, please check.\n ", categoryName(category), cname.c_str()); break; } } // add client if not already there if (it == clients.end()) { clients.push_back(Subscriber(client, scopeModuleId)); } return category; }
int Blackboard::subscribe | ( | ImNotifiable * | client, | |
const BBItem * | category, | |||
int | scopeModuleId = -1 | |||
) |
Subscribe to changes of a specific category. The category is defined by the BBItem class to which this object belongs. Returns the id of this category.
Both subscribe functions subscribe also to children of this category class.
Definition at line 137 of file Blackboard.cc.
References fillParentVector(), and findAndCreateDescription().
Referenced by SimTracer::initialize(), phyPER::initialize(), BatteryStats::initialize(), MoBANLocal::initialize(), BaseUtility::initialize(), BaseModule::initialize(), and ChannelAccess::initialize().
{ if(coreDebug) { Enter_Method("subscribe(%s, %i)", category?category->getClassName() : "n/a", scopeModuleId); } else { Enter_Method_Silent(); } CategoryDescriptions::size_type it = 0; bool isNewEntry; if(category) { it = findAndCreateDescription(&isNewEntry, category); if(isNewEntry) fillParentVector(category, static_cast<int>(it)); subscribe(client, static_cast<int>(it), scopeModuleId); } else { error("BlackBoard::subscribe called without category item"); } return static_cast<int>(it); }
void Blackboard::unsubscribe | ( | ImNotifiable * | client, | |
int | category | |||
) |
Unsubscribe from notifications
Definition at line 159 of file Blackboard.cc.
References categoryName().
{ if(coreDebug) { Enter_Method("unsubscribe(%s)", categoryName(category)); } else { Enter_Method_Silent(); } // find (or create) entry for this category SubscriberVector& clients = clientVector[category]; // remove client if there SubscriberVector::iterator it; // go through the clients for(it = clients.begin(); it != clients.end(); ++it) { // check if client to be unsubscribed was found if((*it).client == client) { // client found, unsubscribe client and end search clients.erase(it); break; } } }