Blackboard Class Reference

#include <Blackboard.h>

List of all members.


Detailed Description

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);
 }
 

Author:
Andras Varga

Public Types

typedef std::vector
< BlackboardAccess * > 
SubscriberVector
typedef BBItemBBItemRef

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

Classes

class  BBItem
class  iterator

Member Typedef Documentation

typedef std::map<std::string, BBItem*> Blackboard::ContentsMap [protected]

"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.


Constructor & Destructor Documentation

Blackboard::Blackboard (  ) 

00036 {
00037 }

Blackboard::~Blackboard (  )  [virtual]

00040 {
00041     while (!contents.empty())
00042     {
00043         ContentsMap::iterator i = contents.begin();
00044         delete (*i).second;
00045         contents.erase(i);
00046     }
00047 }


Member Function Documentation

void Blackboard::initialize (  )  [protected, virtual]

Initialize BB.

00050 {
00051   if(hasPar("coreDebug"))
00052     coreDebug = par("coreDebug").boolValue();
00053   else
00054     coreDebug = false;
00055     WATCH_PTRMAP(contents);
00056 }

void Blackboard::handleMessage ( cMessage *  msg  )  [protected, virtual]

Does nothing.

00059 {
00060     error("Blackboard doesn't handle messages, it can be accessed via direct method calls");
00061 }

BBItemRef Blackboard::publish ( const char *  label,
cPolymorphic *  item 
) [virtual]

Publish new item on the BB, with the given label.

00064 {
00065     Enter_Method("publish(\"%s\", %s *ptr)", label, item->getClassName());
00066 
00067     // check uniqueness of label
00068     ContentsMap::iterator k = contents.find(std::string(label));
00069     if (k!=contents.end())
00070         error("publish(): blackboard already contains an item with label `%s'", label);
00071 
00072     // add to BB contents
00073     BBItem *bbitem = new BBItem();
00074     bbitem->_item = item;
00075     bbitem->_label = label;
00076     contents[bbitem->_label] = bbitem;
00077 
00078     coreEV <<"publish "<<label<<" on bb\n";
00079     coreEV <<"bbItem->label: "<<bbitem->getLabel()<<endl;
00080     // notify
00081     SubscriberVector& vec = registeredClients;
00082     for (SubscriberVector::iterator i=vec.begin(); i!=vec.end(); ++i){
00083         (*i)->blackboardItemPublished(bbitem);
00084     }
00085     return bbitem;
00086 }

void Blackboard::withdraw ( BBItemRef  bbItem  )  [virtual]

Withdraw (unpublish) item from the BB (typically called by publisher).

00089 {
00090     Enter_Method("withdraw(\"%s\")", bbItem->getLabel());
00091 
00092     // find on BB
00093     ContentsMap::iterator k = contents.find(bbItem->_label);
00094     if (k==contents.end())
00095       error("withdraw(): item labelled `%s' is not on clipboard (BBItemRef stale?)", bbItem->_label.c_str());
00096 
00097     // notify subscribers
00098     SubscriberVector& vec = bbItem->subscribers;
00099     for (SubscriberVector::iterator i=vec.begin(); i!=vec.end(); ++i)
00100         (*i)->blackboardItemWithdrawn(bbItem);
00101 
00102     // remove
00103     contents.erase(k);
00104     bbItem->_item = NULL; // may make bogus code crash sooner
00105     delete bbItem;
00106 }

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).

00109 {
00110   coreEV <<"enter changed; item: "<<bbItem->getLabel()<<" changed -> notify subscribers\n";
00111 
00112   Enter_Method("changed(\"%s\", %s *ptr)", bbItem->getLabel(), item->getClassName());
00113 
00114     // update data pointer
00115     if (item)
00116         bbItem->_item = item;
00117     // notify subscribers
00118     SubscriberVector& vec = bbItem->subscribers;
00119     for (SubscriberVector::iterator i=vec.begin(); i!=vec.end(); ++i){
00120         (*i)->blackboardItemChanged(bbItem);
00121     }
00122 }

BBItemRef Blackboard::subscribe ( BlackboardAccess bbClient,
const char *  label 
) [virtual]

Subscribe to a BB item identified by a label

00125 {
00126     Enter_Method("subscribe(this,\"%s\")", label);
00127 
00128     // look up item by label
00129     BBItemRef item = find(label);
00130     if (!item)
00131        error("subscribe(): item labelled `%s' not on blackboard", label);
00132 
00133     // subscribe
00134     coreEV <<"subscribe for "<<label<<" on bb\n";
00135     subscribe(bbClient, item);
00136     return item;
00137 }

BBItemRef Blackboard::find ( const char *  label  )  [virtual]

Find item with given label on the BB

Referenced by subscribe().

00140 {
00141     ContentsMap::iterator k = contents.find(std::string(label));
00142     return k==contents.end() ? NULL : (*k).second;
00143 }

BBItemRef Blackboard::subscribe ( BlackboardAccess bbClient,
BBItemRef  bbItem 
) [virtual]

Subscribe to a BB item identified by item reference

00146 {
00147     Enter_Method("subscribe(this,\"%s\")", bbItem->getLabel());
00148 
00149     // check if already subscribed
00150     SubscriberVector& vec = bbItem->subscribers;
00151     if (std::find(vec.begin(), vec.end(), bbClient)!=vec.end())
00152         return bbItem; // already subscribed
00153 
00154     // add subscriber
00155     vec.push_back(bbClient);
00156 
00157     coreEV <<"sucessfully subscribed for item: "<<bbItem->getLabel()<<endl;
00158     return bbItem;
00159 }

void Blackboard::unsubscribe ( BlackboardAccess bbClient,
BBItemRef  bbItem 
) [virtual]

Unsubcribe module from change notifications

00162 {
00163     Enter_Method("unsubscribe(this,\"%s\")", bbItem->getLabel());
00164 
00165     // check if already subscribed
00166     SubscriberVector& vec = bbItem->subscribers;
00167     SubscriberVector::iterator k = std::find(vec.begin(), vec.end(), bbClient);
00168     if (k==vec.end())
00169         return; // ok, not subscribed
00170 
00171     // remove subscriber
00172     vec.erase(k);
00173 }

void Blackboard::registerClient ( BlackboardAccess bbClient  )  [virtual]

Generally subscribe to notifications about items being published to/withdrawn from BB.

00176 {
00177     Enter_Method("registerClient(this)");
00178 
00179     // check if already subscribed
00180     SubscriberVector& vec = registeredClients;
00181     if (std::find(vec.begin(), vec.end(), bbClient)!=vec.end())
00182         return; // ok, already subscribed
00183 
00184     // add subscriber
00185     vec.push_back(bbClient);
00186 }

void Blackboard::removeClient ( BlackboardAccess bbClient  )  [virtual]

Cancel subscription initiated by registerClient().

00189 {
00190     Enter_Method("removeClient(this)");
00191 
00192     // check if subscribed
00193     SubscriberVector& vec = registeredClients;
00194     SubscriberVector::iterator k = std::find(vec.begin(), vec.end(), bbClient);
00195     if (k==vec.end())
00196         return; // ok, not subscribed
00197 
00198     // remove subscriber
00199     vec.erase(k);
00200 }

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.

00203 {
00204     Enter_Method("getBlackboardContent(this)");
00205 
00206     for (ContentsMap::iterator i=contents.begin(); i!=contents.end(); ++i)
00207         bbClient->blackboardItemPublished((*i).second);
00208 }

iterator Blackboard::begin (  )  [inline]

As with standard C++ classes.

00307 {return iterator(contents.begin());}

iterator Blackboard::end (  )  [inline]

As with standard C++ classes.

00312 {return iterator(contents.end());}


Friends And Related Function Documentation

friend class Iterator [friend]


Member Data Documentation

bool Blackboard::coreDebug [protected]

Set debugging for the basic module.

Referenced by initialize().


The documentation for this class was generated from the following files:

Generated on Fri Mar 20 18:51:18 2009 for INET Framework for OMNeT++/OMNEST by  doxygen 1.5.5