$Date: 2004/06/28 11:58:13 $ |
IMessageSvc
Abstract Base Class(ABC) defining the Message Service component interface.
MessageSvc
A concrete Message service component implementation should inherit from IMessageSvc
interface and Service class.
Since IMessageSvc interface contains redundant IInterface related methods, for example:
virtual unsigned long addRef() = 0; virtual unsigned long release() = 0; |
MsgStream
MsgStream class is used to transmit messages.
This class is intended to ease the use of error logging to the Message service.
It basically performs a role of buffered formatter which, once a message is ready, flushes its stream buffer to a Message service instance.
In the current design it depends on a concrete implementation of IMessageSvc interface,
e.g. an instance of a MessageSvc class.
// MessageSvc implementation, taken from testing code class MessageSvc : public IMessageSvc, public Service { public: MessageSvc(); virtual ~MessageSvc(); /// Query interface call virtual Status queryInterface(const InterfaceID& riid, void** ppvIface) { return Service::queryInterface(riid, ppvIface); }// Mandatory (redundant) implementation of IInterface methods /// Increment the reference count of the Interface instance. virtual unsigned long addRef() { return Service::addRef(); } /// Decrement reference count and release Interface instance when reference count=0. virtual unsigned long release() { return Service::release(); }// IMessageSvc specific interface /// Report a message by specifying the source, severity level and text. virtual void reportMessage( const std::string& source, int type, const std::string& message = "" ); /// Retrieve the current output level threshold for a given message source virtual int outputLevel( const std::string& source ) const; /// Set new output level threshold for a given message source virtual void setOutputLevel( const std::string& source, int new_level); }; |
// Client code seal::MessageSvc msg("MessageSvc",0); seal::MsgStream log(&msg, "Hello"); log << seal::MSG::ALWAYS; log << line << line << line << seal::endmsg << "This is a " << seal::endmsg << "message, which " << seal::endmsg << "spans over several lines." << seal::endmsg; |
Legend: green - standard C++ classes, pink - SEAL classes, bisque - user classes
IMessageSvc
Abstract Base Class(ABC) defining the Message Service component interface. It is assumed that IInterface artifacts are removed,
because they can be inherited from the Service class.
MessageSvc
Message service component implementation now inherits from IMessageSvc interface and Service class.
It does not enforce now the IInterface related stuff. The only thing that has to be taken care of is IID(Interface ID)
and this can be done by overriding of the queryInterface(...) method.
Having this, clients don't have to touch IInterface stuff in the future. If this need arise, one can still do subclassing and
overriding.
This design applies the policy based C++ design. There are two configurable aspects. One is the choice of the output stream class.
Having this as the template argument gives user a choice to select an output stream according to his/her needs.
It does not prevent SEAL from having a Message service default implementation. An example will be shown bellow.
The second aspect is the act of actual reporting facility. In POOL it's the only reason to customize Message service component.
Only the reportMessage(...) method is overriden. By having the second template argument this is turned into a compile time option
without an immediate need for subclassing.
Reporter
The Reporter class is forseen to be a very simple function object with only one method required and this is
overloaded operator (). The default Message service implementation then needs only to call this function object each time
invoked by MsgStream object. The Reporter class may receive one template argument too if there is a need to unify it with the
OutStream template argument of the MessageSvc class.
MsgStream
The role of this class remains the same as in the original design.
User can provide, of course, his/her own version of a MsgStream. That's why on the picture above is in mixed colors.
// Default MessageSvc Reporter implementation template < class OutStream > class Reporter { public: Reporter( const OutStream& os ) : m_os( os ) { } virtual ~Reporter() { } void operator() (const std::string& source, int type, const std::string& message = "") { os << "Reporting...\n"; } protected: const OutStream& m_os; }; |
// Default MessageSvc Reporter specialization template <> class Reporter< std::ostream > { public: Reporter( std::ostream& os = std::cout ) { } virtual ~Reporter() { } void operator() (const std::string& source, int type, const std::string& message = "") { std::cout << "Reporting to cout..." << std::endl; } }; |
// Default MessageSvc implementation template < class OutStream, class MsgReporter = seal::Reporter< OutStream > > class MessageSvcImpl : public IMessageSvc, public Service { public: typedef OutStream Stream; typedef MsgReporter Reporter; public: MessageSvcImpl( Stream& os, Reporter* reporter = 0 ) : m_os( os ), m_reporter( reporter ) { if( !reporter ) { m_reporter = new Reporter(); } } virtual ~MessageSvcImpl() { delete m_reporter; } /// Report a message by specifying the source, severity level and text. virtual void reportMessage( const std::string& source, int type, const std::string& message = "" ) { (*m_reporter)( source, type, message ); } /// Retrieve the current output level threshold for a given message source virtual int outputLevel( const std::string& source ) const; /// Set new output level threshold for a given message source virtual void setOutputLevel( const std::string& source, int new_level); private: MessageSvcImpl(); protected: Stream& m_os; Reporter* m_reporter; }; /// The resulting types for user consuption typedef MessageSvcImpl< std::ostream > MessageSvc; typedef MessageSvc::Stream MessageStream; typedef MessageSvc::Reporter MessageReporter; |
// Client code using default implementation seal::MessageSvc msg( std::cout ); seal::MsgStream log(&msg, "Hello"); log << seal::MSG::ALWAYS; log << line << line << line << seal::endmsg << "This is a " << seal::endmsg << "message, which " << seal::endmsg << "spans over several lines." << seal::endmsg; |
// Client code using default implementation with his/her own Reporter class MyReporter : seal::MessageReporter { public: MyReporter() {} virtual ~MyReporter() {} void operator() (const std::string& source, int type, const std::string& message = "") { // My fancy reporter m_os << "=============== Fancy header ==================" << std::endl; m_os << message << std::endl; } }; seal::MessageSvc msg( std::cout, new MyReporter() ); seal::MsgStream log(&msg, "Hello"); log << seal::MSG::ALWAYS; log << line << line << line << seal::endmsg << "This is a " << seal::endmsg << "message, which " << seal::endmsg << "spans over several lines." << seal::endmsg; |