00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00038
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 }
00089
00090
00091
00092 DATA data;
00093 gzULong senderClass;
00094 gzDouble notifyTime;
00095 gzDouble timeOut;
00096 };
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
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> ©)
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 ¬ifyTime=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
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
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
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
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
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
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
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
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
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> ©)
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
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620 class gzNotifyMessage : public gzReference
00621 {
00622 public:
00623
00624 GZ_DECLARE_TYPE_INTERFACE_EXPORT(GZ_BASE_EXPORT);
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
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;
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
00667
00668 GZ_BASE_EXPORT static gzNotifyManager &getManager();
00669 };
00670
00671 #endif