/**
   * Parse and validate the cli arguments
   *
   * @param ln parsed command line
   * @return parsed cli parameters wrapped in the CliParams
   * @throws InvalidArgumentException in case of nonexistent or incorrect cli args
   */
  protected CliParams parse(CommandLine ln, Properties defaults) throws InvalidArgumentException {
    l.debug("Parsing cli " + ln);
    CliParams cp = new CliParams();

    for (Option o : mandatoryOptions) {
      String name = o.getLongOpt();
      if (ln.hasOption(name)) cp.put(name, ln.getOptionValue(name));
      else if (defaults.getProperty(name) != null) {
        cp.put(name, defaults.getProperty(name));
      } else {
        throw new InvalidArgumentException("Missing the '" + name + "' commandline parameter.");
      }
    }

    for (Option o : optionalOptions) {
      String name = o.getLongOpt();
      if (ln.hasOption(name)) {
        cp.put(name, ln.getOptionValue(name));
      } else if (defaults.getProperty(name) != null) {
        cp.put(name, defaults.getProperty(name));
      }
    }

    if (cp.containsKey(CLI_PARAM_VERSION[0])) {
      l.info(
          "GoodData Notification Tool version 1.2.45"
              + ((BUILD_NUMBER.length() > 0) ? ", build " + BUILD_NUMBER : "."));
      System.exit(0);
    }

    // use default host if there is no host in the CLI params
    if (!cp.containsKey(CLI_PARAM_GDC_HOST[0])) {
      cp.put(CLI_PARAM_GDC_HOST[0], Defaults.DEFAULT_HOST);
    }

    l.debug("Using host " + cp.get(CLI_PARAM_GDC_HOST[0]));

    if (ln.getArgs().length == 0) {
      throw new InvalidArgumentException("No config file has been given, quitting.");
    }

    String configs = "";
    for (final String arg : ln.getArgs()) {
      if (configs.length() > 0) configs += "," + arg;
      else configs += arg;
    }
    cp.put(CLI_PARAM_CONFIG, configs);

    return cp;
  }
 private NotificationTransport selectTransport(String uri) {
   if (uri.startsWith("sfdc")) {
     return SfdcChatterTransport.createTransport(
         cliParams.get(CLI_PARAM_TRANSPORT_USERNAME[0]),
         cliParams.get(CLI_PARAM_TRANSPORT_PASSWORD[0]));
   }
   throw new InvalidParameterException("Can't find transport for uri " + uri);
 }
  private void execute(String config) throws ConnectionException, IOException {

    NotificationConfig c = NotificationConfig.fromXml(new File(config));

    MessageFilter dupFilter = DuplicateMessageFilter.createFilter();

    GdcRESTApiWrapper rest = null;
    try {
      for (NotificationMessage m : c.getMessages()) {
        String dupFilterKind = m.getDupFilterKind();
        if (dupFilterKind != null && dupFilterKind.length() > 0) {
          if (!dupFilter.filter(m.getMessage(), dupFilterKind)) {
            l.debug("Message filtered out by the dup kind filter.");
            l.info("Message filtered out by the dup kind filter.");
            continue;
          }
        }
        rest = new GdcRESTApiWrapper(cliParams.getHttpConfig());
        rest.login();
        Expression e = null;
        JexlEngine jexl = new JexlEngine();
        e = jexl.createExpression(m.getCondition());
        JexlContext jc = new MapContext();
        List<Metric> metrics = m.getMetrics();
        double[] values = null;
        if (metrics != null && metrics.size() > 0) {
          values = new double[metrics.size()];
          for (int i = 0; i < metrics.size(); i++) {
            values[i] = rest.computeMetric(metrics.get(i).getUri());
            jc.set(metrics.get(i).getAlias(), new Double(values[i]));
          }
        }
        String[] texts = null;
        List<Report> reports = m.getReports();
        if (reports != null && reports.size() > 0) {
          texts = new String[reports.size()];
          for (int i = 0; i < reports.size(); i++) {
            texts[i] = rest.computeReport(reports.get(i).getUri());
          }
        }
        boolean result = decide(e.evaluate(jc));
        if (result) {
          NotificationTransport t = selectTransport(m.getUri());
          String msg = m.getMessage();
          if (values != null && values.length > 0 && metrics != null && metrics.size() > 0) {
            for (int i = 0; i < metrics.size(); i++) {
              String fmt = metrics.get(i).getFormat();
              if (fmt == null || fmt.length() <= 0) fmt = DEFAULT_FORMAT;
              DecimalFormat df = new DecimalFormat(fmt);
              msg = msg.replace("%" + metrics.get(i).getAlias() + "%", df.format(values[i]));
            }
          }
          if (texts != null && texts.length > 0 && reports != null && reports.size() > 0) {
            for (int i = 0; i < reports.size(); i++) {
              msg = msg.replace("%" + reports.get(i).getAlias() + "%", texts[i]);
            }
          }
          String dupFilterExact = m.getDupFilterExact();
          if (dupFilterExact != null && dupFilterExact.length() > 0) {
            if (!dupFilter.filter(msg, dupFilterExact)) {
              l.debug("Message filtered out by the dup exact filter.");
              l.info("Message filtered out by the dup exact filter.");
              continue;
            }
          }
          String fmt = m.getMessageTimestampFormat();
          if (fmt != null && fmt.length() > 0) t.send(msg + " (at " + getTimestamp(fmt) + ")");
          else t.send(msg);
          dupFilter.update(msg);
          dupFilter.update(m.getMessage());
          l.info("Notification sent.");
        }
      }
      dupFilter.save();
      rest.logout();
    } catch (Exception e) {
      throw new IOException(e);
    } finally {
      if (rest != null) rest.logout();
    }
  }
 private GdcNotification(CommandLine ln, Properties defaults) {
   try {
     cliParams = parse(ln, defaults);
     cliParams.setHttpConfig(
         new NamePasswordConfiguration(
             "https",
             cliParams.get(CLI_PARAM_GDC_HOST[0]),
             cliParams.get(CLI_PARAM_GDC_USERNAME[0]),
             cliParams.get(CLI_PARAM_GDC_PASSWORD[0])));
     String config = cliParams.get(CLI_PARAM_CONFIG);
     if (config != null && config.length() > 0) {
       execute(config);
     } else {
       l.error("No config file given.");
       commandsHelp();
       System.exit(1);
     }
     finishedSucessfuly = true;
   } catch (ConnectionException e) {
     l.error("Can't connect to SFDC: " + e.getMessage());
     Throwable c = e.getCause();
     while (c != null) {
       l.error("Caused by: " + c.getMessage());
       c = c.getCause();
     }
     l.debug("Can't connect to SFDC:", e);
   } catch (InvalidArgumentException e) {
     l.error("Invalid command line argument: " + e.getMessage());
     Throwable c = e.getCause();
     while (c != null) {
       l.error("Caused by: " + c.getMessage());
       c = c.getCause();
     }
     l.debug("Invalid command line argument:", e);
     l.info(commandsHelp());
   } catch (SfdcException e) {
     l.error("Error communicating with SalesForce: " + e.getMessage());
     Throwable c = e.getCause();
     while (c != null) {
       l.error("Caused by: " + c.getMessage());
       c = c.getCause();
     }
     l.debug("Error communicating with SalesForce.", e);
   } catch (IOException e) {
     l.error(
         "Encountered an IO problem. Please check that all files that you use in your command line arguments and commands exist. More info: '"
             + e.getMessage()
             + "'");
     Throwable c = e.getCause();
     while (c != null) {
       l.error("Caused by: " + c.getMessage());
       c = c.getCause();
     }
     l.debug(
         "Encountered an IO problem. Please check that all files that you use in your command line arguments and commands exist. More info: '"
             + e.getMessage()
             + "'",
         e);
   } catch (InternalErrorException e) {
     Throwable c = e.getCause();
     if (c != null && c instanceof SQLException) {
       l.error(
           "Error extracting data. Can't process the incoming data. Please check the CSV file "
               + "separator and consistency (same number of columns in each row). Also, please make sure "
               + "that the number of columns in your XML config file matches the number of rows in your "
               + "data source. Make sure that your file is readable by other users (particularly the mysql user). "
               + "More info: '"
               + c.getMessage()
               + "'");
       l.debug(
           "Error extracting data. Can't process the incoming data. Please check the CSV file "
               + "separator and consistency (same number of columns in each row). Also, please make sure "
               + "that the number of columns in your XML config file matches the number of rows in your "
               + "data source. Make sure that your file is readable by other users (particularly the mysql user). "
               + "More info: '"
               + c.getMessage()
               + "'",
           c);
     } else {
       l.error("Internal error: " + e.getMessage());
       c = e.getCause();
       while (c != null) {
         l.error("Caused by: " + c.getMessage());
         c = c.getCause();
       }
       l.debug("REST API invocation error: ", e);
     }
   } catch (HttpMethodException e) {
     l.error("Error executing GoodData REST API: " + e.getMessage());
     Throwable c = e.getCause();
     while (c != null) {
       l.error("Caused by: " + c.getMessage());
       c = c.getCause();
     }
     l.debug("Error executing GoodData REST API.", e);
   } catch (GdcRestApiException e) {
     l.error("REST API invocation error: " + e.getMessage());
     Throwable c = e.getCause();
     while (c != null) {
       if (c instanceof HttpMethodException) {
         HttpMethodException ex = (HttpMethodException) c;
         String msg = ex.getMessage();
         if (msg != null && msg.length() > 0 && msg.indexOf("/ldm/manage") > 0) {
           l.error("Error creating/updating logical data model (executing MAQL DDL).");
           if (msg.indexOf(".date") > 0) {
             l.error("Bad time dimension schemaReference.");
           } else {
             l.error(
                 "You are either trying to create a data object that already exists "
                     + "(executing the same MAQL multiple times) or providing a wrong reference "
                     + "or schemaReference in your XML configuration.");
           }
         }
       }
       l.error("Caused by: " + c.getMessage());
       c = c.getCause();
     }
     l.debug("REST API invocation error: ", e);
   } catch (GdcException e) {
     l.error("Unrecognized error: " + e.getMessage());
     Throwable c = e.getCause();
     while (c != null) {
       l.error("Caused by: " + c.getMessage());
       c = c.getCause();
     }
     l.debug("Unrecognized error: ", e);
   }
 }