Skip to content

Commit 85f3cf0

Browse files
committed
feat(NotificationCenter): g++ build and refactoring #4414
1 parent f4787b2 commit 85f3cf0

File tree

8 files changed

+116
-88
lines changed

8 files changed

+116
-88
lines changed

Foundation/include/Poco/AbstractObserver.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,14 @@ class Foundation_API AbstractObserver
3737
AbstractObserver& operator = (const AbstractObserver& observer);
3838

3939
virtual void notify(Notification* pNf) const = 0;
40+
4041
virtual bool equals(const AbstractObserver& observer) const = 0;
41-
virtual bool accepts(Notification* pNf, const char* pName = 0) const = 0;
42+
43+
[[deprecated("use `Poco::Any accepts(Notification*)` instead")]]
44+
virtual bool accepts(Notification* pNf, const char* pName) const = 0;
45+
46+
virtual bool accepts(const Notification::Ptr& pNf) const = 0;
47+
4248
virtual AbstractObserver* clone() const = 0;
4349

4450
virtual void start();

Foundation/include/Poco/AsyncObserver.h

Lines changed: 28 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "Poco/Thread.h"
2424
#include "Poco/Stopwatch.h"
2525
#include "Poco/Debugger.h"
26+
#include "Poco/ErrorHandler.h"
2627
#include "Poco/Format.h"
2728
#include "Poco/RunnableAdapter.h"
2829
#include "Poco/NotificationQueue.h"
@@ -44,22 +45,22 @@ class AsyncObserver: public NObserver<C, N>
4445
{
4546
public:
4647
using Type = AsyncObserver<C, N>;
47-
using Matcher = bool (C::*)(const std::string&);
48+
using Matcher = typename NObserver<C, N>::Matcher;
49+
using Handler = typename NObserver<C, N>::Handler;
50+
using NotificationPtr = typename NObserver<C, N>::NotificationPtr;
4851

4952
AsyncObserver() = delete;
5053

5154
AsyncObserver(C& object, Handler handler, Matcher matcher = nullptr):
52-
NObserver(object, handler),
53-
_matcher(matcher),
55+
NObserver<C, N>(object, handler, matcher),
5456
_ra(*this, &AsyncObserver::dequeue),
5557
_started(false),
5658
_done(false)
5759
{
5860
}
5961

6062
AsyncObserver(const AsyncObserver& observer):
61-
NObserver(observer),
62-
_matcher(observer._matcher),
63+
NObserver<C, N>(observer),
6364
_ra(*this, &AsyncObserver::dequeue),
6465
_started(false),
6566
_done(false)
@@ -77,45 +78,18 @@ class AsyncObserver: public NObserver<C, N>
7778
if (&observer != this)
7879
{
7980
poco_assert(observer._nq.size() == 0);
80-
_pObject = observer._pObject;
81-
_handler = observer._handler;
82-
_matcher = observer._matcher;
81+
setObject(observer._pObject);
82+
setHandler(observer._handler);
83+
setMatcher(observer._matcher);
8384
_started = false;
8485
_done =false;
8586
}
8687
return *this;
8788
}
8889

89-
void notify(Notification* pNf) const
90+
virtual void notify(Notification* pNf) const
9091
{
91-
Poco::ScopedLockWithUnlock l(_mutex);
92-
if (_pObject)
93-
{
94-
if (!_matcher || (_pObject->*_matcher)(pNf->name()))
95-
{
96-
l.unlock();
97-
N* pCastNf = dynamic_cast<N*>(pNf);
98-
if (pCastNf)
99-
{
100-
NotificationPtr ptr(pCastNf, true);
101-
_nq.enqueueNotification(ptr);
102-
}
103-
}
104-
}
105-
}
106-
107-
virtual bool equals(const AbstractObserver& abstractObserver) const
108-
{
109-
const AsyncObserver* pObs = dynamic_cast<const AsyncObserver*>(&abstractObserver);
110-
return pObs && pObs->_pObject == _pObject && pObs->_method == _method && pObs->_matcher == _matcher;
111-
}
112-
113-
virtual bool accepts(Notification* pNf, const char* pName = nullptr) const
114-
{
115-
if (!dynamic_cast<N*>(pNf)) return false;
116-
117-
Poco::ScopedLock l(_mutex);
118-
return _pObject && _matcher && (_pObject->*_matcher)(pNf->name());
92+
_nq.enqueueNotification(NotificationPtr(pNf, true));
11993
}
12094

12195
virtual AbstractObserver* clone() const
@@ -125,7 +99,7 @@ class AsyncObserver: public NObserver<C, N>
12599

126100
virtual void start()
127101
{
128-
Poco::ScopedLock l(_mutex);
102+
Poco::ScopedLock l(this->mutex());
129103
if (_started)
130104
{
131105
throw Poco::InvalidAccessException(
@@ -149,7 +123,7 @@ class AsyncObserver: public NObserver<C, N>
149123
_nq.wakeUpAll();
150124
while (!_done) Thread::sleep(100);
151125
_thread.join();
152-
NObserver::disable();
126+
NObserver<C, N>::disable();
153127
}
154128

155129
virtual int backlog() const
@@ -162,19 +136,25 @@ class AsyncObserver: public NObserver<C, N>
162136
{
163137
NotificationPtr pNf;
164138
_started = true;
139+
_done = false;
165140
while (pNf = _nq.waitDequeueNotification())
166141
{
167142
try
168143
{
169-
_mutex.lock();
170-
try
171-
{
172-
(_pObject->*_method)(pNf);
173-
_mutex.unlock();
174-
}
175-
catch (Poco::SystemException&) { break; }
176-
catch (...) { _mutex.unlock(); }
177-
} catch (Poco::SystemException&) {}
144+
this->handle(pNf);
145+
}
146+
catch (Poco::Exception& ex)
147+
{
148+
Poco::ErrorHandler::handle(ex);
149+
}
150+
catch (std::exception& ex)
151+
{
152+
Poco::ErrorHandler::handle(ex);
153+
}
154+
catch (...)
155+
{
156+
Poco::ErrorHandler::handle();
157+
}
178158
}
179159
_done = true;
180160
_started = false;
@@ -183,7 +163,6 @@ class AsyncObserver: public NObserver<C, N>
183163
using Adapter = RunnableAdapter<AsyncObserver<C, N>>;
184164

185165
Thread _thread;
186-
Matcher _matcher;
187166
mutable NotificationQueue _nq;
188167
Adapter _ra;
189168
std::atomic<bool> _started;

Foundation/include/Poco/NObserver.h

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,29 +37,39 @@ class NObserver: public AbstractObserver
3737
/// to use this template class.
3838
///
3939
/// This class template is quite similar to the Observer class
40-
/// template. The only difference is that the NObserver
41-
/// expects the callback function to accept a const AutoPtr&
42-
/// instead of a plain pointer as argument, thus simplifying memory
43-
/// management.
40+
/// template. The differences are:
41+
///
42+
/// - NObserver expects the callback function to accept a const AutoPtr&
43+
/// instead of a plain pointer as argument, thus simplifying memory
44+
/// management.
45+
///
46+
/// - In addition to dispatching notifications based on the Notification runtime
47+
/// type, NObserver can also notify subscribers based on the Notification name.
48+
/// To enable this functionality, a matcher function must be provided.
49+
/// Null matcher means no matching is performed and all notificiations
50+
/// of the type subscribed to are dispatched.
4451
{
4552
public:
4653
using Type = NObserver<C, N>;
4754
using NotificationPtr = AutoPtr<N>;
4855
using Callback = void (C::*)(const NotificationPtr&);
4956
using Handler = Callback;
57+
using Matcher = bool (C::*)(const std::string&) const;
5058

5159
NObserver() = delete;
5260

53-
NObserver(C& object, Callback method):
61+
NObserver(C& object, Handler method, Matcher matcher = nullptr):
5462
_pObject(&object),
55-
_method(method)
63+
_handler(method),
64+
_matcher(matcher)
5665
{
5766
}
5867

5968
NObserver(const NObserver& observer):
6069
AbstractObserver(observer),
6170
_pObject(observer._pObject),
62-
_method(observer._method)
71+
_handler(observer._handler),
72+
_matcher(observer._matcher)
6373
{
6474
}
6575

@@ -72,35 +82,35 @@ class NObserver: public AbstractObserver
7282
if (&observer != this)
7383
{
7484
_pObject = observer._pObject;
75-
_method = observer._method;
85+
_handler = observer._handler;
86+
_matcher = observer._matcher;
7687
}
7788
return *this;
7889
}
7990

8091
virtual void notify(Notification* pNf) const
8192
{
8293
Poco::Mutex::ScopedLock lock(_mutex);
83-
8494
if (_pObject)
85-
{
86-
N* pCastNf = dynamic_cast<N*>(pNf);
87-
if (pCastNf)
88-
{
89-
NotificationPtr ptr(pCastNf, true);
90-
(_pObject->*_method)(ptr);
91-
}
92-
}
95+
(_pObject->*_handler)(NotificationPtr(pNf, true));
9396
}
9497

9598
virtual bool equals(const AbstractObserver& abstractObserver) const
9699
{
97100
const NObserver* pObs = dynamic_cast<const NObserver*>(&abstractObserver);
98-
return pObs && pObs->_pObject == _pObject && pObs->_method == _method;
101+
return pObs && pObs->_pObject == _pObject && pObs->_handler == _handler && pObs->_matcher == _matcher;
99102
}
100103

101-
virtual bool accepts(Notification* pNf, const char* pName = nullptr) const
104+
[[deprecated("use `bool accepts(const Notification::Ptr&)` instead")]]
105+
virtual bool accepts(Notification* pNf, const char* pName) const
102106
{
103-
return dynamic_cast<N*>(pNf) && (!pName || pNf->name() == pName);
107+
return (!pName || pNf->name() == pName) && dynamic_cast<N*>(pNf) != nullptr;
108+
}
109+
110+
virtual bool accepts(const Notification::Ptr& pNf) const
111+
{
112+
if(match(pNf)) return pNf.cast<N>() != nullptr;
113+
return false;
104114
}
105115

106116
virtual AbstractObserver* clone() const
@@ -116,8 +126,31 @@ class NObserver: public AbstractObserver
116126
}
117127

118128
protected:
129+
130+
void handle(const NotificationPtr& ptr)
131+
{
132+
Mutex::ScopedLock lock(_mutex);
133+
134+
if (_pObject)
135+
(_pObject->*_handler)(ptr);
136+
}
137+
138+
bool match(const NotificationPtr& ptr) const
139+
{
140+
Mutex::ScopedLock l(_mutex);
141+
142+
return _pObject && (!_matcher || (_pObject->*_matcher)(ptr->name()));
143+
}
144+
145+
Mutex& mutex() const
146+
{
147+
return _mutex;
148+
}
149+
150+
private:
119151
C* _pObject;
120-
Callback _method;
152+
Callback _handler;
153+
Matcher _matcher;
121154
mutable Poco::Mutex _mutex;
122155
};
123156

Foundation/include/Poco/NotificationCenter.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ class Foundation_API NotificationCenter
132132
/// NotificationCenter.
133133

134134
private:
135-
typedef SharedPtr<AbstractObserver> AbstractObserverPtr;
136-
typedef std::vector<AbstractObserverPtr> ObserverList;
135+
using AbstractObserverPtr = SharedPtr<AbstractObserver>;
136+
using ObserverList = std::vector<AbstractObserverPtr>;
137137

138-
ObserverList observersToNotify(Notification::Ptr pNotification) const;
138+
ObserverList observersToNotify(const Notification::Ptr& pNotification) const;
139139

140140
ObserverList _observers;
141141
mutable Mutex _mutex;

Foundation/include/Poco/Observer.h

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,10 @@ class Observer: public AbstractObserver
7474
void notify(Notification* pNf) const
7575
{
7676
Poco::Mutex::ScopedLock lock(_mutex);
77-
7877
if (_pObject)
7978
{
80-
N* pCastNf = dynamic_cast<N*>(pNf);
81-
if (pCastNf)
82-
{
83-
pCastNf->duplicate();
84-
(_pObject->*_method)(pCastNf);
85-
}
79+
pNf->duplicate();
80+
(_pObject->*_method)(static_cast<N*>(pNf));
8681
}
8782
}
8883

@@ -92,9 +87,15 @@ class Observer: public AbstractObserver
9287
return pObs && pObs->_pObject == _pObject && pObs->_method == _method;
9388
}
9489

95-
bool accepts(Notification* pNf, const char* pName = 0) const
90+
[[deprecated("use `bool accepts(const Notification::Ptr&)` instead")]]
91+
bool accepts(Notification* pNf, const char* pName) const
92+
{
93+
return (!pName || pNf->name() == pName) && (dynamic_cast<N*>(pNf) != nullptr);
94+
}
95+
96+
bool accepts(const Notification::Ptr& pNf) const
9697
{
97-
return dynamic_cast<N*>(pNf) && (!pName || pNf->name() == pName);
98+
return (pNf.cast<N>() != nullptr);
9899
}
99100

100101
AbstractObserver* clone() const

Foundation/src/NotificationCenter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ bool NotificationCenter::hasObserver(const AbstractObserver& observer) const
7676
}
7777

7878

79-
NotificationCenter::ObserverList NotificationCenter::observersToNotify(Notification::Ptr pNotification) const
79+
NotificationCenter::ObserverList NotificationCenter::observersToNotify(const Notification::Ptr& pNotification) const
8080
{
8181
ObserverList ret;
8282
ScopedLock<Mutex> lock(_mutex);

Foundation/testsuite/src/NotificationCenterTest.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ class TestNotification: public Notification
3131
};
3232

3333

34-
NotificationCenterTest::NotificationCenterTest(const std::string& name): CppUnit::TestCase(name)
34+
NotificationCenterTest::NotificationCenterTest(const std::string& name):
35+
CppUnit::TestCase(name),
36+
_handle1Done(false),
37+
_handle2Done(false)
3538
{
3639
}
3740

@@ -162,11 +165,13 @@ void NotificationCenterTest::testNotificationCenterAsync()
162165
nc.postNotification(new Notification("asyncNotification"));
163166
nc.postNotification(new Notification("anotherNotification"));
164167

165-
while (_set.size() < 2) Poco::Thread::sleep(100);
168+
while (!_handle1Done || !_handle2Done)
169+
Poco::Thread::sleep(100);
166170

167171
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1));
168172
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2));
169173

174+
Poco::Mutex::ScopedLock l(_mutex);
170175
assertTrue(_set.size() == 2);
171176
assertTrue(_set.find("handleAsync1") != _set.end());
172177
assertTrue(_set.find("handleAsync2") != _set.end());
@@ -226,17 +231,19 @@ void NotificationCenterTest::handleAsync1(const AutoPtr<Notification>& pNf)
226231
{
227232
Poco::Mutex::ScopedLock l(_mutex);
228233
_set.insert("handleAsync1");
234+
_handle1Done = true;
229235
}
230236

231237

232238
void NotificationCenterTest::handleAsync2(const AutoPtr<Notification>& pNf)
233239
{
234240
Poco::Mutex::ScopedLock l(_mutex);
235241
_set.insert("handleAsync2");
242+
_handle2Done = true;
236243
}
237244

238245

239-
bool NotificationCenterTest::matchAsync(const std::string& name)
246+
bool NotificationCenterTest::matchAsync(const std::string& name) const
240247
{
241248
return name.find("asyncNotification") == 0;
242249
}

0 commit comments

Comments
 (0)