Online Book Reader

Home Category

Beautiful Code [294]

By Root 5359 0
appropriate subclass instances.

[***] Gamma et al., op. cit.

While a Strategy-based approach is feasible, it is not ideal. Each incoming log record may generate several calls to methods in the Acceptor and Mutex wrapper facades. Performance could therefore degrade, because virtual methods incur more overhead than nonvirtual method calls. Given that dynamically swapping IPC or synchronization mechanisms are not a requirement for our logging servers, a more efficient solution is to use C++ parameterized types to instantiate our logging server classes with the wrapper facades for IPC and synchronization.

We therefore define the following generic abstract base class called Logging_Server from which all logging servers in this chapter will inherit:

Code View: Scroll / Show All

template

class Logging_Server {

public:

typedef Log_Handler HANDLER;

Logging_Server (int argc, const char *argv);

// Template method that runs each step in the main event loop.

virtual void run (void);

protected:

// Hook methods that enable each step to be varied.

virtual void open (void);

virtual void wait_for_multiple_events (void) = 0;

virtual void handle_connections (void) = 0;

virtual void handle_data

(typename ACCEPTOR::PEER_STREAM *stream = 0) = 0;

// Increment the request count, protected by the mutex.

virtual void count_request (size_t number = 1);

// Instance of template parameter that accepts connections.

ACCEPTOR acceptor_;

// Keeps a count of the number of log records received.

size_t request_count_;

// Instance of template parameter that serializes access to

// the request_count_.

MUTEX mutex_;

// Address that the server will listen on for connections.

std:string server_address_;

};

Most methods in Logging_Server are pure virtual, which ensures that subclasses implement them. The open( ) and count_request( ) methods that follow, however, are reused by all logging servers in this chapter:

template

Logging_Server::Logging_Server

(int argc, char *argv[]): request_count_ (0) {

// Parse the argv arguments and store the server address_...

}

template void

Logging_Server::open (void) {

return acceptor_.open (server_address_);

}

template void

Logging_Server::count_request (size_t number) {

mutex_.acquire (); request_count_ += number; mutex_.release ();

}

The Log_Handler class is responsible for demarshaling a log record from a connected data stream whose IPC mechanism is designated by the ACCEPTOR type parameter. The implementation of this class is outside the scope of this chapter, and could itself be another dimension of variability—that is, logging servers might want to support different log message formats. If we were to support varying the format of method of storing incoming log messages, this class could be yet another template parameter in our logging framework. For our purposes, it is sufficient to know that it is parameterized by the IPC mechanism and provides two methods: peer( ), which returns a reference to the data stream, and log_record( ), which reads a single log record from the stream.

The primary entry point into Logging_Server is the template method called run( ), which implements the steps outlined in Figure 26-3, delegating the specific steps to the hook methods declared in the protected section of Logging_Server, as shown in the following code fragment:

template void

Logging_Server::run (void) {

try {

// Step 1: initialize an IPC factory endpoint to listen for

// new connections on the server address.

open ();

// Step 2: Go into an event loop

for (;;) {

// Step 2a: wait for new connections or log records

// to arrive.

wait_for_multiple_events ();

// Step 2b: accept a new connection

Return Main Page Previous Page Next Page

®Online Book Reader