Java tutorial
// Copyright 2016 The Vanadium Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package io.v.todos.persistence.syncbase; import android.support.annotation.NonNull; import android.util.Log; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import java.util.HashMap; import java.util.Map; import javax.annotation.Nullable; import io.v.todos.model.ListMetadata; import io.v.todos.model.ListSpec; import io.v.todos.model.TaskSpec; import io.v.todos.persistence.ListEventListener; import io.v.v23.InputChannel; import io.v.v23.InputChannelCallback; import io.v.v23.InputChannels; import io.v.v23.context.VContext; import io.v.v23.services.syncbase.Id; import io.v.v23.syncbase.ChangeType; import io.v.v23.syncbase.Collection; import io.v.v23.syncbase.Database; import io.v.v23.syncbase.WatchChange; import io.v.v23.syncbase.util.Util; import io.v.v23.verror.NoExistException; /** * This class aggregates Todo-list watch data from Syncbase into {@link ListMetadata}. */ public class MainListTracker { private static final String TAG = MainListTracker.class.getSimpleName(); private final ListEventListener<ListMetadata> mListener; private ListSpec mListSpec; private final Map<String, Boolean> mIsTaskCompleted = new HashMap<>(); private int mNumCompletedTasks; private boolean mListExistsLocally; public final Collection collection; public final ListenableFuture<Void> watchFuture; public MainListTracker(VContext vContext, Database database, final Id listId, ListEventListener<ListMetadata> listener) { collection = database.getCollection(listId); mListener = listener; InputChannel<WatchChange> watch = database.watch(vContext, ImmutableList.of(Util.rowPrefixPattern(collection.id(), ""))); watchFuture = InputChannels.withCallback(watch, new InputChannelCallback<WatchChange>() { @Override public ListenableFuture<Void> onNext(WatchChange change) { processWatchChange(change); return null; } }); // If the watch fails with NoExistException, the collection has been deleted. Futures.addCallback(watchFuture, new FutureCallback<Void>() { @Override public void onSuccess(@Nullable Void result) { } @Override public void onFailure(@NonNull Throwable t) { if (t instanceof NoExistException && mListExistsLocally) { Log.d(TAG, getNameFromId() + " destroyed"); mListener.onItemDelete(getNameFromId()); } } }); } private String getNameFromId() { return SyncbasePersistence.convertIdToString(collection.id()); } public ListMetadata getListMetadata() { return new ListMetadata(getNameFromId(), mListSpec, mNumCompletedTasks, mIsTaskCompleted.size()); } private void processWatchChange(WatchChange change) { String rowName = change.getRowName(); if (rowName.equals(SyncbaseTodoList.LIST_METADATA_ROW_NAME)) { mListSpec = SyncbasePersistence.castFromSyncbase(change.getValue(), ListSpec.class); } else if (change.getChangeType() == ChangeType.DELETE_CHANGE) { if (mIsTaskCompleted.remove(rowName)) { mNumCompletedTasks--; } } else { boolean isDone = SyncbasePersistence.castFromSyncbase(change.getValue(), TaskSpec.class).getDone(); Boolean rawWasDone = mIsTaskCompleted.put(rowName, isDone); boolean wasDone = rawWasDone != null && rawWasDone; if (!wasDone && isDone) { mNumCompletedTasks++; } else if (wasDone && !isDone) { mNumCompletedTasks--; } } // Don't fire events until we've processed the entire batch of watch events. if (!change.isContinued()) { ListMetadata listMetadata = getListMetadata(); Log.d(TAG, listMetadata.toString()); if (mListExistsLocally) { mListener.onItemUpdate(listMetadata); } else { mListExistsLocally = true; mListener.onItemAdd(listMetadata); } } } }