Package co.arcs.groove.basking.task

Source Code of co.arcs.groove.basking.task.SyncTask$Outcome

package co.arcs.groove.basking.task;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Semaphore;

import co.arcs.groove.basking.Config;
import co.arcs.groove.basking.event.Events.SyncProcessFinishedEvent;
import co.arcs.groove.basking.event.Events.SyncProcessFinishedWithErrorEvent;
import co.arcs.groove.basking.event.Events.SyncProcessProgressChangedEvent;
import co.arcs.groove.basking.event.Events.SyncProcessStartedEvent;
import co.arcs.groove.basking.task.BuildSyncPlanTask.SyncPlan;
import co.arcs.groove.basking.task.BuildSyncPlanTask.SyncPlan.Item.Action;
import co.arcs.groove.thresher.Client;
import co.arcs.groove.thresher.Song;

public class SyncTask implements Task<SyncTask.Outcome> {

    public static class Outcome {

        private final int deleted;
        private final int downloaded;
        private final int failedToDownload;

        public Outcome(int deleted, int downloaded, int failedToDownload) {
            this.deleted = deleted;
            this.downloaded = downloaded;
            this.failedToDownload = failedToDownload;
        }

        public int getDeleted() {
            return deleted;
        }

        public int getDownloaded() {
            return downloaded;
        }

        public int getFailedToDownload() {
            return failedToDownload;
        }
    }

    private final Config config;
    private final EventBus bus;
    private final ListeningExecutorService exec;
    private final File tempPath;
    private final Client client;
    private final Semaphore concurrentJobsSemaphore;
    private static final int NUM_STEPS = 6;

    public SyncTask(EventBus bus, ListeningExecutorService exec, Config config) {
        this.bus = bus;
        this.exec = exec;
        this.config = config;
        this.tempPath = new File(config.syncDir, ".gssync");
        this.client = new Client();
        this.concurrentJobsSemaphore = new Semaphore(config.numConcurrent);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Outcome call() throws Exception {

        bus.post(new SyncProcessStartedEvent(this, config));

        try {

            postProgressEvent(0);

            // Ensure sync and temp directories exist
            ListenableFuture<Void> createdRequiredDirectoriesFuture = (ListenableFuture<Void>) ((config.dryRun) ? Futures
                    .immediateFuture(null) : exec.submit(new CreateDirectoriesTask(config.syncDir,
                    tempPath)));

            // Do some clean up before starting
            ListenableFuture<Void> deletedTemporariesFuture = Futures.transform(
                    createdRequiredDirectoriesFuture,
                    new AsyncFunction<Void, Void>() {

                        @Override
                        public ListenableFuture<Void> apply(Void input) throws Exception {
                            if (config.dryRun) {
                                return Futures.immediateFuture(null);
                            } else {
                                return exec.submit(new DeleteTemporariesTask(tempPath));
                            }
                        }
                    }
            );

            // Obtain the user's library/favorites from the API
            ListenableFuture<Set<Song>> getSongsToSyncFuture = Futures.transform(
                    deletedTemporariesFuture,
                    new AsyncFunction<Void, Set<Song>>() {

                        @Override
                        public ListenableFuture<Set<Song>> apply(Void input) throws Exception {
                            postProgressEvent(1);
                            return exec.submit(new GetSongsToSyncTask(bus,
                                    client,
                                    config.username,
                                    config.password));
                        }
                    }
            );

            // Build a plan of what to do
            final ListenableFuture<SyncPlan> buildSyncPlanFuture = Futures.transform(
                    getSongsToSyncFuture,
                    new AsyncFunction<Set<Song>, SyncPlan>() {

                        @Override
                        public ListenableFuture<SyncPlan> apply(Set<Song> songs) throws Exception {
                            postProgressEvent(2);
                            return exec.submit(new BuildSyncPlanTask(bus, config.syncDir, songs));
                        }
                    }
            );

            // Schedule delete files task. (This needs to happen before
            // downloads as the files may overlap)
            final ListenableFuture<List<File>> deleteSongsFuture = Futures.transform(
                    buildSyncPlanFuture,
                    new AsyncFunction<SyncPlan, List<File>>() {

                        @Override
                        public ListenableFuture<List<File>> apply(SyncPlan syncPlan) throws Exception {
                            postProgressEvent(3);
                            List<SyncPlan.Item> deletePlanItems = Lists.newArrayList();
                            for (SyncPlan.Item item : syncPlan.getItems()) {
                                if (item.getAction() == Action.DELETE) {
                                    deletePlanItems.add(item);
                                }
                            }

                            if (deletePlanItems.size() == 0 || config.dryRun) {
                                return Futures.immediateFuture((List<File>) new ArrayList<File>());
                            } else {
                                return exec.submit(new DeleteFilesTask(bus, exec, deletePlanItems));
                            }
                        }
                    }
            );

            // Schedule download songs task
            final ListenableFuture<List<Song>> downloadSongsFuture = Futures.transform(Futures.allAsList(
                            buildSyncPlanFuture,
                            deleteSongsFuture), new AsyncFunction<List<Object>, List<Song>>() {

                        @Override
                        public ListenableFuture<List<Song>> apply(List<Object> input) throws Exception {
                            postProgressEvent(4);
                            SyncPlan syncPlan = (SyncPlan) input.get(0);
                            List<SyncPlan.Item> downloadPlanItems = Lists.newArrayList();
                            for (SyncPlan.Item item : syncPlan.getItems()) {
                                if (item.getAction() == Action.DOWNLOAD) {
                                    downloadPlanItems.add(item);
                                }
                            }

                            if (downloadPlanItems.size() == 0 || config.dryRun) {
                                return Futures.immediateFuture((List<Song>) new ArrayList<Song>());
                            } else {
                                return exec.submit(new DownloadSongsTask(bus,
                                        client,
                                        exec,
                                        tempPath,
                                        concurrentJobsSemaphore,
                                        downloadPlanItems));
                            }
                        }
                    }
            );

            // Schedule write playlists task
            final ListenableFuture<Void> generatePlaylistsFuture = Futures.transform(Futures.allAsList(
                            buildSyncPlanFuture,
                            downloadSongsFuture), new AsyncFunction<List<Object>, Void>() {

                        @Override
                        public ListenableFuture<Void> apply(List<Object> input) throws Exception {
                            postProgressEvent(5);
                            if (config.dryRun) {
                                return Futures.immediateFuture(null);
                            } else {
                                SyncPlan syncPlan = (SyncPlan) input.get(0);
                                List<Song> downloadedSongs = Lists.newArrayList((List<Song>) input.get(
                                        1));

                                return exec.submit(new GeneratePlaylistsTask(bus,
                                        config.syncDir,
                                        syncPlan,
                                        downloadedSongs));
                            }
                        }
                    }
            );

            // Schedule write cache file task
            final ListenableFuture<Integer> writeCacheFileFuture = Futures.transform(Futures.allAsList(
                            buildSyncPlanFuture,
                            downloadSongsFuture), new AsyncFunction<List<Object>, Integer>() {
                        @Override
                        public ListenableFuture<Integer> apply(List<Object> input) throws Exception {

                            if (config.dryRun) {
                                return Futures.immediateFuture(null);
                            } else {
                                SyncPlan syncPlan = (SyncPlan) input.get(0);
                                List<Song> downloadedSongs = Lists.newArrayList((List<Song>) input.get(
                                        1));

                                return exec.submit(new WriteCacheFileTask(config.syncDir,
                                        syncPlan,
                                        downloadedSongs));
                            }
                        }
                    }
            );

            // Aggregate tasks to report metrics
            ListenableFuture<Outcome> outcomeFuture = Futures.transform(Futures.allAsList(
                            deleteSongsFuture,
                            downloadSongsFuture,
                            generatePlaylistsFuture,
                            writeCacheFileFuture), new Function<List<Object>, Outcome>() {

                        @Override
                        public Outcome apply(List<Object> input) {
                            postProgressEvent(6);
                            List<File> deletedFiles = (List<File>) input.get(0);
                            List<Song> downloadedSongs = Lists.newArrayList((List<Song>) input.get(1));

                            int deletions = deletedFiles.size();
                            int totalDownloads = downloadedSongs.size();
                            downloadedSongs.retainAll(Collections.singleton(null));
                            int failedDownloads = downloadedSongs.size();
                            int successfulDownloads = totalDownloads - failedDownloads;

                            return new Outcome(deletions, successfulDownloads, failedDownloads);
                        }
                    }
            );

            Outcome outcome = outcomeFuture.get();
            bus.post(new SyncProcessFinishedEvent(this, config, outcome));
            return outcome;
        } catch (Exception e) {
            bus.post(new SyncProcessFinishedWithErrorEvent(this, config, e));
            throw e;
        }
    }

    private void postProgressEvent(int step) {
        bus.post(new SyncProcessProgressChangedEvent(SyncTask.this, config, step, NUM_STEPS));
    }
}
TOP

Related Classes of co.arcs.groove.basking.task.SyncTask$Outcome

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.