public Object getFromCache(
     LocalUserDetail user, APIResourceCredentials credentials, String cacheKey) {
   if (null != subscriptionStore
       && null != subscriptionStore.getBySubscriptionId(user.getUserId())
       && null != entityCache) {
     return entityCache.get(credentials, cacheKey);
   } else {
     return null;
   }
 }
  /**
   * Removes subscription
   *
   * @param collectionType
   * @param subscriptionId
   */
  public void unsubscribe(
      String subscriberId,
      LocalUserDetail user,
      APICollectionType collectionType,
      final String subscriptionId)
      throws FitbitAPIException {
    if (null == subscriptionStore) {
      throw new FitbitAPIException(
          "Can not deal with subscriptions without a place to store information about them.");
    }

    // This example application only allows a single subscription per
    // (local) user. We use the user's ID as the subscription ID to avoid
    // having to maintain a mapping.
    client.unsubscribe(
        subscriberId, user, FitbitUser.CURRENT_AUTHORIZED_USER, collectionType, subscriptionId);
    LocalSubscriptionDetail subscription = subscriptionStore.getBySubscriptionId(user.getUserId());
    if (null != subscription) {
      subscriptionStore.delete(subscription);
    }
  }
  /**
   * Creates new subscription
   *
   * @param collectionType Collection to receive notifications from
   * @param subscriptionId ID associated with subscription
   * @return SubscriptionDetail
   */
  public SubscriptionDetail subscribe(
      String subscriberId,
      LocalUserDetail user,
      APICollectionType collectionType,
      final String subscriptionId)
      throws FitbitAPIException {
    if (null == subscriptionStore) {
      throw new FitbitAPIException(
          "Can not deal with subscriptions without a place to store information about them.");
    }

    // This example application only allows a single subscription per
    // (local) user. We use the user's ID as the subscription ID to avoid
    // having to maintain a mapping.
    SubscriptionDetail result =
        client.subscribe(
            subscriberId, user, FitbitUser.CURRENT_AUTHORIZED_USER, collectionType, subscriptionId);
    if (null != result) {
      LocalSubscriptionDetail detail = new LocalSubscriptionDetail(result, true);
      subscriptionStore.save(detail);
    }
    return result;
  }
  public void evictUpdatedResourcesFromCache(
      String subscriberId, InputStream updateMessageStream, String serverSignature)
      throws FitbitAPIException {
    try {
      if (null == serverSignature) {
        throw new FitbitAPISecurityException("Missing signature.");
      }

      String updateMessage = APIUtil.inputStreamToString(updateMessageStream);

      String ourSignature = APIUtil.generateSignature(updateMessage, subscriberSecret);
      if (null == ourSignature || !ourSignature.equals(serverSignature)) {
        throw new FitbitAPISecurityException("Signatures do not match, given " + serverSignature);
      }

      UpdateNotification notification = new UpdateNotification(new JSONArray(updateMessage));

      int i = 0;
      for (UpdatedResource resource : notification.getUpdatedResources()) {
        //noinspection UnnecessaryParentheses,ValueOfIncrementOrDecrementUsed
        log.info(
            "Processing update notification "
                + (++i)
                + " for subscription "
                + resource.getSubscriptionId());

        LocalSubscriptionDetail sub =
            subscriptionStore.getBySubscriptionId(resource.getSubscriptionId());
        if (null == sub) {
          log.info(
              "Nothing known about subscription "
                  + resource.getSubscriptionId()
                  + ", creating placeholder.");

          sub =
              new LocalSubscriptionDetail(
                  new SubscriptionDetail(
                      subscriberId,
                      resource.getSubscriptionId(),
                      resource.getOwner(),
                      resource.getCollectionType()),
                  false);
          subscriptionStore.save(sub);
        }

        sub.setLastUpdateNotificationDate(new Date());

        APIResourceCredentials credentials =
            credentialsCache.getResourceCredentials(
                new LocalUserDetail(resource.getSubscriptionId()));

        String cacheKeyWithUserId =
            APIUtil.constructFullUrl(
                client.getApiBaseUrl(),
                client.getApiVersion(),
                resource.getOwner(),
                resource.getCollectionType(),
                resource.getDate(),
                APIFormat.JSON);

        Activities entity = (Activities) entityCache.get(credentials, cacheKeyWithUserId);
        if (null != entity) {
          log.info("Evicting entity " + cacheKeyWithUserId);
          entityCache.remove(credentials, cacheKeyWithUserId);
        } else {
          log.info("There is no cached version of entity " + cacheKeyWithUserId);
        }

        String cacheKeyWithPlaceholder =
            APIUtil.constructFullUrl(
                client.getApiBaseUrl(),
                client.getApiVersion(),
                FitbitUser.CURRENT_AUTHORIZED_USER,
                resource.getCollectionType(),
                resource.getDate(),
                APIFormat.JSON);

        entity = (Activities) entityCache.get(credentials, cacheKeyWithPlaceholder);
        if (null != entity) {
          log.info("Evicting entity " + cacheKeyWithPlaceholder);
          entityCache.remove(credentials, cacheKeyWithPlaceholder);
        } else {
          log.info("There is no cached version of entity " + cacheKeyWithPlaceholder);
        }
      }
    } catch (IOException e) {
      throw new FitbitAPIException("Notification stream is malformed: " + e, e);
    } catch (JSONException e) {
      throw new FitbitAPIException("Unable to parse update message: " + e, e);
    }
  }