package com.badoo.chateau.example.data.repos.messages; import android.support.annotation.NonNull; import android.util.Log; import com.badoo.chateau.core.repos.messages.MessageDataSource; import com.badoo.chateau.core.repos.messages.MessageQueries; import com.badoo.chateau.core.repos.messages.MessageQueries.LoadQuery; import com.badoo.chateau.core.repos.messages.MessageQueries.SendQuery; import com.badoo.chateau.core.repos.messages.MessageQueries.SubscribeQuery; import com.badoo.chateau.example.data.model.ExampleMessage; import com.badoo.chateau.example.data.repos.messages.cache.CacheEntry; import com.badoo.chateau.example.data.repos.messages.cache.MessageMemoryCache; import java.util.List; import rx.Observable; import rx.android.schedulers.AndroidSchedulers; import rx.subjects.PublishSubject; /** * Memory cached message data source built on top of ParseMessageDataSource. */ public class ExampleMessageMemoryDataSource implements MessageDataSource<ExampleMessage> { private static final boolean DEBUG = true; private static final String TAG = ExampleMessageMemoryDataSource.class.getSimpleName(); private final MessageDataSource<ExampleMessage> mNext; private final MessageMemoryCache mCache = new MessageMemoryCache(); private final PublishSubject<Update<ExampleMessage>> mUpdatePublisher = PublishSubject.create(); public ExampleMessageMemoryDataSource(ParseMessageDataSource next) { mNext = next; mNext.subscribe(new SubscribeQuery<>()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(update -> { final String conversationId = update.getConversationId(); if (DEBUG) { Log.d(TAG, "Updating cache for " + conversationId + " with data: " + update); } switch (update.getAction()) { case ADDED: case UPDATED: if (mCache.hasData(conversationId)) { mCache.get(conversationId).update(update); } break; default: throw new IllegalArgumentException("Action not supported: " + update.getAction()); } mUpdatePublisher.onNext(update); }); } @NonNull @Override public Observable<LoadResult<ExampleMessage>> load(@NonNull LoadQuery<ExampleMessage> query) { return loadFromCache(query).switchIfEmpty(loadFromNext(query)); } private Observable<LoadResult<ExampleMessage>> loadFromCache(LoadQuery<ExampleMessage> query) { if (query.getType() == LoadQuery.Type.ALL && mCache.hasData(query.getConversationId())) { CacheEntry entry = mCache.get(query.getConversationId()); if (DEBUG) { Log.d(TAG, "Cache contains " + entry.getMessages().size() + " message for query: " + query); } return Observable.just(new LoadResult<>(entry.getMessages(), entry.canLoadOlder(), entry.canLoadNewer())); } else { if (DEBUG) { Log.d(TAG, "No cached data for query: " + query); } return Observable.empty(); } } private Observable<LoadResult<ExampleMessage>> loadFromNext(LoadQuery<ExampleMessage> query) { ExampleMessage oldest = null; ExampleMessage newest = null; if (mCache.hasData(query.getConversationId())) { final CacheEntry entry = mCache.get(query.getConversationId()); oldest = entry.oldest(); newest = entry.newest(); } LoadQuery<ExampleMessage> updatedQuery = new LoadQuery<>(query.getConversationId(), query.getType(), oldest, newest); return mNext.load(updatedQuery) .observeOn(AndroidSchedulers.mainThread()) .doOnNext(result -> mCache.get(query.getConversationId()).update(updatedQuery, result)); } @NonNull @Override public Observable<List<ExampleMessage>> getUndelivered(@NonNull MessageQueries.GetUndeliveredQuery<ExampleMessage> query) { return mNext.getUndelivered(query); } @NonNull @Override public Observable<Void> send(@NonNull SendQuery<ExampleMessage> query) { return mNext.send(query); } @NonNull @Override public Observable<Update<ExampleMessage>> subscribe(@NonNull SubscribeQuery<ExampleMessage> query) { final String conversationId = query.getConversationId(); return mUpdatePublisher.filter(update -> update.getConversationId().equals(conversationId)); } }