/**
   * Updates an access policy.
   *
   * @param httpServletRequest request
   * @param id The id of the access policy to update.
   * @param accessPolicyEntity An accessPolicyEntity.
   * @return An accessPolicyEntity.
   */
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("{id}")
  // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
  @ApiOperation(
      value = "Updates a access policy",
      response = AccessPolicyEntity.class,
      authorizations = {@Authorization(value = "Data Flow Manager", type = "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 updateAccessPolicy(
      @Context final HttpServletRequest httpServletRequest,
      @ApiParam(value = "The access policy id.", required = true) @PathParam("id") final String id,
      @ApiParam(value = "The access policy configuration details.", required = true)
          final AccessPolicyEntity accessPolicyEntity) {

    if (accessPolicyEntity == null || accessPolicyEntity.getComponent() == null) {
      throw new IllegalArgumentException("Access policy details must be specified.");
    }

    if (accessPolicyEntity.getRevision() == null) {
      throw new IllegalArgumentException("Revision must be specified.");
    }

    // ensure the ids are the same
    final AccessPolicyDTO accessPolicyDTO = accessPolicyEntity.getComponent();
    if (!id.equals(accessPolicyDTO.getId())) {
      throw new IllegalArgumentException(
          String.format(
              "The access policy id (%s) in the request body does not equal the "
                  + "access policy id of the requested resource (%s).",
              accessPolicyDTO.getId(), id));
    }

    if (isReplicateRequest()) {
      return replicate(HttpMethod.PUT, accessPolicyEntity);
    }

    // Extract the revision
    final Revision revision = getRevision(accessPolicyEntity, id);
    return withWriteLock(
        serviceFacade,
        revision,
        lookup -> {
          Authorizable authorizable = lookup.getAccessPolicyById(id);
          authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
        },
        null,
        () -> {
          // update the access policy
          final AccessPolicyEntity entity =
              serviceFacade.updateAccessPolicy(revision, accessPolicyDTO);
          populateRemainingAccessPolicyEntityContent(entity);

          return clusterContext(generateOkResponse(entity)).build();
        });
  }
  /**
   * Creates a new access policy.
   *
   * @param httpServletRequest request
   * @param accessPolicyEntity An accessPolicyEntity.
   * @return An accessPolicyEntity.
   */
  @POST
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
  @ApiOperation(
      value = "Creates an access policy",
      response = AccessPolicyEntity.class,
      authorizations = {@Authorization(value = "Data Flow Manager", type = "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 createAccessPolicy(
      @Context final HttpServletRequest httpServletRequest,
      @ApiParam(value = "The access policy configuration details.", required = true)
          final AccessPolicyEntity accessPolicyEntity) {

    if (accessPolicyEntity == null || accessPolicyEntity.getComponent() == null) {
      throw new IllegalArgumentException("Access policy details must be specified.");
    }

    if (accessPolicyEntity.getRevision() == null
        || (accessPolicyEntity.getRevision().getVersion() == null
            || accessPolicyEntity.getRevision().getVersion() != 0)) {
      throw new IllegalArgumentException(
          "A revision of 0 must be specified when creating a new Policy.");
    }

    final AccessPolicyDTO requestAccessPolicy = accessPolicyEntity.getComponent();
    if (requestAccessPolicy.getId() != null) {
      throw new IllegalArgumentException("Access policy ID cannot be specified.");
    }

    if (requestAccessPolicy.getResource() == null) {
      throw new IllegalArgumentException("Access policy resource must be specified.");
    }

    // ensure this is a valid action
    RequestAction.valueOfValue(requestAccessPolicy.getAction());

    if (isReplicateRequest()) {
      return replicate(HttpMethod.POST, accessPolicyEntity);
    }

    // handle expects request (usually from the cluster manager)
    final boolean validationPhase = isValidationPhase(httpServletRequest);
    if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
      // authorize access
      serviceFacade.authorizeAccess(
          lookup -> {
            final Authorizable accessPolicies =
                lookup.getAccessPolicyByResource(requestAccessPolicy.getResource());
            accessPolicies.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
          });
    }
    if (validationPhase) {
      return generateContinueResponse().build();
    }

    // set the access policy id as appropriate
    requestAccessPolicy.setId(generateUuid());

    // get revision from the config
    final RevisionDTO revisionDTO = accessPolicyEntity.getRevision();
    Revision revision =
        new Revision(
            revisionDTO.getVersion(),
            revisionDTO.getClientId(),
            accessPolicyEntity.getComponent().getId());

    // create the access policy and generate the json
    final AccessPolicyEntity entity =
        serviceFacade.createAccessPolicy(revision, accessPolicyEntity.getComponent());
    populateRemainingAccessPolicyEntityContent(entity);

    // build the response
    return clusterContext(generateCreatedResponse(URI.create(entity.getUri()), entity)).build();
  }