diff --git a/catalogue/CmdLineTool.cpp b/catalogue/CmdLineTool.cpp
index d361c9f19f08ad4cd27e68a57217fb3a9747cf09..ecd12d7a8983bd241eec46bdbc0f0bc9b2a34e9b 100644
--- a/catalogue/CmdLineTool.cpp
+++ b/catalogue/CmdLineTool.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "catalogue/CmdLineTool.hpp"
+#include "common/exception/CommandLineNotParsed.hpp"
 
 #include <unistd.h>
 
@@ -44,7 +45,7 @@ CmdLineTool::~CmdLineTool() noexcept {
 //------------------------------------------------------------------------------
 // getUsername
 //------------------------------------------------------------------------------
-std::string CmdLineTool::getUsername() const {
+std::string CmdLineTool::getUsername() {
   char buf[256];
 
   if(getlogin_r(buf, sizeof(buf))) {
@@ -57,7 +58,7 @@ std::string CmdLineTool::getUsername() const {
 //------------------------------------------------------------------------------
 // getHostname
 //------------------------------------------------------------------------------
-std::string CmdLineTool::getHostname() const {
+std::string CmdLineTool::getHostname() {
   char buf[256];
 
   if(gethostname(buf, sizeof(buf))) {
@@ -68,5 +69,36 @@ std::string CmdLineTool::getHostname() const {
   }
 }
 
+//------------------------------------------------------------------------------
+// main
+//------------------------------------------------------------------------------
+int CmdLineTool::main(const int argc, char *const *const argv) {
+  bool cmdLineNotParsed = false;
+  std::string errorMessage;
+
+  try {
+    return exceptionThrowingMain(argc, argv);
+  } catch(exception::CommandLineNotParsed &ue) {
+    errorMessage = ue.getMessage().str();
+    cmdLineNotParsed = true;
+  } catch(exception::Exception &ex) {
+    errorMessage = ex.getMessage().str();
+  } catch(std::exception &se) {
+    errorMessage = se.what();
+  } catch(...) {
+    errorMessage = "An unknown exception was thrown";
+  }
+
+  // Reaching this point means the command has failed, an exception was throw
+  // and errorMessage has been set accordingly
+
+  m_err << "Aborting: " << errorMessage << std::endl;
+  if(cmdLineNotParsed) {
+    m_err << std::endl;
+    printUsage(m_err);
+  }
+  return 1;
+}
+
 } // namespace catalogue
 } // namespace cta
diff --git a/catalogue/CmdLineTool.hpp b/catalogue/CmdLineTool.hpp
index 5aa24c5adee631b87515d3ccc93c7991b6b657b4..191d66dacaa351ac8b403d7c40819db158ea6b2b 100644
--- a/catalogue/CmdLineTool.hpp
+++ b/catalogue/CmdLineTool.hpp
@@ -44,6 +44,18 @@ public:
    */
   virtual ~CmdLineTool() noexcept = 0;
 
+  /**
+   * The object's implementation of main() that should be called from the main()
+   * of the program.
+   *
+   * @param argc The number of command-line arguments including the program name.
+   * @param argv The command-line arguments.
+   * @return The exit value of the program.
+   */
+  int main(const int argc, char *const *const argv);
+
+protected:
+
   /**
    * An exception throwing version of main().
    *
@@ -53,7 +65,12 @@ public:
    */
   virtual int exceptionThrowingMain(const int argc, char *const *const argv) = 0;
 
-protected:
+  /**
+   * Prints the usage message of the command-line tool.
+   *
+   * @param os The output stream to which the usage message is to be printed.
+   */
+  virtual void printUsage(std::ostream &os) = 0;
 
   /**
    * Standard input stream.
@@ -75,14 +92,14 @@ protected:
    *
    * @return The name of the user running the command-line tool.
    */
-  std::string getUsername() const;
+  static std::string getUsername();
 
   /**
    * Returns the name of the host on which the command-line tool is running.
    *
    * @return The name of the host on which the command-line tool is running.
    */
-  std::string getHostname() const;
+  static std::string getHostname();
 
 }; // class CmdLineTool
 
diff --git a/catalogue/CreateAdminHostCmd.cpp b/catalogue/CreateAdminHostCmd.cpp
index 122b1a8e59b82ed71bda793631e35a5d1c3a36b1..35b995a42d372c5718c0a99213e87706ed3198ff 100644
--- a/catalogue/CreateAdminHostCmd.cpp
+++ b/catalogue/CreateAdminHostCmd.cpp
@@ -48,7 +48,7 @@ int CreateAdminHostCmd::exceptionThrowingMain(const int argc, char *const *const
   const CreateAdminHostCmdLineArgs cmdLineArgs(argc, argv);
 
   if(cmdLineArgs.help) {
-    CreateAdminHostCmdLineArgs::printUsage(m_out);
+    printUsage(m_out);
     return 0;
   }
 
@@ -61,5 +61,12 @@ int CreateAdminHostCmd::exceptionThrowingMain(const int argc, char *const *const
   return 0;
 }
 
+//------------------------------------------------------------------------------
+// printUsage
+//------------------------------------------------------------------------------
+void CreateAdminHostCmd::printUsage(std::ostream &os) {
+  CreateAdminHostCmdLineArgs::printUsage(os);
+}
+
 } // namespace catalogue
 } // namespace cta
diff --git a/catalogue/CreateAdminHostCmd.hpp b/catalogue/CreateAdminHostCmd.hpp
index 384073fdf5571cbe8d11f3fdc54a5b6d6716582d..1b9a680568efb39f9498e9bbef6b4452ee1cd9e3 100644
--- a/catalogue/CreateAdminHostCmd.hpp
+++ b/catalogue/CreateAdminHostCmd.hpp
@@ -44,6 +44,8 @@ public:
    */
   ~CreateAdminHostCmd() noexcept;
 
+private:
+
   /**
    * An exception throwing version of main().
    *
@@ -51,7 +53,14 @@ public:
    * @param argv The command-line arguments.
    * @return The exit value of the program.
    */
-  int exceptionThrowingMain(const int argc, char *const *const argv);
+  int exceptionThrowingMain(const int argc, char *const *const argv) override;
+
+  /**
+   * Prints the usage message of the command-line tool.
+   *
+   * @param os The output stream to which the usage message is to be printed.
+   */
+  void printUsage(std::ostream &os) override;
 
 }; // class CreateAdminHostCmd
 
diff --git a/catalogue/CreateAdminHostCmdMain.cpp b/catalogue/CreateAdminHostCmdMain.cpp
index bf35559631984e3d74231672fb43f3f38f68b050..6817752c4da3e8046835e87ae70ad1c99eb9b3ce 100644
--- a/catalogue/CreateAdminHostCmdMain.cpp
+++ b/catalogue/CreateAdminHostCmdMain.cpp
@@ -17,61 +17,13 @@
  */
 
 #include "catalogue/CreateAdminHostCmd.hpp"
-#include "catalogue/CreateAdminHostCmdLineArgs.hpp"
-#include "common/exception/Exception.hpp"
-#include "common/exception/CommandLineNotParsed.hpp"
 
 #include <iostream>
 
-/**
- * An exception throwing version of main().
- *
- * @param argc The number of command-line arguments including the program name.
- * @param argv The command-line arguments.
- * @return The exit value of the program.
- */
-static int exceptionThrowingMain(const int argc, char *const *const argv);
-
 //------------------------------------------------------------------------------
 // main
 //------------------------------------------------------------------------------
 int main(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  bool cmdLineNotParsed = false;
-  std::string errorMessage;
-
-  try {
-    return exceptionThrowingMain(argc, argv);
-  } catch(exception::CommandLineNotParsed &ue) {
-    errorMessage = ue.getMessage().str();
-    cmdLineNotParsed = true;
-  } catch(exception::Exception &ex) {
-    errorMessage = ex.getMessage().str();
-  } catch(std::exception &se) {
-    errorMessage = se.what();
-  } catch(...) {
-    errorMessage = "An unknown exception was thrown";
-  }
-
-  // Reaching this point means the command has failed, an exception was throw
-  // and errorMessage has been set accordingly
-
-  std::cerr << "Aborting: " << errorMessage << std::endl;
-  if(cmdLineNotParsed) {
-    std::cerr << std::endl;
-    catalogue::CreateAdminHostCmdLineArgs::printUsage(std::cerr);
-  }
-  return 1;
-}
-
-//------------------------------------------------------------------------------
-// exceptionThrowingMain
-//------------------------------------------------------------------------------
-static int exceptionThrowingMain(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  catalogue::CreateAdminHostCmd cmd(std::cin, std::cout, std::cerr);
-
-  return cmd.exceptionThrowingMain(argc, argv);
+  cta::catalogue::CreateAdminHostCmd cmd(std::cin, std::cout, std::cerr);
+  return cmd.main(argc, argv);
 }
diff --git a/catalogue/CreateAdminUserCmd.cpp b/catalogue/CreateAdminUserCmd.cpp
index 15fdccd8b93a0f65a20bddb190e11858ecee44ae..a86de267cd48c68c2ed77359e00dc6fb4fbab499 100644
--- a/catalogue/CreateAdminUserCmd.cpp
+++ b/catalogue/CreateAdminUserCmd.cpp
@@ -48,7 +48,7 @@ int CreateAdminUserCmd::exceptionThrowingMain(const int argc, char *const *const
   const CreateAdminUserCmdLineArgs cmdLineArgs(argc, argv);
 
   if(cmdLineArgs.help) {
-    CreateAdminUserCmdLineArgs::printUsage(m_out);
+    printUsage(m_out);
     return 0;
   }
 
@@ -61,5 +61,12 @@ int CreateAdminUserCmd::exceptionThrowingMain(const int argc, char *const *const
   return 0;
 }
 
+//------------------------------------------------------------------------------
+// printUsage
+//------------------------------------------------------------------------------
+void CreateAdminUserCmd::printUsage(std::ostream &os) {
+  CreateAdminUserCmdLineArgs::printUsage(os);
+}
+
 } // namespace catalogue
 } // namespace cta
diff --git a/catalogue/CreateAdminUserCmd.hpp b/catalogue/CreateAdminUserCmd.hpp
index f0aca419b70a08d7f0b5a02c7caafd0397301b71..d8ef4f9158985d5c91888427d326104d43f353c3 100644
--- a/catalogue/CreateAdminUserCmd.hpp
+++ b/catalogue/CreateAdminUserCmd.hpp
@@ -44,6 +44,8 @@ public:
    */
   ~CreateAdminUserCmd() noexcept;
 
+private:
+
   /**
    * An exception throwing version of main().
    *
@@ -51,7 +53,14 @@ public:
    * @param argv The command-line arguments.
    * @return The exit value of the program.
    */
-  int exceptionThrowingMain(const int argc, char *const *const argv);
+  int exceptionThrowingMain(const int argc, char *const *const argv) override;
+
+  /**
+   * Prints the usage message of the command-line tool.
+   *
+   * @param os The output stream to which the usage message is to be printed.
+   */
+  void printUsage(std::ostream &os) override;
 
 }; // class CreateAdminUserCmd
 
diff --git a/catalogue/CreateAdminUserCmdMain.cpp b/catalogue/CreateAdminUserCmdMain.cpp
index b41f2473b2b91d3f8c8fd33606fb6f0823700cfd..58bb31ea20e8628eb1daf1c6161507947847129d 100644
--- a/catalogue/CreateAdminUserCmdMain.cpp
+++ b/catalogue/CreateAdminUserCmdMain.cpp
@@ -17,61 +17,13 @@
  */
 
 #include "catalogue/CreateAdminUserCmd.hpp"
-#include "catalogue/CreateAdminUserCmdLineArgs.hpp"
-#include "common/exception/Exception.hpp"
-#include "common/exception/CommandLineNotParsed.hpp"
 
 #include <iostream>
 
-/**
- * An exception throwing version of main().
- *
- * @param argc The number of command-line arguments including the program name.
- * @param argv The command-line arguments.
- * @return The exit value of the program.
- */
-static int exceptionThrowingMain(const int argc, char *const *const argv);
-
 //------------------------------------------------------------------------------
 // main
 //------------------------------------------------------------------------------
 int main(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  bool cmdLineNotParsed = false;
-  std::string errorMessage;
-
-  try {
-    return exceptionThrowingMain(argc, argv);
-  } catch(exception::CommandLineNotParsed &ue) {
-    errorMessage = ue.getMessage().str();
-    cmdLineNotParsed = true;
-  } catch(exception::Exception &ex) {
-    errorMessage = ex.getMessage().str();
-  } catch(std::exception &se) {
-    errorMessage = se.what();
-  } catch(...) {
-    errorMessage = "An unknown exception was thrown";
-  }
-
-  // Reaching this point means the command has failed, an exception was throw
-  // and errorMessage has been set accordingly
-
-  std::cerr << "Aborting: " << errorMessage << std::endl;
-  if(cmdLineNotParsed) {
-    std::cerr << std::endl;
-    catalogue::CreateAdminUserCmdLineArgs::printUsage(std::cerr);
-  }
-  return 1;
-}
-
-//------------------------------------------------------------------------------
-// exceptionThrowingMain
-//------------------------------------------------------------------------------
-static int exceptionThrowingMain(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  catalogue::CreateAdminUserCmd cmd(std::cin, std::cout, std::cerr);
-
-  return cmd.exceptionThrowingMain(argc, argv);
+  cta::catalogue::CreateAdminUserCmd cmd(std::cin, std::cout, std::cerr);
+  return cmd.main(argc, argv);
 }
diff --git a/catalogue/CreateSchemaCmd.cpp b/catalogue/CreateSchemaCmd.cpp
index 82cdb51f085a07675a96df39c7e3c0a4a6191bdc..2e03dab2afdf4a38094eec3d569303c9a7b6adc5 100644
--- a/catalogue/CreateSchemaCmd.cpp
+++ b/catalogue/CreateSchemaCmd.cpp
@@ -48,7 +48,7 @@ int CreateSchemaCmd::exceptionThrowingMain(const int argc, char *const *const ar
   const CreateSchemaCmdLineArgs cmdLineArgs(argc, argv);
 
   if(cmdLineArgs.help) {
-    cmdLineArgs.printUsage(m_out);
+    printUsage(m_out);
     return 0;
   }
 
@@ -103,5 +103,12 @@ bool CreateSchemaCmd::tableExists(const std::string tableName, rdbms::Conn &conn
   return false;
 }
 
+//------------------------------------------------------------------------------
+// printUsage
+//------------------------------------------------------------------------------
+void CreateSchemaCmd::printUsage(std::ostream &os) {
+  CreateSchemaCmdLineArgs::printUsage(os);
+}
+
 } // namespace catalogue
 } // namespace cta
diff --git a/catalogue/CreateSchemaCmd.hpp b/catalogue/CreateSchemaCmd.hpp
index 63140e9e15a252b649a4900accb4d8d1ba0b10f9..cae11221e303e371135196e0b016eccb2b727b43 100644
--- a/catalogue/CreateSchemaCmd.hpp
+++ b/catalogue/CreateSchemaCmd.hpp
@@ -44,6 +44,8 @@ public:
    */
   ~CreateSchemaCmd() noexcept;
 
+private:
+
   /**
    * An exception throwing version of main().
    *
@@ -53,7 +55,12 @@ public:
    */
   int exceptionThrowingMain(const int argc, char *const *const argv) override;
 
-private:
+  /**
+   * Prints the usage message of the command-line tool.
+   *
+   * @param os The output stream to which the usage message is to be printed.
+   */
+  void printUsage(std::ostream &os) override;
 
   /**
    * Returns true if the table with the specified name exists in the database
diff --git a/catalogue/CreateSchemaCmdMain.cpp b/catalogue/CreateSchemaCmdMain.cpp
index 0a7ce53afd9479868f63777f5fc5323344e51150..bf212c2c359328ed25e2a2e8bd9f6ee3a3a87535 100644
--- a/catalogue/CreateSchemaCmdMain.cpp
+++ b/catalogue/CreateSchemaCmdMain.cpp
@@ -17,61 +17,13 @@
  */
 
 #include "catalogue/CreateSchemaCmd.hpp"
-#include "catalogue/CreateSchemaCmdLineArgs.hpp"
-#include "common/exception/Exception.hpp"
-#include "common/exception/CommandLineNotParsed.hpp"
 
 #include <iostream>
 
-/**
- * An exception throwing version of main().
- *
- * @param argc The number of command-line arguments including the program name.
- * @param argv The command-line arguments.
- * @return The exit value of the program.
- */
-static int exceptionThrowingMain(const int argc, char *const *const argv);
-
 //------------------------------------------------------------------------------
 // main
 //------------------------------------------------------------------------------
 int main(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  bool cmdLineNotParsed = false;
-  std::string errorMessage;
-
-  try {
-    return exceptionThrowingMain(argc, argv);
-  } catch(exception::CommandLineNotParsed &ue) {
-    errorMessage = ue.getMessage().str();
-    cmdLineNotParsed = true;
-  } catch(exception::Exception &ex) {
-    errorMessage = ex.getMessage().str();
-  } catch(std::exception &se) {
-    errorMessage = se.what();
-  } catch(...) {
-    errorMessage = "An unknown exception was thrown";
-  }
-
-  // Reaching this point means the command has failed, an exception was throw
-  // and errorMessage has been set accordingly
-
-  std::cerr << "Aborting: " << errorMessage << std::endl;
-  if(cmdLineNotParsed) {
-    std::cerr << std::endl;
-    catalogue::CreateSchemaCmdLineArgs::printUsage(std::cerr);
-  }
-  return 1;
-}
-
-//------------------------------------------------------------------------------
-// exceptionThrowingMain
-//------------------------------------------------------------------------------
-static int exceptionThrowingMain(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  catalogue::CreateSchemaCmd cmd(std::cin, std::cout, std::cerr);
-
-  return cmd.exceptionThrowingMain(argc, argv);
+  cta::catalogue::CreateSchemaCmd cmd(std::cin, std::cout, std::cerr);
+  return cmd.main(argc, argv);
 }
diff --git a/catalogue/DeleteAllCatalogueDataCmd.cpp b/catalogue/DeleteAllCatalogueDataCmd.cpp
index 18d19a13f3124ad3144afc1415d779b2ae386e85..c42c38e4afc4c463d824d13341cf517533631c73 100644
--- a/catalogue/DeleteAllCatalogueDataCmd.cpp
+++ b/catalogue/DeleteAllCatalogueDataCmd.cpp
@@ -47,7 +47,7 @@ int DeleteAllCatalogueDataCmd::exceptionThrowingMain(const int argc, char *const
   const DeleteAllCatalogueDataCmdLineArgs cmdLineArgs(argc, argv);
 
   if(cmdLineArgs.help) {
-    DeleteAllCatalogueDataCmdLineArgs::printUsage(m_out);
+    printUsage(m_out);
     return 0;
   }
 
@@ -213,5 +213,12 @@ void DeleteAllCatalogueDataCmd::deleteMountPolicies(Catalogue &catalogue) {
   m_out << "Deleted " << mountPolicies.size() << " mount policies" << std::endl;
 }
 
+//------------------------------------------------------------------------------
+// printUsage
+//------------------------------------------------------------------------------
+void DeleteAllCatalogueDataCmd::printUsage(std::ostream &os) {
+  DeleteAllCatalogueDataCmdLineArgs::printUsage(os);
+}
+
 } // namespace catalogue
 } // namespace cta
diff --git a/catalogue/DeleteAllCatalogueDataCmd.hpp b/catalogue/DeleteAllCatalogueDataCmd.hpp
index 4a208638881f1f769fb150bcb9e96c6dcf8e45f4..0c4fa14f518e7a7f3b5dd442af6a35204ce76eb3 100644
--- a/catalogue/DeleteAllCatalogueDataCmd.hpp
+++ b/catalogue/DeleteAllCatalogueDataCmd.hpp
@@ -45,6 +45,8 @@ public:
    */
   ~DeleteAllCatalogueDataCmd() noexcept;
 
+private:
+
   /**
    * An exception throwing version of main().
    *
@@ -54,7 +56,12 @@ public:
    */
   int exceptionThrowingMain(const int argc, char *const *const argv) override;
 
-private:
+  /**
+   * Prints the usage message of the command-line tool.
+   *
+   * @param os The output stream to which the usage message is to be printed.
+   */
+  void printUsage(std::ostream &os) override;
 
   /**
    * Deletes all of the rows of all of the tables in the specified catalogue
diff --git a/catalogue/DeleteAllCatalogueDataCmdMain.cpp b/catalogue/DeleteAllCatalogueDataCmdMain.cpp
index 3a85de8603e3c7f6bc05219b3acf5bc6681870cb..f8e8c0a2521b564d81e107f6d9e0fbf3fd30159d 100644
--- a/catalogue/DeleteAllCatalogueDataCmdMain.cpp
+++ b/catalogue/DeleteAllCatalogueDataCmdMain.cpp
@@ -17,61 +17,13 @@
  */
 
 #include "catalogue/DeleteAllCatalogueDataCmd.hpp"
-#include "catalogue/DeleteAllCatalogueDataCmdLineArgs.hpp"
-#include "common/exception/Exception.hpp"
-#include "common/exception/CommandLineNotParsed.hpp"
 
 #include <iostream>
 
-/**
- * An exception throwing version of main().
- *
- * @param argc The number of command-line arguments including the program name.
- * @param argv The command-line arguments.
- * @return The exit value of the program.
- */
-static int exceptionThrowingMain(const int argc, char *const *const argv);
-
 //------------------------------------------------------------------------------
 // main
 //------------------------------------------------------------------------------
 int main(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  bool cmdLineNotParsed = false;
-  std::string errorMessage;
-
-  try {
-    return exceptionThrowingMain(argc, argv);
-  } catch(exception::CommandLineNotParsed &ue) {
-    errorMessage = ue.getMessage().str();
-    cmdLineNotParsed = true;
-  } catch(exception::Exception &ex) {
-    errorMessage = ex.getMessage().str();
-  } catch(std::exception &se) {
-    errorMessage = se.what();
-  } catch(...) {
-    errorMessage = "An unknown exception was thrown";
-  }
-
-  // Reaching this point means the command has failed, an exception was throw
-  // and errorMessage has been set accordingly
-
-  std::cerr << "Aborting: " << errorMessage << std::endl;
-  if(cmdLineNotParsed) {
-    std::cerr << std::endl;
-    catalogue::DeleteAllCatalogueDataCmdLineArgs::printUsage(std::cerr);
-  }
-  return 1;
-}
-
-//------------------------------------------------------------------------------
-// exceptionThrowingMain
-//------------------------------------------------------------------------------
-static int exceptionThrowingMain(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  catalogue::DeleteAllCatalogueDataCmd cmd(std::cin, std::cout, std::cerr);
-
-  return cmd.exceptionThrowingMain(argc, argv);
+  cta::catalogue::DeleteAllCatalogueDataCmd cmd(std::cin, std::cout, std::cerr);
+  return cmd.main(argc, argv);
 }
diff --git a/catalogue/DropSchemaCmd.cpp b/catalogue/DropSchemaCmd.cpp
index 673acd403abee5ba25ad7ea5b974bd49826c669c..c39a2c0a0766b81fdbb8e75852bcfe4c2177360f 100644
--- a/catalogue/DropSchemaCmd.cpp
+++ b/catalogue/DropSchemaCmd.cpp
@@ -50,7 +50,7 @@ int DropSchemaCmd::exceptionThrowingMain(const int argc, char *const *const argv
   const DropSchemaCmdLineArgs cmdLineArgs(argc, argv);
 
   if(cmdLineArgs.help) {
-    DropSchemaCmdLineArgs::printUsage(m_out);
+    printUsage(m_out);
     return 0;
   }
 
@@ -123,5 +123,12 @@ void DropSchemaCmd::dropCatalogueSchema(const rdbms::Login &dbLogin) {
   }
 }
 
+//------------------------------------------------------------------------------
+// printUsage
+//------------------------------------------------------------------------------
+void DropSchemaCmd::printUsage(std::ostream &os) {
+  DropSchemaCmdLineArgs::printUsage(os);
+}
+
 } // namespace catalogue
 } // namespace cta
diff --git a/catalogue/DropSchemaCmd.hpp b/catalogue/DropSchemaCmd.hpp
index 73e222b4e921fbe746a5ebf93f892088c9269382..2d551baa76463367bb2bd5c164f51fd7d8138c54 100644
--- a/catalogue/DropSchemaCmd.hpp
+++ b/catalogue/DropSchemaCmd.hpp
@@ -46,6 +46,8 @@ public:
    */
   ~DropSchemaCmd() noexcept;
 
+private:
+
   /**
    * An exception throwing version of main().
    *
@@ -55,7 +57,12 @@ public:
    */
   int exceptionThrowingMain(const int argc, char *const *const argv) override;
 
-private:
+  /**
+   * Prints the usage message of the command-line tool.
+   *
+   * @param os The output stream to which the usage message is to be printed.
+   */
+  void printUsage(std::ostream &os) override;
 
   /**
    * Unconditionally drops the schema of the catalogue database associated with
diff --git a/catalogue/DropSchemaCmdMain.cpp b/catalogue/DropSchemaCmdMain.cpp
index a2345257430fb3ae4c213b07aef52b9ea0b6af2a..ac01967ac9f2d979023f42fd320e97c3a2acb55d 100644
--- a/catalogue/DropSchemaCmdMain.cpp
+++ b/catalogue/DropSchemaCmdMain.cpp
@@ -17,61 +17,13 @@
  */
 
 #include "catalogue/DropSchemaCmd.hpp"
-#include "catalogue/DropSchemaCmdLineArgs.hpp"
-#include "common/exception/Exception.hpp"
-#include "common/exception/CommandLineNotParsed.hpp"
 
 #include <iostream>
 
-/**
- * An exception throwing version of main().
- *
- * @param argc The number of command-line arguments including the program name.
- * @param argv The command-line arguments.
- * @return The exit value of the program.
- */
-static int exceptionThrowingMain(const int argc, char *const *const argv);
-
 //------------------------------------------------------------------------------
 // main
 //------------------------------------------------------------------------------
 int main(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  bool cmdLineNotParsed = false;
-  std::string errorMessage;
-
-  try {
-    return exceptionThrowingMain(argc, argv);
-  } catch(exception::CommandLineNotParsed &ue) {
-    errorMessage = ue.getMessage().str();
-    cmdLineNotParsed = true;
-  } catch(exception::Exception &ex) {
-    errorMessage = ex.getMessage().str();
-  } catch(std::exception &se) {
-    errorMessage = se.what();
-  } catch(...) {
-    errorMessage = "An unknown exception was thrown";
-  }
-
-  // Reaching this point means the command has failed, an exception was throw
-  // and errorMessage has been set accordingly
-
-  std::cerr << "Aborting: " << errorMessage << std::endl;
-  if(cmdLineNotParsed) {
-    std::cerr << std::endl;
-    catalogue::DropSchemaCmdLineArgs::printUsage(std::cerr);
-  }
-  return 1;
-}
-
-//------------------------------------------------------------------------------
-// exceptionThrowingMain
-//------------------------------------------------------------------------------
-static int exceptionThrowingMain(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  catalogue::DropSchemaCmd cmd(std::cin, std::cout, std::cerr);
-
-  return cmd.exceptionThrowingMain(argc, argv);
+  cta::catalogue::DropSchemaCmd cmd(std::cin, std::cout, std::cerr);
+  return cmd.main(argc, argv);
 }
diff --git a/catalogue/LockSchemaCmd.cpp b/catalogue/LockSchemaCmd.cpp
index 7fcb4fd15e0022f7e3eb12945b33782c563d2957..a01541f4efb131e0e4fec572b7d17f7d54094b85 100644
--- a/catalogue/LockSchemaCmd.cpp
+++ b/catalogue/LockSchemaCmd.cpp
@@ -43,7 +43,7 @@ int LockSchemaCmd::exceptionThrowingMain(const int argc, char *const *const argv
   const LockSchemaCmdLineArgs cmdLineArgs(argc, argv);
 
   if(cmdLineArgs.help) {
-    LockSchemaCmdLineArgs::printUsage(m_out);
+    printUsage(m_out);
     return 0;
   }
 
@@ -55,5 +55,13 @@ int LockSchemaCmd::exceptionThrowingMain(const int argc, char *const *const argv
   return 0;
 }
 
+//------------------------------------------------------------------------------
+// printUsage
+//------------------------------------------------------------------------------
+void LockSchemaCmd::printUsage(std::ostream &os) {
+  LockSchemaCmdLineArgs::printUsage(os);
+}
+
+
 } // namespace catalogue
 } // namespace cta
diff --git a/catalogue/LockSchemaCmd.hpp b/catalogue/LockSchemaCmd.hpp
index f325e16a7535664658b5f7a12a815abf63e88c4a..1e999a9e5a53af536c013539e515f866a2a185de 100644
--- a/catalogue/LockSchemaCmd.hpp
+++ b/catalogue/LockSchemaCmd.hpp
@@ -44,6 +44,8 @@ public:
    */
   ~LockSchemaCmd() noexcept;
 
+private:
+
   /**
    * An exception throwing version of main().
    *
@@ -51,7 +53,14 @@ public:
    * @param argv The command-line arguments.
    * @return The exit value of the program.
    */
-  int exceptionThrowingMain(const int argc, char *const *const argv);
+  int exceptionThrowingMain(const int argc, char *const *const argv) override;
+
+  /**
+   * Prints the usage message of the command-line tool.
+   *
+   * @param os The output stream to which the usage message is to be printed.
+   */
+  void printUsage(std::ostream &os) override;
 
 }; // class LockSchemaCmd
 
diff --git a/catalogue/LockSchemaCmdMain.cpp b/catalogue/LockSchemaCmdMain.cpp
index 517234c0c20e848aaf0cc976a4877907b0eb3b5b..672888db66b3479520b2a0e9173b737e1d2fc533 100644
--- a/catalogue/LockSchemaCmdMain.cpp
+++ b/catalogue/LockSchemaCmdMain.cpp
@@ -17,61 +17,13 @@
  */
 
 #include "catalogue/LockSchemaCmd.hpp"
-#include "catalogue/LockSchemaCmdLineArgs.hpp"
-#include "common/exception/Exception.hpp"
-#include "common/exception/CommandLineNotParsed.hpp"
 
 #include <iostream>
 
-/**
- * An exception throwing version of main().
- *
- * @param argc The number of command-line arguments including the program name.
- * @param argv The command-line arguments.
- * @return The exit value of the program.
- */
-static int exceptionThrowingMain(const int argc, char *const *const argv);
-
 //------------------------------------------------------------------------------
 // main
 //------------------------------------------------------------------------------
 int main(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  bool cmdLineNotParsed = false;
-  std::string errorMessage;
-
-  try {
-    return exceptionThrowingMain(argc, argv);
-  } catch(exception::CommandLineNotParsed &ue) {
-    errorMessage = ue.getMessage().str();
-    cmdLineNotParsed = true;
-  } catch(exception::Exception &ex) {
-    errorMessage = ex.getMessage().str();
-  } catch(std::exception &se) {
-    errorMessage = se.what();
-  } catch(...) {
-    errorMessage = "An unknown exception was thrown";
-  }
-
-  // Reaching this point means the command has failed, an exception was throw
-  // and errorMessage has been set accordingly
-
-  std::cerr << "Aborting: " << errorMessage << std::endl;
-  if(cmdLineNotParsed) {
-    std::cerr << std::endl;
-    catalogue::LockSchemaCmdLineArgs::printUsage(std::cerr);
-  }
-  return 1;
-}
-
-//------------------------------------------------------------------------------
-// exceptionThrowingMain
-//------------------------------------------------------------------------------
-static int exceptionThrowingMain(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  catalogue::LockSchemaCmd cmd(std::cin, std::cout, std::cerr);
-
-  return cmd.exceptionThrowingMain(argc, argv);
+  cta::catalogue::LockSchemaCmd cmd(std::cin, std::cout, std::cerr);
+  return cmd.main(argc, argv);
 }
diff --git a/catalogue/PollDatabaseCmd.cpp b/catalogue/PollDatabaseCmd.cpp
index bb0b366d70623d7c7b181bd2dbb3dc778b72414a..9a6af9f241a753e7d57c4d68397d2d0f013e9f3e 100644
--- a/catalogue/PollDatabaseCmd.cpp
+++ b/catalogue/PollDatabaseCmd.cpp
@@ -47,7 +47,7 @@ int PollDatabaseCmd::exceptionThrowingMain(const int argc, char *const *const ar
   const PollDatabaseCmdLineArgs cmdLineArgs(argc, argv);
 
   if(cmdLineArgs.help) {
-    PollDatabaseCmdLineArgs::printUsage(m_out);
+    printUsage(m_out);
     return 0;
   }
 
@@ -75,5 +75,12 @@ int PollDatabaseCmd::exceptionThrowingMain(const int argc, char *const *const ar
   return 0;
 }
 
+//------------------------------------------------------------------------------
+// printUsage
+//------------------------------------------------------------------------------
+void PollDatabaseCmd::printUsage(std::ostream &os) {
+  PollDatabaseCmdLineArgs::printUsage(os);
+}
+
 } // namespace catalogue
 } // namespace cta
diff --git a/catalogue/PollDatabaseCmd.hpp b/catalogue/PollDatabaseCmd.hpp
index ff77011b019c1719d56895d3a4b49f9982f00ee3..15f5d8ea67559f125681eb540f69bcf8640306ad 100644
--- a/catalogue/PollDatabaseCmd.hpp
+++ b/catalogue/PollDatabaseCmd.hpp
@@ -50,6 +50,8 @@ public:
    */
   ~PollDatabaseCmd() noexcept;
 
+private:
+
   /**
    * An exception throwing version of main().
    *
@@ -59,6 +61,13 @@ public:
    */
   int exceptionThrowingMain(const int argc, char *const *const argv) override;
 
+  /**
+   * Prints the usage message of the command-line tool.
+   *
+   * @param os The output stream to which the usage message is to be printed.
+   */
+  void printUsage(std::ostream &os) override;
+
 }; // class PollDatabaseCmd
 
 } // namespace catalogue
diff --git a/catalogue/PollDatabaseCmdMain.cpp b/catalogue/PollDatabaseCmdMain.cpp
index f94fd554fe54b550329eebf203c995c12a87b0df..87174d638ba594f6f00851fee703f584fce5ff06 100644
--- a/catalogue/PollDatabaseCmdMain.cpp
+++ b/catalogue/PollDatabaseCmdMain.cpp
@@ -17,61 +17,13 @@
  */
 
 #include "catalogue/PollDatabaseCmd.hpp"
-#include "catalogue/PollDatabaseCmdLineArgs.hpp"
-#include "common/exception/Exception.hpp"
-#include "common/exception/CommandLineNotParsed.hpp"
 
 #include <iostream>
 
-/**
- * An exception throwing version of main().
- *
- * @param argc The number of command-line arguments including the program name.
- * @param argv The command-line arguments.
- * @return The exit value of the program.
- */
-static int exceptionThrowingMain(const int argc, char *const *const argv);
-
 //------------------------------------------------------------------------------
 // main
 //------------------------------------------------------------------------------
 int main(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  bool cmdLineNotParsed = false;
-  std::string errorMessage;
-
-  try {
-    return exceptionThrowingMain(argc, argv);
-  } catch(exception::CommandLineNotParsed &ue) {
-    errorMessage = ue.getMessage().str();
-    cmdLineNotParsed = true;
-  } catch(exception::Exception &ex) {
-    errorMessage = ex.getMessage().str();
-  } catch(std::exception &se) {
-    errorMessage = se.what();
-  } catch(...) {
-    errorMessage = "An unknown exception was thrown";
-  }
-
-  // Reaching this point means the command has failed, an exception was throw
-  // and errorMessage has been set accordingly
-
-  std::cerr << "Aborting: " << errorMessage << std::endl;
-  if(cmdLineNotParsed) {
-    std::cerr << std::endl;
-    catalogue::PollDatabaseCmdLineArgs::printUsage(std::cerr);
-  }
-  return 1;
-}
-
-//------------------------------------------------------------------------------
-// exceptionThrowingMain
-//------------------------------------------------------------------------------
-static int exceptionThrowingMain(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  catalogue::PollDatabaseCmd cmd(std::cin, std::cout, std::cerr);
-
-  return cmd.exceptionThrowingMain(argc, argv);
+  cta::catalogue::PollDatabaseCmd cmd(std::cin, std::cout, std::cerr);
+  return cmd.main(argc, argv);
 }
diff --git a/catalogue/SchemaStatusCmd.cpp b/catalogue/SchemaStatusCmd.cpp
index 9d438a48d0f656c0f7d248a5e825bc1649514a1c..f6a0b3cb2ca5444e103a3256a620c500908da828 100644
--- a/catalogue/SchemaStatusCmd.cpp
+++ b/catalogue/SchemaStatusCmd.cpp
@@ -43,7 +43,7 @@ int SchemaStatusCmd::exceptionThrowingMain(const int argc, char *const *const ar
   const SchemaStatusCmdLineArgs cmdLineArgs(argc, argv);
 
   if(cmdLineArgs.help) {
-    SchemaStatusCmdLineArgs::printUsage(m_out);
+    printUsage(m_out);
     return 0;
   }
 
@@ -56,5 +56,12 @@ int SchemaStatusCmd::exceptionThrowingMain(const int argc, char *const *const ar
   return 0;
 }
 
+//------------------------------------------------------------------------------
+// printUsage
+//------------------------------------------------------------------------------
+void SchemaStatusCmd::printUsage(std::ostream &os) {
+  SchemaStatusCmdLineArgs::printUsage(os);
+}
+
 } // namespace catalogue
 } // namespace cta
diff --git a/catalogue/SchemaStatusCmd.hpp b/catalogue/SchemaStatusCmd.hpp
index 3027cbf8d402684731300eb54cfa4176f05f07e2..0bcd538a6c1803a755a5da582118356476203688 100644
--- a/catalogue/SchemaStatusCmd.hpp
+++ b/catalogue/SchemaStatusCmd.hpp
@@ -43,6 +43,8 @@ public:
    */
   ~SchemaStatusCmd() noexcept;
 
+private:
+
   /**
    * An exception throwing version of main().
    *
@@ -50,7 +52,14 @@ public:
    * @param argv The command-line arguments.
    * @return The exit value of the program.
    */
-  int exceptionThrowingMain(const int argc, char *const *const argv);
+  int exceptionThrowingMain(const int argc, char *const *const argv) override;
+
+  /**
+   * Prints the usage message of the command-line tool.
+   *
+   * @param os The output stream to which the usage message is to be printed.
+   */
+  void printUsage(std::ostream &os) override;
 
 }; // class SchemaStatusCmd
 
diff --git a/catalogue/SchemaStatusCmdMain.cpp b/catalogue/SchemaStatusCmdMain.cpp
index 159d68fb529373126f648ed2b6d83693fcf11881..e3f363293a56b7f7f42c7a3c82bbf6cf1d976a13 100644
--- a/catalogue/SchemaStatusCmdMain.cpp
+++ b/catalogue/SchemaStatusCmdMain.cpp
@@ -17,61 +17,13 @@
  */
 
 #include "catalogue/SchemaStatusCmd.hpp"
-#include "catalogue/SchemaStatusCmdLineArgs.hpp"
-#include "common/exception/Exception.hpp"
-#include "common/exception/CommandLineNotParsed.hpp"
 
 #include <iostream>
 
-/**
- * An exception throwing version of main().
- *
- * @param argc The number of command-line arguments including the program name.
- * @param argv The command-line arguments.
- * @return The exit value of the program.
- */
-static int exceptionThrowingMain(const int argc, char *const *const argv);
-
 //------------------------------------------------------------------------------
 // main
 //------------------------------------------------------------------------------
 int main(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  bool cmdLineNotParsed = false;
-  std::string errorMessage;
-
-  try {
-    return exceptionThrowingMain(argc, argv);
-  } catch(exception::CommandLineNotParsed &ue) {
-    errorMessage = ue.getMessage().str();
-    cmdLineNotParsed = true;
-  } catch(exception::Exception &ex) {
-    errorMessage = ex.getMessage().str();
-  } catch(std::exception &se) {
-    errorMessage = se.what();
-  } catch(...) {
-    errorMessage = "An unknown exception was thrown";
-  }
-
-  // Reaching this point means the command has failed, an exception was throw
-  // and errorMessage has been set accordingly
-
-  std::cerr << "Aborting: " << errorMessage << std::endl;
-  if(cmdLineNotParsed) {
-    std::cerr << std::endl;
-    catalogue::SchemaStatusCmdLineArgs::printUsage(std::cerr);
-  }
-  return 1;
-}
-
-//------------------------------------------------------------------------------
-// exceptionThrowingMain
-//------------------------------------------------------------------------------
-static int exceptionThrowingMain(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  catalogue::SchemaStatusCmd cmd(std::cin, std::cout, std::cerr);
-
-  return cmd.exceptionThrowingMain(argc, argv);
+  cta::catalogue::SchemaStatusCmd cmd(std::cin, std::cout, std::cerr);
+  return cmd.main(argc, argv);
 }
diff --git a/catalogue/UnlockSchemaCmd.cpp b/catalogue/UnlockSchemaCmd.cpp
index a2cfd0681129d413e1c71149eb7ba3333bdc5465..e4bce86ad571c9a354bab4a57ffa694fb6a1bc24 100644
--- a/catalogue/UnlockSchemaCmd.cpp
+++ b/catalogue/UnlockSchemaCmd.cpp
@@ -43,7 +43,7 @@ int UnlockSchemaCmd::exceptionThrowingMain(const int argc, char *const *const ar
   const UnlockSchemaCmdLineArgs cmdLineArgs(argc, argv);
 
   if(cmdLineArgs.help) {
-    UnlockSchemaCmdLineArgs::printUsage(m_out);
+    printUsage(m_out);
     return 0;
   }
 
@@ -55,5 +55,12 @@ int UnlockSchemaCmd::exceptionThrowingMain(const int argc, char *const *const ar
   return 0;
 }
 
+//------------------------------------------------------------------------------
+// printUsage
+//------------------------------------------------------------------------------
+void UnlockSchemaCmd::printUsage(std::ostream &os) {
+  UnlockSchemaCmdLineArgs::printUsage(os);
+}
+
 } // namespace catalogue
 } // namespace cta
diff --git a/catalogue/UnlockSchemaCmd.hpp b/catalogue/UnlockSchemaCmd.hpp
index 2e401366561834470c54c376918be9295ac9b257..72a1faa98b2cdabdc8bd96b8cef28902826f9d23 100644
--- a/catalogue/UnlockSchemaCmd.hpp
+++ b/catalogue/UnlockSchemaCmd.hpp
@@ -44,6 +44,8 @@ public:
    */
   ~UnlockSchemaCmd() noexcept;
 
+private:
+
   /**
    * An exception throwing version of main().
    *
@@ -51,7 +53,14 @@ public:
    * @param argv The command-line arguments.
    * @return The exit value of the program.
    */
-  int exceptionThrowingMain(const int argc, char *const *const argv);
+  int exceptionThrowingMain(const int argc, char *const *const argv) override;
+
+  /**
+   * Prints the usage message of the command-line tool.
+   *
+   * @param os The output stream to which the usage message is to be printed.
+   */
+  void printUsage(std::ostream &os) override;
 
 }; // class UnlockSchemaCmd
 
diff --git a/catalogue/UnlockSchemaCmdMain.cpp b/catalogue/UnlockSchemaCmdMain.cpp
index e387638ea8a4aeaaa6ea1d02a3d4e8a1e1168273..17e552b72af2f5e1d9a09b8446dc3849fe1aa8f6 100644
--- a/catalogue/UnlockSchemaCmdMain.cpp
+++ b/catalogue/UnlockSchemaCmdMain.cpp
@@ -17,61 +17,13 @@
  */
 
 #include "catalogue/UnlockSchemaCmd.hpp"
-#include "catalogue/UnlockSchemaCmdLineArgs.hpp"
-#include "common/exception/Exception.hpp"
-#include "common/exception/CommandLineNotParsed.hpp"
 
 #include <iostream>
 
-/**
- * An exception throwing version of main().
- *
- * @param argc The number of command-line arguments including the program name.
- * @param argv The command-line arguments.
- * @return The exit value of the program.
- */
-static int exceptionThrowingMain(const int argc, char *const *const argv);
-
 //------------------------------------------------------------------------------
 // main
 //------------------------------------------------------------------------------
 int main(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  bool cmdLineNotParsed = false;
-  std::string errorMessage;
-
-  try {
-    return exceptionThrowingMain(argc, argv);
-  } catch(exception::CommandLineNotParsed &ue) {
-    errorMessage = ue.getMessage().str();
-    cmdLineNotParsed = true;
-  } catch(exception::Exception &ex) {
-    errorMessage = ex.getMessage().str();
-  } catch(std::exception &se) {
-    errorMessage = se.what();
-  } catch(...) {
-    errorMessage = "An unknown exception was thrown";
-  }
-
-  // Reaching this point means the command has failed, an exception was throw
-  // and errorMessage has been set accordingly
-
-  std::cerr << "Aborting: " << errorMessage << std::endl;
-  if(cmdLineNotParsed) {
-    std::cerr << std::endl;
-    catalogue::UnlockSchemaCmdLineArgs::printUsage(std::cerr);
-  }
-  return 1;
-}
-
-//------------------------------------------------------------------------------
-// exceptionThrowingMain
-//------------------------------------------------------------------------------
-static int exceptionThrowingMain(const int argc, char *const *const argv) {
-  using namespace cta;
-
-  catalogue::UnlockSchemaCmd cmd(std::cin, std::cout, std::cerr);
-
-  return cmd.exceptionThrowingMain(argc, argv);
+  cta::catalogue::UnlockSchemaCmd cmd(std::cin, std::cout, std::cerr);
+  return cmd.main(argc, argv);
 }