Gizmo3D

gzNotify.h

Go to the documentation of this file.
00001 //*****************************************************************************
00002 // File         : gzNotify.h
00003 // Module       : gzBase
00004 // Description  : Class definition of gzNotify utilities
00005 // Author       : Anders Modén      
00006 // Product      : GizmoBase 2.1.1
00007 //      
00008 // Copyright © 2003- Saab Training Systems AB, Sweden
00009 //          
00010 // NOTE:    GizmoBase is a platform abstraction utility layer for C++. It contains 
00011 //          design patterns and C++ solutions for the advanced programmer.
00012 //
00013 //
00014 // Revision History...                          
00015 //                                  
00016 // Who  Date    Description                     
00017 //                                  
00018 // AMO  990517  Created file    
00019 //
00020 //******************************************************************************
00021 #ifndef __GZ_NOTIFY_H__
00022 #define __GZ_NOTIFY_H__
00023 
00032 #include "gzBase.h"
00033 #include "gzMutex.h"
00034 #include "gzTime.h"
00035 #include "gzExceptions.h"
00036 
00037 // --------------------- Subscriptions ---------------------------------
00038 // Observer notifier pattern. One master and many subscribing slaves
00039 
00041 enum gzNotifyState
00042 {
00043     GZ_NOTIFY_ADD_SUBSCRIBER,
00044     GZ_NOTIFY_CANCEL_ADD_SUBSCRIBER,
00045     GZ_NOTIFY_MULTIPLE_ADD_SUBSCRIBER,
00046     GZ_NOTIFY_REMOVE_SUBSCRIBER,
00047     GZ_NOTIFY_MASTER_TERMINATE,
00048     GZ_NOTIFY_SLAVE_TERMINATE,
00049 };
00050 
00051 template <class SLAVE> class gzPendSub : public gzReference
00052 {
00053 public:
00054     
00055     gzPendSub()
00056     {
00057     }
00058         
00059     virtual ~gzPendSub()
00060     {
00061     }
00062     
00063     virtual gzBool  useDeepCopy() 
00064     { 
00065         return FALSE; 
00066     }
00067         
00068     SLAVE *         subscriber;
00069     gzULong         senderClass;
00070     gzULong         pendingID;
00071 };
00072 
00073 template <class DATA> class gzPendData : public gzReference
00074 {
00075 public:
00076     
00077     gzPendData()
00078     {
00079     }
00080         
00081     virtual ~gzPendData()
00082     {
00083     }
00084     
00085     virtual gzBool  useDeepCopy() 
00086     { 
00087         return FALSE; 
00088     }   // Default behaviour is to share
00089 
00090 
00091         
00092     DATA            data;
00093     gzULong         senderClass;
00094     gzDouble        notifyTime;
00095     gzDouble        timeOut;
00096 };
00097 
00098 
00099 //******************************************************************************
00100 // Class    : gzNotifyMaster
00101 //                                  
00102 // Purpose  : Template that implements the Notifier Master in a O/N pattern
00103 //                                  
00104 // Notes    : - 
00105 //                                  
00106 // Revision History...                          
00107 //                                  
00108 // Who  Date    Description                     
00109 //                                  
00110 // AMO  031012  Created 
00111 //                                  
00112 //******************************************************************************
00113 template <class MASTER , class SLAVE , class DATA=gzRefPointer<gzReference> > class gzNotifyMaster 
00114 {
00115 public:
00116 
00117     gzNotifyMaster()
00118     {
00119         m_pendingID=0;
00120         m_pendingAddSubs.reuseLinks(TRUE);
00121         m_pendingRemSubs.reuseLinks(TRUE);
00122         m_activeSubs.reuseLinks(TRUE);
00123         m_pendingData.reuseLinks(TRUE);
00124         m_activeData.reuseLinks(TRUE);
00125         m_triggerOnNotifyData=TRUE;
00126         m_inTriggerNotification=FALSE;
00127     }
00128 
00129     gzNotifyMaster(const gzNotifyMaster<MASTER,SLAVE,DATA> &copy)
00130     {
00131         m_pendingID=0;
00132         m_pendingAddSubs.reuseLinks(TRUE);
00133         m_pendingRemSubs.reuseLinks(TRUE);
00134         m_activeSubs.reuseLinks(TRUE);
00135         m_pendingData.reuseLinks(TRUE);
00136         m_activeData.reuseLinks(TRUE);
00137         m_triggerOnNotifyData=TRUE;
00138         m_inTriggerNotification=FALSE;
00139     }
00140 
00141     virtual ~gzNotifyMaster()
00142     {
00143         m_activeSubsLocker.waitLock();
00144 
00145         if(m_activeSubs.entries())
00146         {       
00147             gzListIterator<gzPendSub<SLAVE> > iterator(m_activeSubs);
00148         
00149             gzPendSub<SLAVE> *sub;
00150 
00151             while(sub=iterator())
00152             {
00153                 sub->subscriber->m_subscriptionLocker.waitLock();
00154                 sub->subscriber->m_pendingSubscriptions.remove((MASTER *)this);
00155                 sub->subscriber->onNotifyStatus((MASTER *)this,sub->subscriber,GZ_NOTIFY_MASTER_TERMINATE);
00156                 sub->subscriber->m_subscriptionLocker.unLock();
00157             }
00158         }
00159         
00160         m_activeSubsLocker.unLock();
00161 
00162         m_pendingSubsLocker.waitLock();
00163 
00164         if(m_pendingAddSubs.entries())
00165         {       
00166             gzListIterator<gzPendSub<SLAVE> > iterator(m_pendingAddSubs);
00167         
00168             gzPendSub<SLAVE> *sub;
00169 
00170             while(sub=iterator())
00171             {
00172                 sub->subscriber->m_subscriptionLocker.waitLock();
00173                 sub->subscriber->m_pendingSubscriptions.remove((MASTER *)this);
00174                 sub->subscriber->onNotifyStatus((MASTER *)this,sub->subscriber,GZ_NOTIFY_MASTER_TERMINATE);
00175                 sub->subscriber->m_subscriptionLocker.unLock();
00176             }
00177         }
00178 
00179         if(m_pendingRemSubs.entries())
00180         {       
00181             gzListIterator<gzPendSub<SLAVE> > iterator(m_pendingRemSubs);
00182         
00183             gzPendSub<SLAVE> *sub;
00184 
00185             while(sub=iterator())
00186             {
00187                 sub->subscriber->m_subscriptionLocker.waitLock();
00188                 sub->subscriber->m_pendingSubscriptions.remove((MASTER *)this);
00189                 sub->subscriber->onNotifyStatus((MASTER *)this,sub->subscriber,GZ_NOTIFY_MASTER_TERMINATE);
00190                 sub->subscriber->m_subscriptionLocker.unLock();
00191             }
00192         }
00193         
00194         m_pendingSubsLocker.unLock();
00195 
00196     }
00197 
00198     gzVoid addSubscriber( SLAVE *subscriber , gzULong senderClass=0)
00199     {
00200         if(subscriber)
00201         {
00202             gzPendSub<SLAVE> *pend=new gzPendSub<SLAVE>;
00203 
00204             pend->subscriber=subscriber;
00205             pend->senderClass=senderClass;
00206             pend->pendingID=m_pendingID++;
00207 
00208             m_pendingSubsLocker.waitLock();
00209             m_pendingAddSubs.insert(pend);
00210             m_pendingSubsLocker.unLock();
00211 
00212             subscriber->m_subscriptionLocker.waitLock();
00213             subscriber->m_pendingSubscriptions.insert((MASTER *)this);
00214             subscriber->m_subscriptionLocker.unLock();
00215         }
00216     }
00217 
00218     gzVoid removeSubscriber( SLAVE *subscriber)
00219     {
00220         if(subscriber)
00221         {
00222             gzPendSub<SLAVE> *pend=new gzPendSub<SLAVE>;
00223 
00224             pend->subscriber=subscriber;
00225             pend->senderClass=0;
00226             pend->pendingID=m_pendingID++;
00227 
00228             m_pendingSubsLocker.waitLock();
00229             m_pendingRemSubs.insert(pend);
00230             m_pendingSubsLocker.unLock();
00231 
00232             subscriber->m_subscriptionLocker.waitLock();
00233             subscriber->m_pendingSubscriptions.insert((MASTER *)this);
00234             subscriber->m_subscriptionLocker.unLock();
00235         }
00236     }
00237 
00238     gzVoid notifyData(const DATA &data , gzULong senderClass=0 , const gzDouble &timeOut=GZ_DOUBLE_ZERO, const gzDouble &notifyTime=GZ_DOUBLE_ZERO,const gzULong priority=0 )
00239     {
00240         gzPendData<DATA> *pend=new gzPendData<DATA>;
00241         
00242         pend->data=data;
00243         pend->senderClass=senderClass;
00244 
00245         if(timeOut)
00246             pend->timeOut=gzTime::systemSeconds()+timeOut;
00247         else
00248             pend->timeOut=DBL_MAX;
00249 
00250         pend->notifyTime=notifyTime;
00251 
00252         gzBool trigger;
00253 
00254         m_pendingDataLocker.waitLock();
00255         m_pendingData.post_insert(pend,-(gzDouble)priority);
00256         trigger=m_triggerOnNotifyData;
00257         m_pendingDataLocker.unLock();
00258 
00259         if(trigger)
00260             triggerNotifications();
00261 
00262     }
00263 
00264     gzBool triggerNotifications()
00265     {
00266         gzBool result=triggerSubscriptionChanges();
00267 
00268         m_activeSubsLocker.waitLock();
00269 
00270         if(!m_inTriggerNotification && movePendingToActiveData())
00271         {
00272             m_inTriggerNotification=TRUE;
00273 
00274             if(m_activeData.entries())
00275             {
00276                 result=TRUE;
00277 
00278                 gzDouble now=gzTime::systemSeconds();
00279 
00280                 gzListIterator<gzPendData<DATA> > iterator(m_activeData);
00281                 gzPendData<DATA> *pend;
00282 
00283                 while(pend=iterator())
00284                 {
00285                     if(pend->timeOut>now)
00286                     {
00287                         if(pend->notifyTime<=now)
00288                         {
00289                             if(m_activeSubs.entries())
00290                             {
00291                                 gzListIterator<gzPendSub<SLAVE> > iterator2(m_activeSubs);
00292                                 gzPendSub<SLAVE> *subs;
00293 
00294                                 while(subs=iterator2())
00295                                 {
00296                                     if( (!subs->senderClass) || (subs->senderClass==pend->senderClass))
00297                                         subs->subscriber->onNotify((MASTER *)this,pend->data,pend->senderClass);
00298 
00299                                 }
00300                             }
00301                             iterator.remove();
00302                         }   
00303                         // else leave the pending data
00304                     }
00305                     else
00306                     {
00307                         iterator.remove();
00308                     }
00309                 }
00310             }
00311 
00312             m_inTriggerNotification=FALSE;
00313         }
00314 
00315         m_activeSubsLocker.unLock();
00316 
00317         return result;
00318     }
00319 
00320     gzBool movePendingToActiveData()
00321     {
00322         GZ_ASSERT(!m_activeData.entries());
00323 
00324         m_pendingDataLocker.waitLock();
00325 
00326         m_activeData = m_pendingData;
00327         m_pendingData.clear();
00328 
00329         m_pendingDataLocker.unLock();
00330 
00331         return GZ_BOOL(m_activeData.entries());
00332     }
00333 
00334     gzBool triggerSubscriptionChanges()
00335     {
00336         m_activeSubsLocker.waitLock();
00337         m_pendingSubsLocker.waitLock();
00338 
00339         gzBool result=FALSE;
00340 
00341         // check for removals
00342 
00343         if(m_pendingRemSubs.entries())
00344         {
00345             result=TRUE;
00346 
00347             gzListIterator<gzPendSub<SLAVE> > iterator(m_pendingRemSubs);
00348             gzPendSub<SLAVE> *remove;
00349 
00350             while(remove=iterator())
00351             {
00352                 // Check if cancel any add
00353 
00354                 if(m_pendingAddSubs.entries())
00355                 {
00356                     gzListIterator<gzPendSub<SLAVE> > iterator(m_pendingAddSubs);
00357                     gzPendSub<SLAVE> *add;
00358 
00359                     while(add=iterator())
00360                     {
00361                         if(add->subscriber==remove->subscriber)
00362                         {
00363                             if(add->pendingID<remove->pendingID)
00364                             {
00365                                 remove->subscriber->m_subscriptionLocker.waitLock();
00366     
00367                                 remove->subscriber->m_pendingSubscriptions.remove((MASTER *)this);
00368                             
00369                                 remove->subscriber->onNotifyStatus((MASTER *)this,remove->subscriber,GZ_NOTIFY_REMOVE_SUBSCRIBER);
00370         
00371                                 remove->subscriber->m_subscriptionLocker.unLock();
00372                             
00373                                 onNotifyStatus(remove->subscriber,GZ_NOTIFY_CANCEL_ADD_SUBSCRIBER);
00374 
00375                                 iterator.remove();
00376                             }
00377                         }
00378                     }
00379                 }
00380 
00381                 // Remove from subscriptions
00382 
00383                 if(m_activeSubs.entries())
00384                 {
00385                     gzListIterator<gzPendSub<SLAVE> > iterator(m_activeSubs);
00386                     gzPendSub<SLAVE> *sub;
00387 
00388                     while(sub=iterator())
00389                     {
00390                         if(sub->subscriber==remove->subscriber)
00391                         {
00392                             sub->subscriber->m_subscriptionLocker.waitLock();
00393     
00394                             sub->subscriber->m_pendingSubscriptions.remove((MASTER *)this);
00395                             
00396                             sub->subscriber->onNotifyStatus((MASTER *)this,sub->subscriber,GZ_NOTIFY_REMOVE_SUBSCRIBER);
00397         
00398                             sub->subscriber->m_subscriptionLocker.unLock();
00399                             
00400                             onNotifyStatus(sub->subscriber,GZ_NOTIFY_REMOVE_SUBSCRIBER);
00401                             
00402                             iterator.remove();
00403                         }
00404                     }
00405                 }
00406 
00407                 // remove pending change
00408 
00409                 remove->subscriber->m_subscriptionLocker.waitLock();
00410                 remove->subscriber->m_pendingSubscriptions.remove((MASTER *)this);
00411                 remove->subscriber->m_subscriptionLocker.unLock();
00412                         
00413             }
00414             m_pendingRemSubs.clear();
00415         }
00416 
00417         
00418         // check for adds
00419 
00420         if(m_pendingAddSubs.entries())
00421         {
00422             gzListIterator<gzPendSub<SLAVE> > iterator(m_pendingAddSubs);
00423             gzPendSub<SLAVE> *add;
00424 
00425             gzBool  addItem;
00426 
00427             result=TRUE;
00428 
00429             while(add=iterator())
00430             {
00431                 // Check if cancel any add
00432 
00433                 addItem=TRUE;
00434 
00435                 if(m_activeSubs.entries())
00436                 {
00437                     gzListIterator<gzPendSub<SLAVE> > iterator(m_activeSubs);
00438                     gzPendSub<SLAVE> *sub;
00439 
00440                     while(sub=iterator())
00441                     {
00442                         if(add->subscriber==sub->subscriber)
00443                         {
00444                             if(!sub->senderClass)
00445                                 addItem=FALSE;
00446                             else if(!add->senderClass)
00447                                 iterator.remove();
00448                             else if(add->senderClass==sub->senderClass)
00449                                 addItem=FALSE;
00450                         }
00451                     }
00452                 }
00453 
00454                 if(addItem)
00455                 {
00456                     if(m_pendingRemSubs.entries())
00457                     {
00458                         gzListIterator<gzPendSub<SLAVE> > iterator(m_pendingRemSubs);
00459                         gzPendSub<SLAVE> *sub;
00460 
00461                         while(sub=iterator())
00462                         {
00463                             if(add->subscriber==sub->subscriber)
00464                             {
00465                                 if(!sub->senderClass)
00466                                     addItem=FALSE;
00467                                 else if(add->senderClass==sub->senderClass)
00468                                     addItem=FALSE;
00469                             }
00470                         }
00471                     }
00472                 }
00473 
00474                 if(addItem)
00475                 {
00476                     m_activeSubs.insert(add);
00477                     
00478                     add->subscriber->m_subscriptionLocker.waitLock();
00479                     
00480                     add->subscriber->onNotifyStatus((MASTER *)this,add->subscriber,GZ_NOTIFY_ADD_SUBSCRIBER);
00481                     
00482                     add->subscriber->m_subscriptionLocker.unLock();
00483                     
00484                     onNotifyStatus(add->subscriber,GZ_NOTIFY_ADD_SUBSCRIBER);
00485                 }
00486                 else
00487                 {
00488                     add->subscriber->m_subscriptionLocker.waitLock();
00489     
00490                     add->subscriber->m_pendingSubscriptions.remove((MASTER *)this);
00491                             
00492                     add->subscriber->onNotifyStatus((MASTER *)this,add->subscriber,GZ_NOTIFY_MULTIPLE_ADD_SUBSCRIBER);
00493         
00494                     add->subscriber->m_subscriptionLocker.unLock();
00495                 }
00496                     
00497 
00498         
00499             }
00500 
00501             m_pendingAddSubs.clear();
00502         }
00503 
00504         m_pendingID=0;  
00505 
00506         m_pendingSubsLocker.unLock();
00507         m_activeSubsLocker.unLock();
00508 
00509         return result;
00510     }
00511 
00512     gzVoid triggerOnNotifyData(gzBool on)
00513     {
00514         GZ_BODYGUARD(m_pendingDataLocker);
00515 
00516         m_triggerOnNotifyData=on;
00517     }
00518 
00519     virtual gzVoid onNotifyStatus(SLAVE *slave,gzNotifyState state){};
00520 
00521 
00522 private:
00523 
00524     gzMutex                         m_pendingSubsLocker;
00525     gzRefList<gzPendSub<SLAVE> >    m_pendingAddSubs;
00526     gzRefList<gzPendSub<SLAVE> >    m_pendingRemSubs;
00527 
00528     gzRefList<gzPendSub<SLAVE> >    m_activeSubs;
00529     gzMutex                         m_activeSubsLocker;
00530 
00531     gzULong                         m_pendingID;
00532 
00533     gzMutex                         m_pendingDataLocker;
00534     gzRefList<gzPendData<DATA> >    m_pendingData;
00535     gzRefList<gzPendData<DATA> >    m_activeData;
00536 
00537     gzBool                          m_triggerOnNotifyData;
00538     gzBool                          m_inTriggerNotification;
00539 };
00540 
00541 //******************************************************************************
00542 // Class    : gzNotifySlave
00543 //                                  
00544 // Purpose  : Template that implements the Observer Slave in a O/N pattern
00545 //                                  
00546 // Notes    : - 
00547 //                                  
00548 // Revision History...                          
00549 //                                  
00550 // Who  Date    Description                     
00551 //                                  
00552 // AMO  031012  Created 
00553 //                                  
00554 //******************************************************************************
00555 template <class MASTER , class SLAVE , class DATA=gzRefPointer<gzReference> > class gzNotifySlave 
00556 {
00557 public:
00558 
00559     gzNotifySlave()
00560     {
00561     }
00562 
00563     gzNotifySlave(const gzNotifySlave<MASTER,SLAVE,DATA> &copy)
00564     {
00565     }
00566 
00567     virtual ~gzNotifySlave()
00568     {
00569         m_subscriptionLocker.waitLock();
00570 
00571         if(m_pendingSubscriptions.entries())
00572         {
00573             gzList<MASTER>  pendingSubscriptions=m_pendingSubscriptions;
00574 
00575             m_subscriptionLocker.unLock();
00576         
00577             gzListIterator<MASTER> iterator(pendingSubscriptions);
00578         
00579             MASTER *pending;
00580 
00581             while(pending=iterator())
00582             {
00583                 pending->removeSubscriber((SLAVE *)this);
00584                 pending->triggerSubscriptionChanges();
00585                 pending->onNotifyStatus((SLAVE *)this,GZ_NOTIFY_SLAVE_TERMINATE);
00586             }
00587         }
00588         else
00589             m_subscriptionLocker.unLock();
00590     }
00591 
00592     virtual gzVoid onNotify(MASTER *master,DATA &data,gzULong senderClass)=0;
00593 
00594     virtual gzVoid onNotifyStatus(MASTER *master,SLAVE *slave,gzNotifyState state){};
00595 
00596 protected:
00597 
00598     friend class gzNotifyMaster<MASTER,SLAVE,DATA>;
00599 
00600     gzList<MASTER>  m_pendingSubscriptions;
00601 
00602     gzMutex         m_subscriptionLocker;
00603 };
00604 
00605 
00606 //******************************************************************************
00607 // Class    : gzNotifyMessage
00608 //                                  
00609 // Purpose  : Default notification message
00610 //                                  
00611 // Notes    : - 
00612 //                                  
00613 // Revision History...                          
00614 //                                  
00615 // Who  Date    Description                     
00616 //                                  
00617 // AMO  031012  Created 
00618 //                                  
00619 //******************************************************************************
00620 class gzNotifyMessage : public gzReference
00621 {
00622 public:
00623 
00624     GZ_DECLARE_TYPE_INTERFACE_EXPORT(GZ_BASE_EXPORT);   // RTTI
00625 
00626     GZ_BASE_EXPORT gzNotifyMessage(const gzString &command , const gzDouble & duration , gzTypeInterface *sender, gzReference *data , gzULong counter);
00627 
00628     GZ_BASE_EXPORT virtual ~gzNotifyMessage(){};
00629 
00630     GZ_BASE_EXPORT gzString &           getCommand();
00631     GZ_BASE_EXPORT gzTypeInterface *    getSender();
00632     GZ_BASE_EXPORT gzReference *        getData();
00633     GZ_BASE_EXPORT gzTime &             getTime();
00634     GZ_BASE_EXPORT gzTime &             getLastValidTime();
00635     GZ_BASE_EXPORT gzULong &            getCounter();
00636 
00637     //-------------- clone interface ---------------
00638     GZ_BASE_EXPORT virtual gzReference *clone() const;
00639         
00640 private:
00641 
00642     gzString                        m_command;
00643     gzTypeInterface                 *m_sender;
00644     gzRefPointer<gzReference>       m_data; 
00645     gzTime                          m_time;
00646     gzTime                          m_valid;
00647     gzULong                         m_counter;
00648 };
00649 
00650 class gzNotifyManager; // Forward decl of manager
00651 
00652 class gzNotifyInterface : public gzNotifySlave<gzNotifyManager,gzNotifyInterface,gzRefPointer<gzNotifyMessage> > 
00653 {
00654 public:
00655 };
00656         
00657 class gzNotifyManager : public gzNotifyMaster<gzNotifyManager,gzNotifyInterface,gzRefPointer<gzNotifyMessage> > 
00658 {
00659 public:
00660     GZ_BASE_EXPORT  gzNotifyManager();
00661     GZ_BASE_EXPORT  virtual ~gzNotifyManager();
00662 
00663     GZ_BASE_EXPORT gzVoid notify(const gzString &command , const gzULong priority =0 , const gzDouble & duration=0.0 , gzTypeInterface *sender=NULL, gzReference *data=NULL , gzULong counter=0);
00664     GZ_BASE_EXPORT gzVoid notify_gzString(const gzString &command , const gzString &data, gzTypeInterface *sender=NULL);
00665 
00666     // ------------------ generic notifier ----------------------
00667 
00668     GZ_BASE_EXPORT static gzNotifyManager &getManager();
00669 };
00670 
00671 #endif

Documentation for Gizmo3D generated at Wed Feb 20 11:54:07 2008 by   Saab Training Systems AB, ¸ (c) 2003-and beyond