Classes | Public Member Functions | Protected Member Functions | Protected Attributes | Friends

Blackboard Class Reference
[BaseUtility - blackboard related stuffbaseModules - base module classes of MiXiM]

Provides a blackboard like information distribution. More...

#include <Blackboard.h>

Inherited by BaseUtility, and BaseWorldUtility.

List of all members.

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< SubscriberSubscriberVector
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 &)

Detailed Description

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

See also:
ImNotifiable
Author:
Andras Varga
Andreas Koepke

Definition at line 60 of file Blackboard.h.


Member Function Documentation

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 (

See also:
BBItem) may carry more specific information about the change (e.g. exact location, specific attribute that changed, old value, new value, etc).

This function is very central once you start working with the blackboard. You should heed the following advices:

  • Publish in stage 1 of initialize after everbody was able to subscribe.
  • This function should be the last thing you call in a method. There is a chance that a certain race condition occurs, as in the following case, for simplicity the module is subscribed to the value that it publishes: -- Module::myMethod: lock module; publishBBItem; unlock module -- Module::receiveBBItem: if module not locked, do something Since receiveBBItem is called from within publishBBItem, the module will always be locked and the code in receiveBBItem is never executed.

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


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