private static List<HttpLink> readCustomActionUrls() {

    List<HttpLink> customActionUrls = new ArrayList<>();

    for (int i = 0; i < 1000; i++) {
      String customActionUrlKey = "custom_action_url_" + (i + 1);
      String customActionUrlValue =
          applicationConfiguration_.safeGetString(customActionUrlKey, null);

      if (customActionUrlValue == null) continue;

      try {
        CSVReader reader = new CSVReader(new StringReader(customActionUrlValue));
        List<String[]> csvValuesArray = reader.readAll();

        if ((csvValuesArray != null)
            && !csvValuesArray.isEmpty()
            && (csvValuesArray.get(0) != null)) {
          String[] csvValues = csvValuesArray.get(0);

          if (csvValues.length == 2) {
            String url = csvValues[0];
            String linkText = csvValues[1];

            HttpLink httpLink = new HttpLink(url, linkText);
            customActionUrls.add(httpLink);
          }
        }
      } catch (Exception e) {
        logger.error(e.toString() + System.lineSeparator() + StackTrace.getStringFromStackTrace(e));
      }
    }

    return customActionUrls;
  }
  private static List<GraphiteOutputModule> readGraphiteOutputModules() {

    List<GraphiteOutputModule> graphiteOutputModules = new ArrayList<>();

    for (int i = -1; i < 10000; i++) {
      String graphiteOutputModuleKey = "graphite_output_module_" + (i + 1);
      String graphiteOutputModuleValue =
          applicationConfiguration_.safeGetString(graphiteOutputModuleKey, null);

      if (graphiteOutputModuleValue == null) continue;

      try {
        CSVReader reader = new CSVReader(new StringReader(graphiteOutputModuleValue));
        List<String[]> csvValuesArray = reader.readAll();

        if ((csvValuesArray != null)
            && !csvValuesArray.isEmpty()
            && (csvValuesArray.get(0) != null)) {
          String[] csvValues = csvValuesArray.get(0);

          if (csvValues.length >= 4) {
            boolean isOutputEnabled = Boolean.valueOf(csvValues[0]);
            String host = csvValues[1];
            int port = Integer.valueOf(csvValues[2]);
            int numSendRetryAttempts = Integer.valueOf(csvValues[3]);

            int maxMetricsPerMessage = 1000;
            if (csvValues.length > 4) maxMetricsPerMessage = Integer.valueOf(csvValues[4]);

            boolean sanitizeMetrics = false;
            if (csvValues.length > 5) sanitizeMetrics = Boolean.valueOf(csvValues[5]);

            boolean substituteCharacters = false;
            if (csvValues.length > 6) substituteCharacters = Boolean.valueOf(csvValues[6]);

            String uniqueId = "Graphite-" + (i + 1);

            GraphiteOutputModule graphiteOutputModule =
                new GraphiteOutputModule(
                    isOutputEnabled,
                    host,
                    port,
                    numSendRetryAttempts,
                    maxMetricsPerMessage,
                    sanitizeMetrics,
                    substituteCharacters,
                    uniqueId);

            graphiteOutputModules.add(graphiteOutputModule);
          }
        }
      } catch (Exception e) {
        logger.error(e.toString() + System.lineSeparator() + StackTrace.getStringFromStackTrace(e));
      }
    }

    return graphiteOutputModules;
  }
  private static List<OpenTsdbHttpOutputModule> readOpenTsdbHttpOutputModules() {

    List<OpenTsdbHttpOutputModule> openTsdbHttpOutputModules = new ArrayList<>();

    for (int i = -1; i < 10000; i++) {
      String openTsdbHttpOutputModuleKey = "opentsdb_http_output_module_" + (i + 1);
      String openTsdbHttpOutputModuleValue =
          applicationConfiguration_.safeGetString(openTsdbHttpOutputModuleKey, null);

      if (openTsdbHttpOutputModuleValue == null) continue;

      try {
        CSVReader reader = new CSVReader(new StringReader(openTsdbHttpOutputModuleValue));
        List<String[]> csvValuesArray = reader.readAll();

        if ((csvValuesArray != null)
            && !csvValuesArray.isEmpty()
            && (csvValuesArray.get(0) != null)) {
          String[] csvValues = csvValuesArray.get(0);

          if (csvValues.length >= 4) {
            boolean isOutputEnabled = Boolean.valueOf(csvValues[0]);
            String url = csvValues[1];
            int numSendRetryAttempts = Integer.valueOf(csvValues[2]);
            int maxMetricsPerMessage = Integer.valueOf(csvValues[3]);

            boolean sanitizeMetrics = false;
            if (csvValues.length > 4) sanitizeMetrics = Boolean.valueOf(csvValues[4]);

            String uniqueId = "OpenTSDB-HTTP-" + (i + 1);

            OpenTsdbHttpOutputModule openTsdbHttpOutputModule =
                new OpenTsdbHttpOutputModule(
                    isOutputEnabled,
                    url,
                    numSendRetryAttempts,
                    maxMetricsPerMessage,
                    sanitizeMetrics,
                    uniqueId);
            openTsdbHttpOutputModules.add(openTsdbHttpOutputModule);
          }
        }
      } catch (Exception e) {
        logger.error(e.toString() + System.lineSeparator() + StackTrace.getStringFromStackTrace(e));
      }
    }

    return openTsdbHttpOutputModules;
  }
  public static boolean initialize(
      InputStream configurationInputStream, boolean isUsingDefaultSettings) {

    if (configurationInputStream == null) {
      return false;
    }

    isUsingDefaultSettings_ = isUsingDefaultSettings;
    applicationConfiguration_ = new PropertiesConfigurationWrapper(configurationInputStream);

    if ((applicationConfiguration_ == null) || !applicationConfiguration_.isValid()) {
      return false;
    }

    isInitializeSuccess_ = setApplicationConfigurationValues();
    return isInitializeSuccess_;
  }
  private static List<InfluxdbV1HttpOutputModule> readInfluxdbV1HttpOutputModules() {

    List<InfluxdbV1HttpOutputModule> influxdbV1HttpOutputModules = new ArrayList<>();

    for (int i = -1; i < 10000; i++) {
      String influxdbV1HttpOutputModuleKey = "influxdb_v1_output_module_" + (i + 1);
      String influxdbV1HttpOutputModuleValue =
          applicationConfiguration_.safeGetString(influxdbV1HttpOutputModuleKey, null);

      if (influxdbV1HttpOutputModuleValue == null) continue;

      try {
        CSVReader reader = new CSVReader(new StringReader(influxdbV1HttpOutputModuleValue));
        List<String[]> csvValuesArray = reader.readAll();

        if ((csvValuesArray != null)
            && !csvValuesArray.isEmpty()
            && (csvValuesArray.get(0) != null)) {
          String[] csvValues = csvValuesArray.get(0);

          if (csvValues.length == 4) {
            boolean isOutputEnabled = Boolean.valueOf(csvValues[0]);
            String url = csvValues[1];
            int numSendRetryAttempts = Integer.valueOf(csvValues[2]);
            int maxMetricsPerMessage = Integer.valueOf(csvValues[3]);

            String uniqueId = "InfluxDB-V1-" + (i + 1);

            InfluxdbV1HttpOutputModule influxdbV1HttpOutputModule =
                new InfluxdbV1HttpOutputModule(
                    isOutputEnabled, url, numSendRetryAttempts, maxMetricsPerMessage, uniqueId);

            influxdbV1HttpOutputModules.add(influxdbV1HttpOutputModule);
          }
        }
      } catch (Exception e) {
        logger.error(e.toString() + System.lineSeparator() + StackTrace.getStringFromStackTrace(e));
      }
    }

    return influxdbV1HttpOutputModules;
  }
  private static boolean setApplicationConfigurationValues() {

    try {
      flushTimeAgg_ = applicationConfiguration_.safeGetInteger("flush_time_agg", 10000);
      debugModeEnabled_ = applicationConfiguration_.safeGetBoolean("debug_mode_enabled", false);

      // graphite output configuration
      graphiteOutputModules_.addAll(readGraphiteOutputModules());

      // opentsdb telnet output configuration
      openTsdbTelnetOutputModules_.addAll(readOpenTsdbTelnetOutputModules());

      // opentsdb http output configuration
      openTsdbHttpOutputModules_.addAll(readOpenTsdbHttpOutputModules());

      // opentsdb configuration
      influxdbV1HttpOutputModules_.addAll(readInfluxdbV1HttpOutputModules());

      // listener config
      statsdTcpListenerEnabled_ =
          applicationConfiguration_.safeGetBoolean("statsd_tcp_listener_enabled", true);
      statsdTcpListenerPort_ =
          applicationConfiguration_.safeGetInt("statsd_tcp_listener_port", 8125);
      statsdUdpListenerEnabled_ =
          applicationConfiguration_.safeGetBoolean("statsd_udp_listener_enabled", true);
      statsdUdpListenerPort_ =
          applicationConfiguration_.safeGetInt("statsd_udp_listener_port", 8125);
      graphiteAggregatorTcpListenerEnabled_ =
          applicationConfiguration_.safeGetBoolean(
              "graphite_aggregator_tcp_listener_enabled", true);
      graphiteAggregatorTcpListenerPort_ =
          applicationConfiguration_.safeGetInt("graphite_aggregator_tcp_listener_port", 22003);
      graphiteAggregatorUdpListenerEnabled_ =
          applicationConfiguration_.safeGetBoolean(
              "graphite_aggregator_udp_listener_enabled", true);
      graphiteAggregatorUdpListenerPort_ =
          applicationConfiguration_.safeGetInt("graphite_aggregator_udp_listener_port", 22003);
      graphitePassthroughTcpListenerEnabled_ =
          applicationConfiguration_.safeGetBoolean(
              "graphite_passthrough_tcp_listener_enabled", true);
      graphitePassthroughTcpListenerPort_ =
          applicationConfiguration_.safeGetInt("graphite_passthrough_tcp_listener_port", 2003);
      graphitePassthroughUdpListenerEnabled_ =
          applicationConfiguration_.safeGetBoolean(
              "graphite_passthrough_udp_listener_enabled", true);
      graphitePassthroughUdpListenerPort_ =
          applicationConfiguration_.safeGetInt("graphite_passthrough_udp_listener_port", 2003);
      openTsdbTcpTelnetListenerEnabled_ =
          applicationConfiguration_.safeGetBoolean("opentsdb_tcp_telnet_listener_enabled", true);
      openTsdbTcpTelnetListenerPort_ =
          applicationConfiguration_.safeGetInt("opentsdb_tcp_telnet_listener_port", 4242);
      openTsdbHttpListenerEnabled_ =
          applicationConfiguration_.safeGetBoolean("opentsdb_http_listener_enabled", true);
      openTsdbHttpListenerPort_ =
          applicationConfiguration_.safeGetInt("opentsdb_http_listener_port", 4243);
      influxdbHttpListenerEnabled_ =
          applicationConfiguration_.safeGetBoolean("influxdb_http_listener_enabled", true);
      influxdbHttpListenerPort_ =
          applicationConfiguration_.safeGetInt("influxdb_http_listener_port", 8086);

      // metric naming config
      globalMetricNamePrefixEnabled_ =
          applicationConfiguration_.safeGetBoolean("global_metric_name_prefix_enabled", false);
      globalMetricNamePrefixValue_ =
          applicationConfiguration_.safeGetString("global_metric_name_prefix_value", "statsagg");
      globalAggregatedMetricsSeparatorString_ =
          applicationConfiguration_.safeGetString(
              "global_aggregated_metrics_separator_string", ".");
      statsdMetricNamePrefixEnabled_ =
          applicationConfiguration_.safeGetBoolean("statsd_metric_name_prefix_enabled", false);
      statsdMetricNamePrefixValue_ =
          applicationConfiguration_.safeGetString("statsd_metric_name_prefix_value", "stats");
      statsdMetricNameSuffixEnabled_ =
          applicationConfiguration_.safeGetBoolean("statsd_metric_name_suffix_enabled", false);
      statsdMetricNameSuffixValue_ =
          applicationConfiguration_.safeGetString("statsd_metric_name_suffix_value", "");
      statsdCounterMetricNamePrefixEnabled_ =
          applicationConfiguration_.safeGetBoolean(
              "statsd_counter_metric_name_prefix_enabled", false);
      statsdCounterMetricNamePrefixValue_ =
          applicationConfiguration_.safeGetString(
              "statsd_counter_metric_name_prefix_value", "counters");
      statsdGaugeMetricNamePrefixEnabled_ =
          applicationConfiguration_.safeGetBoolean(
              "statsd_gauge_metric_name_prefix_enabled", false);
      statsdGaugeMetricNamePrefixValue_ =
          applicationConfiguration_.safeGetString(
              "statsd_gauge_metric_name_prefix_value", "gauges");
      statsdTimerMetricNamePrefixEnabled_ =
          applicationConfiguration_.safeGetBoolean(
              "statsd_timer_metric_name_prefix_enabled", false);
      statsdTimerMetricNamePrefixValue_ =
          applicationConfiguration_.safeGetString(
              "statsd_timer_metric_name_prefix_value", "timers");
      statsdSetMetricNamePrefixEnabled_ =
          applicationConfiguration_.safeGetBoolean("statsd_set_metric_name_prefix_enabled", false);
      statsdSetMetricNamePrefixValue_ =
          applicationConfiguration_.safeGetString("statsd_set_metric_name_prefix_value", "sets");
      graphiteAggregatorMetricNamePrefixEnabled_ =
          applicationConfiguration_.safeGetBoolean(
              "graphite_aggregator_metric_name_prefix_enabled", false);
      graphiteAggregatorMetricNamePrefixValue_ =
          applicationConfiguration_.safeGetString(
              "graphite_aggregator_metric_name_prefix_value", "graphite-agg");
      graphitePassthroughMetricNamePrefixEnabled_ =
          applicationConfiguration_.safeGetBoolean(
              "graphite_passthrough_metric_name_prefix_enabled", false);
      graphitePassthroughMetricNamePrefixValue_ =
          applicationConfiguration_.safeGetString(
              "graphite_passthrough_metric_name_prefix_value", "graphite");
      openTsdbMetricNamePrefixEnabled_ =
          applicationConfiguration_.safeGetBoolean("opentsdb_metric_name_prefix_enabled", false);
      openTsdbMetricNamePrefixValue_ =
          applicationConfiguration_.safeGetString("opentsdb_metric_name_prefix_value", "opentsdb");
      influxdbMetricNamePrefixEnabled_ =
          applicationConfiguration_.safeGetBoolean("influxdb_metric_name_prefix_enabled", false);
      influxdbMetricNamePrefixValue_ =
          applicationConfiguration_.safeGetString("influxdb_metric_name_prefix_value", "influxdb");
      influxdbIncludeDatabaseNameInNonNativeOutput_ =
          applicationConfiguration_.safeGetBoolean(
              "influxdb_include_database_name_in_non_native_output", true);

      // statsd specific variables
      statsdCounterSendZeroOnInactive_ =
          applicationConfiguration_.safeGetBoolean("statsd_counter_send_0_on_inactive", true);
      statsdTimerSendZeroOnInactive_ =
          applicationConfiguration_.safeGetBoolean("statsd_timer_send_0_on_inactive", true);
      statsdGaugeSendPreviousValue_ =
          applicationConfiguration_.safeGetBoolean("statsd_gauge_send_previous_value", true);
      statsdSetSendZeroOnInactive_ =
          applicationConfiguration_.safeGetBoolean("statsd_set_send_0_on_inactive", true);
      statsdNthPercentiles_ =
          new StatsdNthPercentiles(
              applicationConfiguration_.safeGetString("statsd_nth_percentiles", "90"));
      statsdHistogramConfigurations_ =
          readStatsdHistogramConfiguration(
              applicationConfiguration_.safeGetString("statsd_histograms", null));
      statsdUseLegacyNameSpacing_ =
          applicationConfiguration_.safeGetBoolean("statsd_use_legacy_name_spacing", false);
      statsdPersistGauges_ =
          applicationConfiguration_.safeGetBoolean("statsd_persist_gauges", true);

      // influxdb specific variables
      influxdbDefaultDatabaseName_ =
          applicationConfiguration_.safeGetString("influxdb_default_database_name", "statsagg");
      influxdbDefaultDatabaseUsername_ =
          applicationConfiguration_.safeGetString("influxdb_default_database_username", "statsagg");
      influxdbDefaultDatabasePassword_ =
          applicationConfiguration_.safeGetString("influxdb_default_database_password", "statsagg");
      if ((influxdbDefaultDatabaseUsername_ != null) && (influxdbDefaultDatabasePassword_ != null))
        influxdbDefaultDatabaseHttpBasicAuthValue_ =
            "Basic "
                + Base64.encodeBase64String(
                    (influxdbDefaultDatabaseUsername_ + ":" + influxdbDefaultDatabasePassword_)
                        .getBytes("UTF-8"));
      else influxdbDefaultDatabaseHttpBasicAuthValue_ = null;

      // alerting variables
      alertRoutineEnabled_ =
          applicationConfiguration_.safeGetBoolean("alert_routine_enabled", true);
      alertRoutineInterval_ =
          applicationConfiguration_.safeGetInteger("alert_routine_interval", 5000);
      alertSendEmailEnabled_ =
          applicationConfiguration_.safeGetBoolean("alert_send_email_enabled", false);
      alertMaxMetricsInEmail_ =
          applicationConfiguration_.safeGetInteger("alert_max_metrics_in_email", 100);
      alertOutputStatus_ = applicationConfiguration_.safeGetBoolean("alert_output_status", true);
      alertOutputStatusMetricPrefix_ =
          applicationConfiguration_.safeGetString(
              "alert_output_status_metric_prefix", "StatsAgg-Alerts");
      alertStatsAggLocation_ =
          applicationConfiguration_.safeGetString("alert_statsagg_location", "");
      alertWaitTimeAfterRestart_ =
          applicationConfiguration_.safeGetInteger("alert_wait_time_after_restart", 120000);

      alertSmtpHost_ = applicationConfiguration_.safeGetString("alert_smtp_host", "127.0.0.1");
      alertSmtpPort_ = applicationConfiguration_.safeGetInteger("alert_smtp_port", 25);
      alertSmtpConnectionTimeout_ =
          applicationConfiguration_.safeGetInteger("alert_smtp_connection_timeout", 15000);
      alertSmtpUsername_ = applicationConfiguration_.safeGetString("alert_smtp_username", "");
      alertSmtpPassword_ = applicationConfiguration_.safeGetString("alert_smtp_password", "");
      alertSmtpUseSslTls_ =
          applicationConfiguration_.safeGetBoolean("alert_smtp_use_ssl_tls", false);
      alertSmtpUseStartTls_ =
          applicationConfiguration_.safeGetBoolean("alert_smtp_use_starttls", false);
      alertSmtpFromAddress_ =
          applicationConfiguration_.safeGetString("alert_smtp_from_address", "*****@*****.**");
      alertSmtpFromName_ =
          applicationConfiguration_.safeGetString("alert_smtp_from_name", "StatsAgg");

      // website custominzation variables
      customActionUrls_.addAll(readCustomActionUrls());

      // advanced
      outputModuleMaxConnectTime_ =
          applicationConfiguration_.safeGetInteger("output_module_max_connect_time", 3000);
      outputModuleMaxReadTime_ =
          applicationConfiguration_.safeGetInteger("output_module_max_read_time", 120000);
      outputModuleMaxConcurrentThreads_ =
          applicationConfiguration_.safeGetInteger("output_module_max_concurrent_threads", 25);
      outputModuleMaxConcurrentThreadsForSingleModule_ =
          applicationConfiguration_.safeGetInteger(
              "output_module_max_concurrent_threads_for_single_module", 10);

      return true;
    } catch (Exception e) {
      logger.error(e.toString() + System.lineSeparator() + StackTrace.getStringFromStackTrace(e));
      return false;
    }
  }