com.seajas.search.codex.service.social.SocialFacade.java Source code

Java tutorial

Introduction

Here is the source code for com.seajas.search.codex.service.social.SocialFacade.java

Source

/**
 * Copyright (C) 2013 Seajas, the Netherlands.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3, as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.seajas.search.codex.service.social;

import com.google.common.collect.Lists;
import com.google.common.primitives.Longs;
import com.seajas.search.codex.model.identity.IdentityAccountToken;
import com.seajas.search.codex.service.codex.CodexService;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.social.facebook.api.Facebook;
import org.springframework.social.facebook.api.FacebookProfile;
import org.springframework.social.facebook.api.FqlOperations;
import org.springframework.social.facebook.api.FqlResult;
import org.springframework.social.facebook.api.FqlResultMapper;
import org.springframework.social.facebook.api.Reference;
import org.springframework.social.facebook.api.impl.FacebookTemplate;
import org.springframework.social.twitter.api.Tweet;
import org.springframework.social.twitter.api.Twitter;
import org.springframework.social.twitter.api.TwitterProfile;
import org.springframework.social.twitter.api.impl.TwitterTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import javax.annotation.Resource;

@Component
public class SocialFacade implements SocialFacadeInterface {

    private static final Logger LOG = LoggerFactory.getLogger(SocialFacade.class);
    private static final String TWITTER_PROFILE_CACHE = "twitterProfileCache";
    private static final String FACEBOOK_PROFILE_CACHE = "facebookProfileCache";
    @Autowired
    private CodexService codexService;
    @Resource(name = "socialProviderKeysAndSecrets")
    private Map<String, List<String>> socialProviderKeysAndSecrets;
    @Autowired
    private EhCacheCacheManager cacheManager;
    private FacebookPageResultMapper facebookPageResultMapper = new FacebookPageResultMapper();
    private FacebookProfileResultMapper facebookProfileResultMapper = new FacebookProfileResultMapper();

    @Override
    @Cacheable("facebookProfileSearchCache")
    public List<Reference> searchFacebookProfiles(final String person) {
        return getFacebookTemplate().userOperations().search(person);
    }

    @Override
    @Cacheable("facebookPageSearchCache")
    public List<Reference> searchFacebookPages(final String person) {
        MultiValueMap<String, String> queryMap = new LinkedMultiValueMap<String, String>();
        queryMap.add("q", person);
        queryMap.add("type", "page");
        return getFacebookTemplate().fetchConnections("search", null, Reference.class, queryMap);
    }

    @Override
    @Cacheable(value = "facebookProfilesCache")
    public List<FacebookProfile> getFacebookProfiles(List<String> ids) {
        String fql = "SELECT uid, name, first_name, middle_name, last_name, sex, locale, pic_small_with_logo, pic_big_with_logo, pic_square_with_logo, pic_with_logo, username FROM user where uid in ('%s')";
        return getFacebookProfiles(fql, ids, facebookProfileResultMapper);
    }

    @Override
    @Cacheable(value = "facebookPagesCache")
    public List<FacebookProfile> getFacebookPages(List<String> ids) {
        String fql = "SELECT page_id, name, pic_small, pic_big, pic_square, pic, username, location, about FROM page where page_id in ('%s')";
        return getFacebookProfiles(fql, ids, facebookPageResultMapper);
    }

    protected List<FacebookProfile> getFacebookProfiles(String fqlQuery, List<String> ids,
            FqlResultMapper<FacebookProfile> resultMapper) {
        List<FacebookProfile> facebookProfiles = Lists.newArrayList();

        List<String> copyOfIds = Lists.newArrayList(ids);
        // first, fetch available profiles from the cache
        Iterator<String> iterator = copyOfIds.iterator();

        while (iterator.hasNext()) {
            String id = iterator.next();
            Cache.ValueWrapper valueWrapper = cacheManager.getCache(FACEBOOK_PROFILE_CACHE).get(id);
            if (valueWrapper != null && valueWrapper.get() != null) {
                LOG.debug(String.format("Read profile with id %s from cache", id));
                facebookProfiles.add((FacebookProfile) valueWrapper.get());
                iterator.remove();
            }
        }

        // secondly, if not in the cache, retrieve from twitter and store in cache
        String joinedIds = StringUtils.join(copyOfIds, "','");
        FqlOperations fql = getFacebookTemplate().fqlOperations();
        List<FacebookProfile> remainingProfiles = fql.query(String.format(fqlQuery, joinedIds), resultMapper);
        for (FacebookProfile profile : remainingProfiles) {
            LOG.debug(String.format("Write profile with id %s to cache", profile.getId()));
            cacheManager.getCache(FACEBOOK_PROFILE_CACHE).put(profile.getId(), profile);
        }

        facebookProfiles.addAll(remainingProfiles);
        return facebookProfiles;
    }

    @Override
    @Cacheable(value = "twitterSearchCache")
    public List<TwitterProfile> searchTwitter(final String person) {
        List<TwitterProfile> profiles = getTwitterTemplate().userOperations().searchForUsers(person);
        for (TwitterProfile profile : profiles) {
            cacheManager.getCache(TWITTER_PROFILE_CACHE).put(profile.getId(), profile);
        }
        return profiles;
    }

    @Override
    @Cacheable(value = TWITTER_PROFILE_CACHE)
    public TwitterProfile getTwitterProfile(Long twitterId) {
        return getTwitterTemplate().userOperations().getUserProfile(twitterId);
    }

    @Override
    @Cacheable(value = "twitterProfilesCache")
    public List<TwitterProfile> getTwitterProfiles(List<Long> searchableProfileIds) {
        // first, fetch available profiles from the cache
        List<TwitterProfile> twitterProfiles = Lists.newArrayList();

        List<Long> idsCopy = Lists.newArrayList(searchableProfileIds);
        Iterator<Long> idIterator = idsCopy.iterator();

        while (idIterator.hasNext()) {
            Long id = idIterator.next();

            Cache.ValueWrapper valueWrapper = cacheManager.getCache(TWITTER_PROFILE_CACHE).get(id);
            if (valueWrapper != null && valueWrapper.get() != null) {
                LOG.debug(String.format("Read profile with id %d from cache", id));
                twitterProfiles.add((TwitterProfile) valueWrapper.get());
                idIterator.remove();
            }
        }

        // secondly, if not in the cache, retrieve from twitter and store in cache
        long[] ids = Longs.toArray(Lists.newArrayList(idsCopy));
        if (ids.length > 0) {
            LOG.debug("Grabbing twitter profiles with ids: " + ids);
            List<TwitterProfile> remainingProfiles = getTwitterTemplate().userOperations().getUsers(ids);
            for (TwitterProfile profile : remainingProfiles) {
                LOG.debug(String.format("Write profile with id %d to cache", profile.getId()));
                cacheManager.getCache(TWITTER_PROFILE_CACHE).put(profile.getId(), profile);
            }
            twitterProfiles.addAll(remainingProfiles);
        }

        return twitterProfiles;
    }

    @Override
    @Cacheable(value = "twitterUserTimelineCache")
    public List<Tweet> getUserTimeline(long twitterProfileId) {
        return getTwitterTemplate().timelineOperations().getUserTimeline(twitterProfileId, 100);
    }

    @Override
    public Twitter getTwitterTemplate() {
        IdentityAccountToken twitterToken = getToken("twitter");
        Twitter twitter = null;
        if (twitterToken != null) {
            String twitterAccessToken = twitterToken.getAccessToken();
            String twitterAccessSecret = twitterToken.getSecret();
            List<String> keyAndSecret = socialProviderKeysAndSecrets.get("twitter");
            String applicationKey = keyAndSecret.get(0);
            String applicationSecret = keyAndSecret.get(1);
            twitter = new TwitterTemplate(applicationKey, applicationSecret, twitterAccessToken,
                    twitterAccessSecret);
        } else {
            LOG.warn("Could not retrieve valid identity account token for twitter");
        }
        return twitter;
    }

    @Override
    public Facebook getFacebookTemplate() {
        Facebook facebook = null;
        IdentityAccountToken facebookToken = getToken("facebook");
        if (facebookToken != null) {
            facebook = new FacebookTemplate(facebookToken.getAccessToken());
        } else {
            LOG.warn("Could not retrieve valid identity account token for facebook");
        }
        return facebook;
    }

    protected IdentityAccountToken getToken(String type) {
        return codexService.getNextValidTokenFromPool(type);
    }

    static class FacebookPageResultMapper implements FqlResultMapper<FacebookProfile> {
        @Override
        public FacebookProfile mapObject(FqlResult objectValues) {
            String id = objectValues.getString("page_id");
            String username = objectValues.getString("username");
            String name = objectValues.getString("name");
            String firstName = objectValues.getString("first_name");
            String lastName = objectValues.getString("last_name");
            String gender = null;
            return new FacebookProfile(id, username, name, firstName, lastName, gender, null);
        }
    }

    static class FacebookProfileResultMapper implements FqlResultMapper<FacebookProfile> {
        @Override
        public FacebookProfile mapObject(FqlResult objectValues) {
            String id = objectValues.getString("uid");
            String username = objectValues.getString("username");
            String name = objectValues.getString("name");
            String firstName = objectValues.getString("first_name");
            String lastName = objectValues.getString("last_name");
            String gender = objectValues.getString("sex");
            return new FacebookProfile(id, username, name, firstName, lastName, gender, null);
        }
    }
}