/**
   * @param controllerId The controller acquiring the lock
   * @return true if the worker was successfully locked, false otherwise
   */
  public boolean acquireLock(UUID controllerId) {
    logger.info("Acquiring lock of worker <" + metadata.getWorkerId() + ">");
    String lockUri = "http://" + metadata.getHostAndPort() + "/control/acquireLock/" + controllerId;
    HttpPost httpPost = new HttpPost(lockUri);

    boolean locked = tellWorker(httpPost, Response.Status.NO_CONTENT);
    if (locked) {
      logger.info("Successfully acquired lock of worker <" + metadata.getWorkerId() + ">");
    } else {
      logger.warn("Acquiring lock of worker <" + metadata.getWorkerId() + "> failed");
    }

    return locked;
  }
  /**
   * Send an HTTP message to a worker, producing helpful logging if there was a problem
   *
   * @param uriRequest The request to make
   * @param expectedStatus The expected return status
   * @return true if the method was successfully delivered & the worker gave the expected response
   */
  private boolean tellWorker(HttpUriRequest uriRequest, Response.Status expectedStatus) {
    try {
      HttpResponse response = httpClient.execute(uriRequest);

      if (response.getStatusLine().getStatusCode() != expectedStatus.getStatusCode()) {
        StatusLine statusLine = response.getStatusLine();
        EntityUtils.consume(response.getEntity());
        logger.warn(
            "Problem telling worker <"
                + metadata.getWorkerId()
                + "> "
                + "("
                + uriRequest.getURI()
                + "), "
                + "reason ["
                + statusLine.getStatusCode()
                + ": "
                + statusLine.getReasonPhrase()
                + "]");
        return false;
      }

      return true;
    } catch (IOException e) {
      logger.warn("Unable to communicated with worker " + metadata.toString());
      return false;
    }
  }
  /**
   * Send an HTTP message to a worker and get the result
   *
   * <p>Note: expects the worker to respond with OK (200) status code.
   *
   * @param uriRequest The request to make
   * @return An InputStream of the response content
   */
  private InputStream askWorker(HttpUriRequest uriRequest) {
    try {
      HttpResponse response = httpClient.execute(uriRequest);

      if (response.getStatusLine().getStatusCode() != Response.Status.OK.getStatusCode()) {
        StatusLine statusLine = response.getStatusLine();
        EntityUtils.consume(response.getEntity());
        logger.warn(
            "Problem asking worker <"
                + metadata.getWorkerId()
                + "> "
                + "("
                + uriRequest.getURI()
                + "), "
                + "reason ["
                + statusLine.getStatusCode()
                + ": "
                + statusLine.getReasonPhrase()
                + "]");
      }

      return response.getEntity().getContent();
    } catch (IOException e) {
      logger.warn("Unable to communicated with worker " + metadata.toString());
      throw Throwables.propagate(e);
    }
  }
  /**
   * Submit a job to this worker.
   *
   * @param jobId The job that this partition is part of
   * @param partition The partition fot the worker to do
   * @return true if the partition was successfully submitted
   */
  public boolean submitPartition(UUID jobId, Partition partition) {
    String submitUri = "http://" + metadata.getHostAndPort() + "/job/" + jobId + "/partition";
    HttpPut httpPut = new HttpPut(submitUri);

    StringEntity stringEntity = null;
    try {
      stringEntity = new StringEntity(objectWriter.writeValueAsString(partition));
      stringEntity.setContentType(MediaType.APPLICATION_JSON);
    } catch (IOException e) {
      logger.warn(
          "Unable to JSONify partition <"
              + partition.getPartitionId()
              + "> for jobId <"
              + jobId
              + ">");
    }
    httpPut.setEntity(stringEntity);

    logger.info(
        "Sending partition <"
            + partition.getPartitionId()
            + "> of jobId <"
            + jobId
            + "> to <"
            + metadata.getWorkerId()
            + ">");
    return tellWorker(httpPut, Response.Status.ACCEPTED);
  }