Using individual classes for each option, instead of doing all the work in one big...
authorGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Sat, 8 Oct 2011 14:10:24 +0000 (11:10 -0300)
committerGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Sat, 8 Oct 2011 14:10:24 +0000 (11:10 -0300)
src/config/configurationoptions.cpp
src/config/configurationoptions.h

index 65fcc89..5947d68 100644 (file)
 
 #include <logfunc.hpp>
 
+#include "config/option/configfileoption.h"
+#include "config/option/daemonoption.h"
+#include "config/option/hostdownlimitoption.h"
+#include "config/option/hostnameoption.h"
+#include "config/option/hostportoption.h"
+#include "config/option/hostpingprotocoloption.h"
+#include "config/option/hostpingintervaloption.h"
+#include "config/option/linkdownintervaloption.h"
+#include "config/option/linkupintervaloption.h"
+#include "config/option/nameserveroption.h"
+#include "config/option/pingfaillimitoption.h"
+#include "config/option/sourcenetworkinterfaceoption.h"
+#include "config/option/statusnotifiercmdoption.h"
+#include "config/option/versionoption.h"
+
 using namespace std;
+using boost::program_options::option_description;
 using boost::program_options::options_description;
 using boost::program_options::value;
 using boost::program_options::variables_map;
+using boost::shared_ptr;
 using I2n::Logger::GlobalLogger;
 
 //-----------------------------------------------------------------------------
@@ -41,45 +58,53 @@ using I2n::Logger::GlobalLogger;
  * @brief Default constructor.
  */
 ConfigurationOptions::ConfigurationOptions() :
+    GenericOptions(),
+    ConfigOptions(),
+    HostOptions(),
     HelpCmdStr( "help" ),
-    HelpCmdDesc( "Print this help and exit." ),
-    VersionCmdStr( "version" ),
-    VersionCmdDesc( "Print the version string and exit." ),
-    DaemonCmdStr( "daemon" ),
-    DaemonCmdDesc( "Run the evil in background." ),
-    DefaultConfigFileName( "/etc/pingcheck.conf" ),
-    ConfigFileCmdStr( "config-file" ),
-    ConfigFileCmdDesc( "Name of the configuration file." ),
-    SourceNetworkInterfaceCmdStr( "source-network-interface" ),
-    SourceNetworkInterfaceCmdDesc( "The network interface from where the packets will be received and originated" ),
-    DefaultNameServer( "127.0.0.1" ),
-    NameServerCmdStr( "nameserver" ),
-    NameServerCmdDesc( "The local address from where the DNS query will be made." ),
-    DefaultHostsDownLimit( 0 ), // no host down
-    HostsDownLimitCmdStr( "hosts-down-limit" ),
-    HostsDownLimitCmdDesc( "Limit of host that have to be down in order to notify." ),
-    DefaultPingFailLimit( 50 ), // 50 pings can fail at most
-    PingFailLimitCmdStr( "ping-fail-limit" ),
-    PingFailLimitCmdDesc( "Maximum percentage of pings that can fail for a given host." ),
-    StatusNotifierCmdCmdStr( "status-notifier-cmd" ),
-    StatusNotifierCmdCmdDesc( "The command to execute to alert about host status." ),
-    DefaultLinkUpIntervalInMin( 5 ), // 5 minutes
-    LinkUpIntervalCmdStr( "link-up-interval" ),
-    LinkUpIntervalCmdDesc( "How long the link must be responsive in order to consider it stable." ),
-    DefaultLinkDownIntervalInMin( 2 ), // 2 minutes
-    LinkDownIntervalCmdStr( "link-down-interval" ),
-    LinkDownIntervalCmdDesc( "How long the link must be offline in order to consider it down." ),
-    HostNameCmdStr( "host.name" ),
-    HostNameCmdDesc( "Host address" ),
-    DefaultHostPort( 80 ), // HTTP port
-    HostPortCmdStr( "host.port" ),
-    HostPortCmdDesc( "Host port number" ),
-    HostPingProtocolCmdStr( "host.ping-protocol" ),
-    HostPingProtocolCmdDesc( "Defines which protocol will be used to ping the destination." ),
-    DefaultHostIntervalInSec( 60 ), // 60 seconds
-    HostIntervalCmdStr( "host.interval" ),
-    HostIntervalCmdDesc( "Interval between each ping to the host" )
+    HelpCmdDesc( "Print this help and exit." )
 {
+    ConfigurationOptionItem config_file( new ConfigFileOption );
+    GenericOptions.push_back( config_file );
+
+    ConfigurationOptionItem daemon( new DaemonOption );
+    GenericOptions.push_back( daemon );
+
+    ConfigurationOptionItem version( new VersionOption );
+    GenericOptions.push_back( version );
+
+    ConfigurationOptionItem host_down_limit( new HostDownLimitOption );
+    ConfigOptions.push_back( host_down_limit );
+
+    ConfigurationOptionItem link_down_interval( new LinkDownIntervalOption );
+    ConfigOptions.push_back( link_down_interval );
+
+    ConfigurationOptionItem link_up_interval( new LinkUpIntervalOption );
+    ConfigOptions.push_back( link_up_interval );
+
+    ConfigurationOptionItem nameserver( new NameserverOption );
+    ConfigOptions.push_back( nameserver );
+
+    ConfigurationOptionItem ping_fail_limit( new PingFailLimitOption );
+    ConfigOptions.push_back( ping_fail_limit );
+
+    ConfigurationOptionItem source_network_interface( new SourceNetworkInterfaceOption );
+    ConfigOptions.push_back( source_network_interface );
+
+    ConfigurationOptionItem status_notifier_cmd( new StatusNotifierCmdOption );
+    ConfigOptions.push_back( status_notifier_cmd );
+
+    HostConfigurationOptionItem host_name( new HostNameOption );
+    HostOptions.push_back( host_name );
+
+    HostConfigurationOptionItem host_port( new HostPortOption );
+    HostOptions.push_back( host_port );
+
+    HostConfigurationOptionItem host_protocol( new HostPingProtocolOption );
+    HostOptions.push_back( host_protocol );
+
+    HostConfigurationOptionItem host_interval( new HostPingIntervalOption );
+    HostOptions.push_back( host_interval );
 }
 
 /**
@@ -90,55 +115,64 @@ ConfigurationOptions::~ConfigurationOptions()
 }
 
 /**
- * @brief TODO
- *
- * @return
+ * @return The options which are common to all kinds of applications.
  */
 options_description ConfigurationOptions::get_generic_options() const
 {
     options_description options( "Generic options" );
+
     options.add_options()
         ( HelpCmdStr.c_str(), HelpCmdDesc.c_str() )
-        ( VersionCmdStr.c_str(), VersionCmdDesc.c_str() )
-        ( DaemonCmdStr.c_str(), DaemonCmdDesc.c_str() )
-        ( ConfigFileCmdStr.c_str(), value<string>()->default_value( DefaultConfigFileName ), ConfigFileCmdDesc.c_str() )
     ;
 
+    BOOST_FOREACH( ConfigurationOptionItem generic_option, GenericOptions )
+    {
+        // Do not pass the the underlying boost::program_options::option_description
+        // object from ConfigurationOption to the
+        // boost::program_options::options_description::add() method, because it
+        // deletes the boost::program_options::option_description, causing
+        // multiple freed when ConfigurationOption try to delete it.
+        option_description option = generic_option->get_option_description();
+        shared_ptr< option_description > ptr( new option_description( option ) );
+        options.add( ptr );
+    }
+
     return options;
 }
 
 /**
- * @brief TODO
- *
- * @return
+ * @return The options which are specific to this application.
  */
 options_description ConfigurationOptions::get_configuration_options() const
 {
     options_description options( "Configuration" );
-    options.add_options()
-        ( SourceNetworkInterfaceCmdStr.c_str(), value<string>(), SourceNetworkInterfaceCmdDesc.c_str() )
-        ( NameServerCmdStr.c_str(), value<string>()->default_value( DefaultNameServer ), NameServerCmdDesc.c_str() )
-        ( HostsDownLimitCmdStr.c_str(), value<int>()->default_value( DefaultHostsDownLimit ), HostsDownLimitCmdDesc.c_str() )
-        ( PingFailLimitCmdStr.c_str(), value<int>()->default_value( DefaultPingFailLimit ), PingFailLimitCmdDesc.c_str() )
-        ( StatusNotifierCmdCmdStr.c_str(), value<string>(), StatusNotifierCmdCmdDesc.c_str() )
-        ( LinkUpIntervalCmdStr.c_str(), value<int>()->default_value( DefaultLinkUpIntervalInMin ), LinkUpIntervalCmdDesc.c_str() )
-        ( LinkDownIntervalCmdStr.c_str(), value<int>()->default_value( DefaultLinkDownIntervalInMin ), LinkDownIntervalCmdDesc.c_str() )
-        ( HostNameCmdStr.c_str(), value< vector<string> >(), HostNameCmdDesc.c_str() )
-        ( HostPortCmdStr.c_str(), value< vector<int> >(), HostPortCmdDesc.c_str() )
-        ( HostPingProtocolCmdStr.c_str(), value< vector<string> >(), HostPingProtocolCmdDesc.c_str() )
-        ( HostIntervalCmdStr.c_str(), value< vector<int> >(), HostIntervalCmdDesc.c_str() )
-    ;
+
+    BOOST_FOREACH( ConfigurationOptionItem configuration_option, ConfigOptions )
+    {
+        option_description option = configuration_option->get_option_description();
+        shared_ptr< option_description > ptr( new option_description( option ) );
+        options.add( ptr );
+    }
+
+    BOOST_FOREACH( ConfigurationOptionItem host_option, HostOptions )
+    {
+        option_description option = host_option->get_option_description();
+        shared_ptr< option_description > ptr( new option_description( option ) );
+        options.add( ptr );
+    }
 
     return options;
 }
 
 /**
- * @brief TODO
+ * @brief Parse the options common to all kinds of applications.
  *
- * @param
- * @param
+ * @param vm The input @c boost::program_options::variables_map.
+ * @param configuration The output @c Configuration filled with the parsed
+ * generic options.
  *
- * @return
+ * @return @c true if it was parsed at least one option, or @c false if there
+ * were no options available in this category.
  */
 bool ConfigurationOptions::parse_generic_options(
         const variables_map& vm,
@@ -146,7 +180,7 @@ bool ConfigurationOptions::parse_generic_options(
 )
 {
     // help
-    if ( vm.count( HelpCmdStr ) > 0)
+    if ( vm.count( HelpCmdStr ) > 0 )
     {
         options_description generic = get_generic_options();
         options_description config = get_configuration_options();
@@ -154,239 +188,85 @@ bool ConfigurationOptions::parse_generic_options(
         options_description visible_options( "Allowed options" );
         visible_options.add( generic ).add( config );
 
-        // TODO return a string with help, does not print to interface
+        // TODO GlobalOutput::print( help )
         cout << visible_options << endl;
         return true;
     }
 
-    // version
-    if ( vm.count( VersionCmdStr ) > 0 )
+    BOOST_FOREACH( ConfigurationOptionItem generic_option, GenericOptions )
     {
-        cout << PROJECT_NAME << " version " << VERSION_STRING << endl;
-        return true;
+        bool validated = generic_option->validate( vm );
+        if ( validated )
+        {
+            generic_option->parse( vm, configuration );
+        }
     }
 
-    // daemon
-    bool have_daemon = ( vm.count( DaemonCmdStr ) > 0 );
-    configuration->set_daemon( have_daemon );
-    GlobalLogger.info() << DaemonCmdStr << "="
-            << have_daemon << endl;
-
-    // config-file
-    if ( vm.count( ConfigFileCmdStr ) > 0 )
-    {
-        string config_file_name = vm[ ConfigFileCmdStr ].as<string> ();
-        configuration->set_config_file_name( config_file_name );
-
-        GlobalLogger.info() << ConfigFileCmdStr << "="
-                << config_file_name << endl;
-    }
 
     return false;
 }
 
 /**
- * @brief TODO
+ * @brief Parse the options specific to this application.
  *
- * @param
- * @param
+ * @param vm The input @c boost::program_options::variables_map.
+ * @param configuration The output @c Configuration filled with the parsed
+ * configuration options.
  *
- * @return
+ * @return @c true if it was parsed at least one option, or @c false if there
+ * were no options available in this category.
  */
 bool ConfigurationOptions::parse_configuration_options(
         const variables_map &vm,
         Configuration *configuration
 )
 {
-    // source-network-interface
-    if ( vm.count( SourceNetworkInterfaceCmdStr ) > 0 )
-    {
-        string source_network_interface =
-                vm[ SourceNetworkInterfaceCmdStr ].as<string> ();
-        configuration->set_source_network_interface( source_network_interface );
-
-        GlobalLogger.info() << SourceNetworkInterfaceCmdStr << "="
-                << source_network_interface << endl;
-    }
-
-    // nameserver
-    if ( vm.count( NameServerCmdStr ) > 0 )
-    {
-        string nameserver = vm[ NameServerCmdStr ].as<string> ();
-        configuration->set_nameserver( nameserver );
-
-        GlobalLogger.info() << NameServerCmdStr << "="
-                << nameserver << endl;
-    }
-
-    // hosts-down-limit
-    int host_down_limit = 0;
-    if ( vm.count( HostsDownLimitCmdStr ) > 0 )
-    {
-        host_down_limit = vm[ HostsDownLimitCmdStr ].as<int> ();
-        configuration->set_hosts_down_limit( host_down_limit );
-
-        GlobalLogger.info() << HostsDownLimitCmdStr << "="
-                << host_down_limit << endl;
-    }
-
-    // ping-fail-limit
-    if ( vm.count( PingFailLimitCmdStr ) > 0 )
+    BOOST_FOREACH( ConfigurationOptionItem configuration_option, ConfigOptions )
     {
-        int ping_fail_limit = vm[ PingFailLimitCmdStr ].as<int> ();
-        configuration->set_ping_fail_limit( ping_fail_limit );
-
-        GlobalLogger.info() << PingFailLimitCmdStr << "="
-                << ping_fail_limit << endl;
-    }
-
-    // status-notifier-cmd
-    if ( vm.count( StatusNotifierCmdCmdStr ) > 0 )
-    {
-        string status_notifier_cmd = vm[ StatusNotifierCmdCmdStr ].as<string>();
-        configuration->set_status_notifier_cmd( status_notifier_cmd );
-
-        GlobalLogger.info() << StatusNotifierCmdCmdStr << "="
-                << status_notifier_cmd << endl;
-    }
-
-    // link-up-interval
-    if ( vm.count( LinkUpIntervalCmdStr ) > 0 )
-    {
-        int link_up_interval_in_min = vm[ LinkUpIntervalCmdStr ].as<int>();
-        configuration->set_link_up_interval_in_min( link_up_interval_in_min );
-
-        GlobalLogger.info() << LinkUpIntervalCmdStr << "="
-                << link_up_interval_in_min << endl;
-    }
-
-    // link-down-interval
-    if ( vm.count( LinkDownIntervalCmdStr ) > 0 )
-    {
-        int link_down_interval_in_min = vm[ LinkDownIntervalCmdStr ].as<int>();
-        configuration->set_link_down_interval_in_min( link_down_interval_in_min );
-
-        GlobalLogger.info() << LinkDownIntervalCmdStr << "="
-                << link_down_interval_in_min << endl;
-    }
-
-    // [host] name
-    size_t hosts_names_count = 0;
-    if ( vm.count( HostNameCmdStr ) > 0 )
-    {
-        HostList hosts_list;
-
-        vector<string> hosts_names = vm[ HostNameCmdStr ].as< vector<string> > ();
-        BOOST_FOREACH( string host_name, hosts_names )
+        bool validated = configuration_option->validate( vm );
+        if ( validated )
         {
-            BOOST_ASSERT( !host_name.empty() );
-
-            HostItem host_item( new Host( host_name ) );
-            hosts_list.push_back( host_item );
-
-            GlobalLogger.info() << HostNameCmdStr << "="
-                    << host_name << endl;
+            configuration_option->parse( vm, configuration );
         }
-
-        configuration->set_hosts( hosts_list );
-
-        hosts_names_count = hosts_names.size();
-
-        BOOST_ASSERT( hosts_names_count >= static_cast<size_t>( host_down_limit ) );
     }
 
-    // [host] port
-    size_t host_port_count = 0;
-    if ( vm.count( HostPortCmdStr ) > 0 )
-    {
-        HostList hosts_list = configuration->get_hosts();
-        HostList::iterator hosts_it = hosts_list.begin();
-
-        vector<int> hosts_ports = vm[ HostPortCmdStr ].as< vector<int> >();
-        BOOST_FOREACH( int host_port, hosts_ports )
-        {
-            BOOST_ASSERT( ( 0 <= host_port ) && ( host_port <= numeric_limits<uint16_t>::max() ) );
+    size_t host_down_limit_count = static_cast<size_t>( configuration->get_hosts_down_limit() );
 
-            HostItem host_item = *hosts_it;
-            host_item->set_port( static_cast<uint16_t>(host_port) );
-            ++hosts_it;
-
-            GlobalLogger.info() <<  HostPortCmdStr << "=" << host_port << endl;
-        }
-
-        host_port_count = hosts_ports.size();
-    }
-
-    // [host] ping-protocol
-    size_t host_ping_protocol_count = 0;
-    if ( vm.count( HostPingProtocolCmdStr ) > 0 )
+    BOOST_FOREACH( HostConfigurationOptionItem host_option, HostOptions )
     {
-        HostList hosts_list = configuration->get_hosts();
-        HostList::iterator hosts_it = hosts_list.begin();
-
-        vector<string> hosts_protocols = vm[ HostPingProtocolCmdStr ].as< vector<string> >();
-        BOOST_FOREACH( string protocol_string, hosts_protocols )
+        bool validated = host_option->validate( vm );
+        bool parsed = host_option->parse( vm, configuration );
+        if ( validated && parsed )
         {
-            BOOST_ASSERT( !protocol_string.empty() );
-
-            HostItem host_item = *hosts_it;
-            PingProtocol host_protocol = get_ping_protocol_from_string( protocol_string );
-            host_item->set_ping_protocol( host_protocol );
-            ++hosts_it;
-
-            GlobalLogger.info() << HostPingProtocolCmdStr << "="
-                    << protocol_string << endl;
+            // The set_hosts_count() method is called in parse() method, that is
+            // why we must parse before check the number of host options
+            size_t hosts_parsed_count = host_option->get_hosts_count();
+            bool have_minimum_hosts = ( host_down_limit_count <= hosts_parsed_count );
+            // Ensure we have all options for each host
+            if ( !have_minimum_hosts ) {
+                // TODO GlobalOutput::print()
+                GlobalLogger.error() << "Could not parse configuration file." <<
+                        " Missing an entry for one of the hosts." << endl;
+                // TODO Assume default value for a missing option
+                return false;
+            }
+
+            BOOST_ASSERT( hosts_parsed_count >= static_cast<size_t>( host_down_limit_count ) );
         }
-
-        host_ping_protocol_count = hosts_protocols.size();
     }
 
-    // [host] interval
-    size_t hosts_interval_count = 0;
-    if ( vm.count( HostIntervalCmdStr ) > 0 )
-    {
-        HostList hosts_list = configuration->get_hosts();
-        HostList::iterator hosts_it = hosts_list.begin();
-
-        vector<int> hosts_intervals = vm[ HostIntervalCmdStr ].as< vector<int> >();
-        BOOST_FOREACH( int host_interval_in_sec, hosts_intervals )
-        {
-            BOOST_ASSERT( 0 < host_interval_in_sec );
-
-            HostItem host_item = *hosts_it;
-            host_item->set_interval_in_sec( host_interval_in_sec );
-            ++hosts_it;
-
-            GlobalLogger.info() << HostIntervalCmdStr << "="
-                    << host_interval_in_sec << endl;
-        }
-
-        hosts_interval_count = hosts_intervals.size();
-    }
-
-    // make sure there is always an interval for each host
-    if ( hosts_names_count != hosts_interval_count )
-    {
-        GlobalLogger.error() << "Could not parse configuration file." <<
-                " Missing an interval entry for one of the hosts." << endl;
-        return false;
-    }
-
-    BOOST_ASSERT( hosts_names_count == host_port_count );
-    BOOST_ASSERT( hosts_names_count == host_ping_protocol_count );
-    BOOST_ASSERT( hosts_names_count == hosts_interval_count );
-
     return true;
 }
 
 /**
  * @return which options must abort the application. Like the --version.
- * TODO rename to is_haltable?
  */
 bool ConfigurationOptions::halt_on_generic_options( const variables_map &vm ) const
 {
+    VersionOption v;
+
     bool is_help = ( vm.count( HelpCmdStr ) > 0 );
-    bool is_version = ( vm.count( VersionCmdStr ) > 0 );
+    bool is_version = ( vm.count( v.get_command_string() ) > 0 );
     bool terminate_app = is_help || is_version;
 
     return terminate_app;
index c68799b..20cd660 100644 (file)
  on this file might be covered by the GNU General Public License.
  */
 
-#ifndef CONFIGURATIONOPTIONS_H
-#define CONFIGURATIONOPTIONS_H
+#ifndef CONFIGURATION_OPTIONS_H
+#define CONFIGURATION_OPTIONS_H
 
 #include <string>
 
 #include <boost/program_options.hpp>
 
 #include "config/configuration.h"
+#include "config/option/configurationoption.h"
+#include "config/option/hostconfigurationoption.h"
 
 //-----------------------------------------------------------------------------
 // ConfigurationOptions
@@ -56,46 +58,14 @@ public:
             const boost::program_options::variables_map &vm
     ) const;
 
-public: // TODO change to private
+private:
+    ConfigurationOptionList GenericOptions;
+    ConfigurationOptionList ConfigOptions;
+    HostConfigurationOptionList HostOptions;
+
     const std::string HelpCmdStr;
     const std::string HelpCmdDesc;
-    const std::string VersionCmdStr;
-    const std::string VersionCmdDesc;
-    const std::string DaemonCmdStr;
-    const std::string DaemonCmdDesc;
-    const std::string DefaultConfigFileName;
-    const std::string ConfigFileCmdStr;
-    const std::string ConfigFileCmdDesc;
-    const std::string SourceNetworkInterfaceCmdStr;
-    const std::string SourceNetworkInterfaceCmdDesc;
-    const std::string DefaultNameServer;
-    const std::string NameServerCmdStr;
-    const std::string NameServerCmdDesc;
-    const int DefaultHostsDownLimit;
-    const std::string HostsDownLimitCmdStr;
-    const std::string HostsDownLimitCmdDesc;
-    const int DefaultPingFailLimit;
-    const std::string PingFailLimitCmdStr;
-    const std::string PingFailLimitCmdDesc;
-    const std::string StatusNotifierCmdCmdStr;
-    const std::string StatusNotifierCmdCmdDesc;
-    const int DefaultLinkUpIntervalInMin;
-    const std::string LinkUpIntervalCmdStr;
-    const std::string LinkUpIntervalCmdDesc;
-    const int DefaultLinkDownIntervalInMin;
-    const std::string LinkDownIntervalCmdStr;
-    const std::string LinkDownIntervalCmdDesc;
-    const std::string HostNameCmdStr;
-    const std::string HostNameCmdDesc;
-    const int DefaultHostPort;
-    const std::string HostPortCmdStr;
-    const std::string HostPortCmdDesc;
-    const std::string HostPingProtocolCmdStr;
-    const std::string HostPingProtocolCmdDesc;
-    const int DefaultHostIntervalInSec;
-    const std::string HostIntervalCmdStr;
-    const std::string HostIntervalCmdDesc;
 
 };
 
-#endif // CONFIGURATIONOPTIONS_H
+#endif // CONFIGURATION_OPTIONS_H