public List<ICTomorrowItemMetadata> getMetadataFile(int jobId) throws ICTomorrowApiException {
    try {
      Element resultElement = getResultElement(client.get(getMetadataFileUrl(jobId)));

      String jobStatus = resultElement.getFirstChildElement("job_status").getValue().trim();

      if ("COMPLETE".equals(jobStatus)) {
        Element downloadElement = resultElement.getFirstChildElement("Download");

        List<ICTomorrowItemMetadata> items = Lists.newArrayList();
        Elements itemElements =
            downloadElement.getFirstChildElement("Items").getChildElements("Item");
        for (int i = 0; i < itemElements.size(); i++) {
          items.add(getItem(itemElements.get(i)));
        }

        return items;
      } else if ("FAILED".equals(jobStatus)) {
        throw new ICTomorrowApiException("Metadata file creation failed");
      }

      return null;
    } catch (HttpException e) {
      throw new ICTomorrowApiException("Exception while recording consumer activity", e);
    }
  }
  public ICTomorrowIncrementMeterResponse incrementMeter(
      int consumerId, int offerId, Integer incrementValue, String freeText)
      throws ICTomorrowApiException {
    try {
      FormEncodedPayload data =
          new FormEncodedPayload()
              .withField("update_type", Integer.toString(METER_OPERATION_INCREMENT));
      addOptionalParameter(data, "increment_value", incrementValue);
      addOptionalParameter(data, "Free_text", freeText);
      HttpResponse res = client.put(meterUrl(consumerId, offerId), data);

      Element resultElement = getResultElement(res);

      Element meterElement = resultElement.getFirstChildElement("meter");

      Boolean incrementGranted =
          Boolean.valueOf(meterElement.getFirstChildElement("granted").getValue().trim());
      Boolean notificationLimitReached =
          Boolean.valueOf(
              meterElement.getFirstChildElement("notificationLimitReached").getValue().trim());
      Boolean maximumLimitReached =
          Boolean.valueOf(
              meterElement.getFirstChildElement("maximumLimitReached").getValue().trim());
      // ICTomorrowMeter meter = parseMeter(resultElement);

      return new ICTomorrowIncrementMeterResponse(
          incrementGranted, notificationLimitReached, maximumLimitReached);
    } catch (HttpException e) {
      throw new ICTomorrowApiException("Exception while incrementing meter", e);
    }
  }
  public ICTomorrowMeter getMeter(int consumerId, int offerId) throws ICTomorrowApiException {
    try {
      HttpResponse res = client.get(meterUrl(consumerId, offerId));

      Element resultElement = getResultElement(res);

      return parseMeter(resultElement.getFirstChildElement("meter"));
    } catch (HttpException e) {
      throw new ICTomorrowApiException("Exception while getting meter", e);
    }
  }
  public int getContentMetadata(Integer csaId, Integer wholesaleOfferId, Integer consumerOfferID)
      throws ICTomorrowApiException {
    try {
      FormEncodedPayload data = new FormEncodedPayload();

      addOptionalParameter(data, "csa_id", csaId);
      addOptionalParameter(data, "wholesale_offer_id", wholesaleOfferId);
      addOptionalParameter(data, "consumer_offer_id", consumerOfferID);
      Element resultElem = getResultElement(client.post(GET_CONTENT_METADATA_URL, data));
      return Integer.valueOf(resultElem.getValue().trim());
    } catch (HttpException e) {
      throw new ICTomorrowApiException("Exception while recording consumer activity", e);
    }
  }
 public boolean registerUserForOffer(int consumerId, int offerId) throws ICTomorrowApiException {
   try {
     HttpResponse res =
         client.post(registerUserForOfferUrl(consumerId, offerId), new FormEncodedPayload());
     return Boolean.valueOf(
         getResultElement(res).getFirstChildElement("result").getValue().trim());
   } catch (HttpException e) {
     // Probably already subscribed, check error code when they are more sensible (currently 55
     // with:
     // Activity [GENERATE-ERROR-2] failed due to [CONTRACT_ALREADY_EXISTS_AN UNIDENTIFIED
     // EXCEPTION HAS OCCURED. PLEASE REPORT FAULT TO ESB DEVELOPMENT TEAM.].
     throw new ICTomorrowApiException("Exception while registering user for offer", e);
   }
 }
  public ICTomorrowMeter updateMeterLimits(
      int consumerId, int offerId, Integer notificationUpdateAmount, Integer maximumUpdateAmount)
      throws ICTomorrowApiException {
    try {
      FormEncodedPayload data =
          new FormEncodedPayload()
              .withField("update_type", Integer.toString(METER_OPERATION_UPDATE_LIMITS));
      addOptionalParameter(data, "notification_update_amount", notificationUpdateAmount);
      addOptionalParameter(data, "maximum_update_amount", maximumUpdateAmount);
      HttpResponse res = client.put(meterUrl(consumerId, offerId), data);

      return parseMeter(getResultElement(res).getFirstChildElement("meter"));
    } catch (HttpException e) {
      throw new ICTomorrowApiException("Exception while updating meter limits", e);
    }
  }
  public int checkAccessToken(String code, String callbackUrl) throws ICTomorrowApiException {
    HttpResponse res;
    try {
      FormEncodedPayload data =
          new FormEncodedPayload()
              .withField("client_id", applicationKey)
              .withField("redirect_uri", callbackUrl)
              .withField("client_secret", clientSecret)
              .withField("code", code);
      res = client.post(TOKEN_URL, data);

      Element resultElement = getResultElement(res);
      return Integer.valueOf(resultElement.getFirstChildElement("access_token").getValue().trim());
    } catch (HttpException e) {
      throw new ICTomorrowAuthException("Exception while fetching consumerId", e);
    }
  }
  public int recordConsumerActivity(
      int consumerId,
      int offerId,
      int trialId,
      String activityType,
      DateTime transactionDate,
      String contentKey,
      String contentHandle,
      Integer incrementValue,
      Integer integerValue,
      String freeText)
      throws ICTomorrowApiException {
    try {
      String transactionDateString = transactionDate.toString("yyyy-MM-dd'T'HH:mm:ssZZ");

      FormEncodedPayload data =
          new FormEncodedPayload()
              .withField("consumer_id", Integer.toString(consumerId))
              .withField("offer_id", Integer.toString(offerId))
              .withField("application_key", applicationKey)
              .withField("trial_id", Integer.toString(trialId))
              .withField("activity_type", activityType)
              .withField("transaction_date", transactionDateString);

      addOptionalParameter(data, "content_handle", contentHandle);
      addOptionalParameter(data, "content_key", contentKey);
      addOptionalParameter(data, "increment_value", incrementValue);
      addOptionalParameter(data, "integer_value", integerValue);
      addOptionalParameter(data, "free_text", freeText);
      HttpResponse res = client.post(RECORD_CONSUMER_ACTIVITY_URL, data);
      Element resultElement = getResultElement(res);
      return Integer.valueOf(
          resultElement
              .getFirstChildElement("transaction")
              .getFirstChildElement("TransactionID")
              .getValue()
              .trim());
    } catch (HttpException e) {
      throw new ICTomorrowApiException("Exception while recording consumer activity", e);
    }
  }