org.apache.streams.facebook.provider.FacebookFriendFeedProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.streams.facebook.provider.FacebookFriendFeedProvider.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.streams.facebook.provider;

import org.apache.streams.config.StreamsConfigurator;
import org.apache.streams.core.DatumStatusCounter;
import org.apache.streams.core.StreamsDatum;
import org.apache.streams.core.StreamsProvider;
import org.apache.streams.core.StreamsResultSet;
import org.apache.streams.facebook.FacebookUserInformationConfiguration;
import org.apache.streams.facebook.FacebookUserstreamConfiguration;
import org.apache.streams.jackson.StreamsJacksonMapper;
import org.apache.streams.util.ComponentUtils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigRenderOptions;
import facebook4j.Facebook;
import facebook4j.FacebookException;
import facebook4j.FacebookFactory;
import facebook4j.Friend;
import facebook4j.Paging;
import facebook4j.Post;
import facebook4j.ResponseList;
import facebook4j.conf.ConfigurationBuilder;
import facebook4j.json.DataObjectFactory;
import org.apache.commons.lang.NotImplementedException;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.Iterator;
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class FacebookFriendFeedProvider implements StreamsProvider, Serializable {

    private static final String STREAMS_ID = "FacebookFriendFeedProvider";

    private static final Logger LOGGER = LoggerFactory.getLogger(FacebookFriendFeedProvider.class);

    private static final ObjectMapper mapper = StreamsJacksonMapper.getInstance();

    private static final String ALL_PERMISSIONS = "ads_management,ads_read,create_event,create_note,email,export_stream,friends_about_me,friends_actions.books,friends_actions.music,friends_actions.news,friends_actions.video,friends_activities,friends_birthday,friends_education_history,friends_events,friends_games_activity,friends_groups,friends_hometown,friends_interests,friends_likes,friends_location,friends_notes,friends_online_presence,friends_photo_video_tags,friends_photos,friends_questions,friends_relationship_details,friends_relationships,friends_religion_politics,friends_status,friends_subscriptions,friends_videos,friends_website,friends_work_history,manage_friendlists,manage_notifications,manage_pages,photo_upload,publish_actions,publish_stream,read_friendlists,read_insights,read_mailbox,read_page_mailboxes,read_requests,read_stream,rsvp_event,share_item,sms,status_update,user_about_me,user_actions.books,user_actions.music,user_actions.news,user_actions.video,user_activities,user_birthday,user_education_history,user_events,user_friends,user_games_activity,user_groups,user_hometown,user_interests,user_likes,user_location,user_notes,user_online_presence,user_photo_video_tags,user_photos,user_questions,user_relationship_details,user_relationships,user_religion_politics,user_status,user_subscriptions,user_videos,user_website,user_work_history,video_upload,xmpp_login";
    private FacebookUserstreamConfiguration configuration;

    private Class klass;
    protected final ReadWriteLock lock = new ReentrantReadWriteLock();

    protected volatile Queue<StreamsDatum> providerQueue = new LinkedBlockingQueue<>();

    public FacebookUserstreamConfiguration getConfig() {
        return configuration;
    }

    public void setConfig(FacebookUserstreamConfiguration config) {
        this.configuration = config;
    }

    protected Iterator<String[]> idsBatches;

    protected ExecutorService executor;

    protected DateTime start;
    protected DateTime end;

    protected final AtomicBoolean running = new AtomicBoolean();

    private DatumStatusCounter countersCurrent = new DatumStatusCounter();
    private DatumStatusCounter countersTotal = new DatumStatusCounter();

    private static ExecutorService newFixedThreadPoolWithQueueSize(int numThreads, int queueSize) {
        return new ThreadPoolExecutor(numThreads, numThreads, 5000L, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(queueSize, true), new ThreadPoolExecutor.CallerRunsPolicy());
    }

    /**
     * FacebookFriendFeedProvider constructor - resolves FacebookUserInformationConfiguration from JVM 'facebook'.
     */
    public FacebookFriendFeedProvider() {
        Config config = StreamsConfigurator.config.getConfig("facebook");
        FacebookUserInformationConfiguration configuration;
        try {
            configuration = mapper.readValue(config.root().render(ConfigRenderOptions.concise()),
                    FacebookUserInformationConfiguration.class);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * FacebookFriendFeedProvider constructor - uses supplied FacebookUserInformationConfiguration.
     */
    public FacebookFriendFeedProvider(FacebookUserstreamConfiguration config) {
        this.configuration = config;
    }

    /**
     * FacebookFriendFeedProvider constructor - output supplied Class.
     * @param klass Class
     */
    public FacebookFriendFeedProvider(Class klass) {
        Config config = StreamsConfigurator.config.getConfig("facebook");
        FacebookUserInformationConfiguration configuration;
        try {
            configuration = mapper.readValue(config.root().render(ConfigRenderOptions.concise()),
                    FacebookUserInformationConfiguration.class);
        } catch (IOException ex) {
            ex.printStackTrace();
            return;
        }
        this.klass = klass;
    }

    public FacebookFriendFeedProvider(FacebookUserstreamConfiguration config, Class klass) {
        this.configuration = config;
        this.klass = klass;
    }

    public Queue<StreamsDatum> getProviderQueue() {
        return this.providerQueue;
    }

    @Override
    public String getId() {
        return STREAMS_ID;
    }

    @Override
    public void startStream() {
        shutdownAndAwaitTermination(executor);
        running.set(true);
    }

    @Override
    public StreamsResultSet readCurrent() {

        StreamsResultSet current;

        synchronized (FacebookUserstreamProvider.class) {
            current = new StreamsResultSet(new ConcurrentLinkedQueue<>(providerQueue));
            current.setCounter(new DatumStatusCounter());
            current.getCounter().add(countersCurrent);
            countersTotal.add(countersCurrent);
            countersCurrent = new DatumStatusCounter();
            providerQueue.clear();
        }

        return current;

    }

    @Override
    public StreamsResultSet readNew(BigInteger sequence) {
        LOGGER.debug("{} readNew", STREAMS_ID);
        throw new NotImplementedException();
    }

    @Override
    public StreamsResultSet readRange(DateTime start, DateTime end) {
        LOGGER.debug("{} readRange", STREAMS_ID);
        this.start = start;
        this.end = end;
        readCurrent();
        return (StreamsResultSet) providerQueue.iterator();
    }

    @Override
    public boolean isRunning() {
        return running.get();
    }

    void shutdownAndAwaitTermination(ExecutorService pool) {
        pool.shutdown(); // Disable new tasks from being submitted
        try {
            // Wait a while for existing tasks to terminate
            if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
                pool.shutdownNow(); // Cancel currently executing tasks
                // Wait a while for tasks to respond to being cancelled
                if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
                    System.err.println("Pool did not terminate");
                }
            }
        } catch (InterruptedException ie) {
            // (Re-)Cancel if current thread also interrupted
            pool.shutdownNow();
            // Preserve interrupt status
            Thread.currentThread().interrupt();
        }
    }

    @Override
    public void prepare(Object configurationObject) {

        executor = newFixedThreadPoolWithQueueSize(5, 20);

        Objects.requireNonNull(providerQueue);
        Objects.requireNonNull(this.klass);
        Objects.requireNonNull(configuration.getOauth().getAppId());
        Objects.requireNonNull(configuration.getOauth().getAppSecret());
        Objects.requireNonNull(configuration.getOauth().getUserAccessToken());

        Facebook client = getFacebookClient();

        try {
            ResponseList<Friend> friendResponseList = client.friends().getFriends();
            Paging<Friend> friendPaging;
            do {

                for (Friend friend : friendResponseList) {
                    executor.submit(new FacebookFriendFeedTask(this, friend.getId()));
                }
                friendPaging = friendResponseList.getPaging();
                friendResponseList = client.fetchNext(friendPaging);
            } while (friendPaging != null && friendResponseList != null);
        } catch (FacebookException ex) {
            ex.printStackTrace();
        }

    }

    protected Facebook getFacebookClient() {

        ConfigurationBuilder cb = new ConfigurationBuilder();
        cb.setDebugEnabled(true).setOAuthAppId(configuration.getOauth().getAppId())
                .setOAuthAppSecret(configuration.getOauth().getAppSecret())
                .setOAuthAccessToken(configuration.getOauth().getUserAccessToken())
                .setOAuthPermissions(ALL_PERMISSIONS).setJSONStoreEnabled(true).setClientVersion("v1.0");

        FacebookFactory ff = new FacebookFactory(cb.build());

        return ff.getInstance();
    }

    @Override
    public void cleanUp() {
        shutdownAndAwaitTermination(executor);
    }

    private class FacebookFriendFeedTask implements Runnable {

        FacebookFriendFeedProvider provider;
        Facebook client;
        String id;

        public FacebookFriendFeedTask(FacebookFriendFeedProvider provider, String id) {
            this.provider = provider;
            this.id = id;
        }

        @Override
        public void run() {
            client = provider.getFacebookClient();
            try {
                ResponseList<Post> postResponseList = client.getFeed(id);
                Paging<Post> postPaging;
                do {

                    for (Post item : postResponseList) {
                        String json = DataObjectFactory.getRawJSON(item);
                        org.apache.streams.facebook.Post post = mapper.readValue(json,
                                org.apache.streams.facebook.Post.class);
                        try {
                            lock.readLock().lock();
                            ComponentUtils.offerUntilSuccess(new StreamsDatum(post), providerQueue);
                            countersCurrent.incrementAttempt();
                        } finally {
                            lock.readLock().unlock();
                        }
                    }
                    postPaging = postResponseList.getPaging();
                    postResponseList = client.fetchNext(postPaging);
                } while (postPaging != null && postResponseList != null);

            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
}