00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "resourcesuser.h"
00022 #include <memory>
00023
00024 namespace farsa {
00025
00026 namespace {
00027
00028
00029
00030 class BeingNotifiedRAII
00031 {
00032 public:
00033 BeingNotifiedRAII(bool* beingNotified) :
00034 m_beingNotified(beingNotified)
00035 {
00036 *m_beingNotified = true;
00037 }
00038
00039 ~BeingNotifiedRAII()
00040 {
00041 *m_beingNotified = false;
00042 }
00043
00044 private:
00045 bool* const m_beingNotified;
00046 };
00047 }
00048
00049 void ResourcesUser::shareResourcesWith(ResourcesUser* other)
00050 {
00051 if (other != NULL) {
00052 m_resources = other->m_resources;
00053 } else {
00054
00055
00056 m_resources = ResourceCollectionHolder();
00057 }
00058 }
00059
00060 ResourcesUser::ResourcesUser() :
00061 m_resources()
00062 {
00063 }
00064
00065 ResourcesUser::ResourcesUser(const ResourcesUser& other) throw() :
00066 m_resources(other.m_resources)
00067 {
00068 }
00069
00070 ResourcesUser& ResourcesUser::operator=(const ResourcesUser& other) throw()
00071 {
00072 if (&other == this) {
00073 return *this;
00074 }
00075
00076 m_resources = other.m_resources;
00077
00078 return *this;
00079 }
00080
00081 ResourcesUser::~ResourcesUser()
00082 {
00083
00084 }
00085
00086 SimpleResourcesUser::SimpleResourcesUser() :
00087 ResourcesUser(),
00088 m_beingNotified(false),
00089 m_notifiedResourceHandler(NULL),
00090 m_observedResources()
00091 {
00092 }
00093
00094 SimpleResourcesUser::SimpleResourcesUser(const SimpleResourcesUser& other) :
00095 ResourcesUser(other),
00096 m_beingNotified(false),
00097 m_notifiedResourceHandler(NULL),
00098 m_observedResources(other.m_observedResources)
00099 {
00100
00101
00102
00103
00104 forceBeingNotified();
00105 }
00106
00107 SimpleResourcesUser& SimpleResourcesUser::operator=(const SimpleResourcesUser& other)
00108 {
00109
00110
00111
00112 if (&other == this) {
00113 return *this;
00114 }
00115
00116
00117 removeAllNotifications();
00118
00119
00120 ResourcesUser::operator=(other);
00121
00122
00123
00124
00125 m_observedResources = other.m_observedResources;
00126
00127
00128 forceBeingNotified();
00129
00130 return *this;
00131 }
00132
00133 SimpleResourcesUser::~SimpleResourcesUser()
00134 {
00135 removeAllNotifications();
00136 }
00137
00138 void SimpleResourcesUser::shareResourcesWith(ResourcesUser* other)
00139 {
00140
00141 removeAllNotifications();
00142
00143
00144 ResourcesUser::shareResourcesWith(other);
00145 }
00146
00147 void SimpleResourcesUser::deleteResource(QString name)
00148 {
00149
00150 ResourceHandler* h = m_resources->getResource(name, false);
00151
00152 if ((h == NULL) || (!h->exists())){
00153 throw ResourceNotDeclaredException(name.toAscii().data());
00154 }
00155
00156
00157 h->unset();
00158 }
00159
00160 void SimpleResourcesUser::resourceChanged(QString, ResourceChangeType)
00161 {
00162
00163 }
00164
00165 void SimpleResourcesUser::notifyResourceChange(ResourceHandler* resource, ResourceChangeType changeType)
00166 {
00167 BeingNotifiedRAII beingNotifiedRAII(&m_beingNotified);
00168 m_notifiedResourceHandler = resource;
00169
00170 resourceChanged(m_notifiedResourceHandler->name(), changeType);
00171 }
00172
00173 void SimpleResourcesUser::removeAllNotifications()
00174 {
00175
00176
00177 foreach (ResourceHandler* h, m_observedResources) {
00178 h->removeNotifee(this);
00179 }
00180
00181 m_observedResources.clear();
00182 }
00183
00184 void SimpleResourcesUser::forceBeingNotified()
00185 {
00186
00187
00188 foreach (ResourceHandler* h, m_observedResources) {
00189 h->addNotifee(this);
00190 }
00191 }
00192
00193 ConcurrentResourcesUser::ConcurrentResourcesUser() :
00194 ResourcesUser(),
00195 m_lockAcquired(0),
00196 m_beingNotified(false),
00197 m_notifiedResourceHandler(NULL),
00198 m_usableResources()
00199 {
00200
00201 m_resources.setUseLock(true);
00202 }
00203
00204 ConcurrentResourcesUser::~ConcurrentResourcesUser()
00205 {
00206
00207 removeAllNotifications();
00208
00209 m_usableResources.clear();
00210 }
00211
00212 void ConcurrentResourcesUser::shareResourcesWith(ResourcesUser* other)
00213 {
00214 if ((m_lockAcquired > 0) || m_beingNotified) {
00215 throw WrongResourceLockStatusForOperation("shareResourcesWith", true);
00216 }
00217
00218
00219
00220
00221 if (other == NULL) {
00222
00223
00224
00225
00226
00227 QSet<QString> m_existingResourcesInOldCollection;
00228 {
00229 QMutexLocker oldCollectionLocker(&(m_resources->getLock()));
00230
00231
00232 removeAllNotifications();
00233
00234 for (QMap<QString, ResourceHandler*>::const_iterator it = m_usableResources.constBegin(); it != m_usableResources.constEnd(); ++it) {
00235 if (it.value()->exists()) {
00236 m_existingResourcesInOldCollection.insert(it.key());
00237 }
00238 }
00239 }
00240
00241
00242 ResourcesUser::shareResourcesWith(other);
00243
00244
00245 QMutexLocker newCollectionLocker(&(m_resources->getLock()));
00246
00247
00248
00249 for (QMap<QString, ResourceHandler*>::iterator it = m_usableResources.begin(); it != m_usableResources.end(); ++it) {
00250 it.value() = m_resources->getResource(it.key(), true);
00251 it.value()->addNotifee(this);
00252 }
00253
00254
00255
00256 ResourcesMutexesLocker resourcesLocker(this, m_usableResources.values());
00257
00258
00259 newCollectionLocker.unlock();
00260
00261
00262 foreach (QString name, m_existingResourcesInOldCollection) {
00263 notifyResourceChange(m_usableResources[name], Deleted);
00264 }
00265 } else {
00266
00267 QMutexLocker newCollectionLocker(&(other->m_resources->getLock()));
00268
00269
00270
00271
00272
00273
00274 QSet<QString> m_existingResourcesInOldCollection;
00275 {
00276 QMutexLocker oldCollectionLocker(&(m_resources->getLock()));
00277
00278
00279 removeAllNotifications();
00280
00281 for (QMap<QString, ResourceHandler*>::const_iterator it = m_usableResources.constBegin(); it != m_usableResources.constEnd(); ++it) {
00282 if (it.value()->exists()) {
00283 m_existingResourcesInOldCollection.insert(it.key());
00284 }
00285 }
00286 }
00287
00288
00289
00290 m_resources.setUseLock(false);
00291 ResourcesUser::shareResourcesWith(other);
00292 m_resources.setUseLock(true);
00293
00294
00295
00296 QSet<QString> m_existingResourcesInNewCollection;
00297 for (QMap<QString, ResourceHandler*>::iterator it = m_usableResources.begin(); it != m_usableResources.end(); ++it) {
00298 it.value() = m_resources->getResource(it.key(), true);
00299 it.value()->addNotifee(this);
00300
00301 if (it.value()->exists()) {
00302 m_existingResourcesInNewCollection.insert(it.key());
00303 }
00304 }
00305
00306
00307
00308 ResourcesMutexesLocker resourcesLocker(this, m_usableResources.values());
00309
00310
00311 newCollectionLocker.unlock();
00312
00313
00314
00315
00316
00317 const QSet<QString> deletedResources = m_existingResourcesInOldCollection - m_existingResourcesInNewCollection;
00318 const QSet<QString> modifiedResources = m_existingResourcesInOldCollection & m_existingResourcesInNewCollection;
00319 const QSet<QString> createdResources = m_existingResourcesInNewCollection - m_existingResourcesInOldCollection;
00320
00321
00322 foreach (QString name, deletedResources) {
00323 notifyResourceChange(m_usableResources[name], Deleted);
00324 }
00325 foreach (QString name, modifiedResources) {
00326 notifyResourceChange(m_usableResources[name], Modified);
00327 }
00328 foreach (QString name, createdResources) {
00329 notifyResourceChange(m_usableResources[name], Created);
00330 }
00331 }
00332 }
00333
00334 void ConcurrentResourcesUser::usableResources(QStringList resources)
00335 {
00336 if ((m_lockAcquired > 0) || m_beingNotified) {
00337 throw WrongResourceLockStatusForOperation("usableResources", true);
00338 }
00339
00340
00341 QMutexLocker collectionLocker(&(m_resources->getLock()));
00342
00343
00344 m_usableResources.clear();
00345
00346 foreach (QString resource, resources) {
00347
00348 ResourceHandler* h = m_resources->getResource(resource, true);
00349
00350 h->addNotifee(this);
00351 m_usableResources[resource] = h;
00352 }
00353
00354
00355
00356 ResourcesMutexesLocker resourcesLocker(this, m_usableResources.values());
00357
00358
00359 collectionLocker.unlock();
00360
00361
00362 foreach (ResourceHandler* h, m_usableResources) {
00363 if (h->exists()) {
00364 notifyResourceChange(h, Created);
00365 }
00366 }
00367 }
00368
00369 void ConcurrentResourcesUser::addUsableResource(QString resource)
00370 {
00371 if ((m_lockAcquired > 0) || m_beingNotified) {
00372 throw WrongResourceLockStatusForOperation("addUsableResource", true);
00373 }
00374
00375
00376 QMutexLocker collectionLocker(&(m_resources->getLock()));
00377
00378
00379 ResourceHandler* h = m_resources->getResource(resource, true);
00380
00381 h->addNotifee(this);
00382 m_usableResources[resource] = h;
00383
00384
00385 if (h->exists()) {
00386
00387 ResourcesMutexesLocker resourceLocker(this, h);
00388
00389
00390 collectionLocker.unlock();
00391
00392
00393 notifyResourceChange(h, Created);
00394 }
00395 }
00396
00397 void ConcurrentResourcesUser::addUsableResources(QStringList resources)
00398 {
00399 if ((m_lockAcquired > 0) || m_beingNotified) {
00400 throw WrongResourceLockStatusForOperation("addUsableResources", true);
00401 }
00402
00403
00404 QMutexLocker collectionLocker(&(m_resources->getLock()));
00405
00406
00407 QList<ResourceHandler *> newResources;
00408 foreach (QString resource, resources) {
00409
00410 ResourceHandler* h = m_resources->getResource(resource, true);
00411
00412 h->addNotifee(this);
00413 m_usableResources[resource] = h;
00414
00415
00416 newResources.append(h);
00417 }
00418
00419
00420
00421 ResourcesMutexesLocker resourcesLocker(this, newResources);
00422
00423
00424 collectionLocker.unlock();
00425
00426
00427 foreach (ResourceHandler* h, newResources) {
00428 if (h->exists()) {
00429 notifyResourceChange(h, Created);
00430 }
00431 }
00432 }
00433
00434 void ConcurrentResourcesUser::removeUsableResource(QString resource)
00435 {
00436 if ((m_lockAcquired > 0) || m_beingNotified) {
00437 throw WrongResourceLockStatusForOperation("removeUsableResource", true);
00438 }
00439
00440 if (m_usableResources.contains(resource)) {
00441
00442 QMutexLocker collectionLocker(&(m_resources->getLock()));
00443
00444
00445 ResourceHandler* h = m_resources->getResource(resource, false);
00446 h->removeNotifee(this);
00447
00448 m_usableResources.remove(resource);
00449
00450
00451 ResourcesMutexesLocker resourceLocker(this, h);
00452
00453
00454 collectionLocker.unlock();
00455
00456
00457 notifyResourceChange(h, Deleted);
00458 }
00459 }
00460
00461 void ConcurrentResourcesUser::removeUsableResources(QStringList resources)
00462 {
00463 if ((m_lockAcquired > 0) || m_beingNotified) {
00464 throw WrongResourceLockStatusForOperation("removeUsableResources", true);
00465 }
00466
00467
00468 QMutexLocker collectionLocker(&(m_resources->getLock()));
00469
00470
00471 QList<ResourceHandler *> deletedResources;
00472 foreach (QString resource, resources) {
00473 if (!m_usableResources.contains(resource)) {
00474 continue;
00475 }
00476
00477
00478
00479 ResourceHandler* h = m_resources->getResource(resource, false);
00480 h->removeNotifee(this);
00481
00482 m_usableResources.remove(resource);
00483
00484
00485 deletedResources.append(h);
00486 }
00487
00488
00489
00490 ResourcesMutexesLocker resourcesLocker(this, deletedResources);
00491
00492
00493 collectionLocker.unlock();
00494
00495
00496 foreach (ResourceHandler* h, deletedResources) {
00497 if (h->exists()) {
00498 notifyResourceChange(h, Deleted);
00499 }
00500 }
00501 }
00502
00503 void ConcurrentResourcesUser::removeAllUsableResources()
00504 {
00505 if ((m_lockAcquired > 0) || m_beingNotified) {
00506 throw WrongResourceLockStatusForOperation("removeAllUsableResources", true);
00507 }
00508
00509
00510 QMutexLocker collectionLocker(&(m_resources->getLock()));
00511
00512
00513 foreach (ResourceHandler* h, m_usableResources) {
00514 h->removeNotifee(this);
00515 }
00516
00517 QList<ResourceHandler *> deletedResources = m_usableResources.values();
00518
00519 m_usableResources.clear();
00520
00521
00522
00523 ResourcesMutexesLocker resourcesLocker(this, deletedResources);
00524
00525
00526 collectionLocker.unlock();
00527
00528
00529 foreach (ResourceHandler* h, deletedResources) {
00530 if (h->exists()) {
00531 notifyResourceChange(h, Deleted);
00532 }
00533 }
00534 }
00535
00536 void ConcurrentResourcesUser::deleteResource(QString name)
00537 {
00538 if ((m_lockAcquired > 0) || m_beingNotified) {
00539 throw WrongResourceLockStatusForOperation("deleteResource", true);
00540 }
00541
00542
00543 QMutexLocker collectionLocker(&(m_resources->getLock()));
00544
00545
00546 ResourceHandler* h = m_resources->getResource(name, false);
00547 if ((h == NULL) || (!h->exists())) {
00548 throw ResourceNotDeclaredException(name.toAscii().data());
00549 }
00550 ResourcesMutexesLocker resourceLocker(this, h);
00551
00552
00553 collectionLocker.unlock();
00554
00555
00556 h->unset();
00557 }
00558
00559 bool ConcurrentResourcesUser::hasResource(QString name) const
00560 {
00561 if ((m_lockAcquired > 0) || m_beingNotified) {
00562 throw WrongResourceLockStatusForOperation("hasResource", true);
00563 }
00564
00565 QMutexLocker locker(&(m_resources->getLock()));
00566
00567 return m_resources->hasResource(name);
00568 }
00569
00570 bool ConcurrentResourcesUser::usedResourcesExist(QStringList* nonExistingResources) const
00571 {
00572 if ((m_lockAcquired > 0) || m_beingNotified) {
00573 throw WrongResourceLockStatusForOperation("usedResourcesExist", true);
00574 }
00575
00576 QMutexLocker locker(&(m_resources->getLock()));
00577
00578 bool allExist = true;
00579
00580 foreach (ResourceHandler* h, m_usableResources) {
00581 if (!h->exists()) {
00582 allExist = false;
00583 if (nonExistingResources != NULL) {
00584 nonExistingResources->append(h->name());
00585 } else {
00586
00587
00588 break;
00589 }
00590 }
00591 }
00592
00593 return allExist;
00594 }
00595
00596 void ConcurrentResourcesUser::resourceChanged(QString, ResourceChangeType)
00597 {
00598
00599 }
00600
00601 void ConcurrentResourcesUser::lockAll()
00602 {
00603
00604 QMutexLocker locker(&(m_resources->getLock()));
00605
00606
00607 lockResources(m_usableResources.values());
00608
00609 ++m_lockAcquired;
00610 }
00611
00612 void ConcurrentResourcesUser::unlockAll()
00613 {
00614
00615
00616
00617 QMutexLocker locker(&(m_resources->getLock()));
00618
00619
00620 unlockResources(m_usableResources.values());
00621
00622 --m_lockAcquired;
00623
00624
00625 }
00626
00627 void ConcurrentResourcesUser::notifyResourceChange(ResourceHandler* resource, ResourceChangeType changeType)
00628 {
00629 BeingNotifiedRAII beingNotifiedRAII(&m_beingNotified);
00630 m_notifiedResourceHandler = resource;
00631
00632 resourceChanged(m_notifiedResourceHandler->name(), changeType);
00633 }
00634
00635 void ConcurrentResourcesUser::removeAllNotifications()
00636 {
00637
00638
00639 foreach (ResourceHandler* h, m_usableResources) {
00640 h->removeNotifee(this);
00641 }
00642 }
00643
00644 void ConcurrentResourcesUser::forceBeingNotified()
00645 {
00646
00647
00648 foreach (ResourceHandler* h, m_usableResources) {
00649 h->addNotifee(this);
00650 }
00651 }
00652
00653 void ConcurrentResourcesUser::lockResources(const QList<ResourceHandler*>& resources)
00654 {
00655
00656 bool oneLockFailed;
00657 do {
00658
00659 oneLockFailed = false;
00660
00661
00662
00663
00664
00665 QList<ResourceHandler*> lockedResources;
00666 foreach (ResourceHandler* resource, resources) {
00667 const bool locked = resource->getLock().tryLock();
00668 if (!locked) {
00669 oneLockFailed = true;
00670 break;
00671 } else {
00672 lockedResources.append(resource);
00673 }
00674 }
00675
00676
00677
00678 if (oneLockFailed) {
00679 foreach (ResourceHandler* resource, lockedResources) {
00680 resource->getLock().unlock();
00681 }
00682
00683
00684 m_resources->getWaitCondition().wait(&(m_resources->getLock()));
00685 }
00686 } while (oneLockFailed);
00687 }
00688
00689 void ConcurrentResourcesUser::unlockResources(const QList<ResourceHandler*>& resources)
00690 {
00691
00692
00693
00694 foreach (ResourceHandler* resource, resources) {
00695 resource->getLock().unlock();
00696 }
00697
00698
00699 m_resources->getWaitCondition().wakeAll();
00700 }
00701
00702 ResourcesLocker::ResourcesLocker(ConcurrentResourcesUser *resourcesUser, bool acquireLock):
00703 m_resourcesUser(resourcesUser),
00704 m_lockedByUs(false)
00705 {
00706 if (acquireLock) {
00707 lock();
00708 }
00709 }
00710
00711 ResourcesLocker::~ResourcesLocker()
00712 {
00713 unlock();
00714 }
00715
00716 void ResourcesLocker::lock()
00717 {
00718 if (m_lockedByUs) {
00719 return;
00720 }
00721
00722 m_resourcesUser->lockAll();
00723
00724 m_lockedByUs = true;
00725 }
00726
00727 void ResourcesLocker::unlock()
00728 {
00729 if (!m_lockedByUs) {
00730 return;
00731 }
00732
00733 m_resourcesUser->unlockAll();
00734
00735 m_lockedByUs = false;
00736 }
00737
00738 }
00739