public static void addNodeSetParams(
      final HashMap<String, String> params,
      final NodeSet nodeSet,
      final Boolean isKeepgoing,
      final String prefix) {

    if (null == nodeSet) {
      return;
    }
    if (nodeSet.getThreadCount() > 0) {
      params.put(prefix + "nodeThreadcount", Integer.toString(nodeSet.getThreadCount()));
    }
    if (null != isKeepgoing) {
      params.put(prefix + "nodeKeepgoing", Boolean.toString(isKeepgoing));
    }
    if (nodeSet.isBlank()) {
      return;
    }
    params.put(prefix + "doNodedispatch", "true");
    boolean excludeprecedence = true;
    if (null != nodeSet.getExclude() && nodeSet.getExclude().isDominant()) {
      excludeprecedence = true;
    } else if (null != nodeSet.getInclude() && nodeSet.getInclude().isDominant()) {
      excludeprecedence = false;
    }
    params.put(prefix + "nodeExcludePrecedence", Boolean.toString(excludeprecedence));

    final NodeSet.Include include = nodeSet.getInclude();

    for (NodeSet.FILTER_ENUM filter : NodeSet.FILTER_ENUM.values()) {
      String value = null;
      if (null != include && !include.isBlank()) {
        value = filter.value(include);
      }

      String key = nodeFilterParams.get(filter.getName());
      if (null != value && !"".equals(value)) {
        params.put(prefix + "nodeInclude" + key, value);
      } else {
        params.put(prefix + "nodeInclude" + key, "");
      }
    }
    final NodeSet.Exclude exclude = nodeSet.getExclude();

    for (NodeSet.FILTER_ENUM filter : NodeSet.FILTER_ENUM.values()) {
      String value = null;
      if (null != exclude && !exclude.isBlank()) {
        value = filter.value(exclude);
      }
      String key = nodeFilterParams.get(filter.getName());
      if (null != value && !"".equals(value)) {
        params.put(prefix + "nodeExclude" + key, value);
      } else {
        params.put(prefix + "nodeExclude" + key, "");
      }
    }
  }
  /**
   * Validate the response is in expected yaml format
   *
   * @param response response
   * @return Collection of job data maps if format is correct and there is no error
   * @throws com.dtolabs.client.services.CentralDispatcherServerRequestException if the format is
   *     incorrect, or the response indicates an error response.
   */
  private Collection<Map> validateJobsResponseYAML(final WebserviceResponse response)
      throws CentralDispatcherServerRequestException {
    if (null == response) {
      throw new CentralDispatcherServerRequestException("Response was null");
    }

    if (null != response.getResponseMessage()) {
      logger.info("Response: " + response.getResponseMessage());
    }
    String resultContentType = response.getResultContentType();
    if (resultContentType.contains(";")) {
      resultContentType = resultContentType.substring(0, resultContentType.indexOf(";"));
    }
    if (!resultContentType.endsWith("/yaml")) {
      throw new CentralDispatcherServerRequestException(
          "Expected YAML response, unexpected content type: " + response.getResultContentType());
    }
    final ArrayList<Map> dataset = new ArrayList<Map>();
    final Object resobj;
    try {
      final Yaml yaml = new Yaml(new SafeConstructor());
      resobj = yaml.load(response.getResults());
    } catch (YAMLException e) {
      throw new CentralDispatcherServerRequestException(
          "Failed to parse YAML: " + e.getMessage(), e);
    }
    if (resobj instanceof Collection) {
      dataset.addAll((Collection) resobj);
    } else {
      throw new CentralDispatcherServerRequestException(
          "Response had unexpected content type: " + resobj);
    }

    for (final Map map : dataset) {
      if (!map.containsKey("name") || !map.containsKey("id") && !map.containsKey("uuid")) {
        throw new CentralDispatcherServerRequestException(
            "Response had unexpected dataset: " + resobj);
      }
    }
    return dataset;
  }
 static {
   nodeFilterParams.put(NodeSet.HOSTNAME, "");
   nodeFilterParams.put(NodeSet.TYPE, "Type");
   nodeFilterParams.put(NodeSet.TAGS, "Tags");
   nodeFilterParams.put(NodeSet.OS_NAME, "OsName");
   nodeFilterParams.put(NodeSet.OS_FAMILY, "OsFamily");
   nodeFilterParams.put(NodeSet.OS_ARCH, "OsArch");
   nodeFilterParams.put(NodeSet.OS_VERSION, "OsVersion");
   nodeFilterParams.put(NodeSet.NAME, "Name");
 }
  private void addLoglevelParams(Map<String, String> params, int loglevel, final String prefix) {

    String loglevelstr = RundeckAppConstants.MSG_INFO.toUpperCase();
    switch (loglevel) {
      case Constants.DEBUG_LEVEL:
        loglevelstr = RundeckAppConstants.MSG_DEBUG.toUpperCase();
        break;
      case Constants.VERBOSE_LEVEL:
        loglevelstr = RundeckAppConstants.MSG_VERBOSE.toUpperCase();
        break;
      case Constants.INFO_LEVEL:
        loglevelstr = RundeckAppConstants.MSG_INFO.toUpperCase();
        break;
      case Constants.WARN_LEVEL:
        loglevelstr = RundeckAppConstants.MSG_WARN.toUpperCase();
        break;
      case Constants.ERR_LEVEL:
        loglevelstr = RundeckAppConstants.MSG_ERR.toUpperCase();
        break;
    }

    params.put(prefix + "loglevel", loglevelstr);
  }
  public Collection<IStoredJob> listStoredJobs(
      final IStoredJobsQuery iStoredJobsQuery,
      final OutputStream output,
      final JobDefinitionFileFormat fformat)
      throws CentralDispatcherException {
    final HashMap<String, String> params = new HashMap<String, String>();
    final String nameMatch = iStoredJobsQuery.getNameMatch();
    String groupMatch = iStoredJobsQuery.getGroupMatch();
    final String projectFilter = iStoredJobsQuery.getProjectFilter();
    final String idlistFilter = iStoredJobsQuery.getIdlist();

    final String expectedContentType;
    if (null != fformat) {
      params.put("format", fformat.getName());
      expectedContentType = fformat == JobDefinitionFileFormat.xml ? "text/xml" : "text/yaml";
    } else {
      params.put("format", JobDefinitionFileFormat.xml.getName());
      expectedContentType = "text/xml";
    }
    if (null != nameMatch) {
      params.put("jobFilter", nameMatch);
    }
    if (null != groupMatch) {
      final Matcher matcher = Pattern.compile("^/*(.+?)/*$").matcher(groupMatch);
      if (matcher.matches()) {
        // strip leading and trailing slashes
        groupMatch = matcher.group(1);
      }
      params.put("groupPath", groupMatch);
    }
    if (null != projectFilter) {
      params.put("project", projectFilter);
    }
    if (null != idlistFilter) {
      params.put("idlist", idlistFilter);
    }

    // 2. send request via ServerService
    final WebserviceResponse response;
    try {
      response =
          serverService.makeRundeckRequest(
              RUNDECK_API_JOBS_EXPORT_PATH, params, null, null, expectedContentType);
    } catch (MalformedURLException e) {
      throw new CentralDispatcherServerRequestException("Failed to make request", e);
    }
    checkErrorResponse(response);
    // if xml, do local validation and listing
    if (null == fformat || fformat == JobDefinitionFileFormat.xml) {
      validateJobsResponse(response);

      ////////////////////
      // parse result list of queued items, return the collection of QueuedItems
      ///////////////////

      final Document resultDoc = response.getResultDoc();

      final Node node = resultDoc.selectSingleNode("/joblist");
      final ArrayList<IStoredJob> list = new ArrayList<IStoredJob>();
      if (null == node) {
        return list;
      }
      final List items = node.selectNodes("job");
      if (null != items && items.size() > 0) {
        for (final Object o : items) {
          final Node node1 = (Node) o;
          final Node uuid = node1.selectSingleNode("uuid");
          final Node id1 = node1.selectSingleNode("id");
          final String id = null != uuid ? uuid.getStringValue() : id1.getStringValue();
          final String name = node1.selectSingleNode("name").getStringValue();
          final String url = createJobURL(id);

          final Node gnode = node1.selectSingleNode("group");
          final String group = null != gnode ? gnode.getStringValue() : null;
          final String description = node1.selectSingleNode("description").getStringValue();
          list.add(StoredJobImpl.create(id, name, url, group, description, projectFilter));
        }
      }

      if (null != output) {
        // write output doc to the outputstream
        final OutputFormat format = OutputFormat.createPrettyPrint();
        try {
          final XMLWriter writer = new XMLWriter(output, format);
          writer.write(resultDoc);
          writer.flush();
        } catch (IOException e) {
          throw new CentralDispatcherServerRequestException(e);
        }
      }
      return list;
    } else if (fformat == JobDefinitionFileFormat.yaml) {
      // do rought yaml parse
      final Collection<Map> mapCollection = validateJobsResponseYAML(response);
      final ArrayList<IStoredJob> list = new ArrayList<IStoredJob>();

      if (null == mapCollection || mapCollection.size() < 1) {
        return list;
      }
      for (final Map map : mapCollection) {
        final Object uuidobj = map.get("uuid");
        final Object idobj = map.get("id");
        final String id = null != uuidobj ? uuidobj.toString() : idobj.toString();
        final String name = (String) map.get("name");
        final String group = map.containsKey("group") ? (String) map.get("group") : null;
        final String desc = map.containsKey("description") ? (String) map.get("description") : "";
        final String url = createJobURL(id);
        list.add(StoredJobImpl.create(id, name, url, group, desc, projectFilter));
      }

      if (null != output) {
        // write output doc to the outputstream
        try {
          final Writer writer = new OutputStreamWriter(output);
          writer.write(response.getResults());
          writer.flush();
        } catch (IOException e) {
          throw new CentralDispatcherServerRequestException(e);
        }
      }
      return list;
    }
    return null;
  }