@POST
  @Timed
  @Consumes(MediaType.APPLICATION_JSON)
  @ApiOperation(value = "Update extractor order of an input")
  @ApiResponses(value = {@ApiResponse(code = 404, message = "No such input on this node.")})
  @Path("order")
  public void order(
      @ApiParam(name = "inputId", value = "Persist ID (!) of input.", required = true)
          @PathParam("inputId")
          String inputPersistId,
      @ApiParam(name = "JSON body", required = true) OrderExtractorsRequest oer)
      throws NotFoundException {
    checkPermission(RestPermissions.INPUTS_EDIT, inputPersistId);

    final Input mongoInput = inputService.find(inputPersistId);

    for (Extractor extractor : inputService.getExtractors(mongoInput)) {
      if (oer.order().containsValue(extractor.getId())) {
        extractor.setOrder(Tools.getKeyByValue(oer.order(), extractor.getId()));
      }

      // Docs embedded in MongoDB array cannot be updated atomically... :/
      inputService.removeExtractor(mongoInput, extractor.getId());
      try {
        inputService.addExtractor(mongoInput, extractor);
      } catch (ValidationException e) {
        LOG.warn("Validation error for extractor update.", e);
      }
    }

    LOG.info("Updated extractor ordering of input <persist:{}>.", inputPersistId);
  }
  @GET
  @Timed
  @ApiOperation(value = "Get information of a single extractor of an input")
  @Path("/{extractorId}")
  @ApiResponses(
      value = {
        @ApiResponse(code = 404, message = "No such input on this node."),
        @ApiResponse(code = 404, message = "No such extractor on this input.")
      })
  @Produces(MediaType.APPLICATION_JSON)
  public ExtractorSummary single(
      @ApiParam(name = "inputId", required = true) @PathParam("inputId") String inputId,
      @ApiParam(name = "extractorId", required = true) @PathParam("extractorId")
          final String extractorId)
      throws NotFoundException {
    checkPermission(RestPermissions.INPUTS_READ, inputId);

    final MessageInput input = persistedInputs.get(inputId);
    if (input == null) {
      LOG.error("Input <{}> not found.", inputId);
      throw new javax.ws.rs.NotFoundException("Couldn't find input " + inputId);
    }

    final Input mongoInput = inputService.find(input.getPersistId());
    final Extractor extractor = inputService.getExtractor(mongoInput, extractorId);

    return toSummary(extractor);
  }
  @POST
  @Timed
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  @ApiOperation(value = "Add an extractor to an input", response = ExtractorCreated.class)
  @ApiResponses(
      value = {
        @ApiResponse(code = 404, message = "No such input on this node."),
        @ApiResponse(code = 400, message = "No such extractor type."),
        @ApiResponse(code = 400, message = "Field the extractor should write on is reserved."),
        @ApiResponse(code = 400, message = "Missing or invalid configuration.")
      })
  public Response create(
      @ApiParam(name = "inputId", required = true) @PathParam("inputId") String inputId,
      @ApiParam(name = "JSON body", required = true) @Valid @NotNull CreateExtractorRequest cer)
      throws NotFoundException {
    checkPermission(RestPermissions.INPUTS_EDIT, inputId);

    final MessageInput input = inputs.getRunningInput(inputId);
    if (input == null) {
      LOG.error("Input <{}> not found.", inputId);
      throw new javax.ws.rs.NotFoundException();
    }

    final Input mongoInput = inputService.find(input.getPersistId());
    final String id = new com.eaio.uuid.UUID().toString();
    final Extractor extractor = buildExtractorFromRequest(cer, id);

    try {
      inputService.addExtractor(mongoInput, extractor);
    } catch (ValidationException e) {
      LOG.error("Extractor persist validation failed.", e);
      throw new BadRequestException(e);
    }

    final String msg =
        "Added extractor <"
            + id
            + "> of type ["
            + cer.extractorType()
            + "] to input <"
            + inputId
            + ">.";
    LOG.info(msg);
    activityWriter.write(new Activity(msg, ExtractorsResource.class));

    final ExtractorCreated result = ExtractorCreated.create(id);
    final URI extractorUri =
        getUriBuilderToSelf().path(ExtractorsResource.class).path("{inputId}").build(input.getId());

    return Response.created(extractorUri).entity(result).build();
  }
  @PUT
  @Timed
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  @ApiOperation(value = "Update an extractor")
  @Path("/{extractorId}")
  @ApiResponses(
      value = {
        @ApiResponse(code = 404, message = "No such input on this node."),
        @ApiResponse(code = 404, message = "No such extractor on this input."),
        @ApiResponse(code = 400, message = "No such extractor type."),
        @ApiResponse(code = 400, message = "Field the extractor should write on is reserved."),
        @ApiResponse(code = 400, message = "Missing or invalid configuration.")
      })
  public ExtractorSummary update(
      @ApiParam(name = "inputId", required = true) @PathParam("inputId") String inputId,
      @ApiParam(name = "extractorId", required = true) @PathParam("extractorId") String extractorId,
      @ApiParam(name = "JSON body", required = true) @Valid @NotNull CreateExtractorRequest cer)
      throws NotFoundException {
    checkPermission(RestPermissions.INPUTS_EDIT, inputId);

    final MessageInput input = persistedInputs.get(inputId);
    if (input == null) {
      LOG.error("Input <{}> not found.", inputId);
      throw new javax.ws.rs.NotFoundException("Couldn't find input " + inputId);
    }

    final Input mongoInput = inputService.find(input.getPersistId());
    final Extractor originalExtractor = inputService.getExtractor(mongoInput, extractorId);
    final Extractor extractor = buildExtractorFromRequest(cer, originalExtractor.getId());

    inputService.removeExtractor(mongoInput, originalExtractor.getId());
    try {
      inputService.addExtractor(mongoInput, extractor);
    } catch (ValidationException e) {
      LOG.error("Extractor persist validation failed.", e);
      throw new BadRequestException(e);
    }

    final String msg =
        "Updated extractor <"
            + originalExtractor.getId()
            + "> of type ["
            + cer.extractorType()
            + "] in input <"
            + inputId
            + ">.";
    LOG.info(msg);
    activityWriter.write(new Activity(msg, ExtractorsResource.class));

    return toSummary(extractor);
  }
  @DELETE
  @Timed
  @ApiOperation(value = "Delete an extractor")
  @Path("/{extractorId}")
  @ApiResponses(
      value = {
        @ApiResponse(code = 400, message = "Invalid request."),
        @ApiResponse(code = 404, message = "Input not found."),
        @ApiResponse(code = 404, message = "Extractor not found.")
      })
  @Produces(MediaType.APPLICATION_JSON)
  public void terminate(
      @ApiParam(name = "inputId", required = true) @PathParam("inputId") String inputId,
      @ApiParam(name = "extractorId", required = true) @PathParam("extractorId") String extractorId)
      throws NotFoundException {
    checkPermission(RestPermissions.INPUTS_EDIT, inputId);

    final MessageInput input = persistedInputs.get(inputId);
    if (input == null) {
      LOG.error("Input <{}> not found.", inputId);
      throw new javax.ws.rs.NotFoundException("Couldn't find input " + inputId);
    }

    // Remove from Mongo.
    final Input mongoInput = inputService.find(input.getPersistId());
    final Extractor extractor = inputService.getExtractor(mongoInput, extractorId);
    inputService.removeExtractor(mongoInput, extractor.getId());

    final String msg =
        "Deleted extractor <"
            + extractorId
            + "> of type ["
            + extractor.getType()
            + "] "
            + "from input <"
            + inputId
            + ">.";
    LOG.info(msg);
    activityWriter.write(new Activity(msg, InputsResource.class));
  }
  @GET
  @Timed
  @ApiOperation(value = "List all extractors of an input")
  @ApiResponses(value = {@ApiResponse(code = 404, message = "No such input on this node.")})
  @Produces(MediaType.APPLICATION_JSON)
  public ExtractorSummaryList list(
      @ApiParam(name = "inputId", required = true) @PathParam("inputId") String inputId)
      throws NotFoundException {
    checkPermission(RestPermissions.INPUTS_READ, inputId);

    final Input input = inputService.find(inputId);
    if (input == null) {
      LOG.error("Input <{}> not found.", inputId);
      throw new javax.ws.rs.NotFoundException();
    }

    final List<ExtractorSummary> extractors = Lists.newArrayList();
    for (Extractor extractor : inputService.getExtractors(input)) {
      extractors.add(toSummary(extractor));
    }

    return ExtractorSummaryList.create(extractors);
  }