/**
   * Gets the details for a provenance event.
   *
   * @param id The id of the event
   * @param clusterNodeId The id of node in the cluster that the event/flowfile originated from.
   *     This is only required when clustered.
   * @return A provenanceEventEntity
   */
  @GET
  @Consumes(MediaType.WILDCARD)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("{id}")
  // TODO - @PreAuthorize("hasRole('ROLE_PROVENANCE')")
  @ApiOperation(
      value = "Gets a provenance event",
      response = ProvenanceEventEntity.class,
      authorizations = {@Authorization(value = "Provenance", type = "ROLE_PROVENANCE")})
  @ApiResponses(
      value = {
        @ApiResponse(
            code = 400,
            message =
                "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
        @ApiResponse(code = 401, message = "Client could not be authenticated."),
        @ApiResponse(code = 403, message = "Client is not authorized to make this request."),
        @ApiResponse(code = 404, message = "The specified resource could not be found."),
        @ApiResponse(
            code = 409,
            message =
                "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
      })
  public Response getProvenanceEvent(
      @ApiParam(
              value = "The id of the node where this event exists if clustered.",
              required = false)
          @QueryParam("clusterNodeId")
          final String clusterNodeId,
      @ApiParam(value = "The provenence event id.", required = true) @PathParam("id")
          final LongParameter id) {

    // ensure the id is specified
    if (id == null) {
      throw new IllegalArgumentException("Provenance event id must be specified.");
    }

    // replicate if cluster manager
    if (isReplicateRequest()) {
      // since we're cluster we must specify the cluster node identifier
      if (clusterNodeId == null) {
        throw new IllegalArgumentException("The cluster node identifier must be specified.");
      }

      return replicate(HttpMethod.GET, clusterNodeId);
    }

    // get the provenance event
    final ProvenanceEventDTO event = serviceFacade.getProvenanceEvent(id.getLong());
    event.setClusterNodeId(clusterNodeId);

    // create a response entity
    final ProvenanceEventEntity entity = new ProvenanceEventEntity();
    entity.setProvenanceEvent(event);

    // generate the response
    return clusterContext(generateOkResponse(entity)).build();
  }
  /**
   * Creates a new replay request for the content associated with the specified provenance event id.
   *
   * @param httpServletRequest request
   * @param replayRequestEntity The replay request
   * @return A provenanceEventEntity
   */
  @POST
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("replays")
  // TODO - @PreAuthorize("hasRole('ROLE_PROVENANCE') and hasRole('ROLE_DFM')")
  @ApiOperation(
      value = "Replays content from a provenance event",
      response = ProvenanceEventEntity.class,
      authorizations = {
        @Authorization(
            value = "Provenance and Data Flow Manager",
            type = "ROLE_PROVENANCE and ROLE_DFM")
      })
  @ApiResponses(
      value = {
        @ApiResponse(
            code = 400,
            message =
                "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
        @ApiResponse(code = 401, message = "Client could not be authenticated."),
        @ApiResponse(code = 403, message = "Client is not authorized to make this request."),
        @ApiResponse(code = 404, message = "The specified resource could not be found."),
        @ApiResponse(
            code = 409,
            message =
                "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
      })
  public Response submitReplay(
      @Context final HttpServletRequest httpServletRequest,
      @ApiParam(value = "The replay request.", required = true)
          final SubmitReplayRequestEntity replayRequestEntity) {

    // ensure the event id is specified
    if (replayRequestEntity == null || replayRequestEntity.getEventId() == null) {
      throw new IllegalArgumentException("The id of the event must be specified.");
    }

    // replicate if cluster manager
    if (isReplicateRequest()) {
      // determine where this request should be sent
      if (replayRequestEntity.getClusterNodeId() == null) {
        throw new IllegalArgumentException("The id of the node in the cluster is required.");
      } else {
        return replicate(
            HttpMethod.POST, replayRequestEntity, replayRequestEntity.getClusterNodeId());
      }
    }

    // handle expects request (usually from the cluster manager)
    final String expects =
        httpServletRequest.getHeader(RequestReplicator.REQUEST_VALIDATION_HTTP_HEADER);
    if (expects != null) {
      return generateContinueResponse().build();
    }

    // submit the provenance replay request
    final ProvenanceEventDTO event = serviceFacade.submitReplay(replayRequestEntity.getEventId());

    // create a response entity
    final ProvenanceEventEntity entity = new ProvenanceEventEntity();
    entity.setProvenanceEvent(event);

    // generate the response
    URI uri = URI.create(generateResourceUri("provenance-events", event.getId()));
    return clusterContext(generateCreatedResponse(uri, entity)).build();
  }