#include <NotificationBoard.h>
Notification events are grouped into "categories." Examples of categories are: NF_HOSTPOSITION_UPDATED, NF_RADIOSTATE_CHANGED, NF_PP_TX_BEGIN, NF_PP_TX_END, NF_IPv4_ROUTE_ADDED, NF_BEACON_LOST NF_NODE_FAILURE, NF_NODE_RECOVERY, etc. Each category is identified by an integer (right now it's assigned in the source code via an enum, in the future we'll convert to dynamic category registration).
To trigger a notification, the client must obtain a pointer to the NotificationBoard of the given host or router (explained later), and call its fireChangeNotification() method. The notification will be delivered to all subscribed clients immediately, inside the fireChangeNotification() call.
Clients that wish to receive notifications should implement (subclass from) the INotifiable interface, obtain a pointer to the NotificationBoard, and subscribe to the categories they are interested in by calling the subscribe() method of the NotificationBoard. Notifications will be delivered to the receiveChangeNotification() method of the client (redefined from INotifiable).
In cases when the category itself (an int) does not carry enough information about the notification event, one can pass additional information in a data class. There is no restriction on what the data class may contain, except that it has to be subclassed from cPolymorphic, and of course producers and consumers of notifications should agree on its contents. If no extra info is needed, one can pass a NULL pointer in the fireChangeNotification() method.
A module which implements INotifiable looks like this:
class Foo : public cSimpleModule, public INotifiable { ... virtual void receiveChangeNotification(int category, const cPolymorphic *details) {..} ... };
Obtaining a pointer to the NotificationBoard module of that host/router:
NotificationBoard *nb; // this is best made a module class member nb = NotificationBoardAccess().get(); // best done in initialize()
See NED file for additional info.
Public Types | |
typedef std::vector < INotifiable * > | NotifiableVector |
typedef std::map< int, NotifiableVector > | ClientMap |
Public Member Functions | |
Methods for consumers of change notifications | |
virtual void | subscribe (INotifiable *client, int category) |
virtual void | unsubscribe (INotifiable *client, int category) |
virtual bool | hasSubscribers (int category) |
Methods for producers of change notifications | |
virtual void | fireChangeNotification (int category, const cPolymorphic *details=NULL) |
Protected Member Functions | |
virtual void | initialize () |
virtual void | handleMessage (cMessage *msg) |
Protected Attributes | |
ClientMap | clientMap |
Friends | |
std::ostream & | operator<< (std::ostream &, const NotifiableVector &) |
typedef std::vector<INotifiable *> NotificationBoard::NotifiableVector |
typedef std::map<int, NotifiableVector> NotificationBoard::ClientMap |
void NotificationBoard::initialize | ( | ) | [protected, virtual] |
void NotificationBoard::handleMessage | ( | cMessage * | msg | ) | [protected, virtual] |
void NotificationBoard::subscribe | ( | INotifiable * | client, | |
int | category | |||
) | [virtual] |
Subscribe to changes of the given category
Referenced by RoutingTable6::initialize(), RoutingTable::initialize(), PPP::initialize(), NAMTraceWriter::initialize(), Mac80211::initialize(), LinkStateRouting::initialize(), LDP::initialize(), Ieee80211MgmtAP::initialize(), Ieee80211Mac::initialize(), Ieee80211AgentSTA::initialize(), CSMAMacLayer::initialize(), ChannelAccess::initialize(), EtherMACBase::initializeNotificationBoard(), and Ieee80211MgmtSTA::processScanCommand().
00062 { 00063 Enter_Method("subscribe(%s)", notificationCategoryName(category)); 00064 00065 // find or create entry for this category 00066 NotifiableVector& clients = clientMap[category]; 00067 00068 // add client if not already there 00069 if (std::find(clients.begin(), clients.end(), client) == clients.end()) 00070 clients.push_back(client); 00071 00072 fireChangeNotification(NF_SUBSCRIBERLIST_CHANGED, NULL); 00073 }
void NotificationBoard::unsubscribe | ( | INotifiable * | client, | |
int | category | |||
) | [virtual] |
Unsubscribe from changes of the given category
Referenced by Ieee80211MgmtSTA::scanNextChannel(), and PPP::~PPP().
00076 { 00077 Enter_Method("unsubscribe(%s)", notificationCategoryName(category)); 00078 00079 // find (or create) entry for this category 00080 NotifiableVector& clients = clientMap[category]; 00081 00082 // remove client if there 00083 NotifiableVector::iterator it = std::find(clients.begin(), clients.end(), client); 00084 if (it!=clients.end()) 00085 clients.erase(it); 00086 00087 fireChangeNotification(NF_SUBSCRIBERLIST_CHANGED, NULL); 00088 }
bool NotificationBoard::hasSubscribers | ( | int | category | ) | [virtual] |
Returns true if any client has subscribed to the given category. This, by using a local boolean 'hasSubscriber' flag, allows performance-critical clients to leave out calls to fireChangeNotification() if there's no one subscribed anyway. The flag should be refreshed on each NF_SUBSCRIBERLIST_CHANGED notification.
Referenced by PPP::updateHasSubcribers(), and EtherMAC2::updateHasSubcribers().
00091 { 00092 ClientMap::iterator it = clientMap.find(category); 00093 return it!=clientMap.end() && !it->second.empty(); 00094 }
void NotificationBoard::fireChangeNotification | ( | int | category, | |
const cPolymorphic * | details = NULL | |||
) | [virtual] |
Tells NotificationBoard that a change of the given category has taken place. The optional details object may carry more specific information about the change (e.g. exact location, specific attribute that changed, old value, new value, etc).
Referenced by InterfaceTable::addInterface(), RoutingTable6::addOrUpdateOnLinkPrefix(), RoutingTable6::addOrUpdateOwnAdvPrefix(), RoutingTable6::addRoute(), RoutingTable::addRoute(), RSVP::announceLinkChange(), LDP::announceLinkChange(), Ieee80211MgmtSTA::beaconLost(), SnrEval::changeChannel(), AbstractRadio::changeChannel(), InterfaceTable::deleteInterface(), RoutingTable::deleteRoute(), EtherMACBase::fireChangeNotification(), Ieee80211MgmtSTA::handleAssociationResponseFrame(), EtherMAC2::handleEndTxPeriod(), SnrEval::handleLowerMsgEnd(), GilbertElliotSnr::handleLowerMsgEnd(), SnrEval::handleLowerMsgStart(), GilbertElliotSnr::handleLowerMsgStart(), PPP::handleMessage(), SnrEval::handleSelfMsg(), GilbertElliotSnr::handleSelfMsg(), SnrEval::handleUpperMsg(), SnrEval::initialize(), AbstractRadio::initialize(), InterfaceTable::interfaceChanged(), EtherMAC2::processMsgFromNetwork(), RoutingTable6::removeRoute(), AbstractRadio::setRadioState(), EtherMAC2::startFrameTransmission(), PPP::startTransmitting(), subscribe(), unsubscribe(), and BasicMobility::updatePosition().
00097 { 00098 Enter_Method("fireChangeNotification(%s, %s)", notificationCategoryName(category), 00099 details?details->info().c_str() : "n/a"); 00100 00101 ClientMap::iterator it = clientMap.find(category); 00102 if (it==clientMap.end()) 00103 return; 00104 NotifiableVector& clients = it->second; 00105 for (NotifiableVector::iterator j=clients.begin(); j!=clients.end(); j++) 00106 (*j)->receiveChangeNotification(category, details); 00107 }
std::ostream& operator<< | ( | std::ostream & | os, | |
const NotifiableVector & | v | |||
) | [friend] |
00026 { 00027 os << v.size() << " client(s)"; 00028 for (unsigned int i=0; i<v.size(); i++) 00029 { 00030 os << (i==0 ? ": " : ", "); 00031 if (dynamic_cast<cModule*>(v[i])) 00032 { 00033 cModule *mod = dynamic_cast<cModule*>(v[i]); 00034 os << "mod (" << mod->getClassName() << ")" << mod->getFullName() << " id=" << mod->getId(); 00035 } 00036 else if (dynamic_cast<cPolymorphic*>(v[i])) 00037 { 00038 cPolymorphic *obj = dynamic_cast<cPolymorphic*>(v[i]); 00039 os << "a " << obj->getClassName(); 00040 } 00041 else 00042 { 00043 os << "a " << opp_typename(typeid(v[i])); 00044 } 00045 } 00046 return os; 00047 }
ClientMap NotificationBoard::clientMap [protected] |
Referenced by fireChangeNotification(), hasSubscribers(), initialize(), subscribe(), and unsubscribe().