public Result importExtractorsPage(String nodeId, String inputId) {
    if (!Permissions.isPermitted(RestPermissions.INPUTS_EDIT, inputId)) {
      return redirect(routes.StartpageController.redirect());
    }
    try {
      Node node = nodeService.loadNode(nodeId);
      Input input = node.getInput(inputId);

      BreadcrumbList bc = standardBreadcrumbs(node, input);
      bc.addCrumb(
          "Import", controllers.routes.ExtractorsController.importExtractorsPage(nodeId, inputId));

      return ok(
          views.html.system.inputs.extractors.importPage.render(currentUser(), bc, node, input));
    } catch (IOException e) {
      return status(500, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
    } catch (APIException e) {
      String message =
          "Could not fetch system information. We expected HTTP 200, but got a HTTP "
              + e.getHttpCode()
              + ".";
      return status(500, views.html.errors.error.render(message, e, request()));
    } catch (NodeService.NodeNotFoundException e) {
      return status(
          404, views.html.errors.error.render(ApiClient.ERROR_MSG_NODE_NOT_FOUND, e, request()));
    }
  }
  public Result manageGlobal(String inputId) {
    if (!Permissions.isPermitted(RestPermissions.INPUTS_EDIT, inputId)) {
      return redirect(routes.StartpageController.redirect());
    }
    try {
      Node node = nodeService.loadMasterNode();
      Input input = node.getInput(inputId);

      return ok(
          views.html.system.inputs.extractors.manage.render(
              currentUser(),
              standardBreadcrumbs(node, input),
              node,
              input,
              extractorService.all(node, input)));
    } catch (IOException e) {
      return status(500, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
    } catch (APIException e) {
      String message =
          "Could not fetch system information. We expected HTTP 200, but got a HTTP "
              + e.getHttpCode()
              + ".";
      return status(500, views.html.errors.error.render(message, e, request()));
    }
  }
  public Result update(String nodeId, String inputId, String extractorId) {
    if (!Permissions.isPermitted(RestPermissions.INPUTS_EDIT, inputId)) {
      return redirect(routes.StartpageController.redirect());
    }
    try {
      final Node node = nodeService.loadNode(nodeId);
      final Input input = node.getInput(inputId);
      final Extractor originalExtractor = extractorService.load(node, input, extractorId);
      final Map<String, String[]> form = request().body().asFormUrlEncoded();
      final String title = form.get("title")[0];

      CreateExtractorRequest request;
      try {
        request = this.generateCreateExtractorRequest(form, originalExtractor);
      } catch (NullPointerException e) {
        Logger.error("Cannot build extractor configuration.", e);
        return badRequest();
      }

      extractorService.update(extractorId, node, input, request);
      flash("success", "Extractor \"" + title + "\" was updated successfully");
      return redirect(controllers.routes.ExtractorsController.manage(nodeId, inputId));
    } catch (IOException e) {
      return status(500, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
    } catch (APIException e) {
      String message =
          "Could not update extractor! We expected HTTP 200, but got a HTTP "
              + e.getHttpCode()
              + ".";
      return status(500, views.html.errors.error.render(message, e, request()));
    } catch (NodeService.NodeNotFoundException e) {
      return status(
          404, views.html.errors.error.render(ApiClient.ERROR_MSG_NODE_NOT_FOUND, e, request()));
    }
  }
  public Result fieldStats(
      String q,
      String field,
      String rangeType,
      int relative,
      String from,
      String to,
      String keyword,
      String streamId) {
    if (q == null || q.isEmpty()) {
      q = "*";
    }

    // Determine timerange type.
    TimeRange timerange;
    try {
      timerange = TimeRange.factory(rangeType, relative, from, to, keyword);
    } catch (InvalidRangeParametersException e2) {
      return status(
          400, views.html.errors.error.render("Invalid range parameters provided.", e2, request()));
    } catch (IllegalArgumentException e1) {
      return status(
          400, views.html.errors.error.render("Invalid range type provided.", e1, request()));
    }

    String filter = null;
    if (streamId != null && !streamId.isEmpty()) {
      filter = "streams:" + streamId;
    }

    try {
      UniversalSearch search = searchFactory.queryWithRangeAndFilter(q, timerange, filter);
      FieldStatsResponse stats = search.fieldStats(field);

      Map<String, Object> result = Maps.newHashMap();
      result.put("count", stats.count);
      result.put("sum", stats.sum);
      result.put("mean", stats.mean);
      result.put("min", stats.min);
      result.put("max", stats.max);
      result.put("variance", stats.variance);
      result.put("sum_of_squares", stats.sumOfSquares);
      result.put("std_deviation", stats.stdDeviation);
      result.put("cardinality", stats.cardinality);

      return ok(Json.toJson(result));
    } catch (IOException e) {
      return internalServerError("io exception");
    } catch (APIException e) {
      if (e.getHttpCode() == 400) {
        // This usually means the field does not have a numeric type. Pass through!
        return badRequest();
      }

      return internalServerError("api exception " + e);
    }
  }
  public Result index(Integer page) {
    try {
      List<NotificationType> notifications = Lists.newArrayList();
      if (isPermitted(NOTIFICATIONS_READ)) {
        for (Notification notification : clusterService.allNotifications())
          notifications.add(notificationTypeFactory.get(notification));
      }
      List<SystemJob> systemJobs =
          isPermitted(SYSTEMJOBS_READ)
              ? clusterService.allSystemJobs()
              : Collections.<SystemJob>emptyList();
      final Boolean permittedSystemMessages = isPermitted(SYSTEMMESSAGES_READ);
      int totalSystemMessages =
          permittedSystemMessages ? clusterService.getNumberOfSystemMessages() : 0;
      List<SystemMessage> systemMessages =
          permittedSystemMessages
              ? clusterService.getSystemMessages(page - 1)
              : Collections.<SystemMessage>emptyList();
      ESClusterHealth clusterHealth =
          isPermitted(INDEXERCLUSTER_READ) ? clusterService.getESClusterHealth() : null;
      long indexFailureCount =
          isPermitted(INDICES_FAILURES) ? clusterService.getIndexerFailureCountLast24Hours() : -1;
      String masterTimezone = nodeService.loadMasterNode().getTimezone();

      return ok(
          views.html.system.index.render(
              currentUser(),
              systemJobs,
              clusterHealth,
              systemMessages,
              totalSystemMessages,
              page,
              notifications,
              indexFailureCount,
              masterTimezone));
    } catch (IOException e) {
      return status(504, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
    } catch (APIException e) {
      String message =
          "Could not fetch system information. We expected HTTP 200, but got a HTTP "
              + e.getHttpCode()
              + ".";
      return status(504, views.html.errors.error.render(message, e, request()));
    }
  }
  public Result delete(String nodeId, String inputId, String extractorId) {
    if (!Permissions.isPermitted(RestPermissions.INPUTS_EDIT, inputId)) {
      return redirect(routes.StartpageController.redirect());
    }
    try {
      Node node = nodeService.loadNode(nodeId);
      extractorService.delete(node, node.getInput(inputId), extractorId);

      return redirect(controllers.routes.ExtractorsController.manage(nodeId, inputId));
    } catch (IOException e) {
      return status(500, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
    } catch (APIException e) {
      String message =
          "Could not delete extractor! We expected HTTP 204, but got a HTTP "
              + e.getHttpCode()
              + ".";
      return status(500, views.html.errors.error.render(message, e, request()));
    } catch (NodeService.NodeNotFoundException e) {
      return status(
          404, views.html.errors.error.render(ApiClient.ERROR_MSG_NODE_NOT_FOUND, e, request()));
    }
  }
  public Result exportExtractors(String nodeId, String inputId) {
    if (!Permissions.isPermitted(RestPermissions.INPUTS_READ, inputId)) {
      return redirect(routes.StartpageController.redirect());
    }
    try {
      Node node = nodeService.loadNode(nodeId);
      Input input = node.getInput(inputId);

      BreadcrumbList bc = standardBreadcrumbs(node, input);
      bc.addCrumb(
          "Export", controllers.routes.ExtractorsController.exportExtractors(nodeId, inputId));

      Map<String, Object> result = Maps.newHashMap();
      List<Map<String, Object>> extractors = Lists.newArrayList();
      for (Extractor extractor : extractorService.all(node, input)) {
        extractors.add(extractor.export());
      }
      result.put("extractors", extractors);
      result.put("version", Version.VERSION.toString());

      String extractorExport = Json.toJsonString(result);

      return ok(
          views.html.system.inputs.extractors.export.render(
              currentUser(), bc, node, input, extractorExport));
    } catch (IOException e) {
      return status(500, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
    } catch (APIException e) {
      String message =
          "Could not fetch system information. We expected HTTP 200, but got a HTTP "
              + e.getHttpCode()
              + ".";
      return status(500, views.html.errors.error.render(message, e, request()));
    } catch (NodeService.NodeNotFoundException e) {
      return status(
          404, views.html.errors.error.render(ApiClient.ERROR_MSG_NODE_NOT_FOUND, e, request()));
    }
  }
  public Result editExtractor(String nodeId, String inputId, String extractorId) {
    if (!Permissions.isPermitted(RestPermissions.INPUTS_EDIT, inputId)) {
      return redirect(routes.StartpageController.redirect());
    }
    try {
      final Node node = nodeService.loadNode(nodeId);
      final Input input = node.getInput(inputId);
      final Extractor extractor = extractorService.load(node, input, extractorId);
      final String sourceField = extractor.getSourceField();
      String example;
      try {
        final MessageResult exampleMessage = input.getRecentlyReceivedMessage(nodeId);
        example = exampleMessage.getFields().get(sourceField).toString();
      } catch (Exception e) {
        example = null;
      }

      return ok(
          views.html.system.inputs.extractors.edit_extractor.render(
              currentUser(),
              standardBreadcrumbs(node, input, extractor),
              node,
              input,
              extractor,
              example));
    } catch (IOException e) {
      return status(500, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
    } catch (APIException e) {
      String message =
          "Could not fetch system information. We expected HTTP 200, but got a HTTP "
              + e.getHttpCode()
              + ".";
      return status(500, views.html.errors.error.render(message, e, request()));
    } catch (NodeService.NodeNotFoundException e) {
      return status(
          404, views.html.errors.error.render(ApiClient.ERROR_MSG_NODE_NOT_FOUND, e, request()));
    }
  }
  public Result newExtractor(
      String nodeId,
      String inputId,
      String extractorType,
      String field,
      String exampleIndex,
      String exampleId) {
    if (!Permissions.isPermitted(RestPermissions.INPUTS_EDIT, inputId)) {
      return redirect(routes.StartpageController.redirect());
    }
    try {
      Node node = nodeService.loadNode(nodeId);
      Input input = node.getInput(inputId);
      MessageResult exampleMessage = messagesService.getMessage(exampleIndex, exampleId);
      String example = exampleMessage.getFields().get(field).toString();

      return ok(
          views.html.system.inputs.extractors.new_extractor.render(
              currentUser(),
              standardBreadcrumbs(node, input),
              node,
              input,
              Extractor.Type.valueOf(extractorType.toUpperCase()),
              field,
              example));
    } catch (IOException e) {
      return status(500, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
    } catch (APIException e) {
      String message =
          "Could not fetch system information. We expected HTTP 200, but got a HTTP "
              + e.getHttpCode()
              + ".";
      return status(500, views.html.errors.error.render(message, e, request()));
    } catch (NodeService.NodeNotFoundException e) {
      return status(
          404, views.html.errors.error.render(ApiClient.ERROR_MSG_NODE_NOT_FOUND, e, request()));
    }
  }
  public Result nodes() {
    final List<NodeDescription> nodes = Lists.newArrayList();

    for (final Node node : serverNodes.all()) {
      nodes.add(new NodeDescription(node));
    }

    try {
      for (final Radio radio : nodeService.radios().values()) {
        nodes.add(new NodeDescription(radio));
      }
    } catch (IOException e) {
      return status(504, e.getMessage());
    } catch (APIException e) {
      String message =
          "Could not fetch radio information. We expected HTTP 200, but got a HTTP "
              + e.getHttpCode()
              + ".";
      return status(504, message);
    }

    return ok(Json.toJson(nodes));
  }
  public Result histogram(
      String q,
      String rangeType,
      int relative,
      String from,
      String to,
      String keyword,
      String interval,
      String streamId,
      int maxDataPoints) {
    if (q == null || q.isEmpty()) {
      q = "*";
    }

    // Interval.
    if (interval == null
        || interval.isEmpty()
        || !SearchTools.isAllowedDateHistogramInterval(interval)) {
      interval = "minute";
    }

    // Determine timerange type.
    TimeRange timerange;
    try {
      timerange = TimeRange.factory(rangeType, relative, from, to, keyword);
    } catch (InvalidRangeParametersException e2) {
      return status(
          400, views.html.errors.error.render("Invalid range parameters provided.", e2, request()));
    } catch (IllegalArgumentException e1) {
      return status(
          400, views.html.errors.error.render("Invalid range type provided.", e1, request()));
    }

    String filter = null;
    if (streamId != null && !streamId.isEmpty()) {
      filter = "streams:" + streamId;
    }

    try {
      UniversalSearch search = searchFactory.queryWithRangeAndFilter(q, timerange, filter);
      DateHistogramResult histogram = search.dateHistogram(interval);
      List<Map<String, Long>> results =
          formatHistogramResults(histogram, maxDataPoints, relative == 0);

      Map<String, Object> result = Maps.newHashMap();
      AbsoluteRange boundaries = histogram.getHistogramBoundaries();
      result.put("time", histogram.getTookMs());
      result.put("interval", histogram.getInterval());
      result.put("values", results);
      result.put("from", boundaries.getFrom());
      result.put("to", boundaries.getTo());

      return ok(Json.toJson(result));
    } catch (IOException e) {
      return internalServerError("io exception");
    } catch (APIException e) {
      if (e.getHttpCode() == 400) {
        // This usually means the field does not have a numeric type. Pass through!
        return badRequest();
      }

      return internalServerError("api exception " + e);
    }
  }