Package com.fitbit.api.client.service

Source Code of com.fitbit.api.client.service.FitbitAPIClientService

package com.fitbit.api.client.service;

import com.fitbit.api.APIUtil;
import com.fitbit.api.FitbitAPIException;
import com.fitbit.api.FitbitAPISecurityException;
import com.fitbit.api.client.FitbitAPIEntityCache;
import com.fitbit.api.client.FitbitApiClientAgent;
import com.fitbit.api.client.FitbitApiCredentialsCache;
import com.fitbit.api.client.FitbitApiSubscriptionStorage;
import com.fitbit.api.client.LocalSubscriptionDetail;
import com.fitbit.api.client.LocalUserDetail;
import com.fitbit.api.client.http.AccessToken;
import com.fitbit.api.client.http.TempCredentials;
import com.fitbit.api.common.model.activities.Activities;
import com.fitbit.api.common.model.foods.Foods;
import com.fitbit.api.model.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.LocalDate;
import org.json.JSONArray;
import org.json.JSONException;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

public class FitbitAPIClientService<C extends FitbitApiClientAgent> {
    protected static final Log log = LogFactory.getLog(FitbitAPIClientService.class);

    protected C client;

    protected FitbitAPIEntityCache entityCache;
    protected FitbitApiCredentialsCache credentialsCache;
    protected FitbitApiSubscriptionStorage subscriptionStore;
    protected String subscriberSecret;

    public FitbitAPIClientService(C client, String consumerKey, String consumerSecret,
                                  FitbitApiCredentialsCache credentialsCache, FitbitAPIEntityCache entityCache,
                                  FitbitApiSubscriptionStorage subscriptionStore) {
        this.client = client;
        client.setOAuthConsumer(consumerKey, consumerSecret);
        subscriberSecret = consumerSecret;
        this.credentialsCache = credentialsCache;
        this.entityCache = entityCache;
        this.subscriptionStore = subscriptionStore;
    }

    public C getClient() {
        return client;
    }
   
    public APIResourceCredentials getResourceCredentialsByUser(LocalUserDetail user) {
        if (null == credentialsCache) {
            return null;
        }
        return credentialsCache.getResourceCredentials(user);
    }

    public APIResourceCredentials getResourceCredentialsByTempToken(String tempToken) {
        if (null == credentialsCache) {
            return null;
        }
        return credentialsCache.getResourceCredentialsByTempToken(tempToken);
    }

    public APIResourceCredentials saveResourceCredentials(LocalUserDetail user, APIResourceCredentials resourceCredentials) {
        if (null == credentialsCache) {
            return null;
        }
        return credentialsCache.saveResourceCredentials(user, resourceCredentials);
    }

    public APIResourceCredentials expireResourceCredentials(LocalUserDetail user) {
        if (null == credentialsCache) {
            return null;
        }
        return credentialsCache.expireResourceCredentials(user);
    }

    public String getResourceOwnerAuthorizationURL(LocalUserDetail user, String callbackURL) throws FitbitAPIException {
        // Get temporary credentials. Include callback URL which the Fitbit API service will save and redirect to when
        // the user authorizes.
        TempCredentials tempCredentials = client.getOAuthTempToken(callbackURL);
        // Create and save temporary resource credentials:
        APIResourceCredentials resourceCredentials = new APIResourceCredentials(user.getUserId(), tempCredentials.getToken(), tempCredentials.getTokenSecret());
        saveResourceCredentials(user, resourceCredentials);
        // Return Fitbit URL to redirect to where the user can authorize:
        return tempCredentials.getAuthorizationURL();
    }

    public void getTokenCredentials(LocalUserDetail user) throws FitbitAPIException {
        // Get cached resource credentials:
        APIResourceCredentials resourceCredentials = getResourceCredentialsByUser(user);
        if (resourceCredentials == null) {
            throw new FitbitAPIException("User " + user.getUserId() + " does not have resource credentials. Need to grant authorization first.");
        }

        String tempToken = resourceCredentials.getTempToken();
        String tempTokenSecret = resourceCredentials.getTempTokenSecret();
        if (tempToken == null || tempTokenSecret == null) {
            throw new FitbitAPIException("Resource credentials for resource " + user.getUserId() + " are in an invalid state: temporary token or secret is null.");
        }

        // Get and save token credentials:
        AccessToken accessToken = client.getOAuthAccessToken(tempToken, tempTokenSecret, resourceCredentials.getTempTokenVerifier());
        resourceCredentials.setAccessToken(accessToken.getToken());
        resourceCredentials.setAccessTokenSecret(accessToken.getTokenSecret());
        resourceCredentials.setResourceId(accessToken.getEncodedUserId());
    }

    public Activities getActivities(LocalUserDetail user, LocalDate date) throws FitbitAPIException {
        return (Activities) getCollectionForDate(user, date, APICollectionType.activities);
    }

    public Foods getFoods(LocalUserDetail user, LocalDate date) throws FitbitAPIException {
        return (Foods) getCollectionForDate(user, date, APICollectionType.foods);
    }

    public Object getCollectionForDate(LocalUserDetail user, LocalDate date, APICollectionType type) throws FitbitAPIException {
        // Get cache key for collection:
        String cacheKey = getCacheKey(date, type);
        // Get the resource credentials:
        APIResourceCredentials credentials = credentialsCache.getResourceCredentials(user);
        // First consult the cache:
        Object result = getFromCache(user, credentials, cacheKey);
        // If not in cache, retrieve from the API service and place in cache:
        if (null == result) {
            result = client.getCollectionForDate(user, FitbitUser.CURRENT_AUTHORIZED_USER, type, date);
            putInCache(result, credentials, cacheKey);
        }
        return result;
    }

    public String getCacheKey(LocalDate date, APICollectionType type) {
        return APIUtil.constructFullUrl(
                client.getApiBaseUrl(),
                client.getApiVersion(),
                FitbitUser.CURRENT_AUTHORIZED_USER,
                type,
                date,
                APIFormat.JSON
        );
    }

    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;
        }
    }

    public void putInCache(Object result, APIResourceCredentials credentials, String cacheKey) {
        if (null != entityCache) {
            entityCache.put(credentials, cacheKey, result);
        }
    }

    public ApiRateLimitStatus getClientRateLimitStatus() throws FitbitAPIException {
        return client.getClientRateLimitStatus();
    }

    public ApiRateLimitStatus getClientAndViewerRateLimitStatus(LocalUserDetail user) throws FitbitAPIException {
        return client.getClientAndViewerRateLimitStatus(user);
    }

    /**
     * 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;
    }

    /**
     * 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);
        }
    }

    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);
        }
    }

}
TOP

Related Classes of com.fitbit.api.client.service.FitbitAPIClientService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.