BDE 4.39.x 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 private:
246 // NOT IMPLEMENTED
248 BroadcastObserver& operator=(const BroadcastObserver&);
249
250 public:
251 // CREATORS
252
253 /// Create a broadcast observer having no registered observers.
254 /// Optionally specify a `basicAllocator` used to supply memory. If
255 /// `basicAllocator` is 0, the currently installed default allocator is
256 /// used.
257 explicit BroadcastObserver(bslma::Allocator *basicAllocator = 0);
258
259 /// Destroy this broadcast observer.
260 /// \note Note that this method has no
261 /// effect on the lifetime of observers registered with this observer,
262 /// if any.
264
265 // MANIPULATORS
266
267 /// Remove all observers from the registry of this broadcast observer.
269
270 /// Remove the observer having the specified `observerName` from the
271 /// registry of this broadcast observer. Return 0 if the observer
272 /// having `observerName` was successfully deregistered, and a non-zero
273 /// value (with no effect) otherwise. Henceforth, the observer that had
274 /// `observerName` will no longer receive log records from this
275 /// observer.
276 int deregisterObserver(const bsl::string_view& observerName);
277
278 /// Return a shared pointer to the observer having the specified
279 /// `observerName` in the registry of this broadcast observer, and an
280 /// empty shared pointer if there is no such observer otherwise.
282 const bsl::string_view& observerName);
283
284 /// Load into the specified `result` a shared pointer to the observer of
285 /// (template parameter) `t_OBSERVER` type having the specified
286 /// `observerName` in the registry of this broadcast observer, and an
287 /// empty shared pointer if there is no such observer otherwise. Return
288 /// 0 if a non-empty shared pointer was loaded, and a non-zero value otherwise.
289 ///
290 /// \note Note that an empty shared pointer will be loaded if
291 /// either no observer having `observerName` is in the registry or the
292 /// observer registered with that name is not of `t_OBSERVER` type.
293 ///
294 /// The implementation is placed here in the class definition to work
295 /// around a Microsoft C++ compiler (version 16) bug where the
296 /// definition cannot be matched to the declaration when an `enable_if`
297 /// is used.
298 template <class t_OBSERVER>
300 bsl::shared_ptr<t_OBSERVER> *result,
301 const bsl::string_view& observerName,
302 typename bsl::enable_if<
303 bsl::is_convertible<t_OBSERVER *, ball::Observer *>::value,
304 void *>::type = 0)
305 {
307 return *result ? 0 : 1;
308 }
309
310 using Observer::publish; // Avoid hiding base class method.
311
312 /// Process the specified log `record` having the specified publishing
313 /// `context` by forwarding `record` and `context` to each of the
314 /// observers registered with this broadcast observer.
316 const Context& context)
318
319 /// Add the specified `observer` with the specified `observerName` to
320 /// the registry of this broadcast observer. Return 0 if `observer` was
321 /// successfully registered, and a non-zero value (with no effect)
322 /// otherwise. Henceforth, this observer will forward each record it
323 /// receives through its `publish` method, including the record's
324 /// context, to the `publish` method of `observer`, until `observer` is deregistered.
325 ///
326 /// \pre The behavior is undefined if a cyclic reference is created among registered observers.
327 ///
328 /// \note Note that this method will fail
329 /// if an observer having `observerName` is already registered.
331 const bsl::string_view& observerName);
332
333 /// Discard any shared reference to a `Record` object that was supplied
334 /// to the `publish` method, and is held by this observer. This
335 /// implementation processes `releaseRecords` by calling
336 /// `releaseRecords` on each of the registered observers.
337 ///
338 /// \note Note that this operation should be called if resources underlying the
339 /// previously provided shared pointers must be released.
341
342 /// Invoke the specified `visitor` functor of (template parameter)
343 /// `t_VISITOR` type on each element in the registry of this broadcast
344 /// observer, supplying that functor modifiable access to each observer.
345 /// `visitor` must be a functor that can be called as if it had the
346 /// following signature:
347 /// @code
348 /// void operator()(const bsl::shared_ptr<Observer>& observer,
349 /// const bsl::string_view& observerName);
350 /// @endcode
351 template <class t_VISITOR>
352 void visitObservers(t_VISITOR& visitor);
353
354 // ACCESSORS
355
356 /// Return a shared pointer to the observer having the specified
357 /// `observerName` in the registry of this broadcast observer, and an
358 /// empty shared pointer if there is no such observer otherwise.
359 bsl::shared_ptr<const Observer> findObserver(
360 const bsl::string_view& observerName) const;
361
362 /// Load into the specified `result` a shared pointer to the observer of
363 /// (template parameter) `t_OBSERVER` type having the specified
364 /// `observerName` in the registry of this broadcast observer, and an
365 /// empty shared pointer if there is no such observer otherwise. Return
366 /// 0 if a non-empty shared pointer was loaded, and a non-zero value otherwise.
367 ///
368 /// \note Note that an empty shared pointer will be loaded if
369 /// either no observer having `observerName` is in the registry or the
370 /// observer registered with that name is not of `t_OBSERVER` type.
371 ///
372 /// The implementation is placed here in the class definition to work
373 /// around a Microsoft C++ compiler (version 16) bug where the
374 /// definition cannot be matched to the declaration when an `enable_if`
375 /// is used.
376 template <class t_OBSERVER>
377 int findObserver(bsl::shared_ptr<const t_OBSERVER> *result,
378 const bsl::string_view& observerName,
379 typename bsl::enable_if<
380 bsl::is_convertible<const t_OBSERVER *,
381 const ball::Observer *>::value,
382 void *>::type = 0) const
383 {
385 return *result ? 0 : 1;
386 }
387
388 /// Return the number of observers registered with this broadcast
389 /// observer.
390 int numRegisteredObservers() const;
391
392 /// Invoke the specified `visitor` functor of (template parameter)
393 /// `t_VISITOR` type on each element in the registry of this broadcast
394 /// observer, supplying that functor modifiable access to each observer.
395 /// `visitor` must be a functor that can be called as if it had the
396 /// following signature:
397 /// @code
398 /// void operator()(const bsl::shared_ptr<Observer>& observer,
399 /// const bsl::string_view& observerName);
400 /// @endcode
401 template <class t_VISITOR>
402 void visitObservers(const t_VISITOR& visitor) const;
403};
404
405// ============================================================================
406// INLINE DEFINITIONS
407// ============================================================================
408
409 // -----------------------
410 // class BroadcastObserver
411 // -----------------------
412
413// CREATORS
414inline
415BroadcastObserver::BroadcastObserver(bslma::Allocator *basicAllocator)
416: d_observers(bslma::Default::allocator(basicAllocator))
417{
418}
419
420// MANIPULATORS
421template <class t_VISITOR>
422inline
423void BroadcastObserver::visitObservers(t_VISITOR& visitor)
424{
426
427 for (ObserverRegistry::const_iterator it = d_observers.cbegin();
428 it != d_observers.cend();
429 ++it) {
430 visitor(it->second, it->first);
431 }
432}
433
434// ACCESSORS
435inline
437{
439
440 return static_cast<int>(d_observers.size());
441}
442
443template <class t_VISITOR>
444inline
445void BroadcastObserver::visitObservers(const t_VISITOR& visitor) const
446{
448
449 for (ObserverRegistry::const_iterator it = d_observers.cbegin();
450 it != d_observers.cend();
451 ++it) {
452 visitor(it->second, it->first);
453 }
454}
455
456} // close package namespace
457
458
459#endif
460
461// ----------------------------------------------------------------------------
462// Copyright 2017 Bloomberg Finance L.P.
463//
464// Licensed under the Apache License, Version 2.0 (the "License");
465// you may not use this file except in compliance with the License.
466// You may obtain a copy of the License at
467//
468// http://www.apache.org/licenses/LICENSE-2.0
469//
470// Unless required by applicable law or agreed to in writing, software
471// distributed under the License is distributed on an "AS IS" BASIS,
472// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
473// See the License for the specific language governing permissions and
474// limitations under the License.
475// ----------------------------- END-OF-FILE ----------------------------------
476
477/** @} */
478/** @} */
479/** @} */
Definition ball_broadcastobserver.h:226
void visitObservers(t_VISITOR &visitor)
Definition ball_broadcastobserver.h:423
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:436
void releaseRecords() BSLS_KEYWORD_OVERRIDE
Definition ball_context.h:297
Definition ball_observer.h:235
virtual void publish(const Record &record, const Context &context)
Definition bslstl_stringview.h:471
Definition bslstl_sharedptr.h:1838
Definition bslstl_unorderedmap.h:1123
const_iterator cbegin() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_unorderedmap.h:3886
size_type size() const BSLS_KEYWORD_NOEXCEPT
Return the number of elements in this unordered map.
Definition bslstl_unorderedmap.h:4078
const_iterator cend() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_unorderedmap.h:3895
BloombergLP::bslstl::HashTableIterator< const value_type, difference_type > const_iterator
Definition bslstl_unorderedmap.h:1235
Definition bslma_allocator.h:545
Definition bslmt_readlockguard.h:287
Definition bslmt_readerwritermutex.h:244
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:695
Definition ball_administration.h:214
Definition bdlat_valuetypefunctions.h:939
basic_string< char > string
Definition bslstl_string.h:844
Definition baljsn_encoder_testtypes.h:76
Definition bdlb_transparentequalto.h:127
Definition bdlb_transparenthash.h:167
static void dynamicCast(bsl::shared_ptr< TARGET > *target, const bsl::shared_ptr< SOURCE > &source)
Definition bslstl_sharedptr.h:6186