BDE 4.14.0 Production release
Loading...
Searching...
No Matches
ball_broadcastobserver.h
Go to the documentation of this file.
1/// @file ball_broadcastobserver.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// ball_broadcastobserver.h -*-C++-*-
8#ifndef INCLUDED_BALL_BROADCASTOBSERVER
9#define INCLUDED_BALL_BROADCASTOBSERVER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup ball_broadcastobserver ball_broadcastobserver
15/// @brief Provide a broadcast observer that forwards to other observers.
16/// @addtogroup bal
17/// @{
18/// @addtogroup ball
19/// @{
20/// @addtogroup ball_broadcastobserver
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#ball_broadcastobserver-purpose"> Purpose</a>
25/// * <a href="#ball_broadcastobserver-classes"> Classes </a>
26/// * <a href="#ball_broadcastobserver-description"> Description </a>
27/// * <a href="#ball_broadcastobserver-thread-safety"> Thread Safety </a>
28/// * <a href="#ball_broadcastobserver-usage"> Usage </a>
29/// * <a href="#ball_broadcastobserver-example-1-delayed-observer-configuration"> Example 1: Delayed Observer Configuration </a>
30///
31/// # Purpose {#ball_broadcastobserver-purpose}
32/// Provide a broadcast observer that forwards to other observers.
33///
34/// # Classes {#ball_broadcastobserver-classes}
35///
36/// - ball::BroadcastObserver: observer that forwards to other observers
37///
38/// @see ball_record, ball_context, ball_observer,
39/// ball_loggermanager
40///
41/// # Description {#ball_broadcastobserver-description}
42/// This component provides a concrete implementation of the
43/// `ball::Observer` protocol for receiving and processing log records:
44/// @code
45/// ,-----------------------.
46/// ( ball::BroadcastObserver )
47/// `-----------------------'
48/// | ctor
49/// | registerObserver
50/// | deregisterObserver
51/// | deregisterAllObservers
52/// | findObserver
53/// | numRegisteredObservers
54/// | visitObservers
55/// V
56/// ,--------------.
57/// ( ball::Observer )
58/// `--------------'
59/// dtor
60/// publish
61/// releaseRecords
62/// @endcode
63/// `ball::BroadcastObserver` is a concrete class derived from `ball::Observer`
64/// that processes the log records it receives through its `publish` method by
65/// forwarding them to other concrete observers. `ball::BroadcastObserver`
66/// maintains a registry of named observers to which it forwards log records.
67/// Clients of `ball::BroadcastObserver` register observers using the
68/// `registerObserver` method and unregister observers with the
69/// `deregisterObserver` method. Once registered, an observer receives all log
70/// records that its associated broadcast observer receives.
71///
72/// ## Thread Safety {#ball_broadcastobserver-thread-safety}
73///
74///
75/// `ball::BroadcastObserver` is thread-safe, meaning that multiple threads may
76/// share the same instance, or may have their own instances (see
77/// @ref bsldoc_glossary ).
78///
79/// ## Usage {#ball_broadcastobserver-usage}
80///
81///
82/// In this section we show intended use of this component.
83///
84/// ### Example 1: Delayed Observer Configuration {#ball_broadcastobserver-example-1-delayed-observer-configuration}
85///
86///
87/// In this example, we will show how `ball::BroadcastObserver` can be used to
88/// implement delayed observer configuration.
89///
90/// First, we define an elided custom observer that conforms to the
91/// `ball::Observer` protocol and supports a `configure` method:
92/// @code
93/// class ConfigurableObserver : public ball::Observer {
94/// // DATA
95/// bool d_configureFlag; // configuration completion flag
96///
97/// public:
98/// // CREATORS
99/// ConfigurableObserver() : d_configureFlag(false)
100/// {
101/// }
102///
103/// // MANIPULATORS
104///
105/// // Configure this observer.
106/// void configure() {
107/// d_configureFlag = true;
108/// }
109///
110/// using Observer::publish; // avoid hiding base class method
111///
112/// /// Publish the specified `record` with the specified `context`.
113/// void publish(const bsl::shared_ptr<ball::Record>& record,
114/// const ball::Context& context)
115/// {
116/// // Do not publish any records until configuration has been done.
117/// if (!d_configureFlag) {
118/// return; // RETURN
119/// }
120/// // Publish the record.
121/// // ...
122/// }
123///
124/// // ACCESSORS
125/// bool isConfigured() const
126/// {
127/// return d_configureFlag;
128/// }
129/// };
130/// @endcode
131/// Then, we create a shared pointer to a `ConfigurableObserver` object and
132/// register it with a broadcast observer:
133/// @code
134/// bsl::shared_ptr<ConfigurableObserver>
135/// myObserverPtr(new ConfigurableObserver());
136///
137/// ball::BroadcastObserver broadcastObserver;
138///
139/// int rc = broadcastObserver.registerObserver(myObserver, "observer");
140///
141/// assert(0 == rc);
142/// @endcode
143/// Finally, we can retrieve the registered observer and configure it:
144/// @code
145/// bsl::shared_ptr<ConfigurableObserver> tmpObserverPtr;
146///
147/// rc = broadcastObserver.findObserver(&tmpObserverPtr, "observer");
148///
149/// assert(0 == rc);
150/// assert(myObserverPtr == tmpObserverPtr);
151/// assert(false == tmpObserverPtr->isConfigured());
152///
153/// tmpObserverPtr->configure();
154///
155/// assert(true == tmpObserverPtr->isConfigured());
156/// @endcode
157/// Note that there is an alternative way to obtain a shared pointer to the
158/// registered observer:
159/// @code
160/// bsl::shared_ptr<Observer> oPtr =
161/// broadcastObserver.findObserver("observer");
162///
163/// assert(oPtr.ptr());
164///
165/// bsl::shared_ptr<ConfigurableObserver> anotherObserverPtr;
166///
167/// bslstl::SharedPtrUtil::dynamicCast(&anotherObserverPtr, oPtr);
168///
169/// assert(myObserverPtr == anotherObserverPtr);
170/// @endcode
171/// @}
172/** @} */
173/** @} */
174
175/** @addtogroup bal
176 * @{
177 */
178/** @addtogroup ball
179 * @{
180 */
181/** @addtogroup ball_broadcastobserver
182 * @{
183 */
184
185#include <balscm_version.h>
186
187#include <ball_observer.h>
188
190#include <bdlb_transparenthash.h>
191
192#include <bslma_allocator.h>
193#include <bslma_default.h>
194
195#include <bslmf_enableif.h>
196#include <bslmf_isconvertible.h>
197
199#include <bslmt_readlockguard.h>
200
201#include <bsls_keyword.h>
202
203#include <bsl_memory.h>
204#include <bsl_string.h>
205#include <bsl_unordered_map.h>
206
207
208
209namespace ball {
210
211class Record;
212class Context;
213
214 // =======================
215 // class BroadcastObserver
216 // =======================
217
218/// This class provides a broadcasting implementation of the `Observer`
219/// protocol. Other concrete observers may be registered and named with
220/// this broadcast observer (`registerObserver` method), retrieved
221/// (`findObserver` method), and unregistered (`deregisterObserver` method).
222/// The `publish` method of this class forwards the log records that it
223/// receives to the `publish` method of each registered observer.
224///
225/// See @ref ball_broadcastobserver
227
228 public:
229 // TYPES
230
231 /// This `typedef` is an alias for the type of the registry maintained
232 /// by this observer.
237
238 private:
239 // DATA
240 ObserverRegistry d_observers; // observer registry
241
242 mutable bslmt::ReaderWriterMutex d_rwMutex; // protects concurrent
243 // access to `d_observers`
244
245 // NOT IMPLEMENTED
247 BroadcastObserver& operator=(const BroadcastObserver&);
248
249 public:
250 // CREATORS
251
252 /// Create a broadcast observer having no registered observers.
253 /// Optionally specify a `basicAllocator` used to supply memory. If
254 /// `basicAllocator` is 0, the currently installed default allocator is
255 /// used.
256 explicit BroadcastObserver(bslma::Allocator *basicAllocator = 0);
257
258 /// Destroy this broadcast observer. Note that this method has no
259 /// effect on the lifetime of observers registered with this observer,
260 /// if any.
262
263 // MANIPULATORS
264
265 /// Remove all observers from the registry of this broadcast observer.
267
268 /// Remove the observer having the specified `observerName` from the
269 /// registry of this broadcast observer. Return 0 if the observer
270 /// having `observerName` was successfully deregistered, and a non-zero
271 /// value (with no effect) otherwise. Henceforth, the observer that had
272 /// `observerName` will no longer receive log records from this
273 /// observer.
274 int deregisterObserver(const bsl::string_view& observerName);
275
276 /// Return a shared pointer to the observer having the specified
277 /// `observerName` in the registry of this broadcast observer, and an
278 /// empty shared pointer if there is no such observer otherwise.
280 const bsl::string_view& observerName);
281
282 /// Load into the specified `result` a shared pointer to the observer of
283 /// (template parameter) `t_OBSERVER` type having the specified
284 /// `observerName` in the registry of this broadcast observer, and an
285 /// empty shared pointer if there is no such observer otherwise. Return
286 /// 0 if a non-empty shared pointer was loaded, and a non-zero value
287 /// otherwise. Note that an empty shared pointer will be loaded if
288 /// either no observer having `observerName` is in the registry or the
289 /// observer registered with that name is not of `t_OBSERVER` type.
290 ///
291 /// The implementation is placed here in the class definition to work
292 /// around a Microsoft C++ compiler (version 16) bug where the
293 /// definition cannot be matched to the declaration when an `enable_if`
294 /// is used.
295 template <class t_OBSERVER>
297 bsl::shared_ptr<t_OBSERVER> *result,
298 const bsl::string_view& observerName,
299 typename bsl::enable_if<
300 bsl::is_convertible<t_OBSERVER *, ball::Observer *>::value,
301 void *>::type = 0)
302 {
304 return *result ? 0 : 1;
305 }
306
307 using Observer::publish; // Avoid hiding base class method.
308
309 /// Process the specified log `record` having the specified publishing
310 /// `context` by forwarding `record` and `context` to each of the
311 /// observers registered with this broadcast observer.
313 const Context& context)
315
316 /// Add the specified `observer` with the specified `observerName` to
317 /// the registry of this broadcast observer. Return 0 if `observer` was
318 /// successfully registered, and a non-zero value (with no effect)
319 /// otherwise. Henceforth, this observer will forward each record it
320 /// receives through its `publish` method, including the record's
321 /// context, to the `publish` method of `observer`, until `observer` is
322 /// deregistered. The behavior is undefined if a cyclic reference is
323 /// created among registered observers. Note that this method will fail
324 /// if an observer having `observerName` is already registered.
326 const bsl::string_view& observerName);
327
328 /// Discard any shared reference to a `Record` object that was supplied
329 /// to the `publish` method, and is held by this observer. This
330 /// implementation processes `releaseRecords` by calling
331 /// `releaseRecords` on each of the registered observers. Note that
332 /// this operation should be called if resources underlying the
333 /// previously provided shared pointers must be released.
335
336 /// Invoke the specified `visitor` functor of (template parameter)
337 /// `t_VISITOR` type on each element in the registry of this broadcast
338 /// observer, supplying that functor modifiable access to each observer.
339 /// `visitor` must be a functor that can be called as if it had the
340 /// following signature:
341 /// @code
342 /// void operator()(const bsl::shared_ptr<Observer>& observer,
343 /// const bsl::string_view& observerName);
344 /// @endcode
345 template <class t_VISITOR>
346 void visitObservers(t_VISITOR& visitor);
347
348 // ACCESSORS
349
350 /// Return a shared pointer to the observer having the specified
351 /// `observerName` in the registry of this broadcast observer, and an
352 /// empty shared pointer if there is no such observer otherwise.
353 bsl::shared_ptr<const Observer> findObserver(
354 const bsl::string_view& observerName) const;
355
356 /// Load into the specified `result` a shared pointer to the observer of
357 /// (template parameter) `t_OBSERVER` type having the specified
358 /// `observerName` in the registry of this broadcast observer, and an
359 /// empty shared pointer if there is no such observer otherwise. Return
360 /// 0 if a non-empty shared pointer was loaded, and a non-zero value
361 /// otherwise. Note that an empty shared pointer will be loaded if
362 /// either no observer having `observerName` is in the registry or the
363 /// observer registered with that name is not of `t_OBSERVER` type.
364 ///
365 /// The implementation is placed here in the class definition to work
366 /// around a Microsoft C++ compiler (version 16) bug where the
367 /// definition cannot be matched to the declaration when an `enable_if`
368 /// is used.
369 template <class t_OBSERVER>
370 int findObserver(bsl::shared_ptr<const t_OBSERVER> *result,
371 const bsl::string_view& observerName,
372 typename bsl::enable_if<
373 bsl::is_convertible<const t_OBSERVER *,
374 const ball::Observer *>::value,
375 void *>::type = 0) const
376 {
378 return *result ? 0 : 1;
379 }
380
381 /// Return the number of observers registered with this broadcast
382 /// observer.
383 int numRegisteredObservers() const;
384
385 /// Invoke the specified `visitor` functor of (template parameter)
386 /// `t_VISITOR` type on each element in the registry of this broadcast
387 /// observer, supplying that functor modifiable access to each observer.
388 /// `visitor` must be a functor that can be called as if it had the
389 /// following signature:
390 /// @code
391 /// void operator()(const bsl::shared_ptr<Observer>& observer,
392 /// const bsl::string_view& observerName);
393 /// @endcode
394 template <class t_VISITOR>
395 void visitObservers(const t_VISITOR& visitor) const;
396};
397
398// ============================================================================
399// INLINE DEFINITIONS
400// ============================================================================
401
402 // -----------------------
403 // class BroadcastObserver
404 // -----------------------
405
406// CREATORS
407inline
408BroadcastObserver::BroadcastObserver(bslma::Allocator *basicAllocator)
409: d_observers(bslma::Default::allocator(basicAllocator))
410{
411}
412
413// MANIPULATORS
414template <class t_VISITOR>
415inline
416void BroadcastObserver::visitObservers(t_VISITOR& visitor)
417{
419
420 for (ObserverRegistry::const_iterator it = d_observers.cbegin();
421 it != d_observers.cend();
422 ++it) {
423 visitor(it->second, it->first);
424 }
425}
426
427// ACCESSORS
428inline
430{
432
433 return static_cast<int>(d_observers.size());
434}
435
436template <class t_VISITOR>
437inline
438void BroadcastObserver::visitObservers(const t_VISITOR& visitor) const
439{
441
442 for (ObserverRegistry::const_iterator it = d_observers.cbegin();
443 it != d_observers.cend();
444 ++it) {
445 visitor(it->second, it->first);
446 }
447}
448
449} // close package namespace
450
451
452#endif
453
454// ----------------------------------------------------------------------------
455// Copyright 2017 Bloomberg Finance L.P.
456//
457// Licensed under the Apache License, Version 2.0 (the "License");
458// you may not use this file except in compliance with the License.
459// You may obtain a copy of the License at
460//
461// http://www.apache.org/licenses/LICENSE-2.0
462//
463// Unless required by applicable law or agreed to in writing, software
464// distributed under the License is distributed on an "AS IS" BASIS,
465// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
466// See the License for the specific language governing permissions and
467// limitations under the License.
468// ----------------------------- END-OF-FILE ----------------------------------
469
470/** @} */
471/** @} */
472/** @} */
Definition ball_broadcastobserver.h:226
void visitObservers(t_VISITOR &visitor)
Definition ball_broadcastobserver.h:416
bsl::unordered_map< bsl::string, bsl::shared_ptr< Observer >, bdlb::TransparentHash, bdlb::TransparentEqualTo > ObserverRegistry
Definition ball_broadcastobserver.h:236
int registerObserver(const bsl::shared_ptr< Observer > &observer, const bsl::string_view &observerName)
int deregisterObserver(const bsl::string_view &observerName)
bsl::shared_ptr< Observer > findObserver(const bsl::string_view &observerName)
~BroadcastObserver() BSLS_KEYWORD_OVERRIDE
void publish(const bsl::shared_ptr< const Record > &record, const Context &context) BSLS_KEYWORD_OVERRIDE
void deregisterAllObservers()
Remove all observers from the registry of this broadcast observer.
int numRegisteredObservers() const
Definition ball_broadcastobserver.h:429
void releaseRecords() BSLS_KEYWORD_OVERRIDE
Definition ball_context.h:295
Definition ball_observer.h:235
virtual void publish(const Record &record, const Context &context)
Definition bslstl_stringview.h:441
Definition bslstl_sharedptr.h:1830
Definition bslstl_unorderedmap.h:1089
const_iterator cbegin() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_unorderedmap.h:3350
size_type size() const BSLS_KEYWORD_NOEXCEPT
Return the number of elements in this unordered map.
Definition bslstl_unorderedmap.h:3544
const_iterator cend() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_unorderedmap.h:3359
BloombergLP::bslstl::HashTableIterator< const value_type, difference_type > const_iterator
Definition bslstl_unorderedmap.h:1160
Definition bslma_allocator.h:457
Definition bslmt_readlockguard.h:287
Definition bslmt_readerwritermutex.h:244
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:653
Definition ball_administration.h:214
Definition bdlb_printmethods.h:283
basic_string< char > string
Definition bslstl_string.h:782
Definition balxml_encoderoptions.h:68
Definition bdlb_transparentequalto.h:124
Definition bdlb_transparenthash.h:158
static void dynamicCast(bsl::shared_ptr< TARGET > *target, const bsl::shared_ptr< SOURCE > &source)
Definition bslstl_sharedptr.h:6111