@POST
  @Path("/request/{requestId}/run")
  @Consumes({MediaType.APPLICATION_JSON})
  @ApiOperation(
      value = "Schedule a one-off or scheduled Singularity request for immediate execution.",
      response = SingularityRequestParent.class)
  @ApiResponses({
    @ApiResponse(code = 400, message = "Singularity Request is not scheduled or one-off"),
  })
  public SingularityPendingRequestParent scheduleImmediately(
      @ApiParam("The request ID to run") @PathParam("requestId") String requestId,
      @ApiParam("Username of the person requesting the execution") @QueryParam("user")
          Optional<String> user,
      @ApiParam("Additional command line arguments to append to the task")
          List<String> commandLineArgs) {
    SingularityRequestWithState requestWithState = fetchRequestWithState(requestId);

    checkConflict(
        requestWithState.getState() != RequestState.PAUSED,
        "Request %s is paused. Unable to run now (it must be manually unpaused first)",
        requestWithState.getRequest().getId());

    PendingType pendingType = null;

    if (requestWithState.getRequest().isScheduled()) {
      pendingType = PendingType.IMMEDIATE;
      checkConflict(
          taskManager.getActiveTaskIdsForRequest(requestId).isEmpty(),
          "Can not request an immediate run of a scheduled job which is currently running (%s)",
          taskManager.getActiveTaskIdsForRequest(requestId));
    } else if (requestWithState.getRequest().isOneOff()) {
      pendingType = PendingType.ONEOFF;
    } else {
      throw badRequest(
          "Can not request an immediate run of a non-scheduled / always running request (%s)",
          requestWithState.getRequest());
    }

    final SingularityPendingRequest pendingRequest =
        new SingularityPendingRequest(
            requestId,
            getAndCheckDeployId(requestId),
            System.currentTimeMillis(),
            user,
            pendingType,
            commandLineArgs);

    SingularityCreateResult result = requestManager.addToPendingQueue(pendingRequest);

    checkConflict(
        result != SingularityCreateResult.EXISTED,
        "%s is already pending, please try again soon",
        requestId);

    return SingularityPendingRequestParent.fromSingularityRequestParent(
        fillEntireRequest(requestWithState), pendingRequest);
  }
  @POST
  @Path("/request/{requestId}/pause")
  @ApiOperation(
      value =
          "Pause a Singularity request, future tasks will not run until it is manually unpaused. API can optionally choose to kill existing tasks",
      response = SingularityRequestParent.class)
  @ApiResponses({
    @ApiResponse(code = 409, message = "Request is already paused or being cleaned"),
  })
  public SingularityRequestParent pause(
      @ApiParam("The request ID to pause") @PathParam("requestId") String requestId,
      @ApiParam("Username of the person requesting the pause") @QueryParam("user")
          Optional<String> user,
      @ApiParam("Pause Request Options") Optional<SingularityPauseRequest> pauseRequest) {
    SingularityRequestWithState requestWithState = fetchRequestWithState(requestId);

    checkConflict(
        requestWithState.getState() != RequestState.PAUSED,
        "Request %s is paused. Unable to pause (it must be manually unpaused first)",
        requestWithState.getRequest().getId());

    Optional<Boolean> killTasks = Optional.absent();
    if (pauseRequest.isPresent()) {
      user = pauseRequest.get().getUser();
      killTasks = pauseRequest.get().getKillTasks();
    }

    final long now = System.currentTimeMillis();

    SingularityCreateResult result =
        requestManager.createCleanupRequest(
            new SingularityRequestCleanup(
                user,
                RequestCleanupType.PAUSING,
                now,
                killTasks,
                requestId,
                Optional.<String>absent()));

    checkConflict(
        result == SingularityCreateResult.CREATED,
        "%s is already pausing - try again soon",
        requestId,
        result);

    mailer.sendRequestPausedMail(requestWithState.getRequest(), user);

    requestManager.pause(requestWithState.getRequest(), now, user);

    return fillEntireRequest(
        new SingularityRequestWithState(requestWithState.getRequest(), RequestState.PAUSED, now));
  }
  @POST
  @Consumes({MediaType.APPLICATION_JSON})
  @ApiOperation(
      value = "Create or update a Singularity Request",
      response = SingularityRequestParent.class)
  @ApiResponses({
    @ApiResponse(code = 400, message = "Request object is invalid"),
    @ApiResponse(code = 409, message = "Request object is being cleaned. Try again shortly"),
  })
  public SingularityRequestParent submit(
      @ApiParam("The Singularity request to create or update") SingularityRequest request,
      @ApiParam("Username of the person requesting to create or update") @QueryParam("user")
          Optional<String> user) {
    checkNotNullBadRequest(request.getId(), "Request must have an id");
    checkConflict(
        !requestManager.cleanupRequestExists(request.getId()),
        "Request %s is currently cleaning. Try again after a few moments",
        request.getId());

    Optional<SingularityRequestWithState> maybeOldRequestWithState =
        requestManager.getRequest(request.getId());
    Optional<SingularityRequest> maybeOldRequest =
        maybeOldRequestWithState.isPresent()
            ? Optional.of(maybeOldRequestWithState.get().getRequest())
            : Optional.<SingularityRequest>absent();

    SingularityRequestDeployHolder deployHolder = getDeployHolder(request.getId());

    SingularityRequest newRequest =
        validator.checkSingularityRequest(
            request,
            maybeOldRequest,
            deployHolder.getActiveDeploy(),
            deployHolder.getPendingDeploy());

    checkConflict(
        maybeOldRequest.isPresent() || !requestManager.cleanupRequestExists(request.getId()),
        "Request %s is currently cleaning. Try again after a few moments",
        request.getId());

    final long now = System.currentTimeMillis();

    requestManager.activate(
        newRequest,
        maybeOldRequest.isPresent() ? RequestHistoryType.UPDATED : RequestHistoryType.CREATED,
        now,
        user);

    checkReschedule(newRequest, maybeOldRequest, now);

    return fillEntireRequest(fetchRequestWithState(request.getId()));
  }
  @POST
  @Path("/request/{requestId}/exit-cooldown")
  public SingularityRequestParent exitCooldown(
      @PathParam("requestId") String requestId, @QueryParam("user") Optional<String> user) {
    final SingularityRequestWithState requestWithState = fetchRequestWithState(requestId);

    checkConflict(
        requestWithState.getState() == RequestState.SYSTEM_COOLDOWN,
        "Request %s is not in SYSTEM_COOLDOWN state, it is in %s",
        requestId,
        requestWithState.getState());

    final Optional<String> maybeDeployId = deployManager.getInUseDeployId(requestId);

    final long now = System.currentTimeMillis();

    requestManager.exitCooldown(requestWithState.getRequest(), now, user);

    if (maybeDeployId.isPresent() && !requestWithState.getRequest().isOneOff()) {
      requestManager.addToPendingQueue(
          new SingularityPendingRequest(
              requestId,
              maybeDeployId.get(),
              now,
              user,
              PendingType.IMMEDIATE,
              Collections.<String>emptyList()));
    }

    return fillEntireRequest(requestWithState);
  }
  private String getAndCheckDeployId(String requestId) {
    Optional<String> maybeDeployId = deployManager.getInUseDeployId(requestId);

    checkConflict(
        maybeDeployId.isPresent(),
        "Can not schedule/bounce a request (%s) with no deploy",
        requestId);

    return maybeDeployId.get();
  }
  @POST
  @Path("/request/{requestId}/bounce")
  @ApiOperation(
      value =
          "Bounce a specific Singularity request. A bounce launches replacement task(s), and then kills the original task(s) if the replacement(s) are healthy.",
      response = SingularityRequestParent.class)
  public SingularityRequestParent bounce(
      @ApiParam("The request ID to bounce") @PathParam("requestId") String requestId,
      @ApiParam("Username of the person requesting the bounce") @QueryParam("user")
          Optional<String> user) {
    SingularityRequestWithState requestWithState = fetchRequestWithState(requestId);

    checkBadRequest(
        requestWithState.getRequest().isLongRunning(),
        "Can not bounce a %s request (%s)",
        requestWithState.getRequest().getRequestType(),
        requestWithState);

    checkConflict(
        requestWithState.getState() != RequestState.PAUSED,
        "Request %s is paused. Unable to bounce (it must be manually unpaused first)",
        requestWithState.getRequest().getId());

    SingularityCreateResult createResult =
        requestManager.createCleanupRequest(
            new SingularityRequestCleanup(
                user,
                RequestCleanupType.BOUNCE,
                System.currentTimeMillis(),
                Optional.<Boolean>absent(),
                requestId,
                Optional.of(getAndCheckDeployId(requestId))));

    checkConflict(
        createResult != SingularityCreateResult.EXISTED, "%s is already bouncing", requestId);

    return fillEntireRequest(requestWithState);
  }
  @PUT
  @Path("/request/{requestId}/instances")
  @ApiOperation(
      value = "Scale the number of instances up or down for a specific Request",
      response = SingularityRequest.class)
  @ApiResponses({
    @ApiResponse(code = 400, message = "Posted object did not match Request ID"),
    @ApiResponse(code = 404, message = "No Request with that ID"),
  })
  public SingularityRequest updateInstances(
      @ApiParam("The Request ID to scale") @PathParam("requestId") String requestId,
      @ApiParam("Username of the person requesting the scale") @QueryParam("user")
          Optional<String> user,
      @ApiParam("Object to hold number of instances to request")
          SingularityRequestInstances newInstances) {

    checkBadRequest(
        requestId != null && newInstances.getId() != null && requestId.equals(newInstances.getId()),
        "Update for request instance must pass a matching non-null requestId in path (%s) and object (%s)",
        requestId,
        newInstances.getId());
    checkConflict(
        !requestManager.cleanupRequestExists(requestId),
        "Request %s is currently cleaning. Try again after a few moments",
        requestId);

    SingularityRequest oldRequest = fetchRequest(requestId);
    Optional<SingularityRequest> maybeOldRequest = Optional.of(oldRequest);

    SingularityRequestDeployHolder deployHolder = getDeployHolder(newInstances.getId());
    SingularityRequest newRequest =
        oldRequest.toBuilder().setInstances(newInstances.getInstances()).build();

    validator.checkSingularityRequest(
        newRequest,
        maybeOldRequest,
        deployHolder.getActiveDeploy(),
        deployHolder.getPendingDeploy());

    final long now = System.currentTimeMillis();

    requestManager.update(newRequest, now, user);

    checkReschedule(newRequest, maybeOldRequest, now);

    return newRequest;
  }
  @POST
  @Path("/request/{requestId}/unpause")
  @ApiOperation(
      value = "Unpause a Singularity Request, scheduling new tasks immediately",
      response = SingularityRequestParent.class)
  @ApiResponses({
    @ApiResponse(code = 409, message = "Request is not paused"),
  })
  public SingularityRequestParent unpause(
      @ApiParam("The request ID to unpause") @PathParam("requestId") String requestId,
      @ApiParam("Username of the person requesting the unpause") @QueryParam("user")
          Optional<String> user) {
    SingularityRequestWithState requestWithState = fetchRequestWithState(requestId);

    checkConflict(
        requestWithState.getState() == RequestState.PAUSED,
        "Request %s is not in PAUSED state, it is in %s",
        requestId,
        requestWithState.getState());

    mailer.sendRequestUnpausedMail(requestWithState.getRequest(), user);

    Optional<String> maybeDeployId = deployManager.getInUseDeployId(requestId);

    final long now = System.currentTimeMillis();

    requestManager.unpause(requestWithState.getRequest(), now, user);

    if (maybeDeployId.isPresent() && !requestWithState.getRequest().isOneOff()) {
      requestManager.addToPendingQueue(
          new SingularityPendingRequest(
              requestId,
              maybeDeployId.get(),
              now,
              user,
              PendingType.UNPAUSED,
              Collections.<String>emptyList()));
    }

    return fillEntireRequest(
        new SingularityRequestWithState(requestWithState.getRequest(), RequestState.ACTIVE, now));
  }