commit
3549b33924
|
|
@ -2,7 +2,7 @@ apply plugin: 'com.android.library'
|
|||
apply plugin: 'me.tatarka.retrolambda'
|
||||
|
||||
android {
|
||||
compileSdkVersion 24
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion '25.0.2'
|
||||
|
||||
compileOptions {
|
||||
|
|
@ -12,11 +12,11 @@ android {
|
|||
|
||||
defaultConfig {
|
||||
minSdkVersion 9
|
||||
targetSdkVersion 24
|
||||
targetSdkVersion 25
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
provided 'com.android.support:support-annotations:24.2.1'
|
||||
provided 'com.android.support:support-annotations:25.2.0'
|
||||
provided 'io.reactivex:rxandroid:1.2.1'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ public class ConsoleLogProcessor extends LogProcessor {
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("WrongConstant")
|
||||
//WrongConstant: level.getPriority() is not wrong constant!
|
||||
public void processLogMessage(@NonNull final LcGroup group, @NonNull final LcLevel level,
|
||||
@NonNull final String tag, @NonNull final String message, @Nullable final Throwable throwable) {
|
||||
final String messageToLog = normalize(message + (throwable != null ? '\n' + Log.getStackTraceString(throwable) : ""));
|
||||
|
|
@ -50,7 +52,6 @@ public class ConsoleLogProcessor extends LogProcessor {
|
|||
newline = newline != -1 ? newline : length;
|
||||
do {
|
||||
final int end = Math.min(newline, i + MAX_LOG_LENGTH);
|
||||
//noinspection WrongConstant
|
||||
Log.println(level.getPriority(), tag, messageToLog.substring(i, end));
|
||||
i = end;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,7 +264,9 @@ public final class Lc {
|
|||
|
||||
public static void printStackTrace(@NonNull final String tag) {
|
||||
final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
Log.d(tag, TextUtils.join("\n", Arrays.copyOfRange(stackTrace, STACK_TRACE_CODE_DEPTH, stackTrace.length)));
|
||||
if (Log.isLoggable(tag, Log.DEBUG)) {
|
||||
Log.d(tag, TextUtils.join("\n", Arrays.copyOfRange(stackTrace, STACK_TRACE_CODE_DEPTH, stackTrace.length)));
|
||||
}
|
||||
}
|
||||
|
||||
private Lc() {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public class ObservableResult<T> {
|
|||
|
||||
@NonNull
|
||||
private final List<T> items = new LinkedList<>();
|
||||
@NonNull
|
||||
private final List<Throwable> errors = new LinkedList<>();
|
||||
@Nullable
|
||||
private Throwable error;
|
||||
|
||||
/**
|
||||
* Passes item to collect.
|
||||
|
|
@ -33,7 +33,7 @@ public class ObservableResult<T> {
|
|||
* @param error Emitted error.
|
||||
*/
|
||||
public void onError(@NonNull final Throwable error) {
|
||||
errors.add(error);
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -47,13 +47,13 @@ public class ObservableResult<T> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns list of collected errors.
|
||||
* Returns collected error.
|
||||
*
|
||||
* @return Errors.
|
||||
* @return Error.
|
||||
*/
|
||||
@NonNull
|
||||
public List<Throwable> getErrors() {
|
||||
return new ArrayList<>(errors);
|
||||
@Nullable
|
||||
public Throwable getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,214 @@
|
|||
/**
|
||||
* Copyright 2014 Netflix, Inc.
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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 ru.touchin.roboswag.core.observables;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import rx.Observable.OnSubscribe;
|
||||
import rx.Scheduler;
|
||||
import rx.Subscriber;
|
||||
import rx.Subscription;
|
||||
import rx.functions.Action0;
|
||||
import rx.functions.Action1;
|
||||
import rx.observables.ConnectableObservable;
|
||||
import rx.schedulers.Schedulers;
|
||||
import rx.subscriptions.CompositeSubscription;
|
||||
import rx.subscriptions.Subscriptions;
|
||||
|
||||
/**
|
||||
* Returns an observable sequence that stays connected to the source as long as
|
||||
* there is at least one subscription to the observable sequence and also it stays connected
|
||||
* for cache time after everyone unsubscribe.
|
||||
*
|
||||
* @param <T> the value type
|
||||
*/
|
||||
@SuppressWarnings({"PMD.AvoidUsingVolatile", "PMD.CompareObjectsWithEquals"})
|
||||
//AvoidUsingVolatile,CompareObjectsWithEquals: from OnSubscribeRefCount code
|
||||
public final class OnSubscribeRefCountWithCacheTime<T> implements OnSubscribe<T> {
|
||||
|
||||
@NonNull
|
||||
private final ConnectableObservable<? extends T> source;
|
||||
@NonNull
|
||||
private volatile CompositeSubscription baseSubscription = new CompositeSubscription();
|
||||
@NonNull
|
||||
private final AtomicInteger subscriptionCount = new AtomicInteger(0);
|
||||
|
||||
@NonNull
|
||||
private final Scheduler scheduler = Schedulers.computation();
|
||||
private final long cacheTime;
|
||||
@NonNull
|
||||
private final TimeUnit cacheTimeUnit;
|
||||
@Nullable
|
||||
private Scheduler.Worker worker;
|
||||
|
||||
/**
|
||||
* Use this lock for every subscription and disconnect action.
|
||||
*/
|
||||
@NonNull
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
public OnSubscribeRefCountWithCacheTime(@NonNull final ConnectableObservable<? extends T> source,
|
||||
final long cacheTime, @NonNull final TimeUnit cacheTimeUnit) {
|
||||
this.source = source;
|
||||
this.cacheTime = cacheTime;
|
||||
this.cacheTimeUnit = cacheTimeUnit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(@NonNull final Subscriber<? super T> subscriber) {
|
||||
|
||||
lock.lock();
|
||||
if (subscriptionCount.incrementAndGet() == 1) {
|
||||
if (worker != null) {
|
||||
worker.unsubscribe();
|
||||
worker = null;
|
||||
}
|
||||
final AtomicBoolean writeLocked = new AtomicBoolean(true);
|
||||
|
||||
try {
|
||||
// need to use this overload of connect to ensure that
|
||||
// baseSubscription is set in the case that source is a
|
||||
// synchronous Observable
|
||||
source.connect(onSubscribe(subscriber, writeLocked));
|
||||
} finally {
|
||||
// need to cover the case where the source is subscribed to
|
||||
// outside of this class thus preventing the Action1 passed
|
||||
// to source.connect above being called
|
||||
if (writeLocked.get()) {
|
||||
// Action1 passed to source.connect was not called
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
// ready to subscribe to source so do it
|
||||
doSubscribe(subscriber, baseSubscription);
|
||||
} finally {
|
||||
// release the read lock
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Action1<Subscription> onSubscribe(@NonNull final Subscriber<? super T> subscriber,
|
||||
@NonNull final AtomicBoolean writeLocked) {
|
||||
return new Action1<Subscription>() {
|
||||
@Override
|
||||
public void call(@NonNull final Subscription subscription) {
|
||||
|
||||
try {
|
||||
baseSubscription.add(subscription);
|
||||
// ready to subscribe to source so do it
|
||||
doSubscribe(subscriber, baseSubscription);
|
||||
} finally {
|
||||
// release the write lock
|
||||
lock.unlock();
|
||||
writeLocked.set(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void doSubscribe(@NonNull final Subscriber<? super T> subscriber, @NonNull final CompositeSubscription currentBase) {
|
||||
subscriber.add(disconnect(currentBase));
|
||||
source.unsafeSubscribe(new Subscriber<T>(subscriber) {
|
||||
@Override
|
||||
public void onError(@NonNull final Throwable throwable) {
|
||||
cleanup();
|
||||
subscriber.onError(throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@Nullable final T item) {
|
||||
subscriber.onNext(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
cleanup();
|
||||
subscriber.onCompleted();
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
// on error or completion we need to unsubscribe the base subscription
|
||||
// and set the subscriptionCount to 0
|
||||
lock.lock();
|
||||
try {
|
||||
if (baseSubscription == currentBase) {
|
||||
if (worker != null) {
|
||||
worker.unsubscribe();
|
||||
worker = null;
|
||||
}
|
||||
baseSubscription.unsubscribe();
|
||||
baseSubscription = new CompositeSubscription();
|
||||
subscriptionCount.set(0);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Subscription disconnect(@NonNull final CompositeSubscription current) {
|
||||
return Subscriptions.create(new Action0() {
|
||||
|
||||
@Override
|
||||
public void call() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (baseSubscription == current && subscriptionCount.decrementAndGet() == 0) {
|
||||
if (worker != null) {
|
||||
worker.unsubscribe();
|
||||
} else {
|
||||
worker = scheduler.createWorker();
|
||||
}
|
||||
worker.schedule(new Action0() {
|
||||
@Override
|
||||
public void call() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (subscriptionCount.get() == 0) {
|
||||
baseSubscription.unsubscribe();
|
||||
// need a new baseSubscription because once
|
||||
// unsubscribed stays that way
|
||||
worker.unsubscribe();
|
||||
worker = null;
|
||||
baseSubscription = new CompositeSubscription();
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}, cacheTime, cacheTimeUnit);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package ru.touchin.roboswag.core.observables;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
import rx.Observable;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 21/05/2016.
|
||||
* Some helper methods to work with JavaRx.
|
||||
*/
|
||||
public final class RxUtils {
|
||||
|
||||
/**
|
||||
* Subscribes to specific {@link Observable} and waits for it's onCompleted event
|
||||
* and then returns {@link ObservableResult} with all collected items and errors during subscription.
|
||||
* You should NOT use such method normally. It is safer than {@link Observable#toBlocking()} but it is also like a hack.
|
||||
*
|
||||
* @param observable {@link Observable} to be executed;
|
||||
* @param <T> Type of {@link Observable}'s items;
|
||||
* @return {@link ObservableResult} which contains all items and errors collected during execution.
|
||||
*/
|
||||
@NonNull
|
||||
public static <T> ObservableResult<T> executeSync(@NonNull final Observable<T> observable) {
|
||||
final ObservableResult<T> result = new ObservableResult<>();
|
||||
final CountDownLatch waiter = new CountDownLatch(1);
|
||||
observable.subscribe(result::onNext, result::onError, waiter::countDown);
|
||||
try {
|
||||
waiter.await();
|
||||
} catch (final InterruptedException exception) {
|
||||
throw new ShouldNotHappenException(exception);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private RxUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -22,6 +22,8 @@ package ru.touchin.roboswag.core.observables.storable;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 04/10/2015.
|
||||
* Interface that is providing logic to convert value from specific type to type allowed to store in {@link Store} object and back.
|
||||
|
|
@ -32,29 +34,29 @@ import android.support.annotation.Nullable;
|
|||
public interface Converter<TObject, TStoreObject> {
|
||||
|
||||
/**
|
||||
* Converts specific object of objectClass to object of storeObjectClass allowed to store.
|
||||
* Converts specific object of objectType to object of storeObjectClass allowed to store.
|
||||
*
|
||||
* @param objectClass Class of object;
|
||||
* @param storeObjectClass Class of store object allowed to store;
|
||||
* @param objectType Type of object;
|
||||
* @param storeObjectType Type of store object allowed to store;
|
||||
* @param object Object to be converted to store object;
|
||||
* @return Object that is allowed to store into specific {@link Store};
|
||||
* @throws ConversionException Exception during conversion. Usually it indicates illegal state.
|
||||
*/
|
||||
@Nullable
|
||||
TStoreObject toStoreObject(@NonNull Class<TObject> objectClass, @NonNull Class<TStoreObject> storeObjectClass, @Nullable TObject object)
|
||||
TStoreObject toStoreObject(@NonNull Type objectType, @NonNull Type storeObjectType, @Nullable TObject object)
|
||||
throws ConversionException;
|
||||
|
||||
/**
|
||||
* Converts specific store object of storeObjectClass to object of objectClass.
|
||||
* Converts specific store object of storeObjectClass to object of objectType.
|
||||
*
|
||||
* @param objectClass Class of object;
|
||||
* @param storeObjectClass Class of store object allowed to store;
|
||||
* @param objectType Type of object;
|
||||
* @param storeObjectType Type of store object allowed to store;
|
||||
* @param storeObject Object from specific {@link Store};
|
||||
* @return Object converted from store object;
|
||||
* @throws ConversionException Exception during conversion. Usually it indicates illegal state.
|
||||
*/
|
||||
@Nullable
|
||||
TObject toObject(@NonNull Class<TObject> objectClass, @NonNull Class<TStoreObject> storeObjectClass, @Nullable TStoreObject storeObject)
|
||||
TObject toObject(@NonNull Type objectType, @NonNull Type storeObjectType, @Nullable TStoreObject storeObject)
|
||||
throws ConversionException;
|
||||
|
||||
class ConversionException extends Exception {
|
||||
|
|
|
|||
|
|
@ -20,11 +20,15 @@
|
|||
package ru.touchin.roboswag.core.observables.storable;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import rx.Completable;
|
||||
import rx.Observable;
|
||||
import rx.Single;
|
||||
import rx.exceptions.OnErrorThrowable;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 06/10/2015.
|
||||
* Object that allows to migrate some store objects from one version to another by migrators passed into constructor.
|
||||
|
|
@ -51,60 +55,102 @@ public class Migration<TKey> {
|
|||
this.migrators = Arrays.asList(migrators);
|
||||
}
|
||||
|
||||
private long loadCurrentVersion(@NonNull final TKey key) throws MigrationException {
|
||||
final Long result;
|
||||
try {
|
||||
result = versionsStore.loadObject(Long.class, key);
|
||||
} catch (final Store.StoreException throwable) {
|
||||
throw new MigrationException(String.format("Can't get version of '%s' from %s", key, versionsStore), throwable);
|
||||
}
|
||||
return result != null ? result : DEFAULT_VERSION;
|
||||
@NonNull
|
||||
private Single<Long> loadCurrentVersion(@NonNull final TKey key) {
|
||||
return versionsStore.loadObject(Long.class, key)
|
||||
.map(version -> version != null ? version : DEFAULT_VERSION)
|
||||
.onErrorResumeNext(throwable
|
||||
-> Single.error(new MigrationException(String.format("Can't get version of '%s' from %s", key, versionsStore), throwable)));
|
||||
}
|
||||
|
||||
private void checkMigrationResult(@NonNull final TKey key, final long oldVersion, final long currentVersion, @Nullable final Migrator migrator)
|
||||
throws MigrationException {
|
||||
if (oldVersion > currentVersion) {
|
||||
throw new MigrationException(String.format("Version of '%s' downgraded from %s to %s [from %s by %s]",
|
||||
key, oldVersion, currentVersion, versionsStore, migrator));
|
||||
}
|
||||
if (currentVersion > latestVersion) {
|
||||
throw new MigrationException(String.format("Version of '%s' is %s and higher than latest version %s [from %s by %s]",
|
||||
key, oldVersion, currentVersion, versionsStore, migrator));
|
||||
}
|
||||
if (oldVersion == currentVersion && migrator != null) {
|
||||
throw new MigrationException(String.format("Version of '%s' is %s and stood same [from %s by %s]",
|
||||
key, currentVersion, versionsStore, migrator));
|
||||
@NonNull
|
||||
private Single<Long> makeMigrationChain(@NonNull final TKey key, @NonNull final VersionUpdater versionUpdater) {
|
||||
Single<Long> chain = Single.fromCallable(() -> versionUpdater.initialVersion);
|
||||
for (final Migrator<TKey, ?, ?> migrator : migrators) {
|
||||
chain = chain.flatMap(updatedVersion ->
|
||||
migrator.canMigrate(key, updatedVersion)
|
||||
.flatMap(canMigrate -> canMigrate
|
||||
? migrator.migrate(key, updatedVersion)
|
||||
.doOnSuccess(newVersion
|
||||
-> versionUpdater.updateVersion(newVersion, latestVersion, migrator))
|
||||
: Single.just(updatedVersion)));
|
||||
}
|
||||
return chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrates some object by key to latest version.
|
||||
*
|
||||
* @param key Key of object to migrate;
|
||||
* @throws MigrationException Exception during object migration. Usually it indicates illegal state.
|
||||
* @param key Key of object to migrate.
|
||||
*/
|
||||
public void migrateToLatestVersion(@NonNull final TKey key) throws MigrationException {
|
||||
long currentVersion = loadCurrentVersion(key);
|
||||
|
||||
while (currentVersion != latestVersion) {
|
||||
final long oldVersion = currentVersion;
|
||||
for (final Migrator<TKey, ?, ?> migrator : migrators) {
|
||||
if (migrator.supportsMigrationFor(currentVersion) && migrator.canMigrate(key, currentVersion)) {
|
||||
currentVersion = migrator.migrate(key, currentVersion);
|
||||
checkMigrationResult(key, oldVersion, currentVersion, migrator);
|
||||
}
|
||||
checkMigrationResult(key, oldVersion, currentVersion, null);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
versionsStore.storeObject(Long.class, key, latestVersion);
|
||||
} catch (final Store.StoreException throwable) {
|
||||
throw new MigrationException(String.format("Can't store version %s of '%s' into %s", key, currentVersion, versionsStore), throwable);
|
||||
}
|
||||
@NonNull
|
||||
public Completable migrateToLatestVersion(@NonNull final TKey key) {
|
||||
return loadCurrentVersion(key)
|
||||
.flatMap(currentVersion -> {
|
||||
final VersionUpdater versionUpdater = new VersionUpdater<>(key, versionsStore, currentVersion);
|
||||
return makeMigrationChain(key, versionUpdater)
|
||||
.doOnSuccess(lastUpdatedVersion -> {
|
||||
if (lastUpdatedVersion < latestVersion) {
|
||||
throw OnErrorThrowable.from(new NextLoopMigrationException());
|
||||
}
|
||||
if (versionUpdater.initialVersion == versionUpdater.oldVersion) {
|
||||
throw new MigrationException(String.format("Version of '%s' not updated from %s",
|
||||
key, versionUpdater.initialVersion));
|
||||
}
|
||||
})
|
||||
.retryWhen(attempts -> attempts.switchMap(throwable -> throwable instanceof NextLoopMigrationException
|
||||
? Observable.just(null) : Observable.error(throwable)));
|
||||
})
|
||||
.toCompletable()
|
||||
.andThen(versionsStore.storeObject(Long.class, key, latestVersion))
|
||||
.onErrorResumeNext(throwable -> {
|
||||
if (throwable instanceof MigrationException) {
|
||||
return Completable.error(throwable);
|
||||
}
|
||||
return Completable.error(new MigrationException(String.format("Can't migrate '%s'", key), throwable));
|
||||
});
|
||||
}
|
||||
|
||||
public static class MigrationException extends Exception {
|
||||
private static class VersionUpdater<TKey> {
|
||||
|
||||
@NonNull
|
||||
private final TKey key;
|
||||
@NonNull
|
||||
private final Store versionsStore;
|
||||
private long oldVersion;
|
||||
private long initialVersion;
|
||||
|
||||
public VersionUpdater(@NonNull final TKey key, @NonNull final Store versionsStore, final long initialVersion) {
|
||||
this.key = key;
|
||||
this.versionsStore = versionsStore;
|
||||
this.oldVersion = initialVersion;
|
||||
this.initialVersion = initialVersion;
|
||||
}
|
||||
|
||||
public void updateVersion(final long updateVersion, final long latestVersion, @NonNull final Migrator migrator) {
|
||||
if (initialVersion > updateVersion) {
|
||||
throw new MigrationException(String.format("Version of '%s' downgraded from %s to %s [from %s by %s]",
|
||||
key, initialVersion, updateVersion, versionsStore, migrator));
|
||||
}
|
||||
if (updateVersion > latestVersion) {
|
||||
throw new MigrationException(
|
||||
String.format("Version of '%s' is %s and higher than latest version %s [from %s by %s]",
|
||||
key, initialVersion, updateVersion, versionsStore, migrator));
|
||||
}
|
||||
if (updateVersion == initialVersion) {
|
||||
throw new MigrationException(String.format("Update version of '%s' equals current version '%s' [from %s by %s]",
|
||||
key, updateVersion, versionsStore, migrator));
|
||||
}
|
||||
oldVersion = initialVersion;
|
||||
initialVersion = updateVersion;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class NextLoopMigrationException extends Exception {
|
||||
}
|
||||
|
||||
public static class MigrationException extends RuntimeException {
|
||||
|
||||
public MigrationException(@NonNull final String message) {
|
||||
super(message);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ package ru.touchin.roboswag.core.observables.storable;
|
|||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import rx.Single;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 05/10/2015.
|
||||
* Abstract class of objects which are able to migrate some values from one version to another.
|
||||
|
|
@ -52,49 +54,44 @@ public abstract class Migrator<TKey, TOldStoreObject, TNewStoreObject> {
|
|||
public abstract boolean supportsMigrationFor(long version);
|
||||
|
||||
/**
|
||||
* Returns if specific object with key of specific version could be migrated by this migrator.
|
||||
* Returns {@link Single} that emits if specific object with key of specific version could be migrated by this migrator.
|
||||
*
|
||||
* @param key Key of object to migrate;
|
||||
* @param version Current version of object;
|
||||
* @return True if object with such key and version could be migrated;
|
||||
* @throws Migration.MigrationException Exception during object migration. Usually it indicates illegal state.
|
||||
* @return {@link Single} that emits true if object with such key and version could be migrated.
|
||||
*/
|
||||
public boolean canMigrate(@NonNull final TKey key, final long version) throws Migration.MigrationException {
|
||||
try {
|
||||
return oldStore.contains(key);
|
||||
} catch (final Store.StoreException exception) {
|
||||
throw new Migration.MigrationException("Version " + version + " not supported by " + this, exception);
|
||||
}
|
||||
@NonNull
|
||||
public Single<Boolean> canMigrate(@NonNull final TKey key, final long version) {
|
||||
return supportsMigrationFor(version) ? oldStore.contains(key) : Single.just(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrates object with specific key from some version to migrator's version.
|
||||
* Single that migrates object with specific key from some version to migrator's version.
|
||||
*
|
||||
* @param key Key of object to migrate;
|
||||
* @param version Current version of object;
|
||||
* @return New version of object after migration process;
|
||||
* @throws Migration.MigrationException Exception during object migration. Usually it indicates illegal state.
|
||||
* @return {@link Single} that emits new version of object after migration process.
|
||||
*/
|
||||
public long migrate(@NonNull final TKey key, final long version) throws Migration.MigrationException {
|
||||
if (!supportsMigrationFor(version)) {
|
||||
throw new Migration.MigrationException(String.format("Version %s of '%s' is not supported by %s", version, key, this));
|
||||
}
|
||||
return migrateInternal(key, version, oldStore, newStore);
|
||||
@NonNull
|
||||
public Single<Long> migrate(@NonNull final TKey key, final long version) {
|
||||
return supportsMigrationFor(version)
|
||||
? migrateInternal(key, version, oldStore, newStore)
|
||||
: Single.error(new Migration.MigrationException(String.format("Version %s of '%s' is not supported by %s", version, key, this)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal migration logic specified by implementation.
|
||||
* Single that represents internal migration logic specified by implementation.
|
||||
*
|
||||
* @param key Key of object to migrate;
|
||||
* @param version Current version of object;
|
||||
* @param oldStore Old store of object;
|
||||
* @param newStore new store of object;
|
||||
* @return New version of object after migration process;
|
||||
* @throws Migration.MigrationException Exception during object migration. Usually it indicates illegal state.
|
||||
* @return {@link Single} that emits new version of object after migration process.
|
||||
*/
|
||||
protected abstract long migrateInternal(@NonNull TKey key,
|
||||
final long version,
|
||||
@NonNull Store<TKey, TOldStoreObject> oldStore,
|
||||
@NonNull Store<TKey, TNewStoreObject> newStore) throws Migration.MigrationException;
|
||||
@NonNull
|
||||
protected abstract Single<Long> migrateInternal(@NonNull TKey key,
|
||||
long version,
|
||||
@NonNull Store<TKey, TOldStoreObject> oldStore,
|
||||
@NonNull Store<TKey, TNewStoreObject> newStore);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 04/10/2015.
|
||||
* Interface that is providing logic to convert value from specific type to type allowed to store in {@link Store} object and back.
|
||||
* The only difference is that it is not throwing exceptions during conversion. It is safe to convert objects with it.
|
||||
*
|
||||
* @param <TObject> Type of original objects;
|
||||
* @param <TStoreObject> Type of objects in store.
|
||||
*/
|
||||
public interface SafeConverter<TObject, TStoreObject> extends Converter<TObject, TStoreObject> {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
TStoreObject toStoreObject(@NonNull Class<TObject> objectClass, @NonNull Class<TStoreObject> storeObjectClass, @Nullable TObject object);
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
TObject toObject(@NonNull Class<TObject> objectClass, @NonNull Class<TStoreObject> storeObjectClass, @Nullable TStoreObject storeObject);
|
||||
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 04/10/2015.
|
||||
* Interface that is providing access to abstract object which can store (e.g. in file, database, remote store)
|
||||
* some type of objects (e.g. String, byte[], Integer) by key.
|
||||
* The only difference is that it is not throwing exceptions during access to store. It is safe to work with such store.
|
||||
*
|
||||
* @param <TKey> Type of keys for values;
|
||||
* @param <TStoreObject> Type of values stored in store.
|
||||
*/
|
||||
public interface SafeStore<TKey, TStoreObject> extends Store<TKey, TStoreObject> {
|
||||
|
||||
@Override
|
||||
boolean contains(@NonNull TKey key);
|
||||
|
||||
@Override
|
||||
void storeObject(@NonNull Class<TStoreObject> storeObjectClass, @NonNull TKey key, @Nullable TStoreObject storeObject);
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
TStoreObject loadObject(@NonNull Class<TStoreObject> storeObjectClass, @NonNull TKey key);
|
||||
|
||||
}
|
||||
|
|
@ -3,22 +3,24 @@ package ru.touchin.roboswag.core.observables.storable;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Simple safe converter that is doing nothing on conversion.
|
||||
*
|
||||
* @param <T> Same type.
|
||||
*/
|
||||
public class SameTypesConverter<T> implements SafeConverter<T, T> {
|
||||
public class SameTypesConverter<T> implements Converter<T, T> {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public T toStoreObject(@NonNull final Class<T> class1, @NonNull final Class<T> class2, @Nullable final T object) {
|
||||
public T toStoreObject(@NonNull final Type type1, @NonNull final Type type2, @Nullable final T object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public T toObject(@NonNull final Class<T> class1, @NonNull final Class<T> class2, @Nullable final T object) {
|
||||
public T toObject(@NonNull final Type type1, @NonNull final Type type2, @Nullable final T object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,18 +22,18 @@ package ru.touchin.roboswag.core.observables.storable;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import ru.touchin.roboswag.core.log.LcGroup;
|
||||
import ru.touchin.roboswag.core.observables.ObservableResult;
|
||||
import ru.touchin.roboswag.core.observables.RxUtils;
|
||||
import ru.touchin.roboswag.core.observables.storable.builders.MigratableStorableBuilder;
|
||||
import ru.touchin.roboswag.core.observables.OnSubscribeRefCountWithCacheTime;
|
||||
import ru.touchin.roboswag.core.observables.storable.builders.NonNullStorableBuilder;
|
||||
import ru.touchin.roboswag.core.observables.storable.builders.SafeStorableBuilder;
|
||||
import ru.touchin.roboswag.core.utils.ObjectUtils;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
import rx.Completable;
|
||||
import rx.Observable;
|
||||
import rx.Scheduler;
|
||||
import rx.exceptions.OnErrorThrowable;
|
||||
import rx.functions.Actions;
|
||||
import rx.schedulers.Schedulers;
|
||||
import rx.subjects.PublishSubject;
|
||||
|
||||
|
|
@ -54,12 +54,25 @@ public class Storable<TKey, TObject, TStoreObject> {
|
|||
|
||||
public static final LcGroup STORABLE_LC_GROUP = new LcGroup("STORABLE");
|
||||
|
||||
private static final long DEFAULT_CACHE_TIME_MILLIS = TimeUnit.SECONDS.toMillis(5);
|
||||
|
||||
@NonNull
|
||||
private static ObserveStrategy getDefaultObserveStrategyFor(@NonNull final Type objectType, @NonNull final Type storeObjectType) {
|
||||
if (objectType instanceof Class && ObjectUtils.isSimpleClass((Class) objectType)) {
|
||||
return ObserveStrategy.CACHE_ACTUAL_VALUE;
|
||||
}
|
||||
if (objectType instanceof Class && ObjectUtils.isSimpleClass((Class) storeObjectType)) {
|
||||
return ObserveStrategy.CACHE_STORE_VALUE;
|
||||
}
|
||||
return ObserveStrategy.NO_CACHE;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private final TKey key;
|
||||
@NonNull
|
||||
private final Class<TObject> objectClass;
|
||||
private final Type objectType;
|
||||
@NonNull
|
||||
private final Class<TStoreObject> storeObjectClass;
|
||||
private final Type storeObjectType;
|
||||
@NonNull
|
||||
private final Store<TKey, TStoreObject> store;
|
||||
@NonNull
|
||||
|
|
@ -67,113 +80,103 @@ public class Storable<TKey, TObject, TStoreObject> {
|
|||
@NonNull
|
||||
private final PublishSubject<TStoreObject> newStoreValueEvent = PublishSubject.create();
|
||||
@NonNull
|
||||
private final Observable<TStoreObject> storeValueObservable;
|
||||
@NonNull
|
||||
private final Observable<TObject> valueObservable;
|
||||
@NonNull
|
||||
private final Scheduler scheduler;
|
||||
|
||||
public Storable(@NonNull final BuilderCore<TKey, TObject, TStoreObject> builderCore) {
|
||||
this(builderCore.key, builderCore.objectClass, builderCore.storeObjectClass,
|
||||
this(builderCore.key, builderCore.objectType, builderCore.storeObjectType,
|
||||
builderCore.store, builderCore.converter, builderCore.observeStrategy,
|
||||
builderCore.migration, builderCore.defaultValue, builderCore.storeScheduler);
|
||||
builderCore.migration, builderCore.defaultValue, builderCore.storeScheduler, builderCore.cacheTimeMillis);
|
||||
}
|
||||
|
||||
public Storable(@NonNull final TKey key,
|
||||
@NonNull final Class<TObject> objectClass,
|
||||
@Nullable final Class<TStoreObject> storeObjectClass,
|
||||
@Nullable final Store<TKey, TStoreObject> store,
|
||||
@Nullable final Converter<TObject, TStoreObject> converter,
|
||||
@Nullable final ObserveStrategy observeStrategy,
|
||||
@Nullable final Migration<TKey> migration,
|
||||
@Nullable final TObject defaultValue,
|
||||
@Nullable final Scheduler storeScheduler) {
|
||||
if (storeObjectClass == null || store == null || converter == null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
@SuppressWarnings("PMD.ExcessiveParameterList")
|
||||
//ExcessiveParameterList: that's why we are using builder to create it
|
||||
private Storable(@NonNull final TKey key,
|
||||
@NonNull final Type objectType,
|
||||
@NonNull final Type storeObjectType,
|
||||
@NonNull final Store<TKey, TStoreObject> store,
|
||||
@NonNull final Converter<TObject, TStoreObject> converter,
|
||||
@Nullable final ObserveStrategy observeStrategy,
|
||||
@Nullable final Migration<TKey> migration,
|
||||
@Nullable final TObject defaultValue,
|
||||
@Nullable final Scheduler storeScheduler,
|
||||
final long cacheTimeMillis) {
|
||||
this.key = key;
|
||||
this.objectClass = objectClass;
|
||||
this.storeObjectClass = storeObjectClass;
|
||||
this.objectType = objectType;
|
||||
this.storeObjectType = storeObjectType;
|
||||
this.store = store;
|
||||
this.converter = converter;
|
||||
final ObserveStrategy nonNullObserveStrategy = observeStrategy != null ? observeStrategy : getDefaultGetStrategy();
|
||||
final Observable<TStoreObject> storeValueObservable
|
||||
= createStoreValueObservable(nonNullObserveStrategy, migration, defaultValue, storeScheduler);
|
||||
valueObservable = createValueObservable(storeValueObservable, nonNullObserveStrategy, storeScheduler);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ObserveStrategy getDefaultGetStrategy() {
|
||||
if (ObjectUtils.isSimpleClass(objectClass)) {
|
||||
return ObserveStrategy.CACHE_ACTUAL_VALUE;
|
||||
}
|
||||
if (ObjectUtils.isSimpleClass(storeObjectClass)) {
|
||||
return ObserveStrategy.CACHE_STORE_VALUE;
|
||||
}
|
||||
return ObserveStrategy.NO_CACHE;
|
||||
final ObserveStrategy nonNullObserveStrategy
|
||||
= observeStrategy != null ? observeStrategy : getDefaultObserveStrategyFor(objectType, storeObjectType);
|
||||
scheduler = storeScheduler != null ? storeScheduler : Schedulers.from(Executors.newSingleThreadExecutor());
|
||||
storeValueObservable
|
||||
= createStoreValueObservable(nonNullObserveStrategy, migration, defaultValue, cacheTimeMillis);
|
||||
valueObservable = createValueObservable(storeValueObservable, nonNullObserveStrategy, cacheTimeMillis);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TStoreObject returnDefaultValueIfNull(@Nullable final TStoreObject storeObject, @Nullable final TObject defaultValue) {
|
||||
if (storeObject == null && defaultValue != null) {
|
||||
try {
|
||||
return converter.toStoreObject(objectClass, storeObjectClass, defaultValue);
|
||||
} catch (final Converter.ConversionException exception) {
|
||||
STORABLE_LC_GROUP.w(exception, "Exception while converting default value of '%s' from '%s' from store %s",
|
||||
key, defaultValue, store);
|
||||
throw OnErrorThrowable.from(exception);
|
||||
} catch (final RuntimeException throwable) {
|
||||
STORABLE_LC_GROUP.assertion(throwable);
|
||||
}
|
||||
if (storeObject != null || defaultValue == null) {
|
||||
return storeObject;
|
||||
}
|
||||
|
||||
try {
|
||||
return converter.toStoreObject(objectType, storeObjectType, defaultValue);
|
||||
} catch (final Converter.ConversionException exception) {
|
||||
STORABLE_LC_GROUP.w(exception, "Exception while converting default value of '%s' from '%s' from store %s",
|
||||
key, defaultValue, store);
|
||||
throw OnErrorThrowable.from(exception);
|
||||
} catch (final RuntimeException throwable) {
|
||||
STORABLE_LC_GROUP.assertion(throwable);
|
||||
throw OnErrorThrowable.from(throwable);
|
||||
}
|
||||
return storeObject;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Observable<TStoreObject> createStoreValueObservable(@NonNull final ObserveStrategy observeStrategy,
|
||||
@Nullable final Migration<TKey> migration,
|
||||
@Nullable final TObject defaultValue,
|
||||
@Nullable final Scheduler storeScheduler) {
|
||||
final Observable<TStoreObject> result = Observable
|
||||
.<TStoreObject>create(subscriber -> {
|
||||
try {
|
||||
if (migration != null) {
|
||||
migration.migrateToLatestVersion(key);
|
||||
}
|
||||
subscriber.onNext(store.loadObject(storeObjectClass, key));
|
||||
subscriber.onCompleted();
|
||||
} catch (final Store.StoreException storeException) {
|
||||
STORABLE_LC_GROUP.w(storeException, "Exception while trying to get value of '%s' from store %s", key, store);
|
||||
subscriber.onError(storeException);
|
||||
} catch (final Migration.MigrationException migrationException) {
|
||||
STORABLE_LC_GROUP.assertion(migrationException);
|
||||
subscriber.onError(migrationException);
|
||||
} catch (final RuntimeException throwable) {
|
||||
final long cacheTimeMillis) {
|
||||
final Observable<TStoreObject> result = (migration != null
|
||||
? migration.migrateToLatestVersion(key).subscribeOn(scheduler)
|
||||
: Completable.complete())
|
||||
.andThen(store.loadObject(storeObjectType, key).toObservable().subscribeOn(scheduler))
|
||||
.doOnError(throwable -> {
|
||||
if (throwable instanceof RuntimeException) {
|
||||
STORABLE_LC_GROUP.assertion(throwable);
|
||||
} else {
|
||||
STORABLE_LC_GROUP.w(throwable, "Exception while trying to load value of '%s' from store %s", key, store);
|
||||
}
|
||||
})
|
||||
.subscribeOn(storeScheduler != null ? storeScheduler : Schedulers.io())
|
||||
.concatWith(newStoreValueEvent)
|
||||
.map(storeObject -> returnDefaultValueIfNull(storeObject, defaultValue));
|
||||
return observeStrategy == ObserveStrategy.CACHE_STORE_VALUE ? result.replay(1).refCount() : result;
|
||||
return observeStrategy == ObserveStrategy.CACHE_STORE_VALUE || observeStrategy == ObserveStrategy.CACHE_STORE_AND_ACTUAL_VALUE
|
||||
? Observable.create(new OnSubscribeRefCountWithCacheTime<>(result.replay(1), cacheTimeMillis, TimeUnit.MILLISECONDS))
|
||||
: result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Observable<TObject> createValueObservable(@NonNull final Observable<TStoreObject> storeValueObservable,
|
||||
@NonNull final ObserveStrategy observeStrategy,
|
||||
@Nullable final Scheduler storeScheduler) {
|
||||
final long cacheTimeMillis) {
|
||||
final Observable<TObject> result = storeValueObservable
|
||||
.map(storeObject -> {
|
||||
try {
|
||||
return converter.toObject(objectClass, storeObjectClass, storeObject);
|
||||
} catch (final Converter.ConversionException exception) {
|
||||
STORABLE_LC_GROUP.w(exception, "Exception while converting value of '%s' from '%s' from store %s",
|
||||
key, storeObject, store);
|
||||
throw OnErrorThrowable.from(exception);
|
||||
} catch (final RuntimeException throwable) {
|
||||
STORABLE_LC_GROUP.assertion(throwable);
|
||||
throw OnErrorThrowable.from(throwable);
|
||||
}
|
||||
})
|
||||
.subscribeOn(storeScheduler != null ? storeScheduler : Schedulers.computation());
|
||||
|
||||
return observeStrategy == ObserveStrategy.CACHE_ACTUAL_VALUE ? result.replay(1).refCount() : result;
|
||||
.switchMap(storeObject -> Observable
|
||||
.fromCallable(() -> converter.toObject(objectType, storeObjectType, storeObject))
|
||||
.subscribeOn(scheduler)
|
||||
.doOnError(throwable -> {
|
||||
if (throwable instanceof RuntimeException) {
|
||||
STORABLE_LC_GROUP.assertion(throwable);
|
||||
} else {
|
||||
STORABLE_LC_GROUP.w(throwable, "Exception while trying to converting value of '%s' from store %s by %s",
|
||||
key, storeObject, store, converter);
|
||||
}
|
||||
}));
|
||||
return observeStrategy == ObserveStrategy.CACHE_ACTUAL_VALUE || observeStrategy == ObserveStrategy.CACHE_STORE_AND_ACTUAL_VALUE
|
||||
? Observable.create(new OnSubscribeRefCountWithCacheTime<>(result.replay(1), cacheTimeMillis, TimeUnit.MILLISECONDS))
|
||||
: result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -187,23 +190,23 @@ public class Storable<TKey, TObject, TStoreObject> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns class of actual object.
|
||||
* Returns type of actual object.
|
||||
*
|
||||
* @return Class of actual object.
|
||||
* @return Type of actual object.
|
||||
*/
|
||||
@NonNull
|
||||
public Class<TObject> getObjectClass() {
|
||||
return objectClass;
|
||||
public Type getObjectType() {
|
||||
return objectType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class of store object.
|
||||
* Returns type of store object.
|
||||
*
|
||||
* @return Class of store object.
|
||||
* @return Type of store object.
|
||||
*/
|
||||
@NonNull
|
||||
public Class<TStoreObject> getStoreObjectClass() {
|
||||
return storeObjectClass;
|
||||
public Type getStoreObjectType() {
|
||||
return storeObjectType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -226,68 +229,81 @@ public class Storable<TKey, TObject, TStoreObject> {
|
|||
return converter;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Completable internalSet(@Nullable final TObject newValue, final boolean checkForEqualityBeforeSet) {
|
||||
return (checkForEqualityBeforeSet ? storeValueObservable.first() : Observable.just(null))
|
||||
.switchMap(oldStoreValue -> Observable
|
||||
.fromCallable(() -> converter.toStoreObject(objectType, storeObjectType, newValue))
|
||||
.subscribeOn(scheduler)
|
||||
.switchMap(newStoreValue -> {
|
||||
if (checkForEqualityBeforeSet && ObjectUtils.equals(newStoreValue, oldStoreValue)) {
|
||||
return Observable.empty();
|
||||
}
|
||||
return store.storeObject(storeObjectType, key, newStoreValue)
|
||||
.doOnCompleted(() -> {
|
||||
newStoreValueEvent.onNext(newStoreValue);
|
||||
if (checkForEqualityBeforeSet) {
|
||||
STORABLE_LC_GROUP.i("Value of '%s' changed from '%s' to '%s'", key, oldStoreValue, newStoreValue);
|
||||
} else {
|
||||
STORABLE_LC_GROUP.i("Value of '%s' force changed to '%s'", key, newStoreValue);
|
||||
}
|
||||
})
|
||||
.toObservable();
|
||||
}))
|
||||
.doOnError(throwable -> {
|
||||
if (throwable instanceof RuntimeException) {
|
||||
STORABLE_LC_GROUP.assertion(throwable);
|
||||
} else {
|
||||
STORABLE_LC_GROUP.w(throwable, "Exception while trying to store value of '%s' from store %s by %s",
|
||||
key, newValue, store, converter);
|
||||
}
|
||||
})
|
||||
.toCompletable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates observable which is async setting value to store.
|
||||
* NOTE: It could emit ONLY completed and errors events. It is not providing onNext event!
|
||||
* Errors won't be emitted if {@link #getStore()} implements {@link SafeStore} and {@link #getConverter()} implements {@link SafeConverter}.
|
||||
* It is not checking if stored value equals new value.
|
||||
* In result it will be faster to not get value from store and compare but it will emit item to {@link #observe()} subscribers.
|
||||
* NOTE: It could emit ONLY completed and errors events. It is not providing onNext event! //TODO: it's Completable :(
|
||||
*
|
||||
* @param newValue Value to set;
|
||||
* @return Observable of setting process.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<?> forceSet(@Nullable final TObject newValue) {
|
||||
return internalSet(newValue, false).toObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates observable which is async setting value to store.
|
||||
* It is checking if stored value equals new value.
|
||||
* In result it will take time to get value from store and compare
|
||||
* but it won't emit item to {@link #observe()} subscribers if stored value equals new value.
|
||||
* NOTE: It could emit ONLY completed and errors events. It is not providing onNext event! //TODO: it's Completable :(
|
||||
*
|
||||
* @param newValue Value to set;
|
||||
* @return Observable of setting process.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<?> set(@Nullable final TObject newValue) {
|
||||
return valueObservable
|
||||
.first()
|
||||
.switchMap(value -> ObjectUtils.equals(value, newValue)
|
||||
? Observable.empty()
|
||||
: Observable
|
||||
.<TStoreObject>create(subscriber -> {
|
||||
try {
|
||||
final TStoreObject storeObject = converter.toStoreObject(objectClass, storeObjectClass, newValue);
|
||||
store.storeObject(storeObjectClass, key, storeObject);
|
||||
newStoreValueEvent.onNext(storeObject);
|
||||
STORABLE_LC_GROUP.i("Value of '%s' changed from '%s' to '%s'", key, value, newValue);
|
||||
subscriber.onCompleted();
|
||||
} catch (final Converter.ConversionException conversionException) {
|
||||
STORABLE_LC_GROUP.w(conversionException, "Exception while converting value of '%s' from '%s' to store object",
|
||||
key, newValue, store);
|
||||
subscriber.onError(conversionException);
|
||||
} catch (final Store.StoreException storeException) {
|
||||
STORABLE_LC_GROUP.w(storeException, "Exception while trying to store value of '%s' to store %s", key, store);
|
||||
subscriber.onError(storeException);
|
||||
} catch (final RuntimeException throwable) {
|
||||
STORABLE_LC_GROUP.assertion(throwable);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting value in background. If error emits then it will raise assertion.
|
||||
*
|
||||
* @param newValue Value to set.
|
||||
*/
|
||||
public void setCalm(@Nullable final TObject newValue) {
|
||||
set(newValue).subscribe(Actions.empty(), STORABLE_LC_GROUP::assertion);
|
||||
return internalSet(newValue, true).toObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets value synchronously. You should NOT use this method normally. Use {@link #set(Object)} asynchronously instead.
|
||||
*
|
||||
* @param newValue Value to set;
|
||||
* @throws Store.StoreException Throws if {@link Store} threw exception during storing;
|
||||
* @throws Converter.ConversionException Throws if {@link Converter} threw exception during conversion;
|
||||
* @throws Migration.MigrationException Throws if {@link Migration} threw exception during migration.
|
||||
*/
|
||||
public void setSync(@Nullable final TObject newValue)
|
||||
throws Store.StoreException, Converter.ConversionException, Migration.MigrationException {
|
||||
final ObservableResult<?> setResult = RxUtils.executeSync(set(newValue));
|
||||
checkStorableObservableResult(setResult);
|
||||
@Deprecated
|
||||
//deprecation: it should be used for debug only and in very rare cases.
|
||||
public void setSync(@Nullable final TObject newValue) {
|
||||
set(newValue).toBlocking().subscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Observable which is emitting item on subscribe and every time when someone have changed value.
|
||||
* It could emit next and error events but not completed.
|
||||
* Errors won't be emitted if {@link #getStore()} implements {@link SafeStore} and {@link #getConverter()} implements {@link SafeConverter}.
|
||||
*
|
||||
* @return Returns observable of value.
|
||||
*/
|
||||
|
|
@ -297,9 +313,8 @@ public class Storable<TKey, TObject, TStoreObject> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns Observable which is emitting only one item on subscribe.
|
||||
* Returns Observable which is emitting only one item on subscribe. //TODO: it's Single :(
|
||||
* It could emit next and error events but not completed.
|
||||
* Errors won't be emitted if {@link #getStore()} implements {@link SafeStore} and {@link #getConverter()} implements {@link SafeConverter}.
|
||||
*
|
||||
* @return Returns observable of value.
|
||||
*/
|
||||
|
|
@ -312,38 +327,16 @@ public class Storable<TKey, TObject, TStoreObject> {
|
|||
* Gets value synchronously. You should NOT use this method normally. Use {@link #get()} or {@link #observe()} asynchronously instead.
|
||||
*
|
||||
* @return Returns value;
|
||||
* @throws Store.StoreException Throws if {@link Store} threw exception during getting from store;
|
||||
* @throws Converter.ConversionException Throws if {@link Converter} threw exception during conversion;
|
||||
* @throws Migration.MigrationException Throws if {@link Migration} threw exception during migration.
|
||||
*/
|
||||
@Deprecated
|
||||
//deprecation: it should be used for debug only and in very rare cases.
|
||||
@Nullable
|
||||
public TObject getSync()
|
||||
throws Store.StoreException, Converter.ConversionException, Migration.MigrationException {
|
||||
final ObservableResult<TObject> getResult = RxUtils.executeSync(get());
|
||||
checkStorableObservableResult(getResult);
|
||||
if (getResult.getItems().size() != 1) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
return getResult.getItems().get(0);
|
||||
}
|
||||
|
||||
private void checkStorableObservableResult(@NonNull final ObservableResult<?> result)
|
||||
throws Store.StoreException, Converter.ConversionException, Migration.MigrationException {
|
||||
for (final Throwable throwable : result.getErrors()) {
|
||||
if (throwable instanceof Store.StoreException) {
|
||||
throw (Store.StoreException) throwable;
|
||||
}
|
||||
if (throwable instanceof Converter.ConversionException) {
|
||||
throw (Converter.ConversionException) throwable;
|
||||
}
|
||||
if (throwable instanceof Migration.MigrationException) {
|
||||
throw (Migration.MigrationException) throwable;
|
||||
}
|
||||
}
|
||||
public TObject getSync() {
|
||||
return get().toBlocking().first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that is representing strategy of observing item from store.
|
||||
* Enum that is representing strategy of observing item from store.
|
||||
*/
|
||||
public enum ObserveStrategy {
|
||||
|
||||
|
|
@ -358,10 +351,19 @@ public class Storable<TKey, TObject, TStoreObject> {
|
|||
CACHE_STORE_VALUE,
|
||||
/**
|
||||
* Caching value so it won't spend time for getting value from {@link #getStore()} and converts it by {@link #getConverter()}.
|
||||
* Do not use such strategy if object could be big (like byte-array of file).
|
||||
* But it will take time for getting value from {@link #getStore()} to set value.
|
||||
* Do not use such strategy if object could be big (like Bitmap or long string).
|
||||
* Do not use such strategy if object is mutable because multiple subscribers could then change it's state.
|
||||
*/
|
||||
CACHE_ACTUAL_VALUE
|
||||
CACHE_ACTUAL_VALUE,
|
||||
/**
|
||||
* Caching value so it won't spend time for getting value from {@link #getStore()} and converts it by {@link #getConverter()}.
|
||||
* It won't take time or getting value from {@link #getStore()} to set value.
|
||||
* Do not use such strategy if store object could be big (like byte-array of file).
|
||||
* Do not use such strategy if object could be big (like Bitmap or long string).
|
||||
* Do not use such strategy if object is mutable because multiple subscribers could then change it's state.
|
||||
*/
|
||||
CACHE_STORE_AND_ACTUAL_VALUE
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -377,112 +379,81 @@ public class Storable<TKey, TObject, TStoreObject> {
|
|||
@NonNull
|
||||
protected final TKey key;
|
||||
@NonNull
|
||||
protected final Class<TObject> objectClass;
|
||||
protected final Type objectType;
|
||||
@NonNull
|
||||
private final Type storeObjectType;
|
||||
@NonNull
|
||||
private final Store<TKey, TStoreObject> store;
|
||||
@NonNull
|
||||
private final Converter<TObject, TStoreObject> converter;
|
||||
@Nullable
|
||||
private Class<TStoreObject> storeObjectClass;
|
||||
@Nullable
|
||||
private Store<TKey, TStoreObject> store;
|
||||
@Nullable
|
||||
private Converter<TObject, TStoreObject> converter;
|
||||
@Nullable
|
||||
protected final ObserveStrategy observeStrategy;
|
||||
private ObserveStrategy observeStrategy;
|
||||
@Nullable
|
||||
private Migration<TKey> migration;
|
||||
@Nullable
|
||||
private TObject defaultValue;
|
||||
@Nullable
|
||||
protected final Scheduler storeScheduler;
|
||||
private Scheduler storeScheduler;
|
||||
private long cacheTimeMillis;
|
||||
|
||||
protected BuilderCore(@NonNull final TKey key,
|
||||
@NonNull final Class<TObject> objectClass,
|
||||
@Nullable final ObserveStrategy observeStrategy,
|
||||
@Nullable final Scheduler storeScheduler) {
|
||||
this(key, objectClass, null, null, null, observeStrategy, null, null, storeScheduler);
|
||||
@NonNull final Type objectType,
|
||||
@NonNull final Type storeObjectType,
|
||||
@NonNull final Store<TKey, TStoreObject> store,
|
||||
@NonNull final Converter<TObject, TStoreObject> converter) {
|
||||
this(key, objectType, storeObjectType, store, converter, null, null, null, null, DEFAULT_CACHE_TIME_MILLIS);
|
||||
}
|
||||
|
||||
protected BuilderCore(@NonNull final BuilderCore<TKey, TObject, TStoreObject> sourceBuilder) {
|
||||
this(sourceBuilder.key, sourceBuilder.objectClass, sourceBuilder.storeObjectClass,
|
||||
this(sourceBuilder.key, sourceBuilder.objectType, sourceBuilder.storeObjectType,
|
||||
sourceBuilder.store, sourceBuilder.converter, sourceBuilder.observeStrategy,
|
||||
sourceBuilder.migration, sourceBuilder.defaultValue, sourceBuilder.storeScheduler);
|
||||
sourceBuilder.migration, sourceBuilder.defaultValue, sourceBuilder.storeScheduler, sourceBuilder.cacheTimeMillis);
|
||||
}
|
||||
|
||||
@SuppressWarnings("CPD-START")
|
||||
//CPD: it is ok that builder copy-pasted parent constructor parameters
|
||||
@SuppressWarnings({"PMD.ExcessiveParameterList", "CPD-START"})
|
||||
//CPD: it is same code as constructor of Storable
|
||||
//ExcessiveParameterList: that's why we are using builder to create it
|
||||
private BuilderCore(@NonNull final TKey key,
|
||||
@NonNull final Class<TObject> objectClass,
|
||||
@Nullable final Class<TStoreObject> storeObjectClass,
|
||||
@Nullable final Store<TKey, TStoreObject> store,
|
||||
@Nullable final Converter<TObject, TStoreObject> converter,
|
||||
@NonNull final Type objectType,
|
||||
@NonNull final Type storeObjectType,
|
||||
@NonNull final Store<TKey, TStoreObject> store,
|
||||
@NonNull final Converter<TObject, TStoreObject> converter,
|
||||
@Nullable final ObserveStrategy observeStrategy,
|
||||
@Nullable final Migration<TKey> migration,
|
||||
@Nullable final TObject defaultValue,
|
||||
@Nullable final Scheduler storeScheduler) {
|
||||
@Nullable final Scheduler storeScheduler,
|
||||
final long cacheTimeMillis) {
|
||||
this.key = key;
|
||||
this.objectClass = objectClass;
|
||||
this.storeObjectClass = storeObjectClass;
|
||||
this.objectType = objectType;
|
||||
this.storeObjectType = storeObjectType;
|
||||
this.store = store;
|
||||
this.converter = converter;
|
||||
this.observeStrategy = observeStrategy;
|
||||
this.migration = migration;
|
||||
this.defaultValue = defaultValue;
|
||||
this.storeScheduler = storeScheduler;
|
||||
this.cacheTimeMillis = cacheTimeMillis;
|
||||
}
|
||||
|
||||
@SuppressWarnings("CPD-END")
|
||||
@Nullable
|
||||
public Class<TStoreObject> getStoreObjectClass() {
|
||||
return storeObjectClass;
|
||||
protected void setStoreSchedulerInternal(@Nullable final Scheduler storeScheduler) {
|
||||
this.storeScheduler = storeScheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link Store} where store class representation of object is storing.
|
||||
*
|
||||
* @return Store.
|
||||
*/
|
||||
@Nullable
|
||||
public Store<TKey, TStoreObject> getStore() {
|
||||
return store;
|
||||
}
|
||||
|
||||
protected void setStoreInternal(@NonNull final Class<TStoreObject> storeObjectClass,
|
||||
@NonNull final Store<TKey, TStoreObject> store,
|
||||
@NonNull final Converter<TObject, TStoreObject> converter) {
|
||||
this.storeObjectClass = storeObjectClass;
|
||||
this.store = store;
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link Converter} to convert values from store class to actual and back.
|
||||
*
|
||||
* @return Converter.
|
||||
*/
|
||||
@Nullable
|
||||
public Converter<TObject, TStoreObject> getConverter() {
|
||||
return converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link Migration} to migrate values from specific version to latest version.
|
||||
*
|
||||
* @return Migration.
|
||||
*/
|
||||
@Nullable
|
||||
public Migration<TKey> getMigration() {
|
||||
return migration;
|
||||
protected void setObserveStrategyInternal(@Nullable final ObserveStrategy observeStrategy) {
|
||||
this.observeStrategy = observeStrategy;
|
||||
}
|
||||
|
||||
protected void setMigrationInternal(@NonNull final Migration<TKey> migration) {
|
||||
this.migration = migration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns value which will be returned instead of null.
|
||||
*
|
||||
* @return Default value.
|
||||
*/
|
||||
protected void setCacheTimeInternal(final long cacheTime, @NonNull final TimeUnit timeUnit) {
|
||||
this.cacheTimeMillis = timeUnit.toMillis(cacheTime);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TObject getDefaultValue() {
|
||||
protected TObject getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
|
@ -502,59 +473,49 @@ public class Storable<TKey, TObject, TStoreObject> {
|
|||
public static class Builder<TKey, TObject, TStoreObject> extends BuilderCore<TKey, TObject, TStoreObject> {
|
||||
|
||||
public Builder(@NonNull final TKey key,
|
||||
@NonNull final Class<TObject> objectClass) {
|
||||
super(key, objectClass, null, null);
|
||||
}
|
||||
|
||||
public Builder(@NonNull final TKey key,
|
||||
@NonNull final Class<TObject> objectClass,
|
||||
@NonNull final ObserveStrategy observeStrategy) {
|
||||
super(key, objectClass, observeStrategy, null);
|
||||
}
|
||||
|
||||
public Builder(@NonNull final TKey key,
|
||||
@NonNull final Class<TObject> objectClass,
|
||||
@NonNull final Scheduler storeScheduler) {
|
||||
super(key, objectClass, null, storeScheduler);
|
||||
}
|
||||
|
||||
public Builder(@NonNull final TKey key,
|
||||
@NonNull final Class<TObject> objectClass,
|
||||
@NonNull final ObserveStrategy observeStrategy,
|
||||
@NonNull final Scheduler storeScheduler) {
|
||||
super(key, objectClass, observeStrategy, storeScheduler);
|
||||
@NonNull final Type objectType,
|
||||
@NonNull final Type storeObjectType,
|
||||
@NonNull final Store<TKey, TStoreObject> store,
|
||||
@NonNull final Converter<TObject, TStoreObject> converter) {
|
||||
super(key, objectType, storeObjectType, store, converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets store and converter.
|
||||
* Sets specific {@link Scheduler} to store/load/convert values on it.
|
||||
*
|
||||
* @param storeObjectClass Class of store object,
|
||||
* @param store Store to store objects into;
|
||||
* @param converter Converter to convert values from store class to actual class and back;
|
||||
* @param storeScheduler Scheduler;
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder<TKey, TObject, TStoreObject> setStore(@NonNull final Class<TStoreObject> storeObjectClass,
|
||||
@NonNull final Store<TKey, TStoreObject> store,
|
||||
@NonNull final Converter<TObject, TStoreObject> converter) {
|
||||
setStoreInternal(storeObjectClass, store, converter);
|
||||
public Builder<TKey, TObject, TStoreObject> setStoreScheduler(@Nullable final Scheduler storeScheduler) {
|
||||
setStoreSchedulerInternal(storeScheduler);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets safe store and converter so in such {@link Storable} it is not needed to specify onError action
|
||||
* when subscribing to {@link Storable#set(Object)}, {@link Storable#get()} or {@link Storable#observe()} methods.
|
||||
* Sets specific {@link ObserveStrategy} to cache value in memory in specific way.
|
||||
*
|
||||
* @param storeObjectClass Class of store object,
|
||||
* @param store Safe store that is not throwing exceptions;
|
||||
* @param converter Safe converter that is not throwing exceptions;
|
||||
* @param observeStrategy ObserveStrategy;
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public SafeStorableBuilder<TKey, TObject, TStoreObject> setSafeStore(@NonNull final Class<TStoreObject> storeObjectClass,
|
||||
@NonNull final SafeStore<TKey, TStoreObject> store,
|
||||
@NonNull final SafeConverter<TObject, TStoreObject> converter) {
|
||||
return new SafeStorableBuilder<>(this, storeObjectClass, store, converter);
|
||||
public Builder<TKey, TObject, TStoreObject> setObserveStrategy(@Nullable final ObserveStrategy observeStrategy) {
|
||||
setObserveStrategyInternal(observeStrategy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets cache time for while value that cached by {@link #setObserveStrategy(ObserveStrategy)} will be in memory after everyone unsubscribe.
|
||||
* It is important for example for cases when user switches between screens and hide/open app very fast.
|
||||
*
|
||||
* @param cacheTime Cache time value;
|
||||
* @param timeUnit Cache time units.
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder<TKey, TObject, TStoreObject> setCacheTime(final long cacheTime, @NonNull final TimeUnit timeUnit) {
|
||||
setCacheTimeInternal(cacheTime, timeUnit);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -564,8 +525,9 @@ public class Storable<TKey, TObject, TStoreObject> {
|
|||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public MigratableStorableBuilder<TKey, TObject, TStoreObject> setMigration(@NonNull final Migration<TKey> migration) {
|
||||
return new MigratableStorableBuilder<>(this, migration);
|
||||
public Builder<TKey, TObject, TStoreObject> setMigration(@NonNull final Migration<TKey> migration) {
|
||||
setMigrationInternal(migration);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -22,6 +22,11 @@ package ru.touchin.roboswag.core.observables.storable;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import rx.Completable;
|
||||
import rx.Single;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 04/10/2015.
|
||||
* Interface that is providing access to abstract object which can store (e.g. in file, database, remote store)
|
||||
|
|
@ -37,41 +42,28 @@ public interface Store<TKey, TStoreObject> {
|
|||
*
|
||||
* @param key Key which is finding in store;
|
||||
* @return True if key have found in store.
|
||||
* @throws StoreException Exception during getting access to store.
|
||||
*/
|
||||
boolean contains(@NonNull TKey key) throws StoreException;
|
||||
@NonNull
|
||||
Single<Boolean> contains(@NonNull TKey key);
|
||||
|
||||
/**
|
||||
* Stores object to store with related key.
|
||||
*
|
||||
* @param storeObjectClass Class of object to store;
|
||||
* @param key Key related to object;
|
||||
* @param storeObject Object to store;
|
||||
* @throws StoreException Exception during getting access to store.
|
||||
* @param storeObjectType Type of object to store;
|
||||
* @param key Key related to object;
|
||||
* @param storeObject Object to store;
|
||||
*/
|
||||
void storeObject(@NonNull Class<TStoreObject> storeObjectClass, @NonNull TKey key, @Nullable TStoreObject storeObject) throws StoreException;
|
||||
@NonNull
|
||||
Completable storeObject(@NonNull Type storeObjectType, @NonNull TKey key, @Nullable TStoreObject storeObject);
|
||||
|
||||
/**
|
||||
* Loads object from store by key.
|
||||
*
|
||||
* @param storeObjectClass Class of object to store;
|
||||
* @param key Key related to object;
|
||||
* @param storeObjectType Type of object to store;
|
||||
* @param key Key related to object;
|
||||
* @return Object from store found by key;
|
||||
* @throws StoreException Exception during getting access to store.
|
||||
*/
|
||||
@Nullable
|
||||
TStoreObject loadObject(@NonNull Class<TStoreObject> storeObjectClass, @NonNull TKey key) throws StoreException;
|
||||
|
||||
class StoreException extends Exception {
|
||||
|
||||
public StoreException(@NonNull final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public StoreException(@NonNull final String message, @NonNull final Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
|
||||
}
|
||||
@NonNull
|
||||
Single<TStoreObject> loadObject(@NonNull Type storeObjectType, @NonNull TKey key);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable.builders;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.Converter;
|
||||
import ru.touchin.roboswag.core.observables.storable.Migration;
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeConverter;
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeStore;
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.observables.storable.Store;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 15/05/2016.
|
||||
* Builder that is already contains not null migration.
|
||||
*
|
||||
* @param <TKey> Type of key to identify object;
|
||||
* @param <TObject> Type of actual object;
|
||||
* @param <TStoreObject> Type of store object. Could be same as {@link TObject}.
|
||||
*/
|
||||
public class MigratableStorableBuilder<TKey, TObject, TStoreObject> extends Storable.BuilderCore<TKey, TObject, TStoreObject> {
|
||||
|
||||
public MigratableStorableBuilder(@NonNull final Storable.Builder<TKey, TObject, TStoreObject> sourceBuilder,
|
||||
@NonNull final Migration<TKey> migration) {
|
||||
super(sourceBuilder);
|
||||
setMigrationInternal(migration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets store and converter.
|
||||
*
|
||||
* @param storeObjectClass Class of store object,
|
||||
* @param store Store to store objects into;
|
||||
* @param converter Converter to convert values from store class to actual class and back;
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public MigratableStorableBuilder<TKey, TObject, TStoreObject> setStore(@NonNull final Class<TStoreObject> storeObjectClass,
|
||||
@NonNull final Store<TKey, TStoreObject> store,
|
||||
@NonNull final Converter<TObject, TStoreObject> converter) {
|
||||
setStoreInternal(storeObjectClass, store, converter);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets safe store and converter so in such {@link Storable} it is not needed to specify onError action
|
||||
* when subscribing to {@link Storable#set(Object)}, {@link Storable#get()} or {@link Storable#observe()} methods.
|
||||
*
|
||||
* @param storeObjectClass Class of store object,
|
||||
* @param store Safe store that is not throwing exceptions;
|
||||
* @param converter Safe converter that is not throwing exceptions;
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public SafeMigratableStorableBuilder<TKey, TObject, TStoreObject> setSafeStore(
|
||||
@NonNull final Class<TStoreObject> storeObjectClass,
|
||||
@NonNull final SafeStore<TKey, TStoreObject> store,
|
||||
@NonNull final SafeConverter<TObject, TStoreObject> converter) {
|
||||
setStoreInternal(storeObjectClass, store, converter);
|
||||
return new SafeMigratableStorableBuilder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets value which will be returned instead of null.
|
||||
*
|
||||
* @param defaultValue Default value;
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public NonNullMigratableStorableBuilder<TKey, TObject, TStoreObject> setDefaultValue(@NonNull final TObject defaultValue) {
|
||||
setDefaultValueInternal(defaultValue);
|
||||
return new NonNullMigratableStorableBuilder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Building {@link Storable} object.
|
||||
*
|
||||
* @return New {@link Storable}.
|
||||
*/
|
||||
@NonNull
|
||||
public Storable<TKey, TObject, TStoreObject> build() {
|
||||
if (getMigration() == null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
return new Storable<>(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable.builders;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.Converter;
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeConverter;
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeStore;
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.observables.storable.Store;
|
||||
import ru.touchin.roboswag.core.observables.storable.concrete.NonNullStorable;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 15/05/2016.
|
||||
* Builder that is already contains not null migration and default value.
|
||||
*
|
||||
* @param <TKey> Type of key to identify object;
|
||||
* @param <TObject> Type of actual object;
|
||||
* @param <TStoreObject> Type of store object. Could be same as {@link TObject}.
|
||||
*/
|
||||
public class NonNullMigratableStorableBuilder<TKey, TObject, TStoreObject> extends Storable.BuilderCore<TKey, TObject, TStoreObject> {
|
||||
|
||||
public NonNullMigratableStorableBuilder(@NonNull final NonNullStorableBuilder<TKey, TObject, TStoreObject> sourceBuilder) {
|
||||
super(sourceBuilder);
|
||||
}
|
||||
|
||||
public NonNullMigratableStorableBuilder(@NonNull final MigratableStorableBuilder<TKey, TObject, TStoreObject> sourceBuilder) {
|
||||
super(sourceBuilder);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public NonNullMigratableStorableBuilder<TKey, TObject, TStoreObject> setStore(@NonNull final Class<TStoreObject> storeObjectClass,
|
||||
@NonNull final Store<TKey, TStoreObject> store,
|
||||
@NonNull final Converter<TObject, TStoreObject> converter) {
|
||||
setStoreInternal(storeObjectClass, store, converter);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets safe store and converter so in such {@link Storable} it is not needed to specify onError action
|
||||
* when subscribing to {@link Storable#set(Object)}, {@link Storable#get()} or {@link Storable#observe()} methods.
|
||||
*
|
||||
* @param storeObjectClass Class of store object,
|
||||
* @param store Safe store that is not throwing exceptions;
|
||||
* @param converter Safe converter that is not throwing exceptions;
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public NonNullSafeMigratableStorableBuilder<TKey, TObject, TStoreObject> setSafeStore(
|
||||
@NonNull final Class<TStoreObject> storeObjectClass,
|
||||
@NonNull final SafeStore<TKey, TStoreObject> store,
|
||||
@NonNull final SafeConverter<TObject, TStoreObject> converter) {
|
||||
setStoreInternal(storeObjectClass, store, converter);
|
||||
return new NonNullSafeMigratableStorableBuilder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Building {@link NonNullStorable} object.
|
||||
*
|
||||
* @return New {@link NonNullStorable}.
|
||||
*/
|
||||
@NonNull
|
||||
public NonNullStorable<TKey, TObject, TStoreObject> build() {
|
||||
if (getDefaultValue() == null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
if (getMigration() == null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
return new NonNullStorable<>(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable.builders;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeConverter;
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeStore;
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.observables.storable.concrete.NonNullSafeStorable;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 15/05/2016.
|
||||
* Builder with safe store and converter inside that is already contains not null migration and default value.
|
||||
*
|
||||
* @param <TKey> Type of key to identify object;
|
||||
* @param <TObject> Type of actual object;
|
||||
* @param <TStoreObject> Type of store object. Could be same as {@link TObject}.
|
||||
*/
|
||||
public class NonNullSafeMigratableStorableBuilder<TKey, TObject, TStoreObject> extends Storable.BuilderCore<TKey, TObject, TStoreObject> {
|
||||
|
||||
public NonNullSafeMigratableStorableBuilder(@NonNull final NonNullMigratableStorableBuilder<TKey, TObject, TStoreObject> sourceBuilder) {
|
||||
super(sourceBuilder);
|
||||
}
|
||||
|
||||
public NonNullSafeMigratableStorableBuilder(@NonNull final NonNullSafeStorableBuilder<TKey, TObject, TStoreObject> sourceBuilder) {
|
||||
super(sourceBuilder);
|
||||
}
|
||||
|
||||
public NonNullSafeMigratableStorableBuilder(@NonNull final SafeMigratableStorableBuilder<TKey, TObject, TStoreObject> sourceBuilder) {
|
||||
super(sourceBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Building {@link NonNullSafeStorable} object.
|
||||
*
|
||||
* @return New {@link NonNullSafeStorable}.
|
||||
*/
|
||||
@NonNull
|
||||
public NonNullSafeStorable<TKey, TObject, TStoreObject> build() {
|
||||
if (!(getStore() instanceof SafeStore) || !(getConverter() instanceof SafeConverter)) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
if (getDefaultValue() == null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
if (getMigration() == null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
return new NonNullSafeStorable<>(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable.builders;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.Migration;
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeConverter;
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeStore;
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.observables.storable.concrete.NonNullSafeStorable;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 15/05/2016.
|
||||
* Builder with safe store and converter inside that is already contains not null default value.
|
||||
*
|
||||
* @param <TKey> Type of key to identify object;
|
||||
* @param <TObject> Type of actual object;
|
||||
* @param <TStoreObject> Type of store object. Could be same as {@link TObject}.
|
||||
*/
|
||||
public class NonNullSafeStorableBuilder<TKey, TObject, TStoreObject> extends Storable.BuilderCore<TKey, TObject, TStoreObject> {
|
||||
|
||||
public NonNullSafeStorableBuilder(@NonNull final NonNullStorableBuilder<TKey, TObject, TStoreObject> sourceBuilder) {
|
||||
super(sourceBuilder);
|
||||
}
|
||||
|
||||
public NonNullSafeStorableBuilder(@NonNull final SafeStorableBuilder<TKey, TObject, TStoreObject> sourceBuilder) {
|
||||
super(sourceBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets specific {@link Migration} to migrate values from specific version to latest version.
|
||||
*
|
||||
* @param migration Migration;
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public NonNullSafeMigratableStorableBuilder<TKey, TObject, TStoreObject> setMigration(@NonNull final Migration<TKey> migration) {
|
||||
setMigrationInternal(migration);
|
||||
return new NonNullSafeMigratableStorableBuilder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Building {@link NonNullSafeStorable} object.
|
||||
*
|
||||
* @return New {@link NonNullSafeStorable}.
|
||||
*/
|
||||
@NonNull
|
||||
public NonNullSafeStorable<TKey, TObject, TStoreObject> build() {
|
||||
if (!(getStore() instanceof SafeStore) || !(getConverter() instanceof SafeConverter)) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
if (getDefaultValue() == null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
return new NonNullSafeStorable<>(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -20,15 +20,15 @@
|
|||
package ru.touchin.roboswag.core.observables.storable.builders;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.Converter;
|
||||
import ru.touchin.roboswag.core.observables.storable.Migration;
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeConverter;
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeStore;
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.observables.storable.Store;
|
||||
import ru.touchin.roboswag.core.observables.storable.concrete.NonNullStorable;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
import rx.Scheduler;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 15/05/2016.
|
||||
|
|
@ -47,36 +47,42 @@ public class NonNullStorableBuilder<TKey, TObject, TStoreObject> extends Storabl
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets store and converter.
|
||||
* Sets specific {@link Scheduler} to store/load/convert values on it.
|
||||
*
|
||||
* @param storeObjectClass Class of store object,
|
||||
* @param store Store to store objects into;
|
||||
* @param converter Converter to convert values from store class to actual class and back;
|
||||
* @param storeScheduler Scheduler;
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public NonNullStorableBuilder<TKey, TObject, TStoreObject> setStore(@NonNull final Class<TStoreObject> storeObjectClass,
|
||||
@NonNull final Store<TKey, TStoreObject> store,
|
||||
@NonNull final Converter<TObject, TStoreObject> converter) {
|
||||
setStoreInternal(storeObjectClass, store, converter);
|
||||
public NonNullStorableBuilder<TKey, TObject, TStoreObject> setStoreScheduler(@Nullable final Scheduler storeScheduler) {
|
||||
setStoreSchedulerInternal(storeScheduler);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets safe store and converter so in such {@link Storable} it is not needed to specify onError action
|
||||
* when subscribing to {@link Storable#set(Object)}, {@link Storable#get()} or {@link Storable#observe()} methods.
|
||||
* Sets specific {@link Storable.ObserveStrategy} to cache value in memory in specific way.
|
||||
*
|
||||
* @param storeObjectClass Class of store object,
|
||||
* @param store Safe store that is not throwing exceptions;
|
||||
* @param converter Safe converter that is not throwing exceptions;
|
||||
* @param observeStrategy ObserveStrategy;
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public NonNullSafeStorableBuilder<TKey, TObject, TStoreObject> setSafeStore(@NonNull final Class<TStoreObject> storeObjectClass,
|
||||
@NonNull final SafeStore<TKey, TStoreObject> store,
|
||||
@NonNull final SafeConverter<TObject, TStoreObject> converter) {
|
||||
setStoreInternal(storeObjectClass, store, converter);
|
||||
return new NonNullSafeStorableBuilder<>(this);
|
||||
public NonNullStorableBuilder<TKey, TObject, TStoreObject> setObserveStrategy(@Nullable final Storable.ObserveStrategy observeStrategy) {
|
||||
setObserveStrategyInternal(observeStrategy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets cache time for while value that cached by {@link #setObserveStrategy(Storable.ObserveStrategy)}
|
||||
* will be in memory after everyone unsubscribe.
|
||||
* It is important for example for cases when user switches between screens and hide/open app very fast.
|
||||
*
|
||||
* @param cacheTime Cache time value;
|
||||
* @param timeUnit Cache time units.
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public NonNullStorableBuilder<TKey, TObject, TStoreObject> setCacheTime(final long cacheTime, @NonNull final TimeUnit timeUnit) {
|
||||
setCacheTimeInternal(cacheTime, timeUnit);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -86,9 +92,9 @@ public class NonNullStorableBuilder<TKey, TObject, TStoreObject> extends Storabl
|
|||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public NonNullMigratableStorableBuilder<TKey, TObject, TStoreObject> setMigration(@NonNull final Migration<TKey> migration) {
|
||||
public NonNullStorableBuilder<TKey, TObject, TStoreObject> setMigration(@NonNull final Migration<TKey> migration) {
|
||||
setMigrationInternal(migration);
|
||||
return new NonNullMigratableStorableBuilder<>(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable.builders;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeConverter;
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeStore;
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.observables.storable.concrete.SafeStorable;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 15/05/2016.
|
||||
* Builder with safe store and converter inside that is already contains not null migration.
|
||||
*
|
||||
* @param <TKey> Type of key to identify object;
|
||||
* @param <TObject> Type of actual object;
|
||||
* @param <TStoreObject> Type of store object. Could be same as {@link TObject}.
|
||||
*/
|
||||
public class SafeMigratableStorableBuilder<TKey, TObject, TStoreObject> extends Storable.BuilderCore<TKey, TObject, TStoreObject> {
|
||||
|
||||
public SafeMigratableStorableBuilder(@NonNull final MigratableStorableBuilder<TKey, TObject, TStoreObject> sourceBuilder) {
|
||||
super(sourceBuilder);
|
||||
}
|
||||
|
||||
public SafeMigratableStorableBuilder(@NonNull final SafeStorableBuilder<TKey, TObject, TStoreObject> sourceBuilder) {
|
||||
super(sourceBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets value which will be returned instead of null.
|
||||
*
|
||||
* @param defaultValue Default value;
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public NonNullSafeMigratableStorableBuilder<TKey, TObject, TStoreObject> setDefaultValue(@NonNull final TObject defaultValue) {
|
||||
setDefaultValueInternal(defaultValue);
|
||||
return new NonNullSafeMigratableStorableBuilder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Building {@link SafeStorable} object.
|
||||
*
|
||||
* @return New {@link SafeStorable}.
|
||||
*/
|
||||
@NonNull
|
||||
public SafeStorable<TKey, TObject, TStoreObject> build() {
|
||||
if (!(getStore() instanceof SafeStore) || !(getConverter() instanceof SafeConverter)) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
if (getMigration() == null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
return new SafeStorable<>(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable.builders;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.Migration;
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeConverter;
|
||||
import ru.touchin.roboswag.core.observables.storable.SafeStore;
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.observables.storable.concrete.SafeStorable;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 15/05/2016.
|
||||
* Builder with safe store and converter inside.
|
||||
*
|
||||
* @param <TKey> Type of key to identify object;
|
||||
* @param <TObject> Type of actual object;
|
||||
* @param <TStoreObject> Type of store object. Could be same as {@link TObject}.
|
||||
*/
|
||||
public class SafeStorableBuilder<TKey, TObject, TStoreObject> extends Storable.BuilderCore<TKey, TObject, TStoreObject> {
|
||||
|
||||
public SafeStorableBuilder(@NonNull final Storable.Builder<TKey, TObject, TStoreObject> sourceBuilder,
|
||||
@NonNull final Class<TStoreObject> storeObjectClass,
|
||||
@NonNull final SafeStore<TKey, TStoreObject> store,
|
||||
@NonNull final SafeConverter<TObject, TStoreObject> converter) {
|
||||
super(sourceBuilder);
|
||||
setStoreInternal(storeObjectClass, store, converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets specific {@link Migration} to migrate values from specific version to latest version.
|
||||
*
|
||||
* @param migration Migration;
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public SafeMigratableStorableBuilder<TKey, TObject, TStoreObject> setMigration(@NonNull final Migration<TKey> migration) {
|
||||
setMigrationInternal(migration);
|
||||
return new SafeMigratableStorableBuilder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets value which will be returned instead of null.
|
||||
*
|
||||
* @param defaultValue Default value;
|
||||
* @return Builder that allows to specify other fields.
|
||||
*/
|
||||
@NonNull
|
||||
public NonNullSafeStorableBuilder<TKey, TObject, TStoreObject> setDefaultValue(@NonNull final TObject defaultValue) {
|
||||
setDefaultValueInternal(defaultValue);
|
||||
return new NonNullSafeStorableBuilder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Building {@link SafeStorable} object.
|
||||
*
|
||||
* @return New {@link SafeStorable}.
|
||||
*/
|
||||
@NonNull
|
||||
public SafeStorable<TKey, TObject, TStoreObject> build() {
|
||||
if (!(getStore() instanceof SafeStore) || !(getConverter() instanceof SafeConverter)) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
return new SafeStorable<>(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable.concrete;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.Converter;
|
||||
import ru.touchin.roboswag.core.observables.storable.Migration;
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.observables.storable.Store;
|
||||
import rx.Observable;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 20/12/2016.
|
||||
* List wrapper of {@link Storable}.
|
||||
*
|
||||
* @param <TKey> Type of key to identify object;
|
||||
* @param <TItemObject> Type of items in actual list object;
|
||||
* @param <TStoreObject> Type of store object.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "CPD-START"})
|
||||
public class ListStorable<TKey, TItemObject, TStoreObject> {
|
||||
|
||||
@NonNull
|
||||
private final Storable<TKey, List, TStoreObject> storable;
|
||||
|
||||
public ListStorable(@NonNull final Storable<TKey, List, TStoreObject> storable) {
|
||||
this.storable = storable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#get()}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<List<TItemObject>> get() {
|
||||
return storable.get().map(list -> (List<TItemObject>) list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#observe()}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<List<TItemObject>> observe() {
|
||||
return storable.observe().map(list -> (List<TItemObject>) list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#set(Object)}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<?> set(@Nullable final List<TItemObject> list) {
|
||||
return storable.set(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#setCalm(Object)}.
|
||||
*/
|
||||
public void setCalm(@Nullable final List<TItemObject> list) {
|
||||
storable.setCalm(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#getSync()}.
|
||||
*/
|
||||
@Nullable
|
||||
public List<TItemObject> getSync()
|
||||
throws Store.StoreException, Converter.ConversionException, Migration.MigrationException {
|
||||
return (List<TItemObject>) storable.getSync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#setSync(Object)}.
|
||||
*/
|
||||
public void setSync(@Nullable final List<TItemObject> list)
|
||||
throws Store.StoreException, Converter.ConversionException, Migration.MigrationException {
|
||||
storable.setSync(list);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable.concrete;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.Converter;
|
||||
import ru.touchin.roboswag.core.observables.storable.Migration;
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.observables.storable.Store;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
import rx.Observable;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 20/12/2016.
|
||||
* List wrapper of {@link Storable} that should return not null value on get.
|
||||
* If this rules are violated then it will throw {@link ShouldNotHappenException}.
|
||||
*
|
||||
* @param <TKey> Type of key to identify object;
|
||||
* @param <TItemObject> Type of items in actual list object;
|
||||
* @param <TStoreObject> Type of store object.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "CPD-START"})
|
||||
public class NonNullListStorable<TKey, TItemObject, TStoreObject> {
|
||||
|
||||
@NonNull
|
||||
private final NonNullStorable<TKey, List, TStoreObject> storable;
|
||||
|
||||
public NonNullListStorable(@NonNull final NonNullStorable<TKey, List, TStoreObject> storable) {
|
||||
this.storable = storable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#get()}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<List<TItemObject>> get() {
|
||||
return storable.get().map(list -> (List<TItemObject>) list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#observe()}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<List<TItemObject>> observe() {
|
||||
return storable.observe().map(list -> (List<TItemObject>) list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#set(Object)}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<?> set(@Nullable final List<TItemObject> list) {
|
||||
return storable.set(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#setCalm(Object)}.
|
||||
*/
|
||||
public void setCalm(@Nullable final List<TItemObject> list) {
|
||||
storable.setCalm(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#getSync()}.
|
||||
*/
|
||||
@NonNull
|
||||
public List<TItemObject> getSync()
|
||||
throws Store.StoreException, Converter.ConversionException, Migration.MigrationException {
|
||||
return (List<TItemObject>) storable.getSync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#setSync(Object)}.
|
||||
*/
|
||||
public void setSync(@Nullable final List<TItemObject> list)
|
||||
throws Store.StoreException, Converter.ConversionException, Migration.MigrationException {
|
||||
storable.setSync(list);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable.concrete;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
import rx.Observable;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 20/12/2016.
|
||||
* List wrapper of {@link Storable} that should not throw exceptions on set or get and return not null value on get.
|
||||
* If this rules are violated then it will throw {@link ShouldNotHappenException}.
|
||||
*
|
||||
* @param <TKey> Type of key to identify object;
|
||||
* @param <TItemObject> Type of items in actual list object;
|
||||
* @param <TStoreObject> Type of store object.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "CPD-START"})
|
||||
public class NonNullSafeListStorable<TKey, TItemObject, TStoreObject> {
|
||||
|
||||
@NonNull
|
||||
private final NonNullSafeStorable<TKey, List, TStoreObject> storable;
|
||||
|
||||
public NonNullSafeListStorable(@NonNull final NonNullSafeStorable<TKey, List, TStoreObject> storable) {
|
||||
this.storable = storable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#get()}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<List<TItemObject>> get() {
|
||||
return storable.get().map(list -> (List<TItemObject>) list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#observe()}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<List<TItemObject>> observe() {
|
||||
return storable.observe().map(list -> (List<TItemObject>) list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#set(Object)}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<?> set(@Nullable final List<TItemObject> list) {
|
||||
return storable.set(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#setCalm(Object)}.
|
||||
*/
|
||||
public void setCalm(@Nullable final List<TItemObject> list) {
|
||||
storable.setCalm(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#getSync()}.
|
||||
*/
|
||||
@NonNull
|
||||
public List<TItemObject> getSync() {
|
||||
return (List<TItemObject>) storable.getSync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#setSync(Object)}.
|
||||
*/
|
||||
public void setSync(@Nullable final List<TItemObject> list) {
|
||||
storable.setSync(list);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable.concrete;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.observables.storable.builders.NonNullSafeMigratableStorableBuilder;
|
||||
import ru.touchin.roboswag.core.observables.storable.builders.NonNullSafeStorableBuilder;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 04/10/2015.
|
||||
* {@link Storable} that should not throw exceptions on set or get and return not null value on get.
|
||||
* If this rules are violated then it will throw {@link ShouldNotHappenException}.
|
||||
*
|
||||
* @param <TKey> Type of key to identify object;
|
||||
* @param <TObject> Type of actual object;
|
||||
* @param <TStoreObject> Type of store object. Could be same as {@link TObject}.
|
||||
*/
|
||||
public class NonNullSafeStorable<TKey, TObject, TStoreObject> extends Storable<TKey, TObject, TStoreObject> {
|
||||
|
||||
public NonNullSafeStorable(@NonNull final NonNullSafeStorableBuilder<TKey, TObject, TStoreObject> builderCore) {
|
||||
super(builderCore);
|
||||
}
|
||||
|
||||
public NonNullSafeStorable(@NonNull final NonNullSafeMigratableStorableBuilder<TKey, TObject, TStoreObject> builderCore) {
|
||||
super(builderCore);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TObject getSync() {
|
||||
final TObject result;
|
||||
try {
|
||||
result = super.getSync();
|
||||
} catch (final Exception exception) {
|
||||
throw new ShouldNotHappenException(exception);
|
||||
}
|
||||
if (result == null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSync(@Nullable final TObject newValue) {
|
||||
try {
|
||||
super.setSync(newValue);
|
||||
} catch (final Exception exception) {
|
||||
throw new ShouldNotHappenException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,11 +21,7 @@ package ru.touchin.roboswag.core.observables.storable.concrete;
|
|||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.Converter;
|
||||
import ru.touchin.roboswag.core.observables.storable.Migration;
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.observables.storable.Store;
|
||||
import ru.touchin.roboswag.core.observables.storable.builders.NonNullMigratableStorableBuilder;
|
||||
import ru.touchin.roboswag.core.observables.storable.builders.NonNullStorableBuilder;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
|
|
@ -44,13 +40,9 @@ public class NonNullStorable<TKey, TObject, TStoreObject> extends Storable<TKey,
|
|||
super(builderCore);
|
||||
}
|
||||
|
||||
public NonNullStorable(@NonNull final NonNullMigratableStorableBuilder<TKey, TObject, TStoreObject> builderCore) {
|
||||
super(builderCore);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TObject getSync() throws Store.StoreException, Converter.ConversionException, Migration.MigrationException {
|
||||
public TObject getSync() {
|
||||
final TObject result = super.getSync();
|
||||
if (result == null) {
|
||||
throw new ShouldNotHappenException();
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable.concrete;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
import rx.Observable;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 20/12/2016.
|
||||
* List wrapper of {@link Storable} that should not throw exceptions on set or get.
|
||||
* If this rules are violated then it will throw {@link ShouldNotHappenException}.
|
||||
*
|
||||
* @param <TKey> Type of key to identify object;
|
||||
* @param <TItemObject> Type of items in actual list object;
|
||||
* @param <TStoreObject> Type of store object.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "CPD-START"})
|
||||
public class SafeListStorable<TKey, TItemObject, TStoreObject> {
|
||||
|
||||
@NonNull
|
||||
private final SafeStorable<TKey, List, TStoreObject> storable;
|
||||
|
||||
public SafeListStorable(@NonNull final SafeStorable<TKey, List, TStoreObject> storable) {
|
||||
this.storable = storable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#get()}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<List<TItemObject>> get() {
|
||||
return storable.get().map(list -> (List<TItemObject>) list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#observe()}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<List<TItemObject>> observe() {
|
||||
return storable.observe().map(list -> (List<TItemObject>) list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#set(Object)}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<?> set(@Nullable final List<TItemObject> list) {
|
||||
return storable.set(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#setCalm(Object)}.
|
||||
*/
|
||||
public void setCalm(@Nullable final List<TItemObject> list) {
|
||||
storable.setCalm(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#getSync()}.
|
||||
*/
|
||||
@Nullable
|
||||
public List<TItemObject> getSync() {
|
||||
return (List<TItemObject>) storable.getSync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link Storable#setSync(Object)}.
|
||||
*/
|
||||
public void setSync(@Nullable final List<TItemObject> list) {
|
||||
storable.setSync(list);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 ru.touchin.roboswag.core.observables.storable.concrete;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import ru.touchin.roboswag.core.observables.storable.Storable;
|
||||
import ru.touchin.roboswag.core.observables.storable.builders.SafeMigratableStorableBuilder;
|
||||
import ru.touchin.roboswag.core.observables.storable.builders.SafeStorableBuilder;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 04/10/2015.
|
||||
* {@link Storable} that should not throw exceptions on set or get.
|
||||
* If this rules are violated then it will throw {@link ShouldNotHappenException}.
|
||||
*
|
||||
* @param <TKey> Type of key to identify object;
|
||||
* @param <TObject> Type of actual object;
|
||||
* @param <TStoreObject> Type of store object. Could be same as {@link TObject}.
|
||||
*/
|
||||
public class SafeStorable<TKey, TObject, TStoreObject> extends Storable<TKey, TObject, TStoreObject> {
|
||||
|
||||
public SafeStorable(@NonNull final SafeStorableBuilder<TKey, TObject, TStoreObject> builderCore) {
|
||||
super(builderCore);
|
||||
}
|
||||
|
||||
public SafeStorable(@NonNull final SafeMigratableStorableBuilder<TKey, TObject, TStoreObject> builderCore) {
|
||||
super(builderCore);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TObject getSync() {
|
||||
try {
|
||||
return super.getSync();
|
||||
} catch (final Exception exception) {
|
||||
throw new ShouldNotHappenException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSync(@Nullable final TObject newValue) {
|
||||
try {
|
||||
super.setSync(newValue);
|
||||
} catch (final Exception exception) {
|
||||
throw new ShouldNotHappenException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue