// ball_multiplexobserver.h                                           -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#ifndef INCLUDED_BALL_MULTIPLEXOBSERVER
#define INCLUDED_BALL_MULTIPLEXOBSERVER

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a multiplexing observer that forwards to other observers.
//
//@DEPRECATED: Use 'ball_broadcastobserver' instead.
//
//@CLASSES:
//  ball::MultiplexObserver: multiplexing observer that forwards log records
//
//@SEE_ALSO: ball_record, ball_context, ball_streamobserver, ball_loggermanager
//
//@DESCRIPTION: This component provides a concrete implementation of the
// 'ball::Observer' protocol for receiving and processing log records:
//..
//               ( ball::MultiplexObserver )
//                            |             ctor
//                            |             registerObserver
//                            |             deregisterObserver
//                            |             numRegisteredObservers
//                            V
//                    ( ball::Observer )
//                                          dtor
//                                          publish
//                                          releaseRecords
//..
// 'ball::MultiplexObserver' is a concrete class derived from 'ball::Observer'
// that processes the log records it receives through its 'publish' method by
// forwarding them to other concrete observers.  'ball::MultiplexObserver'
// maintains a registry of observers to which it forwards log records.  Clients
// of 'ball::MultiplexObserver' register observers using the 'registerObserver'
// method and unregister observers with the 'deregisterObserver' method.  Once
// registered, an observer receives all log records that its associated
// multiplexing observer receives.
//
///Thread Safety
///-------------
// 'ball::MultiplexObserver' is thread-safe and thread-enabled, meaning that
// multiple threads may share the same instance, or may have their own
// instances.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example: Basic Usage
/// - - - - - - - - - -
// Note: This usage example retained here for reference purposes for legacy
// code that still uses multiplex observers.  The use of this component is
// strongly discouraged.
//
// Multiplexing observers are used to interface a 'ball' logging system, which
// generates log records, with the multiplicity of observers that are to
// receive the generated records that are published.  Establishing this
// interface proceeds in three logical steps:
//..
//    (1) Create a distinguished 'ball::MultiplexObserver' that will be the
//        unique observer to receive log records directly from the logging
//        system.
//    (2) Create the other observers required by the application and register
//        each of these observers with some 'ball::MultiplexObserver'.  (Note
//        that a 'ball::MultiplexObserver' may be registered with another
//        'ball::MultiplexObserver'.)
//    (3) Install the distinguished multiplexor from step (1) within the
//        'ball' logging system.
//..
// This example demonstrates the use of a multiplexing observer to forward log
// records from a 'ball' logging system to three registered observers.  Each of
// the three registered observers performs distinct actions upon receipt of log
// records:
//..
//    (1) 'defaultObserver', an instance of 'ball::StreamObserver', formats
//        the records it receives and outputs them to 'stdout'.
//    (2) 'logfileObserver', an instance of 'my_LogfileObserver' (assumed to
//        be a concrete class derived from 'ball::Observer') writes selected
//        records to a log file.
//    (3) 'encryptingObserver', an instance of 'my_EncryptingObserver' (also
//        assumed to be a concrete class derived from 'ball::Observer') creates
//        a compact, encrypted representation of each record, suitable for
//        sending over an unsecure network.
//..
// First, we create the three downstream observers that will be registered with
// multiplexor observer:
//..
//     ball::StreamObserver   defaultObserver(&bsl::cout);
//     my_LogfileObserver     logfileObserver(&bsl::cout);
//     my_EncryptingObserver  encryptingObserver(&bsl::cout);
//..
// Next, we create an initially empty multiplexing observer 'multiplexor' and
// register the three downstream observers 'multiplexor':
//..
//     ball::MultiplexObserver multiplexor;
//     assert(0 == multiplexor.numRegisteredObservers());
//
//     multiplexor.registerObserver(&defaultObserver);
//     multiplexor.registerObserver(&logfileObserver);
//     multiplexor.registerObserver(&encryptingObserver);
//     assert(3 == multiplexor.numRegisteredObservers());
//..
// Then, 'multiplexor' is installed within a 'ball' logging system to be the
// direct recipient of published log records.  The code uses deprecated
// 'ball::LoggerManager' API and is elided.
//
// Henceforth, all log records that are published by the logging system will be
// transmitted to the 'publish' method of 'multiplexor' which, in turn,
// forwards them to 'defaultObserver', 'logfileObserver', and
// 'encryptingObserver' by calling their respective 'publish' methods.
//
// Finally, deregister the three observers when the logs have been all
// forwarded:
//..
//     multiplexor.deregisterObserver(&defaultObserver);
//     multiplexor.deregisterObserver(&logfileObserver);
//     multiplexor.deregisterObserver(&encryptingObserver);
//..
// Note that any observer must exist before registering with multiplexor.  Any
// observer already registered must deregister before its destruction.
// Additional observers may be registered with 'multiplexor' at any time.
// Similarly, observers may be unregistered at any time.  This capability
// allows for extremely flexible observation scenarios.

#include <balscm_version.h>

#include <ball_observer.h>

#include <bslma_allocator.h>

#include <bslmt_readlockguard.h>
#include <bslmt_rwmutex.h>
#include <bslmt_writelockguard.h>

#include <bsl_memory.h>
#include <bsl_set.h>
#include <bsl_vector.h>

namespace BloombergLP {
namespace ball {

class Record;
class Context;

                         // =======================
                         // class MultiplexObserver
                         // =======================

class MultiplexObserver : public Observer {
    // This class provides a multiplexing implementation of the 'Observer'
    // protocol.  Other concrete observers may be registered with a
    // multiplexing observer ('registerObserver' method) and later unregistered
    // ('deregisterObserver' method).  The 'publish' method of this class
    // forwards the log records that it receives to the 'publish' method of
    // each registered observer.

    // DATA
    bsl::set<Observer *>   d_observerSet;  // observer registry

    mutable bslmt::RWMutex d_rwMutex;      // protects concurrent access to
                                           // 'd_observerSet'

    // NOT IMPLEMENTED
    MultiplexObserver(const MultiplexObserver&);
    MultiplexObserver& operator=(const MultiplexObserver&);

  public:
    // CREATORS
    explicit MultiplexObserver(bslma::Allocator *basicAllocator = 0);
        // Create a multiplexing observer having no registered observers.
        // Optionally specify a 'basicAllocator' used to supply memory.  If
        // 'basicAllocator' is 0, the currently installed default allocator is
        // used.

    virtual ~MultiplexObserver();
        // Destroy this multiplexing observer.  Note that this method has no
        // effect on the lifetime of observers registered with this observer,
        // if any.

    // MANIPULATORS
    virtual void publish(const Record& record, const Context& context);
        // Process the specified log 'record' having the specified publishing
        // 'context' by forwarding 'record' and 'context' to each of the
        // observers registered with this multiplexing observer.
        //
        // !DEPRECATED!: Use the alternative 'publish' overload instead.

    virtual void publish(const bsl::shared_ptr<const Record>& record,
                         const Context&                       context);
        // Process the specified log 'record' having the specified publishing
        // 'context'.  This concrete publish implementations processes the
        // 'record' by forwarding 'record' and 'context' to each of the
        // observers registered with this multiplexing observer.

    virtual void releaseRecords();
        // Discard any shared reference to a 'Record' object that was supplied
        // to the 'publish' method, and is held by this observer.  This
        // implementation processes 'releaseRecords' by calling
        // 'releaseRecords' on each of the registered observers.  Note that
        // this operation should be called if resources underlying the
        // previously provided shared pointers must be released.

    int registerObserver(Observer *observer);
        // Add the specified 'observer' to the registry of this multiplexing
        // observer.  Return 0 if 'observer' is non-null and was not already
        // registered with this multiplexing observer, and a non-zero value
        // (with no effect) otherwise.  Henceforth, this multiplexing observer
        // will forward each record it receives through its 'publish' method,
        // including the record's context, to the 'publish' method of
        // 'observer', until 'observer' is deregistered.  The behavior is
        // undefined unless 'observer' remains valid until it is deregistered
        // from this multiplexing observer or until this observer is destroyed.

    int deregisterObserver(Observer *observer);
        // Remove the specified 'observer' from the registry of this
        // multiplexing observer.  Return 0 if 'observer' is non-null and was
        // registered with this multiplexing observer, and a non-zero value
        // (with no effect) otherwise.  Henceforth, 'observer' will no longer
        // receive log records from this multiplexing observer.

    // ACCESSORS
    int numRegisteredObservers() const;
        // Return the number of observers registered with this multiplexing
        // observer.
};

// ============================================================================
//                              INLINE DEFINITIONS
// ============================================================================

                         // -----------------------
                         // class MultiplexObserver
                         // -----------------------

// CREATORS
inline
MultiplexObserver::MultiplexObserver(bslma::Allocator *basicAllocator)
: d_observerSet(basicAllocator)
{
}

// ACCESSORS
inline
int MultiplexObserver::numRegisteredObservers() const
{
    bslmt::ReadLockGuard<bslmt::RWMutex> guard(&d_rwMutex);
    return static_cast<int>(d_observerSet.size());
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------