face: consistently use the template method pattern in ProtocolFactory

Change-Id: Ied0bf02cfcdffc7e9b2c28c5452441c01f98ccbc
diff --git a/daemon/face/ethernet-factory.cpp b/daemon/face/ethernet-factory.cpp
index aab8aa4..7603343 100644
--- a/daemon/face/ethernet-factory.cpp
+++ b/daemon/face/ethernet-factory.cpp
@@ -37,7 +37,7 @@
 NFD_REGISTER_PROTOCOL_FACTORY(EthernetFactory);
 
 const std::string&
-EthernetFactory::getId()
+EthernetFactory::getId() noexcept
 {
   static std::string id("ether");
   return id;
@@ -53,8 +53,8 @@
 }
 
 void
-EthernetFactory::processConfig(OptionalConfigSection configSection,
-                               FaceSystem::ConfigContext& context)
+EthernetFactory::doProcessConfig(OptionalConfigSection configSection,
+                                 FaceSystem::ConfigContext& context)
 {
   // ether
   // {
@@ -165,18 +165,15 @@
 }
 
 void
-EthernetFactory::createFace(const CreateFaceRequest& req,
-                            const FaceCreatedCallback& onCreated,
-                            const FaceCreationFailedCallback& onFailure)
+EthernetFactory::doCreateFace(const CreateFaceRequest& req,
+                              const FaceCreatedCallback& onCreated,
+                              const FaceCreationFailedCallback& onFailure)
 {
-  BOOST_ASSERT(req.remoteUri.isCanonical());
-
   if (!req.localUri || req.localUri->getScheme() != "dev") {
     NFD_LOG_TRACE("Cannot create unicast Ethernet face without dev:// LocalUri");
     onFailure(406, "Creation of unicast Ethernet faces requires a LocalUri with dev:// scheme");
     return;
   }
-  BOOST_ASSERT(req.localUri->isCanonical());
 
   if (req.params.persistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
     NFD_LOG_TRACE("createFace does not support FACE_PERSISTENCY_ON_DEMAND");
@@ -228,12 +225,11 @@
 
   auto channel = std::make_shared<EthernetChannel>(localEndpoint, idleTimeout);
   m_channels[localEndpoint->getName()] = channel;
-
   return channel;
 }
 
 std::vector<shared_ptr<const Channel>>
-EthernetFactory::getChannels() const
+EthernetFactory::doGetChannels() const
 {
   return getChannelsFromMap(m_channels);
 }
@@ -348,7 +344,7 @@
 }
 
 void
-EthernetFactory::applyConfig(const FaceSystem::ConfigContext& context)
+EthernetFactory::applyConfig(const FaceSystem::ConfigContext&)
 {
   if (m_unicastConfig.isEnabled) {
     providedSchemes.insert("ether");
diff --git a/daemon/face/ethernet-factory.hpp b/daemon/face/ethernet-factory.hpp
index 11dac9c..9b25b3c 100644
--- a/daemon/face/ethernet-factory.hpp
+++ b/daemon/face/ethernet-factory.hpp
@@ -32,28 +32,17 @@
 namespace nfd {
 namespace face {
 
-/** \brief protocol factory for Ethernet
+/** \brief Protocol factory for Ethernet
  */
 class EthernetFactory : public ProtocolFactory
 {
 public:
   static const std::string&
-  getId();
+  getId() noexcept;
 
   explicit
   EthernetFactory(const CtorParams& params);
 
-  /** \brief process face_system.ether config section
-   */
-  void
-  processConfig(OptionalConfigSection configSection,
-                FaceSystem::ConfigContext& context) override;
-
-  void
-  createFace(const CreateFaceRequest& req,
-             const FaceCreatedCallback& onCreated,
-             const FaceCreationFailedCallback& onFailure) override;
-
   /**
    * \brief Create Ethernet-based channel on the specified network interface
    *
@@ -68,9 +57,6 @@
   createChannel(const shared_ptr<const ndn::net::NetworkInterface>& localEndpoint,
                 time::nanoseconds idleTimeout);
 
-  std::vector<shared_ptr<const Channel>>
-  getChannels() const override;
-
   /**
    * \brief Create a face to communicate on the given Ethernet multicast group
    *
@@ -87,6 +73,20 @@
                       const ethernet::Address& group);
 
 private:
+  /** \brief process face_system.ether config section
+   */
+  void
+  doProcessConfig(OptionalConfigSection configSection,
+                  FaceSystem::ConfigContext& context) override;
+
+  void
+  doCreateFace(const CreateFaceRequest& req,
+               const FaceCreatedCallback& onCreated,
+               const FaceCreationFailedCallback& onFailure) override;
+
+  std::vector<shared_ptr<const Channel>>
+  doGetChannels() const override;
+
   /** \brief Create EthernetChannel on \p netif if requested by \p m_unicastConfig.
    *  \return new or existing channel, or nullptr if no channel should be created
    */
diff --git a/daemon/face/protocol-factory.cpp b/daemon/face/protocol-factory.cpp
index fb1440d..cdb6cb1 100644
--- a/daemon/face/protocol-factory.cpp
+++ b/daemon/face/protocol-factory.cpp
@@ -24,6 +24,7 @@
  */
 
 #include "protocol-factory.hpp"
+
 #include <boost/range/adaptor/map.hpp>
 #include <boost/range/algorithm/copy.hpp>
 
@@ -66,20 +67,66 @@
   BOOST_ASSERT(netmon != nullptr);
 }
 
+ProtocolFactory::~ProtocolFactory() = default;
+
+void
+ProtocolFactory::processConfig(OptionalConfigSection configSection,
+                               FaceSystem::ConfigContext& context)
+{
+  doProcessConfig(configSection, context);
+}
+
+void
+ProtocolFactory::doProcessConfig(OptionalConfigSection,
+                                 FaceSystem::ConfigContext&)
+{
+}
+
+void
+ProtocolFactory::createFace(const CreateFaceRequest& req,
+                            const FaceCreatedCallback& onCreated,
+                            const FaceCreationFailedCallback& onFailure)
+{
+  BOOST_ASSERT(!FaceUri::canCanonize(req.remoteUri.getScheme()) ||
+               req.remoteUri.isCanonical());
+  BOOST_ASSERT(!req.localUri || !FaceUri::canCanonize(req.localUri->getScheme()) ||
+               req.localUri->isCanonical());
+  doCreateFace(req, onCreated, onFailure);
+}
+
+void
+ProtocolFactory::doCreateFace(const CreateFaceRequest&,
+                              const FaceCreatedCallback&,
+                              const FaceCreationFailedCallback& onFailure)
+{
+  onFailure(406, "Unsupported protocol");
+}
+
 shared_ptr<Face>
 ProtocolFactory::createNetdevBoundFace(const FaceUri& remote,
                                        const shared_ptr<const ndn::net::NetworkInterface>& netif)
 {
   BOOST_ASSERT(remote.isCanonical());
-  return this->doCreateNetdevBoundFace(remote, netif);
+  return doCreateNetdevBoundFace(remote, netif);
 }
 
 shared_ptr<Face>
-ProtocolFactory::doCreateNetdevBoundFace(const FaceUri& remote,
-                                         const shared_ptr<const ndn::net::NetworkInterface>& netif)
+ProtocolFactory::doCreateNetdevBoundFace(const FaceUri&,
+                                         const shared_ptr<const ndn::net::NetworkInterface>&)
 {
-  BOOST_THROW_EXCEPTION(Error(
-    "this protocol factory does not support netdev-bound faces"));
+  BOOST_THROW_EXCEPTION(Error("This protocol factory does not support netdev-bound faces"));
+}
+
+std::vector<shared_ptr<const Channel>>
+ProtocolFactory::getChannels() const
+{
+  return doGetChannels();
+}
+
+std::vector<shared_ptr<const Channel>>
+ProtocolFactory::doGetChannels() const
+{
+  return {};
 }
 
 } // namespace face
diff --git a/daemon/face/protocol-factory.hpp b/daemon/face/protocol-factory.hpp
index f3d7807..a3cb625 100644
--- a/daemon/face/protocol-factory.hpp
+++ b/daemon/face/protocol-factory.hpp
@@ -62,7 +62,7 @@
   using CtorParams = ProtocolFactoryCtorParams;
 
   /** \brief Register a protocol factory type
-   *  \tparam S subclass of ProtocolFactory
+   *  \tparam PF subclass of ProtocolFactory
    *  \param id factory identifier
    */
   template<typename PF>
@@ -71,16 +71,16 @@
   {
     Registry& registry = getRegistry();
     BOOST_ASSERT(registry.count(id) == 0);
-    registry[id] = &make_unique<PF, const CtorParams&>;
+    registry[id] = [] (const CtorParams& p) { return make_unique<PF>(p); };
   }
 
   /** \brief Create a protocol factory instance
-   *  \retval nullptr if factory with \p id is not registered
+   *  \retval nullptr if a factory with the given \p id is not registered
    */
   static unique_ptr<ProtocolFactory>
   create(const std::string& id, const CtorParams& params);
 
-  /** \brief Get registered protocol factory ids
+  /** \brief Get all registered protocol factory ids
    */
   static std::set<std::string>
   listRegistered();
@@ -91,44 +91,40 @@
   class Error : public std::runtime_error
   {
   public:
-    explicit
-    Error(const std::string& what)
-      : std::runtime_error(what)
-    {
-    }
+    using std::runtime_error::runtime_error;
   };
 
+  explicit
+  ProtocolFactory(const CtorParams& params);
+
   virtual
-  ~ProtocolFactory() = default;
+  ~ProtocolFactory() = 0;
 
 #ifdef DOXYGEN
-  /** \brief Get id for this ProtocolFactory
+  /** \brief Get id for this protocol factory
    *
    *  face_system.factory-id config section is processed by the protocol factory.
    */
   static const std::string&
-  getId();
+  getId() noexcept;
 #endif
 
-  /** \brief Process face_system subsection that corresponds to this ProtocolFactory type
-   *  \param configSection the configuration section or boost::null to indicate it is omitted
-   *  \param context provides access to data structures and contextual information
-   *  \throw ConfigFile::Error invalid configuration
-   *
-   *  This function updates \p providedSchemes
-   */
-  virtual void
-  processConfig(OptionalConfigSection configSection,
-                FaceSystem::ConfigContext& context) = 0;
-
-  /** \brief Get FaceUri schemes accepted by this ProtocolFactory
+  /** \brief Get FaceUri schemes accepted by this protocol factory
    */
   const std::set<std::string>&
-  getProvidedSchemes()
+  getProvidedSchemes() const
   {
     return providedSchemes;
   }
 
+  /** \brief Process face_system subsection that corresponds to this protocol factory id
+   *  \param configSection the configuration section or boost::none to indicate it is omitted
+   *  \param context provides access to data structures and contextual information
+   *  \throw ConfigFile::Error invalid configuration
+   */
+  void
+  processConfig(OptionalConfigSection configSection, FaceSystem::ConfigContext& context);
+
   /** \brief Encapsulates a face creation request and all its parameters
    *
    *  Parameters are passed as a struct rather than individually, so that a future change in the list
@@ -141,20 +137,16 @@
     FaceParams params;
   };
 
-  /** \brief Try to create a unicast face using the supplied parameters
-   *
-   * \param req request object containing the face creation parameters
-   * \param onCreated callback if face creation succeeds or face already exists; the settings
-   *                  of an existing face are not updated if they differ from the request
-   * \param onFailure callback if face creation fails
+  /** \brief Create a unicast face
+   *  \param req request object containing the face creation parameters
+   *  \param onCreated callback if face creation succeeds or face already exists; the settings
+   *                   of an existing face are not updated if they differ from the request
+   *  \param onFailure callback if face creation fails
    */
-  virtual void
+  void
   createFace(const CreateFaceRequest& req,
              const FaceCreatedCallback& onCreated,
-             const FaceCreationFailedCallback& onFailure) = 0;
-
-  virtual std::vector<shared_ptr<const Channel>>
-  getChannels() const = 0;
+             const FaceCreationFailedCallback& onFailure);
 
   /** \brief Create a netdev-bound face
    *  \param remote remote FaceUri, must be canonical
@@ -168,10 +160,12 @@
   createNetdevBoundFace(const FaceUri& remote,
                         const shared_ptr<const ndn::net::NetworkInterface>& netdev);
 
-protected:
-  explicit
-  ProtocolFactory(const CtorParams& params);
+  /** \brief Get list of open channels (listening + non-listening)
+   */
+  std::vector<shared_ptr<const Channel>>
+  getChannels() const;
 
+protected:
   template<typename ChannelMap>
   static std::vector<shared_ptr<const Channel>>
   getChannelsFromMap(const ChannelMap& channelMap)
@@ -182,10 +176,34 @@
   }
 
 private:
+  /** \brief Process face_system subsection that corresponds to this protocol factory id
+   *  \sa processConfig
+   *
+   *  A subclass should override this method if it supports configuration options in the config
+   *  file, and do all the required processing here. The subclass should throw ConfigFile::Error
+   *  if it encounters unrecognized options or invalid values. It should also update
+   *  \p providedSchemes as needed.
+   *
+   *  The base class implementation does nothing.
+   */
+  virtual void
+  doProcessConfig(OptionalConfigSection configSection, FaceSystem::ConfigContext& context);
+
+  /** \brief Create a unicast face
+   *  \sa createFace
+   *
+   *  The base class implementation always invokes the failure callback with error code 406,
+   *  indicating unicast face creation is not supported.
+   */
+  virtual void
+  doCreateFace(const CreateFaceRequest& req,
+               const FaceCreatedCallback& onCreated,
+               const FaceCreationFailedCallback& onFailure);
+
   /** \brief Create a netdev-bound face
    *  \sa createNetdevBoundFace
    *
-   *  The base class implementation always throws Error indicating netdev-bound faces are not
+   *  The base class implementation always throws Error, indicating netdev-bound faces are not
    *  supported.
    *
    *  A subclass that offers netdev-bound faces should override this method, and also expose
@@ -201,6 +219,14 @@
   doCreateNetdevBoundFace(const FaceUri& remote,
                           const shared_ptr<const ndn::net::NetworkInterface>& netif);
 
+  /** \brief Get list of open channels (listening + non-listening)
+   *  \sa getChannels
+   *
+   *  The base class implementation returns an empty list.
+   */
+  virtual std::vector<shared_ptr<const Channel>>
+  doGetChannels() const;
+
 private: // registry
   using CreateFunc = std::function<unique_ptr<ProtocolFactory>(const CtorParams&)>;
   using Registry = std::map<std::string, CreateFunc>; // indexed by factory id
@@ -209,7 +235,7 @@
   getRegistry();
 
 protected:
-  std::set<std::string> providedSchemes; ///< FaceUri schemes provided by this ProtocolFactory
+  std::set<std::string> providedSchemes; ///< FaceUri schemes provided by this protocol factory
   FaceCreatedCallback addFace; ///< callback when a new face is created
 
   /** \brief NetworkMonitor for listing available network interfaces and monitoring their changes
@@ -223,9 +249,9 @@
 } // namespace face
 } // namespace nfd
 
-/** \brief registers a protocol factory
+/** \brief Registers a protocol factory
  *
- *  This macro should appear once in .cpp of each protocol factory.
+ *  This macro should appear once in the .cpp file of each protocol factory.
  */
 #define NFD_REGISTER_PROTOCOL_FACTORY(PF)                      \
 static class NfdAuto ## PF ## ProtocolFactoryRegistrationClass \
diff --git a/daemon/face/tcp-factory.cpp b/daemon/face/tcp-factory.cpp
index 5b56839..d77b639 100644
--- a/daemon/face/tcp-factory.cpp
+++ b/daemon/face/tcp-factory.cpp
@@ -34,20 +34,15 @@
 NFD_REGISTER_PROTOCOL_FACTORY(TcpFactory);
 
 const std::string&
-TcpFactory::getId()
+TcpFactory::getId() noexcept
 {
   static std::string id("tcp");
   return id;
 }
 
-TcpFactory::TcpFactory(const CtorParams& params)
-  : ProtocolFactory(params)
-{
-}
-
 void
-TcpFactory::processConfig(OptionalConfigSection configSection,
-                          FaceSystem::ConfigContext& context)
+TcpFactory::doProcessConfig(OptionalConfigSection configSection,
+                            FaceSystem::ConfigContext& context)
 {
   // tcp
   // {
@@ -61,7 +56,7 @@
 
   if (!configSection) {
     if (!context.isDryRun && !m_channels.empty()) {
-      NFD_LOG_WARN("Cannot disable tcp4 and tcp6 channels after initialization");
+      NFD_LOG_WARN("Cannot disable TCP channels after initialization");
     }
     return;
   }
@@ -117,44 +112,44 @@
       "TCP channels or enable at least one channel type."));
   }
 
-  if (!context.isDryRun) {
-    providedSchemes.insert("tcp");
-
-    if (enableV4) {
-      tcp::Endpoint endpoint(ip::tcp::v4(), port);
-      shared_ptr<TcpChannel> v4Channel = this->createChannel(endpoint);
-      if (wantListen && !v4Channel->isListening()) {
-        v4Channel->listen(this->addFace, nullptr);
-      }
-      providedSchemes.insert("tcp4");
-    }
-    else if (providedSchemes.count("tcp4") > 0) {
-      NFD_LOG_WARN("Cannot close tcp4 channel after its creation");
-    }
-
-    if (enableV6) {
-      tcp::Endpoint endpoint(ip::tcp::v6(), port);
-      shared_ptr<TcpChannel> v6Channel = this->createChannel(endpoint);
-      if (wantListen && !v6Channel->isListening()) {
-        v6Channel->listen(this->addFace, nullptr);
-      }
-      providedSchemes.insert("tcp6");
-    }
-    else if (providedSchemes.count("tcp6") > 0) {
-      NFD_LOG_WARN("Cannot close tcp6 channel after its creation");
-    }
-
-    m_local = std::move(local);
+  if (context.isDryRun) {
+    return;
   }
+
+  providedSchemes.insert("tcp");
+
+  if (enableV4) {
+    tcp::Endpoint endpoint(ip::tcp::v4(), port);
+    auto v4Channel = this->createChannel(endpoint);
+    if (wantListen && !v4Channel->isListening()) {
+      v4Channel->listen(this->addFace, nullptr);
+    }
+    providedSchemes.insert("tcp4");
+  }
+  else if (providedSchemes.count("tcp4") > 0) {
+    NFD_LOG_WARN("Cannot close tcp4 channel after its creation");
+  }
+
+  if (enableV6) {
+    tcp::Endpoint endpoint(ip::tcp::v6(), port);
+    auto v6Channel = this->createChannel(endpoint);
+    if (wantListen && !v6Channel->isListening()) {
+      v6Channel->listen(this->addFace, nullptr);
+    }
+    providedSchemes.insert("tcp6");
+  }
+  else if (providedSchemes.count("tcp6") > 0) {
+    NFD_LOG_WARN("Cannot close tcp6 channel after its creation");
+  }
+
+  m_local = std::move(local);
 }
 
 void
-TcpFactory::createFace(const CreateFaceRequest& req,
-                       const FaceCreatedCallback& onCreated,
-                       const FaceCreationFailedCallback& onFailure)
+TcpFactory::doCreateFace(const CreateFaceRequest& req,
+                         const FaceCreatedCallback& onCreated,
+                         const FaceCreationFailedCallback& onFailure)
 {
-  BOOST_ASSERT(req.remoteUri.isCanonical());
-
   if (req.localUri) {
     NFD_LOG_TRACE("Cannot create unicast TCP face with LocalUri");
     onFailure(406, "Unicast TCP faces cannot be created with a LocalUri");
@@ -212,7 +207,7 @@
 }
 
 std::vector<shared_ptr<const Channel>>
-TcpFactory::getChannels() const
+TcpFactory::doGetChannels() const
 {
   return getChannelsFromMap(m_channels);
 }
diff --git a/daemon/face/tcp-factory.hpp b/daemon/face/tcp-factory.hpp
index dddcd40..0c22738 100644
--- a/daemon/face/tcp-factory.hpp
+++ b/daemon/face/tcp-factory.hpp
@@ -32,27 +32,15 @@
 namespace nfd {
 namespace face {
 
-/** \brief protocol factory for TCP over IPv4 and IPv6
+/** \brief Protocol factory for TCP over IPv4 and IPv6
  */
 class TcpFactory : public ProtocolFactory
 {
 public:
   static const std::string&
-  getId();
+  getId() noexcept;
 
-  explicit
-  TcpFactory(const CtorParams& params);
-
-  /** \brief process face_system.tcp config section
-   */
-  void
-  processConfig(OptionalConfigSection configSection,
-                FaceSystem::ConfigContext& context) override;
-
-  void
-  createFace(const CreateFaceRequest& req,
-             const FaceCreatedCallback& onCreated,
-             const FaceCreationFailedCallback& onFailure) override;
+  using ProtocolFactory::ProtocolFactory;
 
   /**
    * \brief Create TCP-based channel using tcp::Endpoint
@@ -68,10 +56,21 @@
   shared_ptr<TcpChannel>
   createChannel(const tcp::Endpoint& localEndpoint);
 
-  std::vector<shared_ptr<const Channel>>
-  getChannels() const override;
-
 private:
+  /** \brief process face_system.tcp config section
+   */
+  void
+  doProcessConfig(OptionalConfigSection configSection,
+                  FaceSystem::ConfigContext& context) override;
+
+  void
+  doCreateFace(const CreateFaceRequest& req,
+               const FaceCreatedCallback& onCreated,
+               const FaceCreationFailedCallback& onFailure) override;
+
+  std::vector<shared_ptr<const Channel>>
+  doGetChannels() const override;
+
   ndn::nfd::FaceScope
   determineFaceScopeFromAddresses(const boost::asio::ip::address& local,
                                   const boost::asio::ip::address& remote) const;
diff --git a/daemon/face/udp-factory.cpp b/daemon/face/udp-factory.cpp
index e649871..6c261fb 100644
--- a/daemon/face/udp-factory.cpp
+++ b/daemon/face/udp-factory.cpp
@@ -41,7 +41,7 @@
 NFD_REGISTER_PROTOCOL_FACTORY(UdpFactory);
 
 const std::string&
-UdpFactory::getId()
+UdpFactory::getId() noexcept
 {
   static std::string id("udp");
   return id;
@@ -56,8 +56,8 @@
 }
 
 void
-UdpFactory::processConfig(OptionalConfigSection configSection,
-                          FaceSystem::ConfigContext& context)
+UdpFactory::doProcessConfig(OptionalConfigSection configSection,
+                            FaceSystem::ConfigContext& context)
 {
   // udp
   // {
@@ -236,12 +236,10 @@
 }
 
 void
-UdpFactory::createFace(const CreateFaceRequest& req,
-                       const FaceCreatedCallback& onCreated,
-                       const FaceCreationFailedCallback& onFailure)
+UdpFactory::doCreateFace(const CreateFaceRequest& req,
+                         const FaceCreatedCallback& onCreated,
+                         const FaceCreationFailedCallback& onFailure)
 {
-  BOOST_ASSERT(req.remoteUri.isCanonical());
-
   if (req.localUri) {
     NFD_LOG_TRACE("Cannot create unicast UDP face with LocalUri");
     onFailure(406, "Unicast UDP faces cannot be created with a LocalUri");
@@ -307,12 +305,11 @@
 
   auto channel = std::make_shared<UdpChannel>(localEndpoint, idleTimeout, m_wantCongestionMarking);
   m_channels[localEndpoint] = channel;
-
   return channel;
 }
 
 std::vector<shared_ptr<const Channel>>
-UdpFactory::getChannels() const
+UdpFactory::doGetChannels() const
 {
   return getChannelsFromMap(m_channels);
 }
@@ -444,7 +441,7 @@
 }
 
 void
-UdpFactory::applyMcastConfig(const FaceSystem::ConfigContext& context)
+UdpFactory::applyMcastConfig(const FaceSystem::ConfigContext&)
 {
   // collect old faces
   std::set<shared_ptr<Face>> facesToClose;
diff --git a/daemon/face/udp-factory.hpp b/daemon/face/udp-factory.hpp
index 4f9d71d..a57cb25 100644
--- a/daemon/face/udp-factory.hpp
+++ b/daemon/face/udp-factory.hpp
@@ -32,44 +32,23 @@
 namespace nfd {
 namespace face {
 
-/** \brief protocol factory for UDP over IPv4 and IPv6
- *
- *  UDP unicast is available over both IPv4 and IPv6.
- *  UDP multicast is available over IPv4 only.
+/** \brief Protocol factory for UDP over IPv4 and IPv6
  */
 class UdpFactory : public ProtocolFactory
 {
 public:
-  /**
-   * \brief Exception of UdpFactory
-   */
   class Error : public ProtocolFactory::Error
   {
   public:
-    explicit
-    Error(const std::string& what)
-      : ProtocolFactory::Error(what)
-    {
-    }
+    using ProtocolFactory::Error::Error;
   };
 
   static const std::string&
-  getId();
+  getId() noexcept;
 
   explicit
   UdpFactory(const CtorParams& params);
 
-  /** \brief process face_system.udp config section
-   */
-  void
-  processConfig(OptionalConfigSection configSection,
-                FaceSystem::ConfigContext& context) override;
-
-  void
-  createFace(const CreateFaceRequest& req,
-             const FaceCreatedCallback& onCreated,
-             const FaceCreationFailedCallback& onFailure) override;
-
   /**
    * \brief Create UDP-based channel using udp::Endpoint
    *
@@ -89,9 +68,6 @@
   createChannel(const udp::Endpoint& localEndpoint,
                 time::nanoseconds idleTimeout);
 
-  std::vector<shared_ptr<const Channel>>
-  getChannels() const override;
-
   /**
    * \brief Create a multicast UDP face
    *
@@ -120,6 +96,20 @@
                       const udp::Endpoint& multicastEndpoint);
 
 private:
+  /** \brief process face_system.udp config section
+   */
+  void
+  doProcessConfig(OptionalConfigSection configSection,
+                  FaceSystem::ConfigContext& context) override;
+
+  void
+  doCreateFace(const CreateFaceRequest& req,
+               const FaceCreatedCallback& onCreated,
+               const FaceCreationFailedCallback& onFailure) override;
+
+  std::vector<shared_ptr<const Channel>>
+  doGetChannels() const override;
+
   /** \brief Create UDP multicast faces on \p netif if needed by \p m_mcastConfig
    *  \return list of faces (just created or already existing) on \p netif
    */
diff --git a/daemon/face/unix-stream-factory.cpp b/daemon/face/unix-stream-factory.cpp
index 2d8567a..211203a 100644
--- a/daemon/face/unix-stream-factory.cpp
+++ b/daemon/face/unix-stream-factory.cpp
@@ -34,20 +34,15 @@
 NFD_REGISTER_PROTOCOL_FACTORY(UnixStreamFactory);
 
 const std::string&
-UnixStreamFactory::getId()
+UnixStreamFactory::getId() noexcept
 {
   static std::string id("unix");
   return id;
 }
 
-UnixStreamFactory::UnixStreamFactory(const CtorParams& params)
-  : ProtocolFactory(params)
-{
-}
-
 void
-UnixStreamFactory::processConfig(OptionalConfigSection configSection,
-                                 FaceSystem::ConfigContext& context)
+UnixStreamFactory::doProcessConfig(OptionalConfigSection configSection,
+                                   FaceSystem::ConfigContext& context)
 {
   // unix
   // {
@@ -58,7 +53,7 @@
 
   if (!configSection) {
     if (!context.isDryRun && !m_channels.empty()) {
-      NFD_LOG_WARN("Cannot disable unix channel after initialization");
+      NFD_LOG_WARN("Cannot disable Unix channel after initialization");
     }
     return;
   }
@@ -77,20 +72,14 @@
     }
   }
 
-  if (!context.isDryRun) {
-    auto channel = this->createChannel(path);
-    if (!channel->isListening()) {
-      channel->listen(this->addFace, nullptr);
-    }
+  if (context.isDryRun) {
+    return;
   }
-}
 
-void
-UnixStreamFactory::createFace(const CreateFaceRequest& req,
-                              const FaceCreatedCallback& onCreated,
-                              const FaceCreationFailedCallback& onFailure)
-{
-  onFailure(406, "Unsupported protocol");
+  auto channel = this->createChannel(path);
+  if (!channel->isListening()) {
+    channel->listen(this->addFace, nullptr);
+  }
 }
 
 shared_ptr<UnixStreamChannel>
@@ -100,30 +89,20 @@
   p = boost::filesystem::canonical(p.parent_path()) / p.filename();
   unix_stream::Endpoint endpoint(p.string());
 
-  auto channel = findChannel(endpoint);
-  if (channel)
-    return channel;
+  auto it = m_channels.find(endpoint);
+  if (it != m_channels.end())
+    return it->second;
 
-  channel = make_shared<UnixStreamChannel>(endpoint, m_wantCongestionMarking);
+  auto channel = make_shared<UnixStreamChannel>(endpoint, m_wantCongestionMarking);
   m_channels[endpoint] = channel;
   return channel;
 }
 
 std::vector<shared_ptr<const Channel>>
-UnixStreamFactory::getChannels() const
+UnixStreamFactory::doGetChannels() const
 {
   return getChannelsFromMap(m_channels);
 }
 
-shared_ptr<UnixStreamChannel>
-UnixStreamFactory::findChannel(const unix_stream::Endpoint& endpoint) const
-{
-  auto i = m_channels.find(endpoint);
-  if (i != m_channels.end())
-    return i->second;
-  else
-    return nullptr;
-}
-
 } // namespace face
 } // namespace nfd
diff --git a/daemon/face/unix-stream-factory.hpp b/daemon/face/unix-stream-factory.hpp
index 9ce7c76..8e4bee5 100644
--- a/daemon/face/unix-stream-factory.hpp
+++ b/daemon/face/unix-stream-factory.hpp
@@ -32,27 +32,15 @@
 namespace nfd {
 namespace face {
 
-/** \brief protocol factory for stream-oriented Unix sockets
+/** \brief Protocol factory for stream-oriented Unix sockets
  */
 class UnixStreamFactory : public ProtocolFactory
 {
 public:
   static const std::string&
-  getId();
+  getId() noexcept;
 
-  explicit
-  UnixStreamFactory(const CtorParams& params);
-
-  /** \brief process face_system.unix config section
-   */
-  void
-  processConfig(OptionalConfigSection configSection,
-                FaceSystem::ConfigContext& context) override;
-
-  void
-  createFace(const CreateFaceRequest& req,
-             const FaceCreatedCallback& onCreated,
-             const FaceCreationFailedCallback& onFailure) override;
+  using ProtocolFactory::ProtocolFactory;
 
   /**
    * \brief Create stream-oriented Unix channel using specified socket path
@@ -67,18 +55,15 @@
   shared_ptr<UnixStreamChannel>
   createChannel(const std::string& unixSocketPath);
 
-  std::vector<shared_ptr<const Channel>>
-  getChannels() const override;
-
 private:
-  /**
-   * \brief Look up UnixStreamChannel using specified endpoint
-   *
-   * \returns shared pointer to the existing UnixStreamChannel object
-   *          or empty shared pointer when such channel does not exist
+  /** \brief process face_system.unix config section
    */
-  shared_ptr<UnixStreamChannel>
-  findChannel(const unix_stream::Endpoint& endpoint) const;
+  void
+  doProcessConfig(OptionalConfigSection configSection,
+                  FaceSystem::ConfigContext& context) override;
+
+  std::vector<shared_ptr<const Channel>>
+  doGetChannels() const override;
 
 private:
   bool m_wantCongestionMarking = false;
diff --git a/daemon/face/websocket-factory.cpp b/daemon/face/websocket-factory.cpp
index 6b493de..e3d8d57 100644
--- a/daemon/face/websocket-factory.cpp
+++ b/daemon/face/websocket-factory.cpp
@@ -34,20 +34,15 @@
 NFD_REGISTER_PROTOCOL_FACTORY(WebSocketFactory);
 
 const std::string&
-WebSocketFactory::getId()
+WebSocketFactory::getId() noexcept
 {
   static std::string id("websocket");
   return id;
 }
 
-WebSocketFactory::WebSocketFactory(const CtorParams& params)
-  : ProtocolFactory(params)
-{
-}
-
 void
-WebSocketFactory::processConfig(OptionalConfigSection configSection,
-                                FaceSystem::ConfigContext& context)
+WebSocketFactory::doProcessConfig(OptionalConfigSection configSection,
+                                  FaceSystem::ConfigContext& context)
 {
   // websocket
   // {
@@ -119,14 +114,6 @@
   }
 }
 
-void
-WebSocketFactory::createFace(const CreateFaceRequest& req,
-                             const FaceCreatedCallback& onCreated,
-                             const FaceCreationFailedCallback& onFailure)
-{
-  onFailure(406, "Unsupported protocol");
-}
-
 shared_ptr<WebSocketChannel>
 WebSocketFactory::createChannel(const websocket::Endpoint& endpoint)
 {
@@ -136,12 +123,11 @@
 
   auto channel = make_shared<WebSocketChannel>(endpoint);
   m_channels[endpoint] = channel;
-
   return channel;
 }
 
 std::vector<shared_ptr<const Channel>>
-WebSocketFactory::getChannels() const
+WebSocketFactory::doGetChannels() const
 {
   return getChannelsFromMap(m_channels);
 }
diff --git a/daemon/face/websocket-factory.hpp b/daemon/face/websocket-factory.hpp
index 9c8639e..a4b6a46 100644
--- a/daemon/face/websocket-factory.hpp
+++ b/daemon/face/websocket-factory.hpp
@@ -32,29 +32,15 @@
 namespace nfd {
 namespace face {
 
-/** \brief protocol factory for WebSocket
+/** \brief Protocol factory for WebSocket
  */
 class WebSocketFactory : public ProtocolFactory
 {
 public:
   static const std::string&
-  getId();
+  getId() noexcept;
 
-  explicit
-  WebSocketFactory(const CtorParams& params);
-
-  /** \brief process face_system.websocket config section
-   */
-  void
-  processConfig(OptionalConfigSection configSection,
-                FaceSystem::ConfigContext& context) override;
-
-  /** \brief unicast face creation is not supported and will always fail
-   */
-  void
-  createFace(const CreateFaceRequest& req,
-             const FaceCreatedCallback& onCreated,
-             const FaceCreationFailedCallback& onFailure) override;
+  using ProtocolFactory::ProtocolFactory;
 
   /**
    * \brief Create WebSocket-based channel using websocket::Endpoint
@@ -71,8 +57,15 @@
   shared_ptr<WebSocketChannel>
   createChannel(const websocket::Endpoint& localEndpoint);
 
+private:
+  /** \brief process face_system.websocket config section
+   */
+  void
+  doProcessConfig(OptionalConfigSection configSection,
+                  FaceSystem::ConfigContext& context) override;
+
   std::vector<shared_ptr<const Channel>>
-  getChannels() const override;
+  doGetChannels() const override;
 
 private:
   std::map<websocket::Endpoint, shared_ptr<WebSocketChannel>> m_channels;