// ball_observer.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_OBSERVER
#define INCLUDED_BALL_OBSERVER

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

//@PURPOSE: Define a protocol for receiving and processing log records.
//
//@CLASSES:
//  ball::Observer: protocol class for receiving and processing log records
//
//@SEE_ALSO: ball_record, ball_loggermanager
//
//@DESCRIPTION: This component defines the base-level protocol,
// 'ball::Observer', for receiving and processing log records.  Concrete types
// derived from this protocol, receive log records, and process them in a
// manner defined by the derived class author.
//
///Usage
///-----
// This example shows the definition and use of a simple concrete observer that
// writes three of the log record's fields, timestamp, process ID, and thread
// ID, to an 'ostream' that is provided to the observer at construction.  This
// (trivial) functionality suffices to demonstrate the requisite steps for
// having a working observer:
//
//: 1 Define a concrete class derived from 'ball::Observer'.
//: 2 Implement the pure virtual 'publish' method.
//: 3 Instantiate and use an object of the concrete type.
//
// Note that the "publish attributes" object provided to the 'publish' method
// indicates, among other properties, whether the log record to be published is
// a "solo" message or whether it is one of a sequence.  In general, a useful
// observer object should incorporate the attributes information as part of
// the "publication" of the log record.  In this example, the attributes
// information is used to generate an appropriate heading for each log record
// that is printed to the observer's 'ostream'.
//
// We first define the (derived) 'my_OstreamObserver' class and implement its
// simple constructor inline (for convenience, directly within the
// derived-class definition):
//..
//     // my_ostreamobserver.h
//
//     class my_OstreamObserver : public ball::Observer {
//         ostream& d_stream;
//
//       public:
//         my_OstreamObserver(ostream& stream) : d_stream(stream) { }
//         virtual ~my_OstreamObserver();
//         virtual void publish(const ball::Record&  record,
//                              const ball::Context& context);
//     };
//..
// Note, however, that we always implement a virtual destructor (non-inline)
// in the .cpp file (to indicate the *unique* location of the class's virtual
// table):
//..
//     // my_ostreamobserver.cpp
//
//     // ...
//
//     my_OstreamObserver::~my_OstreamObserver() { }
//..
// We next implement the (virtual) 'publish' method, which incorporates the
// "policy" of what it means for this observer to "publish" a log record.  In
// this example, the policy is that three log record fields are written to an
// 'ostream', along with an appropriate heading, and the rest of the log record
// is ignored.  Note that, in this implementation, the zero-based 'index'
// attribute is incremented by one before it is written, which produces a more
// natural record count:
//..
//     // my_ostreamobserver.cpp
//
//     // ...
//
//     my_OstreamObserver::~my_OstreamObserver() { }
//
//     void my_OstreamObserver::publish(const ball::Record&  record,
//                                      const ball::Context& context)
//     {
//         using namespace std;
//
//         d_stream << endl;  // skip a line
//
//         switch (context.transmissionCause()) {
//           case ball::Transmission::PASSTHROUGH: {
//             d_stream << "Single Pass-through Message:" << endl;
//           } break;
//           case ball::Transmission::TRIGGER_ALL: {
//             d_stream << "Remotely ";      // no 'break'; concatenated output
//           }
//           case ball::Transmission::TRIGGER: {
//             d_stream << "Triggered Publication Sequence: Message "
//                      << context.recordIndex() + 1  // Account for 0-based
//                                                    // index.
//                      << " of " << context.sequenceLength()
//                      << ':' << endl;
//           } break;
//           default: {
//             d_stream << "***ERROR*** Unknown Message Cause:" << endl;
//             return;
//           } break;
//         }
//
//         d_stream << "\tTimestamp:  " << record.fixedFields().timestamp()
//                  << endl;
//         d_stream << "\tProcess ID: " << record.fixedFields().processID()
//                  << endl;
//         d_stream << "\tThread ID:  " << record.fixedFields().threadID()
//                  << endl;
//     }
//..
// We now want to use the 'my_OstreamObserver' object and its 'publish' method;
// we illustrate this use in the body of the otherwise-unrealistic function
// 'recordPublisher', which generates the relevant fields of four dummy
// records.  The first record is published singly (i.e., as a "Pass-through"
// record).  Note that we call the observer's 'publish' method with a
// 'ball::Context' object appropriately initialized for a "Pass-through".  The
// last three records are published as a sequence of "Triggered" records.  Note
// that, in the sequenced output, the 'publish' method is called with a
// zero-based 'index' attribute; in this example, the 'publish' implementation
// will print a natural-number message count equal to index + 1:
//..
//     void recordPublisher()
//     {
//         my_OstreamObserver     myObserver(bsl::cout);
//         bdlt::Datetime         now;
//         ball::RecordAttributes fixed;
//         ball::UserFields       emptyList;
//
//         bdlt::EpochUtil::convertFromTimeT(&now, time(0));
//         fixed.setTimestamp(now);
//         fixed.setProcessID(100);
//         fixed.setThreadID(0);
//         myObserver.publish(ball::Record(fixed, emptyList),
//                            ball::Context(ball::Transmission::PASSTHROUGH,
//                                         0,
//                                         1));
//
//         const int NUM_MESSAGES = 3;
//         for (int n = 0; n < NUM_MESSAGES; ++n) {
//             bdlt::EpochUtil::convertFromTimeT(&now, time(0));
//             fixed.setTimestamp(now);
//             fixed.setProcessID(201 + n);
//             fixed.setThreadID(31 + n);
//             myObserver.publish(ball::Record(fixed, emptyList),
//                                ball::Context(ball::Transmission::TRIGGER,
//                                             n,
//                                             NUM_MESSAGES));
//         }
//     }
//..
// 'recordPublisher', when invoked, prints the following to 'stdout':
//..
//     Single Pass-through Message:
//             Timestamp:  15JAN2004_23:12:59.000
//             Process ID: 100
//             Thread ID:  0
//
//     Triggered Publication Sequence: Message 1 of 3:
//             Timestamp:  15JAN2004_23:12:59.000
//             Process ID: 201
//             Thread ID:  31
//
//     Triggered Publication Sequence: Message 2 of 3:
//             Timestamp:  15JAN2004_23:12:59.000
//             Process ID: 202
//             Thread ID:  32
//
//     Triggered Publication Sequence: Message 3 of 3:
//             Timestamp:  15JAN2004_23:12:59.000
//             Process ID: 203
//             Thread ID:  33
//..

#include <balscm_version.h>

#include <bsl_memory.h>

namespace BloombergLP {
namespace ball {

class Record;
class Context;

                         // ==============
                         // class Observer
                         // ==============

class Observer {
    // This class provides a protocol for receiving and processing log record
    // output.

  public:
    // CREATORS
    virtual ~Observer();
        // Destroy this observer.

    // MANIPULATORS
    virtual void publish(const Record& record, const Context& context);
        // Process the specified log 'record' having the specified publishing
        // 'context'.
        //
        // !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'.  The exact definition of publish depends on the
        // implementing class, though the intention is that the log 'record'
        // (whose publication has occurred according to 'context') be
        // distributed in a human or machine readable form.

    virtual void releaseRecords();
        // Discard any shared references to 'Record' objects that were supplied
        // to the 'publish' method, and are held by this observer.  Note that
        // this operation should be called if resources underlying the
        // previously provided shared pointers must be released.
};

}  // 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 ----------------------------------