net.awairo.favdler.favlist.FavoriteListService.java Source code

Java tutorial

Introduction

Here is the source code for net.awairo.favdler.favlist.FavoriteListService.java

Source

/*
 * FavDownloader
 *
 * (c) 2014 alalwww
 * https://github.com/alalwww
 *
 * This software is released under the MIT License.
 * http://opensource.org/licenses/mit-license.php
 */

package net.awairo.favdler.favlist;

import static com.google.common.base.Preconditions.*;

import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;

import javafx.concurrent.Task;
import lombok.val;
import lombok.extern.log4j.Log4j2;
import twitter4j.Paging;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;

import net.awairo.common.javafx.MyTask;
import net.awairo.common.javafx.ServiceBase;
import net.awairo.common.util.RB;
import net.awairo.favdler.twitter.FavoriteListItems;
import net.awairo.favdler.twitter.TwitterAccessor;

/**
 * ???.
 *
 * @author alalwww
 */
@Log4j2
final class FavoriteListService extends ServiceBase<FavoriteListItems, FavoriteListService> {

    // TODO: ?????????
    private static final int RATE_LIMIT_EXCEEDED = 88;

    private final AtomicReference<FindType> state = new AtomicReference<>(FindType.RESET);
    private final Paging paging = new Paging().count(200);

    enum FindType {
        /** ???????. */
        RESET,
        /** ?????. */
        GET_LATESTS,
        /** ?????. */
        CONTINUE
    }

    enum TaskState {
        /** Twitter????. */
        GET_FAVOLITES("empty", "load_favorite_list"),
        /** ??. */
        UPDATE_VALUE("empty", "update_favorite_list"),
        /** . */
        FINISH("empty", "empty");

        static final int SIZE = values().length;
        final String titleKey;
        final String messageKey;

        private TaskState(String titleKey, String messageKey) {
            this.titleKey = checkNotNull(titleKey);
            this.messageKey = checkNotNull(messageKey);
        }
    }

    private Twitter twitter;

    private String screenName;
    private Optional<Long> sinceId = Optional.empty();
    private Optional<Long> maxId = Optional.empty();

    /**
     * Constructor.
     */
    FavoriteListService() {
        super(true);
    }

    void initialize(TwitterAccessor accessor) {
        checkNotNull(accessor, "accessor");
        checkState(twitter == null);

        twitter = accessor.twitter();
        screenName(accessor.accessToken().getScreenName());
    }

    FavoriteListService screenName(String screenName) {
        checkNotNull(screenName, "screenName");
        checkArgument(!screenName.isEmpty(), "screenName is empty.");

        if (!Objects.equals(this.screenName, screenName))
            state.set(FindType.RESET);

        this.screenName = screenName;
        return this;
    }

    /**
     * ?????200?.
     * ???????200?.
     */
    void refresh() {
        super.reset();
        super.start();
    }

    /**
     * ?????200?.
     */
    void continueLoad() {
        state.set(FindType.CONTINUE);

        refresh();
    }

    @Deprecated
    @Override
    public void start() {
        super.start();
    }

    @Deprecated
    @Override
    public void restart() {
        super.restart();
    }

    @Deprecated
    @Override
    public void reset() {
        super.reset();
    }

    @Override
    protected Task<FavoriteListItems> newTask() {

        return new MyTask<FavoriteListItems>() {

            @Override
            protected FavoriteListItems execute() throws Exception {

                // TODO: 
                // TODO: ?

                changeState(TaskState.GET_FAVOLITES);

                val lastValue = setupAndGetCurrentList();

                ResponseList<Status> res;
                try {
                    res = twitter.favorites().getFavorites(screenName, paging());
                } catch (TwitterException e) {
                    val rateLimitStatus = e.getRateLimitStatus();

                    if (e.getErrorCode() != RATE_LIMIT_EXCEEDED || rateLimitStatus == null)
                        throw e;

                    log.warn("?????????????? {}",
                            rateLimitStatus);

                    changeState(TaskState.UPDATE_VALUE);

                    val ret = new FavoriteListItems(e.getRateLimitStatus());

                    changeState(TaskState.FINISH);
                    return ret;
                }

                changeState(TaskState.UPDATE_VALUE);

                if (!lastValue.isPresent()) {
                    val ret = new FavoriteListItems(res);
                    changeState(TaskState.FINISH);
                    return ret;
                }

                lastValue.ifPresent(v -> v.update(res));
                changeState(TaskState.FINISH);
                return lastValue.get();
            }

            private void changeState(TaskState state) {
                updateProgress(state.ordinal(), TaskState.SIZE);
                updateTitle(RB.labelOf(state.titleKey));
                updateMessage(RB.messageOf(state.messageKey));
            }
        };
    }

    private Optional<FavoriteListItems> setupAndGetCurrentList() {

        Optional<FavoriteListItems> lastValue;
        switch (state.getAndSet(FavoriteListService.FindType.GET_LATESTS)) {

        case CONTINUE:
            lastValue = getLastValue();
            sinceId = Optional.empty();
            lastValue.ifPresent(items -> maxId = items.oldestId());
            return lastValue;

        case GET_LATESTS:
            lastValue = getLastValue();
            lastValue.ifPresent(items -> sinceId = items.latestId().map(id -> id + 1L));
            maxId = Optional.empty();
            return lastValue;

        case RESET:
            lastValue = Optional.empty();
            sinceId = Optional.empty();
            maxId = Optional.empty();
            return lastValue;

        default:
            throw new InternalError("unreachable");
        }
    }

    private Paging paging() {
        sinceId.map(v -> v < 0 ? null : v).ifPresent(paging::setSinceId);
        maxId.map(v -> v < 0 ? null : v).ifPresent(paging::setMaxId);
        return paging;
    }

}