public BodymediaUpdater() {
   super();
   ObjectType burn = ObjectType.getObjectType(connector(), "burn");
   ObjectType sleep = ObjectType.getObjectType(connector(), "sleep");
   ObjectType steps = ObjectType.getObjectType(connector(), "steps");
   url.put(burn, "burn/day/minute/intensity/");
   url.put(sleep, "sleep/day/period/");
   url.put(steps, "step/day/hour/");
   maxIncrement.put(burn, 1);
   maxIncrement.put(sleep, 1);
   maxIncrement.put(steps, 31);
 }
  /**
   * Retrieves that history for the given facet from the start date to the end date. It peforms the
   * api calls in reverse order starting from the end date. This is so that the most recent
   * information is retrieved first.
   *
   * @param updateInfo The api's info
   * @param ot The ObjectType that represents the facet to be updated
   * @param start The earliest date for which the burn history is retrieved. This date is included
   *     in the update.
   * @param end The latest date for which the burn history is retrieved. This date is also included
   *     in the update.
   * @throws Exception If either storing the data fails or if the rate limit is reached on
   *     Bodymedia's api
   */
  private void retrieveHistory(UpdateInfo updateInfo, ObjectType ot, DateTime start, DateTime end)
      throws Exception {
    final String urlExtension = url.get(ot);
    final int increment = maxIncrement.get(ot);
    DateTimeComparator comparator = DateTimeComparator.getDateOnlyInstance();
    DateTime current = start;

    // Setup the rate delay if we haven't already
    Long rateDelay = getRateDelay(updateInfo);

    try {
      //  Loop from start to end, incrementing by the max number of days you can
      //  specify for a given type of query.  This is 1 for burn and sleep, and 31 for steps.
      // @ loop_invariant date.compareTo(userRegistrationDate) >= 0;
      while (comparator.compare(current, end) < 0) {
        if (guestService.getApiKey(updateInfo.apiKey.getId()) == null) {
          logger.info("Not updating BodyMedia connector instance with a deleted apiKeyId");
          return;
        }
        String startPeriod = current.toString(formatter);
        String endPeriod = current.plusDays(increment - 1).toString(formatter);
        String minutesUrl =
            "http://api.bodymedia.com/v2/json/"
                + urlExtension
                + startPeriod
                + "/"
                + endPeriod
                + "?api_key="
                + guestService.getApiKeyAttribute(updateInfo.apiKey, "bodymediaConsumerKey");
        // The following call may fail due to bodymedia's api. That is expected behavior
        enforceRateLimits(rateDelay);
        String json = signpostHelper.makeRestCall(updateInfo.apiKey, ot.value(), minutesUrl);
        guestService.setApiKeyAttribute(
            updateInfo.apiKey, "timeOfLastCall", String.valueOf(System.currentTimeMillis()));
        JSONObject bodymediaResponse = JSONObject.fromObject(json);
        JSONArray daysArray = bodymediaResponse.getJSONArray("days");
        if (bodymediaResponse.has("lastSync")) {
          DateTime d =
              form.parseDateTime(bodymediaResponse.getJSONObject("lastSync").getString("dateTime"));

          // Get timezone map from UpdateInfo context
          TimezoneMap tzMap = (TimezoneMap) updateInfo.getContext("tzMap");

          // Insert lastSync into the updateInfo context so it's accessible to the updater
          updateInfo.setContext("lastSync", d);
          List<AbstractFacet> newFacets = new ArrayList<AbstractFacet>();
          for (Object o : daysArray) {
            if (o instanceof JSONObject) {
              if (ot == ObjectType.getObjectType(connector(), "steps"))
                newFacets.add(createOrUpdateStepsFacet((JSONObject) o, updateInfo, d, tzMap));
              else if (ot == ObjectType.getObjectType(connector(), "burn"))
                newFacets.add(createOrUpdateBurnFacet((JSONObject) o, updateInfo, d, tzMap));
              else newFacets.add(createOrUpdateSleepFacet((JSONObject) o, updateInfo, d, tzMap));
            }
          }
          bodyTrackStorageService.storeApiData(updateInfo.getGuestId(), newFacets);
        }

        current = current.plusDays(increment);

        // Update the stored value that controls when we will start updating next time
        updateStartDate(updateInfo, ot, current);
      }

    } catch (Exception e) {
      StringBuilder sb =
          new StringBuilder(
                  "module=updateQueue component=updater action=BodymediaUpdater.retrieveHistory")
              .append(" message=\"exception while retrieving history\" connector=")
              .append(updateInfo.apiKey.getConnector().toString())
              .append(" guestId=")
              .append(updateInfo.apiKey.getGuestId())
              .append(" updatingDate=")
              .append(current);
      logger.info(sb.toString());

      // Update the stored value that controls when we will start updating next time
      updateStartDate(updateInfo, ot, current);

      // Rethrow the error so that this task gets rescheduled
      throw e;
    }
  }