BIND 10 trac558, updated. 2ad85af5e37a9e393903a8c0b3589b9c086c16ec [trac558] Address more initialization points

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Feb 7 11:30:50 UTC 2011


The branch, trac558 has been updated
       via  2ad85af5e37a9e393903a8c0b3589b9c086c16ec (commit)
       via  d588ec8aafe64a586cc1bccab6be4a9fc50886d4 (commit)
      from  0afb9dde6cef8abfa38935e85030ab975002cf91 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 2ad85af5e37a9e393903a8c0b3589b9c086c16ec
Author: Stephen Morris <stephen at isc.org>
Date:   Mon Feb 7 11:27:51 2011 +0000

    [trac558] Address more initialization points
    
    * RootLoggerName now correctly avoids static initialization fiasco.
    * Message header file now references message definition file.
    * Moved message identifiers in logging subsystem into isc::log namespace.

commit d588ec8aafe64a586cc1bccab6be4a9fc50886d4
Author: Stephen Morris <stephen at isc.org>
Date:   Mon Feb 7 10:26:35 2011 +0000

    [trac558] Address some of initialization points
    
    * Logger implementation now not created until logger is first used.
    * Messages are now "const char*" to avoid problems if a reference
      to a message is made in a static initialization.
    * Message compiler now recognises $NAMESPACE directive

-----------------------------------------------------------------------

Summary of changes:
 src/lib/log/Makefile.am                            |    2 +-
 src/lib/log/compiler/message.cc                    |  166 ++++++++++++++++----
 src/lib/log/logger.cc                              |   54 +++---
 src/lib/log/logger.h                               |   43 ++++-
 src/lib/log/logger_impl.cc                         |   21 ++--
 src/lib/log/logger_impl.h                          |   10 +-
 src/lib/log/logger_impl_log4cxx.h                  |   14 +-
 src/lib/log/logger_support.cc                      |    6 +-
 src/lib/log/message_dictionary.cc                  |   30 ++--
 src/lib/log/message_dictionary.h                   |   62 ++++++--
 src/lib/log/message_initializer.cc                 |    5 +
 src/lib/log/message_initializer.h                  |   24 +++
 src/lib/log/message_reader.cc                      |   81 ++++++++--
 src/lib/log/message_reader.h                       |   34 ++++-
 src/lib/log/{message_types.h => message_types.cc}  |   21 ++-
 src/lib/log/message_types.h                        |   11 +-
 src/lib/log/messagedef.cc                          |   17 ++-
 src/lib/log/messagedef.h                           |   48 ++++--
 src/lib/log/messagedef.mes                         |   24 +++-
 src/lib/log/root_logger_name.cc                    |    5 +-
 src/lib/log/root_logger_name.h                     |   15 ++-
 src/lib/log/tests/Makefile.am                      |    2 +
 src/lib/log/tests/logger_support_test.cc           |    4 +-
 src/lib/log/tests/message_dictionary_unittest.cc   |    4 +-
 src/lib/log/tests/message_reader_unittest.cc       |   58 ++++++--
 .../message_types_unittest.cc}                     |   29 +++-
 .../message_types_unittest_2.cc}                   |   16 +--
 27 files changed, 599 insertions(+), 207 deletions(-)
 copy src/lib/log/{message_types.h => message_types.cc} (62%)
 copy src/lib/log/{message_exception.cc => tests/message_types_unittest.cc} (53%)
 copy src/lib/log/{message_exception.cc => tests/message_types_unittest_2.cc} (79%)

-----------------------------------------------------------------------
diff --git a/src/lib/log/Makefile.am b/src/lib/log/Makefile.am
index b362eba..1f91eda 100644
--- a/src/lib/log/Makefile.am
+++ b/src/lib/log/Makefile.am
@@ -20,7 +20,7 @@ liblog_la_SOURCES += message_dictionary.cc message_dictionary.h
 liblog_la_SOURCES += message_exception.h message_exception.cc
 liblog_la_SOURCES += message_initializer.cc message_initializer.h
 liblog_la_SOURCES += message_reader.cc message_reader.h
-liblog_la_SOURCES += message_types.h
+liblog_la_SOURCES += message_types.h message_types.cc
 liblog_la_SOURCES += root_logger_name.cc root_logger_name.h
 liblog_la_SOURCES += strutil.h strutil.cc
 # liblog_la_SOURCES += xdebuglevel.cc xdebuglevel.h
diff --git a/src/lib/log/compiler/message.cc b/src/lib/log/compiler/message.cc
index 8496d90..6303888 100644
--- a/src/lib/log/compiler/message.cc
+++ b/src/lib/log/compiler/message.cc
@@ -15,6 +15,7 @@
 // $Id$
 
 #include <cctype>
+#include <cstddef>
 #include <fstream>
 #include <iostream>
 #include <string>
@@ -69,7 +70,8 @@ static const char* VERSION = "1.0-0";
 ///
 /// Prints the program's version number.
 
-static void version() {
+void
+version() {
     cout << VERSION << "\n";
 }
 
@@ -77,15 +79,14 @@ static void version() {
 ///
 /// Prints program usage to stdout.
 
-static void usage() {
+void
+usage() {
     cout <<
         "Usage: message [-h] [-p] [-v] <message-file>\n" <<
         "\n" <<
         "-h       Print this message and exit\n" <<
         "-p       Output a Python module holding the message definitions.\n" <<
         "         By default a C++ header file and implementation file are\n" <<
-
-
         "         written.\n" <<
         "-v       Print the program version and exit\n" <<
         "\n" <<
@@ -99,7 +100,8 @@ static void usage() {
 ///
 /// \return Current time
 
-static string currentTime() {
+string
+currentTime() {
 
     // Get a text representation of the current time.
     time_t curtime;
@@ -124,7 +126,8 @@ static string currentTime() {
 ///
 /// \return Sentinel name
 
-static string sentinel(Filename& file) {
+string
+sentinel(Filename& file) {
 
     string name = file.name();
     string ext = file.extension();
@@ -140,7 +143,8 @@ static string sentinel(Filename& file) {
 /// characters.  This is used to handle the fact that the input file does not
 /// contain quotes, yet the string will be included in a C++ literal string.
 
-string quoteString(const string& instring) {
+string
+quoteString(const string& instring) {
 
     // Create the output string and reserve the space needed to hold the input
     // string. (Most input strings will not contain quotes, so this single
@@ -169,8 +173,9 @@ string quoteString(const string& instring) {
 ///
 /// \return Sorted list of message IDs
 
-vector<MessageID> sortedIdentifiers(MessageDictionary* dictionary) {
-    vector<MessageID> ident;
+vector<string>
+sortedIdentifiers(MessageDictionary* dictionary) {
+    vector<string> ident;
 
     for (MessageDictionary::const_iterator i = dictionary->begin();
          i != dictionary->end(); ++i) {
@@ -182,6 +187,63 @@ vector<MessageID> sortedIdentifiers(MessageDictionary* dictionary) {
 }
 
 
+/// \brief Split Namespace
+///
+/// The $NAMESPACE directive may well specify a namespace in the form a::b.
+/// Unfortunately, the C++ "namespace" statement can only accept a single
+/// string - to set up the namespace of "a::b" requires two statements, one
+/// for "namspace a" and the other for "namespace b".
+///
+/// This function returns the set of namespace components as a vector of
+/// strings.
+///
+/// \param ns Argument to $NAMESPACE (passed by valid, as we will be modifying
+/// it.)
+
+vector<string>
+splitNamespace(string ns) {
+
+    // Namespaces components are separated by double colon characters - convert
+    // to single colons.
+    size_t dcolon;
+    while ((dcolon = ns.find("::")) != string::npos) {
+        ns.replace(dcolon, 2, ":");
+    }
+
+    // ... and return the vector of namespace components split on the single
+    // colon.
+    return isc::strutil::tokens(ns, ":");
+}
+
+
+/// \brief Write Opening Namespace(s)
+///
+/// Writes the lines listing the namespaces in use.
+void
+writeOpeningNamespace(ostream& output, vector<string>& ns) {
+    if (!ns.empty()) {
+        for (int i = 0; i < ns.size(); ++i) {
+            output << "namespace " << ns[i] << " {\n";
+        }
+        output << "\n";
+    }
+}
+
+
+/// \brief Write Closing Namespace(s)
+///
+/// Writes the lines listing the namespaces in use.
+void
+writeClosingNamespace(ostream& output, vector<string>& ns) {
+    if (!ns.empty()) {
+        for (int i = ns.size() - 1; i >= 0; --i) {
+            output << "} // namespace " << ns[i] << "\n";
+        }
+        output << "\n";
+    }
+}
+
+
 /// \brief Write Header File
 ///
 /// Writes the C++ header file containing the symbol definitions.
@@ -189,10 +251,13 @@ vector<MessageID> sortedIdentifiers(MessageDictionary* dictionary) {
 /// \param file Name of the message file.  The header file is written to a
 /// file of the same name but with a .h suffix.
 /// \param prefix Prefix string to use in symbols
+/// \param ns Namespace in which the definitions are to be placed.  An empty
+/// string indicates no namespace.
 /// \param dictionary Dictionary holding the message definitions.
 
-void writeHeaderFile(const string& file, const string& prefix,
-    MessageDictionary* dictionary)
+void
+writeHeaderFile(const string& file, const string& prefix, const string& ns,
+    string& mi_name, MessageDictionary* dictionary)
 {
     Filename message_file(file);
     Filename header_file(message_file.useAsDefault(".h"));
@@ -220,23 +285,41 @@ void writeHeaderFile(const string& file, const string& prefix,
              "#define "  << sentinel_text << "\n" <<
              "\n" <<
              "#include <log/message_types.h>\n" <<
-             "\n" <<
-             "namespace {\n" <<
+             "#include <log/message_initializer.h>\n" <<
              "\n";
 
-        vector<MessageID> idents = sortedIdentifiers(dictionary);
-        for (vector<MessageID>::const_iterator j = idents.begin();
+        // Namespaces
+        vector<string> ns_components = splitNamespace(ns);
+        writeOpeningNamespace(hfile, ns_components);
+
+        // Now the m,essage identifications themselves.
+        vector<string> idents = sortedIdentifiers(dictionary);
+        for (vector<string>::const_iterator j = idents.begin();
             j != idents.end(); ++j) {
-            hfile << "isc::log::MessageID " << prefix << *j <<
+            hfile << "static const isc::log::MessageID " << prefix << *j <<
                 " = \"" << *j << "\";\n";
         }
+        hfile << "\n";
 
-        // ... and finally the postamble
-        hfile <<
+        // Close off namespaces if appropriate.
+        writeClosingNamespace(hfile, ns_components);
+
+        // Now create the reference to the message initializer to ensure that
+        // it gets run at program startup.
+
+        hfile << "namespace isc {\n" <<
+            "namespace log {\n" <<
             "\n" <<
-            "} // Anonymous namespace\n" <<
+            "extern MessageInitializer " << mi_name << ";\n" <<
+            "static MessageInstantiator m(&" << mi_name << ");\n" <<
             "\n" <<
-            "#endif // " << sentinel_text << "\n";
+            "} // namespace log\n" <<
+            "} // namespace isc\n" <<
+            "\n";
+
+
+        // ... and finally the postamble
+        hfile << "#endif // " << sentinel_text << "\n";
 
         // Report errors (if any) and exit
         if (hfile.fail()) {
@@ -257,7 +340,8 @@ void writeHeaderFile(const string& file, const string& prefix,
 ///
 /// Simple function for use in a call to transform
 
-char replaceNonAlphaNum(char c) {
+char
+replaceNonAlphaNum(char c) {
     return (isalnum(c) ? c : '_');
 }
 
@@ -268,7 +352,8 @@ char replaceNonAlphaNum(char c) {
 /// constructor is run at initialization time.  The constructor adds the message
 /// definitions to the main global dictionary.
 
-void writeProgramFile(const string& file, MessageDictionary* dictionary)
+string
+writeProgramFile(const string& file, MessageDictionary* dictionary)
 {
     Filename message_file(file);
     Filename program_file(message_file.useAsDefault(".cc"));
@@ -291,15 +376,13 @@ void writeProgramFile(const string& file, MessageDictionary* dictionary)
              "#include <cstddef>\n" <<
              "#include <log/message_initializer.h>\n" <<
              "\n" <<
-             "using namespace isc::log;\n" <<
-             "\n" <<
              "namespace {\n" <<
              "\n" <<
              "const char* values[] = {\n";
 
         // Output the identifiers and the associated text.
-        vector<MessageID> idents = sortedIdentifiers(dictionary);
-        for (vector<MessageID>::const_iterator i = idents.begin();
+        vector<string> idents = sortedIdentifiers(dictionary);
+        for (vector<string>::const_iterator i = idents.begin();
             i != idents.end(); ++i) {
                 ccfile << "    \"" << *i << "\", \"" <<
                     quoteString(dictionary->getText(*i)) << "\",\n";
@@ -323,7 +406,14 @@ void writeProgramFile(const string& file, MessageDictionary* dictionary)
 
         // ... and write the initialization code
         ccfile <<
-            "MessageInitializer " << unique_name << "(values);\n";
+            "namespace isc {\n" <<
+            "namespace log {\n" <<
+            "\n" <<
+            "MessageInitializer " << unique_name << "(values);\n" <<
+            "\n" <<
+            "} // namespace log\n" <<
+            "} // namespace isc\n" <<
+            "\n";
 
         // Report errors (if any) and exit
         if (ccfile.fail()) {
@@ -332,6 +422,8 @@ void writeProgramFile(const string& file, MessageDictionary* dictionary)
         }
 
         ccfile.close();
+
+        return unique_name;
     }
     catch (MessageException&) {
         ccfile.close();
@@ -347,7 +439,8 @@ void writeProgramFile(const string& file, MessageDictionary* dictionary)
 ///
 /// \param reader Message Reader used to read the file
 
-static void warnDuplicates(MessageReader& reader) {
+void
+warnDuplicates(MessageReader& reader) {
 
     // Get the duplicates (the overflow) and, if present, sort them into some
     // order and remove those which occur more than once (which mean that they
@@ -372,7 +465,8 @@ static void warnDuplicates(MessageReader& reader) {
 /// Parses the options then dispatches to the appropriate function.  See the
 /// main file header for the invocation.
 
-int main(int argc, char** argv) {
+int
+main(int argc, char** argv) {
     
     const struct option loptions[] = {          // Long options
         {"help",    no_argument, NULL, 'h'},
@@ -421,11 +515,13 @@ int main(int argc, char** argv) {
         MessageReader reader(&dictionary);
         reader.readFile(message_file);
 
-        // Now write the header file.
-        writeHeaderFile(message_file, reader.getPrefix(), &dictionary);
+        // Write the file that defines the message text
+        std::string mi_name =
+            writeProgramFile(message_file, &dictionary);
 
-        // ... and the message text file.
-        writeProgramFile(message_file, &dictionary);
+        // Now write the header file.
+        writeHeaderFile(message_file, reader.getPrefix(), reader.getNamespace(),
+            mi_name, &dictionary);
 
         // Finally, warn of any duplicates encountered.
         warnDuplicates(reader);
@@ -433,7 +529,9 @@ int main(int argc, char** argv) {
     catch (MessageException& e) {
         // Create an error message from the ID and the text
         MessageDictionary* global = MessageDictionary::globalDictionary();
-        string text = e.id() + ", " + global->getText(e.id());
+        string text = e.id();
+        text += ", ";
+        text += global->getText(e.id());
 
         // Format with arguments
         text = isc::strutil::format(text, e.arguments());
diff --git a/src/lib/log/logger.cc b/src/lib/log/logger.cc
index f9017bb..0f4490e 100644
--- a/src/lib/log/logger.cc
+++ b/src/lib/log/logger.cc
@@ -31,11 +31,11 @@ using namespace std;
 namespace isc {
 namespace log {
 
-// Constructor
-
-Logger::Logger(const std::string& name, bool infunc) :
-    loggerptr_(new LoggerImpl(name, infunc))
-{}
+// Initialize Logger implementation.  Does not check whether the implementation
+// has already been ionitialized - that was done by the caller (getLoggerptr()).
+void Logger::initLoggerImpl() {
+    loggerptr_ = new LoggerImpl(name_, infunc_);
+}
 
 // Destructor.
 
@@ -47,62 +47,62 @@ Logger::~Logger() {
 
 std::string
 Logger::getName() {
-    return (loggerptr_->getName());
+    return (getLoggerptr()->getName());
 }
 
 // Set the severity for logging.
 
 void
 Logger::setSeverity(isc::log::Severity severity, int dbglevel) {
-    loggerptr_->setSeverity(severity, dbglevel);
+    getLoggerptr()->setSeverity(severity, dbglevel);
 }
 
 // Return the severity of the logger.
 
 isc::log::Severity
 Logger::getSeverity() {
-    return (loggerptr_->getSeverity());
+    return (getLoggerptr()->getSeverity());
 }
 
 // Get Effective Severity Level for Logger
 
 isc::log::Severity
 Logger::getEffectiveSeverity() {
-    return (loggerptr_->getEffectiveSeverity());
+    return (getLoggerptr()->getEffectiveSeverity());
 }
 
 // Debug level (only relevant if messages of severity DEBUG are being logged).
 
 int
 Logger::getDebugLevel() {
-    return (loggerptr_->getDebugLevel());
+    return (getLoggerptr()->getDebugLevel());
 }
 
 // Check on the current severity settings
 
 bool
 Logger::isDebugEnabled(int dbglevel) {
-    return (loggerptr_->isDebugEnabled(dbglevel));
+    return (getLoggerptr()->isDebugEnabled(dbglevel));
 }
 
 bool
 Logger::isInfoEnabled() {
-    return (loggerptr_->isInfoEnabled());
+    return (getLoggerptr()->isInfoEnabled());
 }
 
 bool
 Logger::isWarnEnabled() {
-    return (loggerptr_->isWarnEnabled());
+    return (getLoggerptr()->isWarnEnabled());
 }
 
 bool
 Logger::isErrorEnabled() {
-    return (loggerptr_->isErrorEnabled());
+    return (getLoggerptr()->isErrorEnabled());
 }
 
 bool
 Logger::isFatalEnabled() {
-    return (loggerptr_->isFatalEnabled());
+    return (getLoggerptr()->isFatalEnabled());
 }
 
 // Format a message: looks up the message text in the dictionary and formats
@@ -129,52 +129,52 @@ Logger::isFatalEnabled() {
 // Output methods
 
 void
-Logger::debug(int dbglevel, isc::log::MessageID ident, ...) {
+Logger::debug(int dbglevel, const isc::log::MessageID& ident, ...) {
     if (isDebugEnabled(dbglevel)) {
         char message[MESSAGE_SIZE];
         FORMAT_MESSAGE(message);
-        loggerptr_->debug(ident, message);
+        getLoggerptr()->debug(ident, message);
     }
 }
 
 void
-Logger::info(isc::log::MessageID ident, ...) {
+Logger::info(const isc::log::MessageID& ident, ...) {
     if (isInfoEnabled()) {
         char message[MESSAGE_SIZE];
         FORMAT_MESSAGE(message);
-        loggerptr_->info(ident, message);
+        getLoggerptr()->info(ident, message);
     }
 }
 
 void
-Logger::warn(isc::log::MessageID ident, ...) {
+Logger::warn(const isc::log::MessageID& ident, ...) {
     if (isWarnEnabled()) {
         char message[MESSAGE_SIZE];
         FORMAT_MESSAGE(message);
-        loggerptr_->warn(ident, message);
+        getLoggerptr()->warn(ident, message);
     }
 }
 
 void
-Logger::error(isc::log::MessageID ident, ...) {
+Logger::error(const isc::log::MessageID& ident, ...) {
     if (isErrorEnabled()) {
         char message[MESSAGE_SIZE];
         FORMAT_MESSAGE(message);
-        loggerptr_->error(ident, message);
+        getLoggerptr()->error(ident, message);
     }
 }
 
 void
-Logger::fatal(isc::log::MessageID ident, ...) {
+Logger::fatal(const isc::log::MessageID& ident, ...) {
     if (isFatalEnabled()) {
         char message[MESSAGE_SIZE];
         FORMAT_MESSAGE(message);
-        loggerptr_->fatal(ident, message);
+        getLoggerptr()->fatal(ident, message);
     }
 }
 
-bool Logger::operator==(const Logger& other) {
-    return (*loggerptr_ == *other.loggerptr_);
+bool Logger::operator==(Logger& other) {
+    return (*getLoggerptr() == *other.getLoggerptr());
 }
 
 // Protected methods (used for testing)
diff --git a/src/lib/log/logger.h b/src/lib/log/logger.h
index 4fdabe9..d706c64 100644
--- a/src/lib/log/logger.h
+++ b/src/lib/log/logger.h
@@ -81,7 +81,9 @@ public:
     /// manifests itself during program rundown.
     /// \n
     /// The flag has no effect on non-log4cxx implementations.
-    Logger(const std::string& name, bool infunc = false);
+    Logger(const std::string& name, bool infunc = false) :
+        loggerptr_(NULL), name_(name), infunc_(infunc)
+    {}
 
 
     /// \brief Destructor
@@ -158,35 +160,35 @@ public:
     /// are used for more verbose output.
     /// \param ident Message identification.
     /// \param ... Optional arguments for the message.
-    void debug(int dbglevel, MessageID ident, ...);
+    void debug(int dbglevel, const MessageID& ident, ...);
 
 
     /// \brief Output Informational Message
     ///
     /// \param ident Message identification.
     /// \param ... Optional arguments for the message.
-    void info(MessageID ident, ...);
+    void info(const MessageID& ident, ...);
 
 
     /// \brief Output Warning Message
     ///
     /// \param ident Message identification.
     /// \param ... Optional arguments for the message.
-    void warn(MessageID ident, ...);
+    void warn(const MessageID& ident, ...);
 
 
     /// \brief Output Error Message
     ///
     /// \param ident Message identification.
     /// \param ... Optional arguments for the message.
-    void error(MessageID ident, ...);
+    void error(const MessageID& ident, ...);
 
 
     /// \brief Output Fatal Message
     ///
     /// \param ident Message identification.
     /// \param ... Optional arguments for the message.
-    void fatal(MessageID ident, ...);
+    void fatal(const MessageID& ident, ...);
 
     /// \brief Equality
     ///
@@ -194,7 +196,7 @@ public:
     /// (This method is principally for testing.)
     ///
     /// \return true if the logger objects are instances of the same logger.
-    bool operator==(const Logger& other);
+    bool operator==(Logger& other);
 
 protected:
 
@@ -205,7 +207,32 @@ protected:
     static void reset();
 
 private:
-    LoggerImpl*     loggerptr_;     /// Pointer to the underlying logger
+    /// \brief Initialize Implementation
+    ///
+    /// Returns the logger pointer.  If not yet set, the underlying
+    /// implementation class is initialized.\n
+    /// \n
+    /// The reason for this indirection is to avoid the "static initialization
+    /// fiacso", whereby we cannot rely on the order of static initializations.
+    /// The main problem is the root logger name - declared statically - which
+    /// is referenced by various loggers.  By deferring a reference to it until
+    /// after the program starts executing - by which time the root name object
+    /// will be initialized - we avoid this problem.
+    ///
+    /// \return Returns pointer to implementation
+    LoggerImpl* getLoggerptr() {
+        if (!loggerptr_) {
+            initLoggerImpl();
+        }
+        return loggerptr_;
+    }
+
+    /// \brief Initialize Underlying Implementation and Set loggerptr_
+    void initLoggerImpl();
+
+    LoggerImpl*     loggerptr_;     ///< Pointer to the underlying logger
+    std::string     name_;          ///< Copy of the logger name
+    bool            infunc_;        ///< Copy of the infunc argument
 };
 
 } // namespace log
diff --git a/src/lib/log/logger_impl.cc b/src/lib/log/logger_impl.cc
index 271d5d2..2e1f337 100644
--- a/src/lib/log/logger_impl.cc
+++ b/src/lib/log/logger_impl.cc
@@ -19,6 +19,7 @@
 
 #include <stdarg.h>
 #include <stdio.h>
+#include <boost/lexical_cast.hpp>
 
 #include <log/debug_levels.h>
 #include <log/root_logger_name.h>
@@ -223,32 +224,32 @@ LoggerImpl::output(const char* sev_text, const string& message) {
 // Output various levels
 
 void
-LoggerImpl::debug(MessageID ident, const char* text) {
-    string message = ident + ", " + text;
+LoggerImpl::debug(const MessageID& ident, const char* text) {
+    string message = boost::lexical_cast<string>(ident) + ", " + text;
     output("DEBUG", message);
 }
 
 void
-LoggerImpl::info(MessageID ident, const char* text) {
-    string message = ident + ", " + text;
+LoggerImpl::info(const MessageID& ident, const char* text) {
+    string message = boost::lexical_cast<string>(ident) + ", " + text;
     output("INFO ", message);
 }
 
 void
-LoggerImpl::warn(MessageID ident, const char* text) {
-    string message = ident + ", " + text;
+LoggerImpl::warn(const MessageID& ident, const char* text) {
+    string message = boost::lexical_cast<string>(ident) + ", " + text;
     output("WARN ", message);
 }
 
 void
-LoggerImpl::error(MessageID ident, const char* text) {
-    string message = ident + ", " + text;
+LoggerImpl::error(const MessageID& ident, const char* text) {
+    string message = boost::lexical_cast<string>(ident) + ", " + text;
     output("ERROR", message);
 }
 
 void
-LoggerImpl::fatal(MessageID ident, const char* text) {
-    string message = ident + ", " + text;
+LoggerImpl::fatal(const MessageID& ident, const char* text) {
+    string message = boost::lexical_cast<string>(ident) + ", " + text;
     output("FATAL", message);
 }
 
diff --git a/src/lib/log/logger_impl.h b/src/lib/log/logger_impl.h
index 9d9ec44..a9314fc 100644
--- a/src/lib/log/logger_impl.h
+++ b/src/lib/log/logger_impl.h
@@ -192,35 +192,35 @@ public:
     ///
     /// \param ident Message identification.
     /// \param text Text to log
-    void debug(MessageID ident, const char* text);
+    void debug(const MessageID& ident, const char* text);
 
 
     /// \brief Output Informational Message
     ///
     /// \param ident Message identification.
     /// \param text Text to log
-    void info(MessageID ident, const char* text);
+    void info(const MessageID& ident, const char* text);
 
 
     /// \brief Output Warning Message
     ///
     /// \param ident Message identification.
     /// \param text Text to log
-    void warn(MessageID ident, const char* text);
+    void warn(const MessageID& ident, const char* text);
 
 
     /// \brief Output Error Message
     ///
     /// \param ident Message identification.
     /// \param text Text to log
-    void error(MessageID ident, const char* text);
+    void error(const MessageID& ident, const char* text);
 
 
     /// \brief Output Fatal Message
     ///
     /// \param ident Message identification.
     /// \param text Text to log
-    void fatal(MessageID ident, const char* text);
+    void fatal(const MessageID& ident, const char* text);
 
 
     /// \brief Equality
diff --git a/src/lib/log/logger_impl_log4cxx.h b/src/lib/log/logger_impl_log4cxx.h
index c371fda..84fef57 100644
--- a/src/lib/log/logger_impl_log4cxx.h
+++ b/src/lib/log/logger_impl_log4cxx.h
@@ -168,7 +168,7 @@ public:
     ///
     /// \param ident Message identification.
     /// \param text Text to log
-    void debug(MessageID ident, const char* text) {
+    void debug(const MessageID& ident, const char* text) {
         LOG4CXX_DEBUG(getLogger(), ident << ", " << text);
     }
 
@@ -177,7 +177,7 @@ public:
     ///
     /// \param ident Message identification.
     /// \param text Text to log
-    void info(MessageID ident, const char* text) {
+    void info(const MessageID& ident, const char* text) {
         LOG4CXX_INFO(getLogger(), ident << ", " << text);
     }
 
@@ -186,7 +186,7 @@ public:
     ///
     /// \param ident Message identification.
     /// \param text Text to log
-    void warn(MessageID ident, const char* text) {
+    void warn(const MessageID& ident, const char* text) {
         LOG4CXX_WARN(getLogger(), ident << ", " << text);
     }
 
@@ -195,7 +195,7 @@ public:
     ///
     /// \param ident Message identification.
     /// \param text Text to log
-    void error(MessageID ident, const char* text) {
+    void error(const MessageID& ident, const char* text) {
         LOG4CXX_ERROR(getLogger(), ident << ", " << text);
     }
 
@@ -204,7 +204,7 @@ public:
     ///
     /// \param ident Message identification.
     /// \param text Text to log
-    void fatal(MessageID ident, const char* text) {
+    void fatal(const MessageID& ident, const char* text) {
         LOG4CXX_FATAL(getLogger(), ident << ", " << text);
     }
 
@@ -220,7 +220,7 @@ public:
     /// (This method is principally for testing.)
     ///
     /// \return true if the logger objects are instances of the same logger.
-    bool operator==(const LoggerImpl& other) {
+    bool operator==(LoggerImpl& other) {
         return (*loggerptr_ == *other.loggerptr_);
     }
 
@@ -302,7 +302,7 @@ private:
     // problems with memory deletion on program exit, explained in the comments
     // for the "exit_delete" parameter in this class's constructor.
 
-    mutable log4cxx::LoggerPtr*  loggerptr_; ///< Pointer to the underlying logger
+    log4cxx::LoggerPtr*  loggerptr_;    ///< Pointer to the underlying logger
     std::string          name_;         ///< Name of this logger]
     bool                 exit_delete_;  ///< Delete loggerptr_ on exit?
 
diff --git a/src/lib/log/logger_support.cc b/src/lib/log/logger_support.cc
index a20ef96..efed2b6 100644
--- a/src/lib/log/logger_support.cc
+++ b/src/lib/log/logger_support.cc
@@ -29,6 +29,7 @@
 /// the logging parameters from the configuration database.
 
 #include <vector>
+#include <boost/lexical_cast.hpp>
 
 #include <log/logger.h>
 #include <log/logger_support.h>
@@ -67,12 +68,13 @@ readLocalMessageFile(const char* file) {
         MessageReader::MessageIDCollection unknown = reader.getNotAdded();
         for (MessageReader::MessageIDCollection::const_iterator
             i = unknown.begin(); i != unknown.end(); ++i) {
-                logger.warn(MSG_IDNOTFND, (*i).c_str());
+            string message_id = boost::lexical_cast<string>(*i);
+                logger.warn(MSG_IDNOTFND, message_id.c_str());
         }
     }
     catch (MessageException& e) {
         MessageID ident = e.id();
-        vector<MessageID> args = e.arguments();
+        vector<string> args = e.arguments();
         switch (args.size()) {
         case 0:
             logger.error(ident);
diff --git a/src/lib/log/message_dictionary.cc b/src/lib/log/message_dictionary.cc
index 05c79f8..7976578 100644
--- a/src/lib/log/message_dictionary.cc
+++ b/src/lib/log/message_dictionary.cc
@@ -14,6 +14,8 @@
 
 // $Id$
 
+#include <iostream>
+
 #include <cstddef>
 #include <log/message_dictionary.h>
 #include <log/message_types.h>
@@ -31,8 +33,8 @@ MessageDictionary::~MessageDictionary() {
 // Add message and note if ID already exists
 
 bool
-MessageDictionary::add(const MessageID& ident, const std::string& text) {
-    map<MessageID, string>::iterator i = dictionary_.find(ident);
+MessageDictionary::add(const string& ident, const string& text) {
+    Dictionary::iterator i = dictionary_.find(ident);
     bool not_found = (i == dictionary_.end());
     if (not_found) {
 
@@ -46,8 +48,8 @@ MessageDictionary::add(const MessageID& ident, const std::string& text) {
 // Add message and note if ID does not already exist
 
 bool
-MessageDictionary::replace(const MessageID& ident, const std::string& text) {
-    map<MessageID, string>::iterator i = dictionary_.find(ident);
+MessageDictionary::replace(const string& ident, const string& text) {
+    Dictionary::iterator i = dictionary_.find(ident);
     bool found = (i != dictionary_.end());
     if (found) {
 
@@ -60,14 +62,14 @@ MessageDictionary::replace(const MessageID& ident, const std::string& text) {
 
 // Load a set of messages
 
-vector<MessageID>
+vector<std::string>
 MessageDictionary::load(const char* messages[]) {
-    vector<MessageID> duplicates;
+    vector<std::string> duplicates;
     int i = 0;
     while (messages[i]) {
 
         // ID present, so note it and point to text.
-        MessageID ident(messages[i++]);
+        const MessageID ident(messages[i++]);
         if (messages[i]) {
 
             // Text not null, note it and point to next ident. 
@@ -77,7 +79,7 @@ MessageDictionary::load(const char* messages[]) {
             // already present.
             bool added = add(ident, text);
             if (!added) {
-                duplicates.push_back(ident);
+                duplicates.push_back(boost::lexical_cast<string>(ident));
             }
         }
     }
@@ -87,8 +89,8 @@ MessageDictionary::load(const char* messages[]) {
 // Return message text or blank string
 
 string
-MessageDictionary::getText(const MessageID& ident) const {
-    map<MessageID, string>::const_iterator i = dictionary_.find(ident);
+MessageDictionary::getText(const string& ident) const {
+    Dictionary::const_iterator i = dictionary_.find(ident);
     if (i == dictionary_.end()) {
         return string("");
     }
@@ -101,12 +103,8 @@ MessageDictionary::getText(const MessageID& ident) const {
 
 MessageDictionary*
 MessageDictionary::globalDictionary() {
-    static MessageDictionary* global = NULL;
-
-    if (global == NULL) {
-        global = new MessageDictionary();
-    }
-    return global;
+    static MessageDictionary global;
+    return &global;
 }
 
 
diff --git a/src/lib/log/message_dictionary.h b/src/lib/log/message_dictionary.h
index 0b2e704..07ad369 100644
--- a/src/lib/log/message_dictionary.h
+++ b/src/lib/log/message_dictionary.h
@@ -22,6 +22,8 @@
 #include <map>
 #include <vector>
 
+#include <boost/lexical_cast.hpp>
+
 #include <log/message_types.h>
 
 namespace isc {
@@ -48,6 +50,9 @@ namespace log {
 class MessageDictionary {
 public:
 
+    typedef std::map<std::string, std::string> Dictionary;
+    typedef Dictionary::const_iterator  const_iterator;
+
     // Default constructor and assignment operator are OK for this class
 
     /// \brief Virtual Destructor
@@ -63,7 +68,20 @@ public:
     ///
     /// \return true if the message was added to the dictionary, false if the
     /// message existed and it was not added.
-    virtual bool add(const MessageID& ident, const std::string& text);
+    virtual bool add(const MessageID& ident, const std::string& text) {
+        return (add(boost::lexical_cast<std::string>(ident), text));
+    }
+
+    /// \brief Add Message
+    ///
+    /// Alternate signature.
+    ///
+    /// \param ident Identification of the message to add
+    /// \param text Message text
+    ///
+    /// \return true if the message was added to the dictionary, false if the
+    /// message existed and it was not added.
+    virtual bool add (const std::string& ident, const std::string& test);
 
 
     /// \brief Replace Message
@@ -76,7 +94,21 @@ public:
     ///
     /// \return true if the message was added to the dictionary, false if the
     /// message did not exist and it was not added.
-    virtual bool replace(const MessageID& ident, const std::string& text);
+    virtual bool replace(const MessageID& ident, const std::string& text) {
+        return (replace(boost::lexical_cast<std::string>(ident), text));
+    }
+
+
+    /// \brief Replace Message
+    ///
+    /// Alternate signature.
+    ///
+    /// \param ident Identification of the message to replace
+    /// \param text Message text
+    ///
+    /// \return true if the message was added to the dictionary, false if the
+    /// message did not exist and it was not added.
+    virtual bool replace(const std::string& ident, const std::string& text);
 
 
     /// \brief Load Dictionary
@@ -94,7 +126,7 @@ public:
     /// \return Vector of message IDs that were not loaded because an ID of the
     /// same name already existing in the dictionary.  This vector may be
     /// empty.
-    virtual std::vector<MessageID> load(const char* elements[]);
+    virtual std::vector<std::string> load(const char* elements[]);
 
 
     /// \brief Get Message Text
@@ -106,7 +138,21 @@ public:
     /// \return Text associated with message or empty string if the ID is not
     /// recognised.  (Note: this precludes an ID being associated with an empty
     /// string.)
-    virtual std::string getText(const MessageID& ident) const;
+    virtual std::string getText(const MessageID& ident) const {
+        return(getText(boost::lexical_cast<std::string>(ident)));
+    }
+
+
+    /// \brief Get Message Text
+    ///
+    /// Alternate signature.
+    ///
+    /// \param ident Message identification
+    ///
+    /// \return Text associated with message or empty string if the ID is not
+    /// recognised.  (Note: this precludes an ID being associated with an empty
+    /// string.)
+    virtual std::string getText(const std::string& ident) const;
 
 
     /// \brief Number of Items in Dictionary
@@ -115,11 +161,7 @@ public:
     virtual size_t size() const {
         return dictionary_.size();
     }
-
-
-    // Allow access to the internal map structure, but don't allow alteration.
-    typedef std::map<MessageID, std::string>::const_iterator const_iterator;
-
+    
 
     /// \brief Return begin() iterator of internal map
     const_iterator begin() const {
@@ -141,7 +183,7 @@ public:
     static MessageDictionary* globalDictionary();
 
 private:
-    std::map<MessageID, std::string>  dictionary_;
+    Dictionary       dictionary_;   ///< Holds the ID to text lookups
 };
 
 } // namespace log
diff --git a/src/lib/log/message_initializer.cc b/src/lib/log/message_initializer.cc
index 914ed17..37de5a5 100644
--- a/src/lib/log/message_initializer.cc
+++ b/src/lib/log/message_initializer.cc
@@ -28,5 +28,10 @@ MessageInitializer::MessageInitializer(const char* values[]) {
     global->load(values);
 }
 
+// Dummy constructor for the MessageInstantiator
+
+MessageInstantiator::MessageInstantiator(MessageInitializer*) {
+}
+
 } // namespace log
 } // namespace isc
diff --git a/src/lib/log/message_initializer.h b/src/lib/log/message_initializer.h
index a776a02..531cb1c 100644
--- a/src/lib/log/message_initializer.h
+++ b/src/lib/log/message_initializer.h
@@ -57,6 +57,30 @@ public:
     MessageInitializer(const char* values[]);
 };
 
+/// \brief Instantiate Message Initializer
+///
+/// A problem with the MessageInitializer class is that an instance of it is
+/// created in an external file and initialization of a set of messages requires
+/// that that file be included in the link.  Unfortunately, if there is no
+/// reference to the MessageInitializer object, we cannot guarantee that that
+/// will be the case.\n
+/// \n
+/// The MessageInitializer object is created as a global object, so in theory
+/// an "extern" reference to it should work.  However, that reference may well
+/// be optimised away.  To overcome this, the MessageInstantiator class is
+/// used.\n
+/// \n
+/// In the message header file, an instance of MessageInstantiator is created
+/// that takes the extern reference to the MessageInitializer as its constructor
+/// argument.  The constructor - declared in another file - is a no-op.  But as
+/// the linker doesn't know, it must resolve the reference, hence pulling in the
+/// file containing the MessageInitializr.
+
+class MessageInstantiator {
+public:
+    MessageInstantiator(MessageInitializer* dummy);
+};
+
 } // namespace log
 } // namespace isc
 
diff --git a/src/lib/log/message_reader.cc b/src/lib/log/message_reader.cc
index 203b836..20ab86d 100644
--- a/src/lib/log/message_reader.cc
+++ b/src/lib/log/message_reader.cc
@@ -93,32 +93,45 @@ MessageReader::processLine(const string& line, MessageReader::Mode mode) {
 void
 MessageReader::parseDirective(const std::string& text) {
 
-    static string valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
 
-    // Regardless of what happens, all prefixes will be uppercase (as will
-    // all symbols).
-    string line = text;
-    isc::strutil::uppercase(line);
-    vector<string> tokens = isc::strutil::tokens(line);
+    // Break into tokens
+    vector<string> tokens = isc::strutil::tokens(text);
 
-    // Only $PREFIX is recognised so far, so we'll handle it here.
-    if (tokens[0] != string("$PREFIX")) {
+    // Uppercase directive and branch on valid ones
+    isc::strutil::uppercase(tokens[0]);
+    if (tokens[0] == string("$PREFIX")) {
+        parsePrefix(tokens);
+    } else if (tokens[0] == string("$NAMESPACE")) {
+        parseNamespace(tokens);
+    } else {
         throw MessageException(MSG_UNRECDIR, tokens[0]);
+    }
+}
 
-    } else if (tokens.size() < 2) {
-        throw MessageException(MSG_PRFNOARG);
+// Process $PREFIX
+
+void
+MessageReader::parsePrefix(const vector<string>& tokens) {
+
+    // Check argument count
 
+    static string valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+    if (tokens.size() < 2) {
+        throw MessageException(MSG_PRFNOARG);
     } else if (tokens.size() > 2) {
         throw MessageException(MSG_PRFEXTRARG);
 
     }
 
+    // As a style, we are going to have the symbols in uppercase
+    string prefix = tokens[1];
+    isc::strutil::uppercase(prefix);
+
     // Token is potentially valid providing it only contains alphabetic
     // and numeric characters (and underscores) and does not start with a
     // digit.
-    
-    if ((tokens[1].find_first_not_of(valid) != string::npos) ||
-        (std::isdigit(tokens[1][0]))) {
+    if ((prefix.find_first_not_of(valid) != string::npos) ||
+        (std::isdigit(prefix[0]))) {
 
         // Invalid character in string or it starts with a digit.
         throw MessageException(MSG_PRFINVARG, tokens[1]);
@@ -132,7 +145,45 @@ MessageReader::parseDirective(const std::string& text) {
 
     // Prefix has not been set, so set it and return success.
 
-    prefix_ = tokens[1];
+    prefix_ = prefix;
+}
+
+// Process $NAMESPACE.  A lot of the processing is similar to that of $PREFIX,
+// except that only limited checks will be done on the namespace (to avoid a
+// lot of parsing and separating out of the namespace components.)
+
+void
+MessageReader::parseNamespace(const vector<string>& tokens) {
+
+    // Check argument count
+
+    static string valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_:"
+        "abcdefghijklmnopqrstuvwxyz";
+
+    if (tokens.size() < 2) {
+        throw MessageException(MSG_NSNOARG);
+
+    } else if (tokens.size() > 2) {
+        throw MessageException(MSG_NSEXTRARG);
+
+    }
+
+    // Token is potentially valid providing it only contains alphabetic
+    // and numeric characters (and underscores and colons).
+    if (tokens[1].find_first_not_of(valid) != string::npos) {
+
+        // Invalid character in string or it starts with a digit.
+        throw MessageException(MSG_NSINVARG, tokens[1]);
+    }
+
+    // All OK - unless the namespace has already been set.
+    if (ns_.size() != 0) {
+        throw MessageException(MSG_DUPLNS);
+    }
+
+    // Prefix has not been set, so set it and return success.
+
+    ns_ = tokens[1];
 }
 
 // Process message.  By the time this method is called, the line has been
@@ -154,7 +205,7 @@ MessageReader::parseMessage(const std::string& text, MessageReader::Mode mode) {
     }
 
     // Extract the first token into the message ID
-    MessageID ident = text.substr(0, first_delim);
+    string ident = text.substr(0, first_delim);
 
     // Locate the start of the message text
     size_t first_text = text.find_first_not_of(delimiters, first_delim);
diff --git a/src/lib/log/message_reader.h b/src/lib/log/message_reader.h
index 84ffce9..bfb9e54 100644
--- a/src/lib/log/message_reader.h
+++ b/src/lib/log/message_reader.h
@@ -50,7 +50,7 @@ public:
     } Mode;
 
     /// \brief Visible collection types
-    typedef std::vector<MessageID>   MessageIDCollection;
+    typedef std::vector<std::string>   MessageIDCollection;
 
     /// \brief Constructor
     ///
@@ -116,6 +116,22 @@ public:
     virtual void processLine(const std::string& line, Mode mode = ADD);
 
 
+    /// \brief Get Namespace
+    ///
+    /// \return Argument to the $NAMESPACE directive (if present)
+    virtual std::string getNamespace() const {
+        return ns_;
+    }
+
+
+    /// \brief Clear Namespace
+    ///
+    /// Clears the current namespace.
+    virtual void clearNamespace() {
+        ns_ = "";
+    }
+
+
     /// \brief Get Prefix
     ///
     /// \return Argument to the $PREFIX directive (if present)
@@ -163,10 +179,24 @@ private:
     /// \param line Line of text that starts with "$",
     void parseDirective(const std::string& line);
 
+
+    /// \brief Parse $PREFIX line
+    ///
+    /// \param tokens $PREFIX line split into tokens
+    void parsePrefix(const std::vector<std::string>& tokens);
+
+
+    /// \brief Parse $NAMESPACE line
+    ///
+    /// \param tokens $NAMESPACE line split into tokens
+    void parseNamespace(const std::vector<std::string>& tokens);
+
+
     /// Attributes
     MessageDictionary*  dictionary_;    ///< Dictionary to add messages to
     MessageIDCollection not_added_;     ///< List of IDs not added
-    std::string         prefix_;        ///< Input of $PREFIX statement
+    std::string         prefix_;        ///< Argument of $PREFIX statement
+    std::string         ns_;            ///< Argument of $NAMESPACE statement
 };
 
 } // namespace log
diff --git a/src/lib/log/message_types.cc b/src/lib/log/message_types.cc
new file mode 100644
index 0000000..3d64634
--- /dev/null
+++ b/src/lib/log/message_types.cc
@@ -0,0 +1,37 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string.h>
+#include <log/message_types.h>
+
+namespace isc {
+namespace log {
+
+// Compare MessageID for Equality
+
+bool equalMessageID(const MessageID& m1, const MessageID& m2) {
+
+    // Attempt to optimise the check.  If both are the same instance of the
+    // message ID, the check for addresses will successed.  If both are the
+    // same message ID but declared in a separate files (so different
+    // addresses but pointing to the same string), the string equality check
+    // will work.
+    return ((m1 == m2) || (strcmp(m1, m2) == 0));
+}
+
+} // namespace log
+} // namespace isc
+
+
+
diff --git a/src/lib/log/message_types.h b/src/lib/log/message_types.h
index b101401..dcb53f7 100644
--- a/src/lib/log/message_types.h
+++ b/src/lib/log/message_types.h
@@ -17,12 +17,19 @@
 #ifndef __MESSAGE_TYPES_H
 #define __MESSAGE_TYPES_H
 
-#include <string>
+#include <string.h>
 
 namespace isc {
 namespace log {
 
-typedef std::string MessageID;
+typedef const char* MessageID;
+
+/// \brief Compare MessageID for Equality
+///
+/// \param m1 First message ID
+/// \param m2 Second message ID
+/// \return true if they are equal, false if not
+bool equalMessageID(const MessageID& m1, const MessageID& m2);
 
 } // namespace log
 } // namespace isc
diff --git a/src/lib/log/messagedef.cc b/src/lib/log/messagedef.cc
index 7dfa4f6..ca3ae2e 100644
--- a/src/lib/log/messagedef.cc
+++ b/src/lib/log/messagedef.cc
@@ -1,15 +1,17 @@
-// File created from messagedef.mes on Mon Jan 17 15:25:32 2011
+// File created from messagedef.mes on Mon Feb  7 11:18:04 2011
 
 #include <cstddef>
 #include <log/message_initializer.h>
 
-using namespace isc::log;
-
 namespace {
 
 const char* values[] = {
+    "DUPLNS", "duplicate $NAMESPACE directive found",
     "DUPLPRFX", "duplicate $PREFIX directive found",
     "IDNOTFND", "could not replace message for '%s': no such message identification",
+    "NSEXTRARG", "$NAMESPACE directive has too many arguments",
+    "NSINVARG", "$NAMESPACE directive has an invalid argument ('%s')",
+    "NSNOARG", "no arguments were given to the $NAMESPACE directive",
     "ONETOKEN", "a line containing a message ID ('%s') and nothing else was found",
     "OPENIN", "unable to open message file %s for input: %s",
     "OPENOUT", "unable to open %s for output: %s",
@@ -24,4 +26,11 @@ const char* values[] = {
 
 } // Anonymous namespace
 
-MessageInitializer messagedef_cc_Mon_Jan_17_15_25_32_2011(values);
+namespace isc {
+namespace log {
+
+MessageInitializer messagedef_cc_Mon_Feb__7_11_18_04_2011(values);
+
+} // namespace log
+} // namespace isc
+
diff --git a/src/lib/log/messagedef.h b/src/lib/log/messagedef.h
index ae0a99d..d4b6d7f 100644
--- a/src/lib/log/messagedef.h
+++ b/src/lib/log/messagedef.h
@@ -1,24 +1,40 @@
-// File created from messagedef.mes on Mon Jan 17 15:25:32 2011
+// File created from messagedef.mes on Mon Feb  7 11:18:04 2011
 
 #ifndef __MESSAGEDEF_H
 #define __MESSAGEDEF_H
 
 #include <log/message_types.h>
+#include <log/message_initializer.h>
 
-namespace {
-
-isc::log::MessageID MSG_DUPLPRFX = "DUPLPRFX";
-isc::log::MessageID MSG_IDNOTFND = "IDNOTFND";
-isc::log::MessageID MSG_ONETOKEN = "ONETOKEN";
-isc::log::MessageID MSG_OPENIN = "OPENIN";
-isc::log::MessageID MSG_OPENOUT = "OPENOUT";
-isc::log::MessageID MSG_PRFEXTRARG = "PRFEXTRARG";
-isc::log::MessageID MSG_PRFINVARG = "PRFINVARG";
-isc::log::MessageID MSG_PRFNOARG = "PRFNOARG";
-isc::log::MessageID MSG_READERR = "READERR";
-isc::log::MessageID MSG_UNRECDIR = "UNRECDIR";
-isc::log::MessageID MSG_WRITERR = "WRITERR";
-
-} // Anonymous namespace
+namespace isc {
+namespace log {
+
+static const isc::log::MessageID MSG_DUPLNS = "DUPLNS";
+static const isc::log::MessageID MSG_DUPLPRFX = "DUPLPRFX";
+static const isc::log::MessageID MSG_IDNOTFND = "IDNOTFND";
+static const isc::log::MessageID MSG_NSEXTRARG = "NSEXTRARG";
+static const isc::log::MessageID MSG_NSINVARG = "NSINVARG";
+static const isc::log::MessageID MSG_NSNOARG = "NSNOARG";
+static const isc::log::MessageID MSG_ONETOKEN = "ONETOKEN";
+static const isc::log::MessageID MSG_OPENIN = "OPENIN";
+static const isc::log::MessageID MSG_OPENOUT = "OPENOUT";
+static const isc::log::MessageID MSG_PRFEXTRARG = "PRFEXTRARG";
+static const isc::log::MessageID MSG_PRFINVARG = "PRFINVARG";
+static const isc::log::MessageID MSG_PRFNOARG = "PRFNOARG";
+static const isc::log::MessageID MSG_READERR = "READERR";
+static const isc::log::MessageID MSG_UNRECDIR = "UNRECDIR";
+static const isc::log::MessageID MSG_WRITERR = "WRITERR";
+
+} // namespace log
+} // namespace isc
+
+namespace isc {
+namespace log {
+
+extern MessageInitializer messagedef_cc_Mon_Feb__7_11_18_04_2011;
+static MessageInstantiator m(&messagedef_cc_Mon_Feb__7_11_18_04_2011);
+
+} // namespace log
+} // namespace isc
 
 #endif // __MESSAGEDEF_H
diff --git a/src/lib/log/messagedef.mes b/src/lib/log/messagedef.mes
index 1535fc6..3a9facc 100644
--- a/src/lib/log/messagedef.mes
+++ b/src/lib/log/messagedef.mes
@@ -15,6 +15,7 @@
 # $Id$
 
 $PREFIX MSG_
+$NAMESPACE isc::log
 
 # \brief Message Utility Message File
 #
@@ -24,6 +25,11 @@ $PREFIX MSG_
 # chicken-and-egg situation where we need the files to build the message
 # compiler, yet we need the compiler to build the files.
 
+DUPLNS    duplicate $NAMESPACE directive found
++ When reading a message file, more than one $NAMESPACE directive was found.  In
++ this version of the code, such a condition is regarded as an error and the
++ read will be abandonded.
+
 DUPLPRFX    duplicate $PREFIX directive found
 + When reading a message file, more than one $PREFIX directive was found.  In
 + this version of the code, such a condition is regarded as an error and the
@@ -40,6 +46,22 @@ IDNOTFND    could not replace message for '%s': no such message identification
 + This message may appear a number of times in the file, once for every such
 + unknown mnessage identification.
 
+NSEXTRARG  $NAMESPACE directive has too many arguments
++ The $NAMESPACE directive takes a single argument, a namespace in which all the
++ generated symbol names are placed.  This error is generated when the
++ compiler finds a $NAMESPACE directive with more than one argument.
+
+NSINVARG   $NAMESPACE directive has an invalid argument ('%s')
++ The $NAMESPACE argument should be a valid C++ namespace.  The reader does a
++ cursory check on its validity, checking that the characters in the namspace
++ are correct.  The error is generated when the reader finds an invalid
++ character. (Valid are alphanumeric characters, underscroes and colons.)
+
+NSNOARG    no arguments were given to the $NAMESPACE directive
++ The $NAMESPACE directive takes a single argument, a namespace in which all the
++ generated symbol names are placed.  This error is generated when the
++ compiler finds a $NAMESPACE directive with no arguments.
+
 ONETOKEN    a line containing a message ID ('%s') and nothing else was found
 + Message definitions comprise lines starting with a message identification (a
 + symbolic name for the message) and followed by the text of the message.  This
@@ -69,7 +91,7 @@ PRFINVARG   $PREFIX directive has an invalid argument ('%s')
 PRFNOARG    no arguments were given to the $PREFIX directive
 + The $PREFIX directive takes a single argument, a prefix to be added to the
 + symbol names when a C++ .h file is created.  This error is generated when the
-+ compiler finds a $PREFIX directive with noa rguments.
++ compiler finds a $PREFIX directive with no arguments.
 
 READERR     error reading from %s: %s
 + The specified error was encountered reading from the named input file.
diff --git a/src/lib/log/root_logger_name.cc b/src/lib/log/root_logger_name.cc
index 9378857..f330515 100644
--- a/src/lib/log/root_logger_name.cc
+++ b/src/lib/log/root_logger_name.cc
@@ -20,7 +20,10 @@
 namespace isc {
 namespace log {
 
-std::string RootLoggerName::name_("");
+std::string& RootLoggerName::rootName() {
+    static std::string root_name("");
+    return root_name;
+}
 
 }
 }
diff --git a/src/lib/log/root_logger_name.h b/src/lib/log/root_logger_name.h
index 80691d1..dc58206 100644
--- a/src/lib/log/root_logger_name.h
+++ b/src/lib/log/root_logger_name.h
@@ -46,18 +46,27 @@ public:
     /// \param name Name of the root logger.  This should be the program
     /// name.
     static void setName(const std::string& name) {
-        name_ = name;
+        rootName() = name;
     }
 
     /// \brief Get Root Logger Name
     ///
     /// \return Name of the root logger.
     static std::string getName() {
-        return name_;
+        return rootName();
     }
     
 private:
-    static std::string name_;      ///< Name of the root logger
+    /// \brief Store Root Logger Name
+    ///
+    /// Access the singleton root logger name.  This is stored as a static
+    /// variable inside a method to avoid the "static initialization fiasco";
+    /// when accessed by another class during initialization, the name will be
+    /// instantiated. (Else it will be only by chance that it is instantiated
+    /// before the cassling class.)
+    ///
+    /// \return Name addisnged to the root logger.
+    static std::string& rootName();
 };
 
 }
diff --git a/src/lib/log/tests/Makefile.am b/src/lib/log/tests/Makefile.am
index 9693270..8589501 100644
--- a/src/lib/log/tests/Makefile.am
+++ b/src/lib/log/tests/Makefile.am
@@ -22,6 +22,8 @@ run_unittests_SOURCES += message_dictionary_unittest.cc
 run_unittests_SOURCES += message_reader_unittest.cc
 run_unittests_SOURCES += message_initializer_unittest.cc
 run_unittests_SOURCES += message_initializer_unittest_2.cc
+run_unittests_SOURCES += message_types_unittest.cc
+run_unittests_SOURCES += message_types_unittest_2.cc
 run_unittests_SOURCES += strutil_unittest.cc
 # run_unittests_SOURCES += xdebuglevel_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
diff --git a/src/lib/log/tests/logger_support_test.cc b/src/lib/log/tests/logger_support_test.cc
index 4b0c30b..8c05f18 100644
--- a/src/lib/log/tests/logger_support_test.cc
+++ b/src/lib/log/tests/logger_support_test.cc
@@ -32,9 +32,7 @@
 
 using namespace isc::log;
 
-// Declare root logger and a logger to use an example.
-//RootLoggerName root_name("testing");
-
+// Declare root logger and a loggers to use an example.
 RootLoggerName root("alpha");
 Logger logger_ex("example");
 Logger logger_dlm("dlm");
diff --git a/src/lib/log/tests/message_dictionary_unittest.cc b/src/lib/log/tests/message_dictionary_unittest.cc
index 78aa851..2414b14 100644
--- a/src/lib/log/tests/message_dictionary_unittest.cc
+++ b/src/lib/log/tests/message_dictionary_unittest.cc
@@ -122,7 +122,7 @@ TEST_F(MessageDictionaryTest, LoadTest) {
     EXPECT_EQ(0, dictionary1.size());
 
     // Load a dictionary1.
-    vector<MessageID> duplicates = dictionary1.load(data1);
+    vector<string> duplicates = dictionary1.load(data1);
     EXPECT_EQ(3, dictionary1.size());
     EXPECT_EQ(string(data1[1]), dictionary1.getText(data1[0]));
     EXPECT_EQ(string(data1[3]), dictionary1.getText(data1[2]));
@@ -157,7 +157,7 @@ TEST_F(MessageDictionaryTest, Lookups) {
     };
 
     MessageDictionary dictionary;
-    vector<MessageID> duplicates = dictionary.load(data);
+    vector<string> duplicates = dictionary.load(data);
     EXPECT_EQ(3, dictionary.size());
     EXPECT_EQ(0, duplicates.size());
 
diff --git a/src/lib/log/tests/message_reader_unittest.cc b/src/lib/log/tests/message_reader_unittest.cc
index 2891805..3f61ddf 100644
--- a/src/lib/log/tests/message_reader_unittest.cc
+++ b/src/lib/log/tests/message_reader_unittest.cc
@@ -76,7 +76,7 @@ TEST_F(MessageReaderTest, BlanksAndComments) {
 
     // ... and (b) nothing gets added to either the map or the not-added section.
     EXPECT_EQ(0, dictionary_->size());
-    vector<MessageID> not_added = reader_.getNotAdded();
+    vector<string> not_added = reader_.getNotAdded();
     EXPECT_EQ(0, not_added.size());
 }
 
@@ -85,14 +85,15 @@ TEST_F(MessageReaderTest, BlanksAndComments) {
 
 void
 processLineException(MessageReader& reader, const char* what,
-    MessageID& expected) {
+    const MessageID& expected) {
 
     try {
         reader.processLine(what);
         FAIL() << "MessageReader::processLine() should throw an exception " <<
             " with message ID " << expected << " for '" << what << "'\n";
     } catch (MessageException& e) {
-        EXPECT_EQ(expected, e.id());
+        EXPECT_EQ(boost::lexical_cast<string>(expected),
+            boost::lexical_cast<string>(e.id()));
     } catch (...) {
         FAIL() << "Unknown exception thrown by MessageReader::processLine()\n";
     }
@@ -102,13 +103,13 @@ processLineException(MessageReader& reader, const char* what,
 
 TEST_F(MessageReaderTest, Prefix) {
 
-    // Check that no prefix is present
+    // Check that no $PREFIX is present
     EXPECT_EQ(string(""), reader_.getPrefix());
 
-    // Check that a prefix directive with no argument generates an error.
+    // Check that a $PREFIX directive with no argument generates an error.
     processLineException(reader_, "$PREFIX", MSG_PRFNOARG);
 
-    // Check a prefix with multiple arguments is invalid
+    // Check a $PREFIX with multiple arguments is invalid
     processLineException(reader_, "$prefix A B", MSG_PRFEXTRARG);
 
     // Prefixes should be alphanumeric (with underscores) and not start
@@ -132,6 +133,43 @@ TEST_F(MessageReaderTest, Prefix) {
     EXPECT_EQ(string(""), reader_.getPrefix());
 }
 
+// Check that it can parse a namespace
+
+TEST_F(MessageReaderTest, Namespace) {
+
+    // Check that no $NAMESPACE is present
+    EXPECT_EQ(string(""), reader_.getNamespace());
+
+    // Check that a $NAMESPACE directive with no argument generates an error.
+    processLineException(reader_, "$NAMESPACE", MSG_NSNOARG);
+
+    // Check a $NAMESPACE with multiple arguments is invalid
+    processLineException(reader_, "$namespace A B", MSG_NSEXTRARG);
+
+    // Namespaces should be alphanumeric (with underscores and colons)
+    processLineException(reader_, "$namespace ab[cd", MSG_NSINVARG);
+
+    // A valid $NAMESPACE should be accepted
+    EXPECT_NO_THROW(reader_.processLine("$NAMESPACE isc"));
+    EXPECT_EQ(string("isc"), reader_.getNamespace());
+
+    // (Check that we can clear the namespace)
+    reader_.clearNamespace();
+    EXPECT_EQ(string(""), reader_.getNamespace());
+
+    // Check that a valid namespace can include colons
+    EXPECT_NO_THROW(reader_.processLine("$NAMESPACE isc::log"));
+    EXPECT_EQ(string("isc::log"), reader_.getNamespace());
+
+    // Check that the indication of the anonymous namespace will be recognised.
+    reader_.clearNamespace();
+    EXPECT_NO_THROW(reader_.processLine("$NAMESPACE ::"));
+    EXPECT_EQ(string("::"), reader_.getNamespace());
+
+    // ... and that another $NAMESPACE is rejected
+    processLineException(reader_, "$NAMESPACE ABC", MSG_DUPLNS);
+}
+
 // Check that it can parse a line
 
 TEST_F(MessageReaderTest, ValidMessageAddDefault) {
@@ -148,7 +186,7 @@ TEST_F(MessageReaderTest, ValidMessageAddDefault) {
     EXPECT_EQ(2, dictionary_->size());
 
     // ... and ensure no messages were not added
-    vector<MessageID> not_added = reader_.getNotAdded();
+    vector<string> not_added = reader_.getNotAdded();
     EXPECT_EQ(0, not_added.size());
 }
 
@@ -168,7 +206,7 @@ TEST_F(MessageReaderTest, ValidMessageAdd) {
     EXPECT_EQ(2, dictionary_->size());
 
     // ... and ensure no messages were not added
-    vector<MessageID> not_added = reader_.getNotAdded();
+    vector<string> not_added = reader_.getNotAdded();
     EXPECT_EQ(0, not_added.size());
 }
 
@@ -191,7 +229,7 @@ TEST_F(MessageReaderTest, ValidMessageReplace) {
     EXPECT_EQ(2, dictionary_->size());
 
     // ... and ensure no messages were not added
-    vector<MessageID> not_added = reader_.getNotAdded();
+    vector<string> not_added = reader_.getNotAdded();
     EXPECT_EQ(0, not_added.size());
 }
 
@@ -219,7 +257,7 @@ TEST_F(MessageReaderTest, Overflows) {
     EXPECT_EQ(2, dictionary_->size());
 
     // ... and ensure no overflows
-    vector<MessageID> not_added = reader_.getNotAdded();
+    vector<string> not_added = reader_.getNotAdded();
     ASSERT_EQ(2, not_added.size());
 
     sort(not_added.begin(), not_added.end());
diff --git a/src/lib/log/tests/message_types_unittest.cc b/src/lib/log/tests/message_types_unittest.cc
new file mode 100644
index 0000000..0c95c48
--- /dev/null
+++ b/src/lib/log/tests/message_types_unittest.cc
@@ -0,0 +1,39 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+#include <log/message_types.h>
+#include <log/messagedef.h>
+
+using namespace isc::log;
+
+class MessageTypesTest : public ::testing::Test {
+public:
+    MessageTypesTest()
+    {
+    }
+};
+
+MessageID MessageTypeTest_MSG_DUPLNS();
+
+
+// Check that the message type equality check works.  This compares
+// two message IDs in the "messagedef.h" file declared here, with
+// the returned ID (which should be MSG_DUPLNS) declared elsewhere.
+
+TEST_F(MessageTypesTest, EqualID) {
+    EXPECT_TRUE(equalMessageID(MSG_DUPLNS, MSG_DUPLNS));
+    EXPECT_FALSE(equalMessageID(MSG_DUPLNS, MSG_DUPLPRFX));
+    EXPECT_TRUE(equalMessageID(MSG_DUPLNS, MessageTypeTest_MSG_DUPLNS()));
+}
diff --git a/src/lib/log/tests/message_types_unittest_2.cc b/src/lib/log/tests/message_types_unittest_2.cc
new file mode 100644
index 0000000..cc51734
--- /dev/null
+++ b/src/lib/log/tests/message_types_unittest_2.cc
@@ -0,0 +1,22 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <log/message_types.h>
+#include <log/messagedef.h>
+
+// Return a value for testing in message_types_unittest.cc
+
+isc::log::MessageID MessageTypeTest_MSG_DUPLNS() {
+    return (isc::log::MSG_DUPLNS);
+}




More information about the bind10-changes mailing list