From d22b0b34724f42007a30c498db15831b03243445 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 9 Jun 2020 21:52:53 +0200 Subject: [PATCH] Use DI for store injection --- .../android/di/component/AppComponent.java | 19 +++++--- ...Module.java => AndroidDatabaseModule.java} | 23 +-------- .../di/module/AndroidSchedulersModule.java | 48 +++++++++++++++++++ ...ewModel.java => AndroidChatViewModel.java} | 22 ++++++--- .../android/ui/chat/ChatActivity.java | 18 +++---- .../roster/contacts/ContactListViewModel.java | 8 ++-- cli/build.gradle | 2 - .../mercury_im/messenger/cli/MercuryCli.java | 1 - .../cli/di/component/CliComponent.java | 13 +++-- ...enceModule.java => CliDatabaseModule.java} | 19 +------- .../cli/di/module/CliSchedulersModule.java | 35 ++++++++++++++ .../repository/RxEntityCapsRepository.java | 10 ++-- domain/build.gradle | 1 + .../mercury_im/messenger/core/Messenger.java | 16 +++---- .../messenger/core/SchedulersFacade.java | 32 +++++++++---- .../data/repository/EntityCapsRepository.java | 3 ++ .../RxMercuryMessageStoreFactoryModule.java | 26 ++++++++++ .../RxMercuryRosterStoreFactoryModule.java | 22 +++++++++ .../core/di/module/ViewModelModule.java | 20 +++++--- .../{ => caps}/MercuryEntityCapsStore.java | 17 +++++-- .../{ => message}/MercuryMessageStore.java | 32 ++++++++----- .../message/MercuryMessageStoreFactory.java | 8 ++++ .../{ => roster}/MercuryRosterStore.java | 24 ++++++---- .../roster/MercuryRosterStoreFactory.java | 8 ++++ .../core/usecase/RosterStoreBinder.java | 22 +++------ .../messenger/core/util/ThreadUtils.java | 18 ------- .../viewmodel/accounts/AccountsViewModel.java | 20 +++----- .../viewmodel/accounts/LoginViewModel.java | 22 ++++----- .../core/viewmodel/chat/ChatViewModel.java | 20 ++++++++ .../core/xmpp/MercuryConnectionManager.java | 27 +++++++---- 30 files changed, 364 insertions(+), 192 deletions(-) rename app/src/main/java/org/mercury_im/messenger/android/di/module/{AndroidPersistenceModule.java => AndroidDatabaseModule.java} (65%) create mode 100644 app/src/main/java/org/mercury_im/messenger/android/di/module/AndroidSchedulersModule.java rename app/src/main/java/org/mercury_im/messenger/android/ui/chat/{ChatViewModel.java => AndroidChatViewModel.java} (86%) rename cli/src/main/java/org/mercury_im/messenger/cli/di/module/{CliPersistenceModule.java => CliDatabaseModule.java} (78%) create mode 100644 cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliSchedulersModule.java create mode 100644 domain/src/main/java/org/mercury_im/messenger/core/di/module/RxMercuryMessageStoreFactoryModule.java create mode 100644 domain/src/main/java/org/mercury_im/messenger/core/di/module/RxMercuryRosterStoreFactoryModule.java rename domain/src/main/java/org/mercury_im/messenger/core/store/{ => caps}/MercuryEntityCapsStore.java (81%) rename domain/src/main/java/org/mercury_im/messenger/core/store/{ => message}/MercuryMessageStore.java (80%) create mode 100644 domain/src/main/java/org/mercury_im/messenger/core/store/message/MercuryMessageStoreFactory.java rename domain/src/main/java/org/mercury_im/messenger/core/store/{ => roster}/MercuryRosterStore.java (92%) create mode 100644 domain/src/main/java/org/mercury_im/messenger/core/store/roster/MercuryRosterStoreFactory.java delete mode 100644 domain/src/main/java/org/mercury_im/messenger/core/util/ThreadUtils.java create mode 100644 domain/src/main/java/org/mercury_im/messenger/core/viewmodel/chat/ChatViewModel.java diff --git a/app/src/main/java/org/mercury_im/messenger/android/di/component/AppComponent.java b/app/src/main/java/org/mercury_im/messenger/android/di/component/AppComponent.java index abe1b91..f96bb3f 100644 --- a/app/src/main/java/org/mercury_im/messenger/android/di/component/AppComponent.java +++ b/app/src/main/java/org/mercury_im/messenger/android/di/component/AppComponent.java @@ -1,20 +1,23 @@ package org.mercury_im.messenger.android.di.component; import org.mercury_im.messenger.android.MercuryImApplication; +import org.mercury_im.messenger.android.di.module.AndroidDatabaseModule; +import org.mercury_im.messenger.android.di.module.AndroidSchedulersModule; +import org.mercury_im.messenger.core.di.module.RxMercuryMessageStoreFactoryModule; +import org.mercury_im.messenger.core.di.module.RxMercuryRosterStoreFactoryModule; import org.mercury_im.messenger.core.di.module.XmppTcpConnectionFactoryModule; import org.mercury_im.messenger.data.di.RepositoryModule; -import org.mercury_im.messenger.android.di.module.AndroidPersistenceModule; import org.mercury_im.messenger.android.di.module.AppModule; import org.mercury_im.messenger.core.di.module.ViewModelModule; import org.mercury_im.messenger.android.service.MercuryConnectionService; -import org.mercury_im.messenger.core.store.MercuryEntityCapsStore; +import org.mercury_im.messenger.core.store.caps.MercuryEntityCapsStore; import org.mercury_im.messenger.android.ui.MainActivity; import org.mercury_im.messenger.android.ui.account.AndroidAccountsViewModel; import org.mercury_im.messenger.android.ui.account.AndroidLoginViewModel; import org.mercury_im.messenger.android.ui.chat.ChatActivity; import org.mercury_im.messenger.android.ui.chat.ChatInputFragment; import org.mercury_im.messenger.android.ui.chat.ChatInputViewModel; -import org.mercury_im.messenger.android.ui.chat.ChatViewModel; +import org.mercury_im.messenger.android.ui.chat.AndroidChatViewModel; import org.mercury_im.messenger.android.ui.chatlist.ChatListViewModel; import org.mercury_im.messenger.android.ui.roster.contacts.ContactListViewModel; import org.mercury_im.messenger.android.ui.roster.contacts.detail.ContactDetailActivity; @@ -34,10 +37,13 @@ import dagger.Component; @Component( modules = { AppModule.class, - AndroidPersistenceModule.class, + AndroidDatabaseModule.class, + AndroidSchedulersModule.class, RepositoryModule.class, ViewModelModule.class, - XmppTcpConnectionFactoryModule.class + XmppTcpConnectionFactoryModule.class, + RxMercuryMessageStoreFactoryModule.class, + RxMercuryRosterStoreFactoryModule.class }) public interface AppComponent { @@ -62,7 +68,7 @@ public interface AppComponent { void inject(ContactListViewModel contactListViewModel); - void inject(ChatViewModel chatViewModel); + void inject(AndroidChatViewModel androidChatViewModel); void inject(ChatInputViewModel chatInputViewModel); @@ -85,6 +91,5 @@ public interface AppComponent { void inject(MercuryConnectionService service); - void inject(MercuryEntityCapsStore store); } diff --git a/app/src/main/java/org/mercury_im/messenger/android/di/module/AndroidPersistenceModule.java b/app/src/main/java/org/mercury_im/messenger/android/di/module/AndroidDatabaseModule.java similarity index 65% rename from app/src/main/java/org/mercury_im/messenger/android/di/module/AndroidPersistenceModule.java rename to app/src/main/java/org/mercury_im/messenger/android/di/module/AndroidDatabaseModule.java index 30e1d8d..9c26a3c 100644 --- a/app/src/main/java/org/mercury_im/messenger/android/di/module/AndroidPersistenceModule.java +++ b/app/src/main/java/org/mercury_im/messenger/android/di/module/AndroidDatabaseModule.java @@ -2,18 +2,13 @@ package org.mercury_im.messenger.android.di.module; import android.app.Application; -import org.mercury_im.messenger.data.model.Models; -import org.mercury_im.messenger.core.util.ThreadUtils; import org.mercury_im.messenger.BuildConfig; +import org.mercury_im.messenger.data.model.Models; -import javax.inject.Named; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; -import io.reactivex.Scheduler; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; import io.requery.Persistable; import io.requery.android.sqlite.DatabaseSource; import io.requery.reactivex.ReactiveEntityStore; @@ -23,7 +18,7 @@ import io.requery.sql.EntityDataStore; import io.requery.sql.TableCreationMode; @Module -public class AndroidPersistenceModule { +public class AndroidDatabaseModule { @Provides @Singleton @@ -36,18 +31,4 @@ public class AndroidPersistenceModule { Configuration configuration = source.getConfiguration(); return ReactiveSupport.toReactiveStore(new EntityDataStore<>(configuration)); } - - @Provides - @Named(value = ThreadUtils.SCHEDULER_IO) - @Singleton - static Scheduler provideDatabaseThread() { - return Schedulers.io(); - } - - @Provides - @Named(value = ThreadUtils.SCHEDULER_UI) - @Singleton - static Scheduler providerUIThread() { - return AndroidSchedulers.mainThread(); - } } diff --git a/app/src/main/java/org/mercury_im/messenger/android/di/module/AndroidSchedulersModule.java b/app/src/main/java/org/mercury_im/messenger/android/di/module/AndroidSchedulersModule.java new file mode 100644 index 0000000..a1a8bec --- /dev/null +++ b/app/src/main/java/org/mercury_im/messenger/android/di/module/AndroidSchedulersModule.java @@ -0,0 +1,48 @@ +package org.mercury_im.messenger.android.di.module; + +import android.app.Application; + +import org.mercury_im.messenger.core.SchedulersFacade; +import org.mercury_im.messenger.data.model.Models; +import org.mercury_im.messenger.BuildConfig; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; +import io.reactivex.Scheduler; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; +import io.requery.Persistable; +import io.requery.android.sqlite.DatabaseSource; +import io.requery.reactivex.ReactiveEntityStore; +import io.requery.reactivex.ReactiveSupport; +import io.requery.sql.Configuration; +import io.requery.sql.EntityDataStore; +import io.requery.sql.TableCreationMode; + +@Module +public class AndroidSchedulersModule { + + @Provides + @Named(value = SchedulersFacade.SCHEDULER_IO) + @Singleton + static Scheduler provideDatabaseThread() { + return Schedulers.io(); + } + + @Provides + @Named(value = SchedulersFacade.SCHEDULER_UI) + @Singleton + static Scheduler providerUIThread() { + return AndroidSchedulers.mainThread(); + } + + @Provides + @Named(value = SchedulersFacade.SCHEDULER_NEW_THREAD) + @Singleton + static Scheduler provideNewThread() { + return Schedulers.newThread(); + } +} diff --git a/app/src/main/java/org/mercury_im/messenger/android/ui/chat/ChatViewModel.java b/app/src/main/java/org/mercury_im/messenger/android/ui/chat/AndroidChatViewModel.java similarity index 86% rename from app/src/main/java/org/mercury_im/messenger/android/ui/chat/ChatViewModel.java rename to app/src/main/java/org/mercury_im/messenger/android/ui/chat/AndroidChatViewModel.java index 506b7e1..4c6cfca 100644 --- a/app/src/main/java/org/mercury_im/messenger/android/ui/chat/ChatViewModel.java +++ b/app/src/main/java/org/mercury_im/messenger/android/ui/chat/AndroidChatViewModel.java @@ -6,10 +6,12 @@ import androidx.lifecycle.ViewModel; import org.jxmpp.jid.EntityBareJid; import org.mercury_im.messenger.android.MercuryImApplication; +import org.mercury_im.messenger.android.ui.MercuryAndroidViewModel; import org.mercury_im.messenger.core.Messenger; import org.mercury_im.messenger.core.data.repository.DirectChatRepository; import org.mercury_im.messenger.core.data.repository.MessageRepository; import org.mercury_im.messenger.core.data.repository.PeerRepository; +import org.mercury_im.messenger.core.viewmodel.chat.ChatViewModel; import org.mercury_im.messenger.entity.chat.DirectChat; import org.mercury_im.messenger.entity.contact.Peer; import org.mercury_im.messenger.entity.message.Message; @@ -27,10 +29,13 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; -public class ChatViewModel extends ViewModel { +public class AndroidChatViewModel extends ViewModel implements MercuryAndroidViewModel { private final CompositeDisposable disposable = new CompositeDisposable(); - private static final Logger LOGGER = Logger.getLogger(ChatViewModel.class.getName()); + private static final Logger LOGGER = Logger.getLogger(AndroidChatViewModel.class.getName()); + + @Inject + ChatViewModel commonViewModel; @Inject PeerRepository contactRepository; @@ -49,7 +54,7 @@ public class ChatViewModel extends ViewModel { private MutableLiveData contactDisplayName = new MutableLiveData<>(); private MutableLiveData chat = new MutableLiveData<>(); - public ChatViewModel() { + public AndroidChatViewModel() { super(); MercuryImApplication.getApplication().getAppComponent().inject(this); } @@ -78,7 +83,7 @@ public class ChatViewModel extends ViewModel { disposable.add(messageRepository.observeMessages(chat) .subscribe(messageList -> { LOGGER.log(Level.INFO, "NEW MESSAGES."); - ChatViewModel.this.messages.setValue(messageList); + AndroidChatViewModel.this.messages.setValue(messageList); }, error -> LOGGER.log(Level.SEVERE, "Error subscribing to messages", error))); } @@ -108,13 +113,13 @@ public class ChatViewModel extends ViewModel { messageRepository.findMessagesWithBody(chat.getValue(), query); disposable.add(observable.subscribe(messages -> - ChatViewModel.this.messages.setValue(messages))); + AndroidChatViewModel.this.messages.setValue(messages))); } public Completable requestMamMessages() { /* return Completable.fromAction(() -> { - ChatModel chatModel = ChatViewModel.this.chat.getValue(); + ChatModel chatModel = AndroidChatViewModel.this.chat.getValue(); if (chatModel == null) { return; } @@ -139,4 +144,9 @@ public class ChatViewModel extends ViewModel { disposable.add(messenger.sendMessage(getContact().getValue(), body) .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe()); } + + @Override + public ChatViewModel getCommonViewModel() { + return commonViewModel; + } } diff --git a/app/src/main/java/org/mercury_im/messenger/android/ui/chat/ChatActivity.java b/app/src/main/java/org/mercury_im/messenger/android/ui/chat/ChatActivity.java index 7a5d239..04b8332 100644 --- a/app/src/main/java/org/mercury_im/messenger/android/ui/chat/ChatActivity.java +++ b/app/src/main/java/org/mercury_im/messenger/android/ui/chat/ChatActivity.java @@ -43,7 +43,7 @@ public class ChatActivity extends AppCompatActivity private final MessagesRecyclerViewAdapter recyclerViewAdapter = new MessagesRecyclerViewAdapter(); - private ChatViewModel chatViewModel; + private AndroidChatViewModel androidChatViewModel; private final CompositeDisposable disposable = new CompositeDisposable(); @@ -79,10 +79,10 @@ public class ChatActivity extends AppCompatActivity getSupportActionBar().setSubtitle(jid.asUnescapedString()); accountId = UUID.fromString(savedInstanceState.getString(EXTRA_ACCOUNT)); - chatViewModel = new ViewModelProvider(this).get(ChatViewModel.class); - chatViewModel.init(accountId, jid); + androidChatViewModel = new ViewModelProvider(this).get(AndroidChatViewModel.class); + androidChatViewModel.init(accountId, jid); // Listen for updates to contact information and messages - observeViewModel(chatViewModel); + observeViewModel(androidChatViewModel); } toolbar.setOnClickListener(new View.OnClickListener() { @@ -97,7 +97,7 @@ public class ChatActivity extends AppCompatActivity }); } - public void observeViewModel(ChatViewModel viewModel) { + public void observeViewModel(AndroidChatViewModel viewModel) { viewModel.getContactDisplayName().observe(this, name -> getSupportActionBar().setTitle(name)); @@ -128,14 +128,14 @@ public class ChatActivity extends AppCompatActivity public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_debug: - Peer peer = chatViewModel.getContact().getValue(); + Peer peer = androidChatViewModel.getContact().getValue(); Toast.makeText(this, "subscription: " + peer.getSubscriptionDirection().toString() + " isApproved: " + peer.isSubscriptionApproved() + " isPending: " + peer.isSubscriptionPending(), Toast.LENGTH_SHORT).show(); break; // menu_chat case R.id.action_delete_contact: - chatViewModel.deleteContact(); + androidChatViewModel.deleteContact(); break; case R.id.action_call: case R.id.action_clear_history: @@ -188,7 +188,7 @@ public class ChatActivity extends AppCompatActivity return; } - chatViewModel.sendMessage(msg); + androidChatViewModel.sendMessage(msg); } @Override @@ -199,7 +199,7 @@ public class ChatActivity extends AppCompatActivity @Override public boolean onQueryTextChange(String query) { - chatViewModel.queryTextChanged(query); + androidChatViewModel.queryTextChanged(query); return false; } diff --git a/app/src/main/java/org/mercury_im/messenger/android/ui/roster/contacts/ContactListViewModel.java b/app/src/main/java/org/mercury_im/messenger/android/ui/roster/contacts/ContactListViewModel.java index 3b8068e..bd42b15 100644 --- a/app/src/main/java/org/mercury_im/messenger/android/ui/roster/contacts/ContactListViewModel.java +++ b/app/src/main/java/org/mercury_im/messenger/android/ui/roster/contacts/ContactListViewModel.java @@ -8,8 +8,8 @@ import androidx.lifecycle.ViewModel; import org.mercury_im.messenger.android.MercuryImApplication; import org.mercury_im.messenger.core.Messenger; -import org.mercury_im.messenger.data.repository.XmppAccountRepository; -import org.mercury_im.messenger.data.repository.XmppPeerRepository; +import org.mercury_im.messenger.data.repository.RxAccountRepository; +import org.mercury_im.messenger.data.repository.RxPeerRepository; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.contact.Peer; @@ -24,10 +24,10 @@ import lombok.Getter; public class ContactListViewModel extends ViewModel { @Inject - XmppPeerRepository xmppContactRepository; + RxPeerRepository xmppContactRepository; @Inject - XmppAccountRepository accountRepository; + RxAccountRepository accountRepository; @Inject @Getter diff --git a/cli/build.gradle b/cli/build.gradle index bd1c973..80672e6 100644 --- a/cli/build.gradle +++ b/cli/build.gradle @@ -3,8 +3,6 @@ plugins { id 'application' } -group 'org.mercury_im' -version '1.0' mainClassName = "org.mercury_im.messenger.cli.MercuryCli" repositories { diff --git a/cli/src/main/java/org/mercury_im/messenger/cli/MercuryCli.java b/cli/src/main/java/org/mercury_im/messenger/cli/MercuryCli.java index 3aa72db..99ab76f 100644 --- a/cli/src/main/java/org/mercury_im/messenger/cli/MercuryCli.java +++ b/cli/src/main/java/org/mercury_im/messenger/cli/MercuryCli.java @@ -51,7 +51,6 @@ public class MercuryCli { public MercuryCli() { createCliComponent(); userInterface = ConsoleUserInterface.isSupported() ? new ConsoleUserInterface() : new ScannerUserInterface(); - //connectionStateDisposable = messenger.getConnectionCenter().observeConnectionPoolState().subscribe(System.out::println); } private void loginDialog() { diff --git a/cli/src/main/java/org/mercury_im/messenger/cli/di/component/CliComponent.java b/cli/src/main/java/org/mercury_im/messenger/cli/di/component/CliComponent.java index 16e7b9e..5517a58 100644 --- a/cli/src/main/java/org/mercury_im/messenger/cli/di/component/CliComponent.java +++ b/cli/src/main/java/org/mercury_im/messenger/cli/di/component/CliComponent.java @@ -1,9 +1,11 @@ package org.mercury_im.messenger.cli.di.component; import org.mercury_im.messenger.cli.MercuryCli; -import org.mercury_im.messenger.cli.X509WorkaroundConnectionFactory; -import org.mercury_im.messenger.cli.di.module.CliPersistenceModule; +import org.mercury_im.messenger.cli.di.module.CliDatabaseModule; +import org.mercury_im.messenger.cli.di.module.CliSchedulersModule; import org.mercury_im.messenger.cli.di.module.X509WorkaroundConnectionFactoryModule; +import org.mercury_im.messenger.core.di.module.RxMercuryMessageStoreFactoryModule; +import org.mercury_im.messenger.core.di.module.RxMercuryRosterStoreFactoryModule; import org.mercury_im.messenger.core.di.module.ViewModelModule; import org.mercury_im.messenger.data.di.RepositoryModule; @@ -14,10 +16,13 @@ import dagger.Component; @Singleton @Component( modules = { - CliPersistenceModule.class, + CliDatabaseModule.class, + CliSchedulersModule.class, RepositoryModule.class, ViewModelModule.class, - X509WorkaroundConnectionFactoryModule.class + X509WorkaroundConnectionFactoryModule.class, + RxMercuryMessageStoreFactoryModule.class, + RxMercuryRosterStoreFactoryModule.class }) public interface CliComponent { diff --git a/cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliPersistenceModule.java b/cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliDatabaseModule.java similarity index 78% rename from cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliPersistenceModule.java rename to cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliDatabaseModule.java index 39d2b98..1a125a7 100644 --- a/cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliPersistenceModule.java +++ b/cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliDatabaseModule.java @@ -1,7 +1,7 @@ package org.mercury_im.messenger.cli.di.module; import org.h2.jdbcx.JdbcDataSource; -import org.mercury_im.messenger.core.util.ThreadUtils; +import org.mercury_im.messenger.core.SchedulersFacade; import org.mercury_im.messenger.data.model.Models; import java.util.concurrent.Executors; @@ -24,9 +24,7 @@ import io.requery.sql.SchemaModifier; import io.requery.sql.TableCreationMode; @Module -public class CliPersistenceModule { - - private static Scheduler scheduler = Schedulers.newThread(); +public class CliDatabaseModule { @Provides @Singleton @@ -50,17 +48,4 @@ public class CliPersistenceModule { return ReactiveSupport.toReactiveStore(new EntityDataStore<>(configuration)); } - @Provides - @Named(value = ThreadUtils.SCHEDULER_IO) - @Singleton - static Scheduler provideDatabaseThread() { - return Schedulers.io(); - } - - @Provides - @Named(value = ThreadUtils.SCHEDULER_UI) - @Singleton - static Scheduler providerUIThread() { - return scheduler; - } } diff --git a/cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliSchedulersModule.java b/cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliSchedulersModule.java new file mode 100644 index 0000000..14e2a24 --- /dev/null +++ b/cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliSchedulersModule.java @@ -0,0 +1,35 @@ +package org.mercury_im.messenger.cli.di.module; + +import org.mercury_im.messenger.core.SchedulersFacade; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; +import io.reactivex.Scheduler; +import io.reactivex.schedulers.Schedulers; + +@Module +public class CliSchedulersModule { + + @Provides + @Named(value = SchedulersFacade.SCHEDULER_IO) + @Singleton + static Scheduler provideDatabaseThread() { + return Schedulers.io(); + } + + @Provides + @Named(value = SchedulersFacade.SCHEDULER_UI) + @Singleton + static Scheduler provideUIThread() { + return Schedulers.newThread(); + } + + @Provides + @Named(value = SchedulersFacade.SCHEDULER_NEW_THREAD) + static Scheduler provideNewThread() { + return Schedulers.newThread(); + } +} diff --git a/data/src/main/java/org/mercury_im/messenger/data/repository/RxEntityCapsRepository.java b/data/src/main/java/org/mercury_im/messenger/data/repository/RxEntityCapsRepository.java index d509f36..def5ce0 100644 --- a/data/src/main/java/org/mercury_im/messenger/data/repository/RxEntityCapsRepository.java +++ b/data/src/main/java/org/mercury_im/messenger/data/repository/RxEntityCapsRepository.java @@ -1,6 +1,5 @@ package org.mercury_im.messenger.data.repository; -import org.mercury_im.messenger.core.SchedulersFacade; import org.mercury_im.messenger.core.data.repository.EntityCapsRepository; import org.mercury_im.messenger.data.mapping.EntityCapsMapping; import org.mercury_im.messenger.data.model.EntityCapsModel; @@ -10,12 +9,11 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.inject.Inject; -import javax.inject.Named; import io.reactivex.Completable; import io.reactivex.Maybe; import io.reactivex.Observable; -import io.reactivex.Scheduler; +import io.reactivex.Single; import io.requery.Persistable; import io.requery.reactivex.ReactiveEntityStore; import io.requery.reactivex.ReactiveResult; @@ -77,4 +75,10 @@ public class RxEntityCapsRepository extends RequeryRepository implements EntityC return data().upsert(entityCapsMapping.toModel(entityCapsRecord)) .ignoreElement(); } + + @Override + public Single deleteAllEntityCapsRecords() { + return data().delete().from(EntityCapsModel.class) + .get().single(); + } } diff --git a/domain/build.gradle b/domain/build.gradle index 45da3a3..b5f2665 100644 --- a/domain/build.gradle +++ b/domain/build.gradle @@ -11,6 +11,7 @@ dependencies { api "org.igniterealtime.smack:smack-extensions:$smackExtensionsVersion" api "org.igniterealtime.smack:smack-im:$smackImVersion" api "org.igniterealtime.smack:smack-tcp:$smackTcpVersion" + api "org.igniterealtime.smack:smack-openpgp:$smackOpenpgpVersion" testImplementation "org.igniterealtime.smack:smack-java7:$smackJava7Version" diff --git a/domain/src/main/java/org/mercury_im/messenger/core/Messenger.java b/domain/src/main/java/org/mercury_im/messenger/core/Messenger.java index dc886c3..bc43826 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/Messenger.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/Messenger.java @@ -1,6 +1,5 @@ package org.mercury_im.messenger.core; -import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.chat2.ChatManager; @@ -10,11 +9,11 @@ import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.stringprep.XmppStringprepException; import org.mercury_im.messenger.core.data.repository.Repositories; -import org.mercury_im.messenger.entity.contact.Peer; import org.mercury_im.messenger.core.exception.ConnectionNotFoundException; import org.mercury_im.messenger.core.exception.ContactAlreadyAddedException; import org.mercury_im.messenger.core.xmpp.MercuryConnection; import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager; +import org.mercury_im.messenger.entity.contact.Peer; import java.util.UUID; import java.util.logging.Level; @@ -25,7 +24,6 @@ import javax.inject.Singleton; import io.reactivex.Completable; import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; @Singleton public class Messenger { @@ -35,17 +33,17 @@ public class Messenger { private final MercuryConnectionManager connectionManager; private final Repositories repositories; + private final SchedulersFacade schedulers; private CompositeDisposable disposable = new CompositeDisposable(); - static { - //SmackConfiguration.DEBUG = true; - } - @Inject - public Messenger(Repositories repositories, MercuryConnectionManager connectionManager) { + public Messenger(Repositories repositories, + MercuryConnectionManager connectionManager, + SchedulersFacade schedulers) { this.repositories = repositories; this.connectionManager = connectionManager; + this.schedulers = schedulers; performInitialLogin(); } @@ -56,7 +54,7 @@ public class Messenger { public void performInitialLogin() { LOGGER.log(Level.INFO, "Perform initial login."); disposable.add(repositories.getAccountRepository().observeAllAccounts().firstOrError() - .subscribeOn(Schedulers.io()) + .subscribeOn(schedulers.getIoScheduler()) .subscribe(connectionManager::doRegisterConnections)); } diff --git a/domain/src/main/java/org/mercury_im/messenger/core/SchedulersFacade.java b/domain/src/main/java/org/mercury_im/messenger/core/SchedulersFacade.java index 18312b4..4272023 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/SchedulersFacade.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/SchedulersFacade.java @@ -1,7 +1,5 @@ package org.mercury_im.messenger.core; -import org.mercury_im.messenger.core.util.ThreadUtils; - import javax.inject.Inject; import javax.inject.Named; @@ -10,19 +8,35 @@ import lombok.Getter; public class SchedulersFacade { + /** + * Name for the database / io thread scheduler. + */ + public static final String SCHEDULER_IO = "DatabaseThread"; + + /** + * Name for the UI / main thread scheduler. + */ + public static final String SCHEDULER_UI = "UIThread"; + + /** + * Name for a new thread scheduler. + */ + public static final String SCHEDULER_NEW_THREAD = "NewThread"; + + @Getter - private final Scheduler io; + private final Scheduler ioScheduler; @Getter - private final Scheduler ui; + private final Scheduler uiScheduler; @Getter private final Scheduler newThread; @Inject - public SchedulersFacade(@Named(value = ThreadUtils.SCHEDULER_IO) Scheduler io, - @Named(value = ThreadUtils.SCHEDULER_UI) Scheduler ui, - @Named(value = ThreadUtils.SCHEDULER_NEW_THREAD) Scheduler newThread) { - this.io = io; - this.ui = ui; + public SchedulersFacade(@Named(value = SCHEDULER_IO) Scheduler ioScheduler, + @Named(value = SCHEDULER_UI) Scheduler uiScheduler, + @Named(value = SCHEDULER_NEW_THREAD) Scheduler newThread) { + this.ioScheduler = ioScheduler; + this.uiScheduler = uiScheduler; this.newThread = newThread; } } diff --git a/domain/src/main/java/org/mercury_im/messenger/core/data/repository/EntityCapsRepository.java b/domain/src/main/java/org/mercury_im/messenger/core/data/repository/EntityCapsRepository.java index 82b8d6a..23b1978 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/data/repository/EntityCapsRepository.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/data/repository/EntityCapsRepository.java @@ -7,6 +7,7 @@ import java.util.Map; import io.reactivex.Completable; import io.reactivex.Maybe; import io.reactivex.Observable; +import io.reactivex.Single; public interface EntityCapsRepository { @@ -17,4 +18,6 @@ public interface EntityCapsRepository { Maybe maybeGetEntityCapsRecord(String nodeVer); Completable insertEntityCapsRecord(EntityCapsRecord entityCapsRecord); + + Single deleteAllEntityCapsRecords(); } diff --git a/domain/src/main/java/org/mercury_im/messenger/core/di/module/RxMercuryMessageStoreFactoryModule.java b/domain/src/main/java/org/mercury_im/messenger/core/di/module/RxMercuryMessageStoreFactoryModule.java new file mode 100644 index 0000000..4a28e6e --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/core/di/module/RxMercuryMessageStoreFactoryModule.java @@ -0,0 +1,26 @@ +package org.mercury_im.messenger.core.di.module; + +import org.mercury_im.messenger.core.SchedulersFacade; +import org.mercury_im.messenger.core.data.repository.Repositories; +import org.mercury_im.messenger.core.store.message.MercuryMessageStore; +import org.mercury_im.messenger.core.store.message.MercuryMessageStoreFactory; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class RxMercuryMessageStoreFactoryModule { + + @Provides + @Singleton + static MercuryMessageStoreFactory provideMessageStoreFactory(Repositories repositories, SchedulersFacade schedulers) { + + return account -> new MercuryMessageStore(account, + repositories.getPeerRepository(), + repositories.getDirectChatRepository(), + repositories.getMessageRepository(), + schedulers); + } +} diff --git a/domain/src/main/java/org/mercury_im/messenger/core/di/module/RxMercuryRosterStoreFactoryModule.java b/domain/src/main/java/org/mercury_im/messenger/core/di/module/RxMercuryRosterStoreFactoryModule.java new file mode 100644 index 0000000..6b306b1 --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/core/di/module/RxMercuryRosterStoreFactoryModule.java @@ -0,0 +1,22 @@ +package org.mercury_im.messenger.core.di.module; + +import org.mercury_im.messenger.core.SchedulersFacade; +import org.mercury_im.messenger.core.data.repository.AccountRepository; +import org.mercury_im.messenger.core.data.repository.PeerRepository; +import org.mercury_im.messenger.core.store.roster.MercuryRosterStore; +import org.mercury_im.messenger.core.store.roster.MercuryRosterStoreFactory; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class RxMercuryRosterStoreFactoryModule { + + @Provides + @Singleton + static MercuryRosterStoreFactory provideRosterStoreFactory(PeerRepository peerRepository, AccountRepository accountRepository, SchedulersFacade schedulers) { + return accountId -> new MercuryRosterStore(accountId, peerRepository, accountRepository, schedulers); + } +} diff --git a/domain/src/main/java/org/mercury_im/messenger/core/di/module/ViewModelModule.java b/domain/src/main/java/org/mercury_im/messenger/core/di/module/ViewModelModule.java index 72f951f..a949caf 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/di/module/ViewModelModule.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/di/module/ViewModelModule.java @@ -1,9 +1,11 @@ package org.mercury_im.messenger.core.di.module; +import org.mercury_im.messenger.core.SchedulersFacade; import org.mercury_im.messenger.core.data.repository.AccountRepository; -import org.mercury_im.messenger.core.util.ThreadUtils; +import org.mercury_im.messenger.core.data.repository.Repositories; import org.mercury_im.messenger.core.viewmodel.accounts.AccountsViewModel; import org.mercury_im.messenger.core.viewmodel.accounts.LoginViewModel; +import org.mercury_im.messenger.core.viewmodel.chat.ChatViewModel; import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager; import javax.inject.Named; @@ -20,17 +22,21 @@ public class ViewModelModule { @Singleton static LoginViewModel provideLoginViewModel(MercuryConnectionManager connectionManager, AccountRepository accountRepository, - @Named(ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler, - @Named(ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) { - return new LoginViewModel(connectionManager, accountRepository, ioScheduler, uiScheduler); + SchedulersFacade schedulers) { + return new LoginViewModel(connectionManager, accountRepository, schedulers); } @Provides @Singleton static AccountsViewModel provideAccountsViewModel(MercuryConnectionManager connectionManager, AccountRepository accountRepository, - @Named(ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler, - @Named(ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) { - return new AccountsViewModel(connectionManager, accountRepository, ioScheduler, uiScheduler); + SchedulersFacade schedulers) { + return new AccountsViewModel(connectionManager, accountRepository, schedulers); + } + + @Provides + @Singleton + static ChatViewModel provideChatViewModel(Repositories repositories, SchedulersFacade schedulers) { + return new ChatViewModel(repositories, schedulers); } } diff --git a/domain/src/main/java/org/mercury_im/messenger/core/store/MercuryEntityCapsStore.java b/domain/src/main/java/org/mercury_im/messenger/core/store/caps/MercuryEntityCapsStore.java similarity index 81% rename from domain/src/main/java/org/mercury_im/messenger/core/store/MercuryEntityCapsStore.java rename to domain/src/main/java/org/mercury_im/messenger/core/store/caps/MercuryEntityCapsStore.java index b3b75fd..4c268b6 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/store/MercuryEntityCapsStore.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/store/caps/MercuryEntityCapsStore.java @@ -1,9 +1,10 @@ -package org.mercury_im.messenger.core.store; +package org.mercury_im.messenger.core.store.caps; import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.xml.XmlPullParser; import org.jivesoftware.smackx.caps.cache.EntityCapsPersistentCache; import org.jivesoftware.smackx.disco.packet.DiscoverInfo; +import org.mercury_im.messenger.core.SchedulersFacade; import org.mercury_im.messenger.core.data.repository.EntityCapsRepository; import org.mercury_im.messenger.entity.caps.EntityCapsRecord; import org.mercury_im.messenger.core.logging.Tags; @@ -24,10 +25,13 @@ public class MercuryEntityCapsStore implements EntityCapsPersistentCache { private final CompositeDisposable disposable = new CompositeDisposable(); private final EntityCapsRepository repository; + private final SchedulersFacade schedulers; @Inject - public MercuryEntityCapsStore(EntityCapsRepository entityCapsRepository) { + public MercuryEntityCapsStore(EntityCapsRepository entityCapsRepository, + SchedulersFacade schedulers) { this.repository = entityCapsRepository; + this.schedulers = schedulers; } @Override @@ -37,7 +41,9 @@ public class MercuryEntityCapsStore implements EntityCapsPersistentCache { record.setNodeVer(nodeVer); record.setXml(info.toXML().toString()); - disposable.add(repository.insertEntityCapsRecord(record).subscribe()); + disposable.add(repository.insertEntityCapsRecord(record) + .subscribeOn(schedulers.getIoScheduler()) + .subscribe()); } @Override @@ -46,6 +52,7 @@ public class MercuryEntityCapsStore implements EntityCapsPersistentCache { EntityCapsRecord defaultIfEmpty = new EntityCapsRecord(); EntityCapsRecord record = repository.maybeGetEntityCapsRecord(nodeVer) .defaultIfEmpty(defaultIfEmpty) + .subscribeOn(schedulers.getIoScheduler()) .blockingGet(); if (record == defaultIfEmpty) { return null; @@ -66,6 +73,8 @@ public class MercuryEntityCapsStore implements EntityCapsPersistentCache { @Override public void emptyCache() { LOGGER.log(Level.INFO, "MercuryEntityCapsStore: emptyCache."); - // Not needed? + disposable.add(repository.deleteAllEntityCapsRecords() + .subscribeOn(schedulers.getIoScheduler()) + .subscribe()); } } diff --git a/domain/src/main/java/org/mercury_im/messenger/core/store/MercuryMessageStore.java b/domain/src/main/java/org/mercury_im/messenger/core/store/message/MercuryMessageStore.java similarity index 80% rename from domain/src/main/java/org/mercury_im/messenger/core/store/MercuryMessageStore.java rename to domain/src/main/java/org/mercury_im/messenger/core/store/message/MercuryMessageStore.java index 2208164..1f54efb 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/store/MercuryMessageStore.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/store/message/MercuryMessageStore.java @@ -1,10 +1,11 @@ -package org.mercury_im.messenger.core.store; +package org.mercury_im.messenger.core.store.message; import org.jivesoftware.smack.chat2.IncomingChatMessageListener; import org.jivesoftware.smack.chat2.OutgoingChatMessageListener; import org.jivesoftware.smack.packet.MessageBuilder; import org.jivesoftware.smackx.delay.packet.DelayInformation; import org.jxmpp.jid.EntityBareJid; +import org.mercury_im.messenger.core.SchedulersFacade; import org.mercury_im.messenger.core.data.repository.DirectChatRepository; import org.mercury_im.messenger.core.data.repository.MessageRepository; import org.mercury_im.messenger.core.data.repository.PeerRepository; @@ -16,9 +17,13 @@ import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; +import javax.inject.Inject; +import javax.inject.Singleton; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; + +@Singleton public class MercuryMessageStore implements IncomingChatMessageListener, OutgoingChatMessageListener { private static final Logger LOGGER = Logger.getLogger(MercuryMessageStore.class.getName()); @@ -26,19 +31,23 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin private final MessageRepository messageRepository; private final DirectChatRepository directChatRepository; private final PeerRepository peerRepository; + private final SchedulersFacade schedulers; private Account account; private CompositeDisposable disposable = new CompositeDisposable(); + @Inject public MercuryMessageStore(Account account, PeerRepository peerRepository, DirectChatRepository directChatRepository, - MessageRepository messageRepository) { + MessageRepository messageRepository, + SchedulersFacade schedulers) { this.account = account; this.peerRepository = peerRepository; this.directChatRepository = directChatRepository; this.messageRepository = messageRepository; + this.schedulers = schedulers; } @Override @@ -54,11 +63,7 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin if (smackMessage.getBody() != null) { message.setBody(smackMessage.getBody()); } - disposable.add(peerRepository.getOrCreatePeer(account, from.asEntityBareJidString()) - .flatMap(directChatRepository::getOrCreateChatWithPeer) - .flatMap(chat -> messageRepository.insertMessage(chat, message)) - .subscribeOn(Schedulers.io()) - .subscribe(m -> LOGGER.log(Level.INFO, "Message written"), e -> LOGGER.log(Level.SEVERE, "Error: ", e))); + disposable.add(writeMessageToStore(from.asEntityBareJidString(), message)); } @Override @@ -73,9 +78,14 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin if (smackMessage.getBody() != null) { message.setBody(smackMessage.getBody().getMessage()); } - disposable.add(peerRepository.getOrCreatePeer(account, to.asEntityBareJidString()) + disposable.add(writeMessageToStore(to.asEntityBareJidString(), message)); + } + + private Disposable writeMessageToStore(String peer, Message message) { + return peerRepository.getOrCreatePeer(account, peer) .flatMap(directChatRepository::getOrCreateChatWithPeer) .flatMap(chat -> messageRepository.insertMessage(chat, message)) - .subscribe(m -> LOGGER.log(Level.INFO, "Message written"), e -> LOGGER.log(Level.SEVERE, "Error: ", e))); + .subscribeOn(schedulers.getIoScheduler()) + .subscribe(m -> LOGGER.log(Level.INFO, "Message written"), e -> LOGGER.log(Level.SEVERE, "Error: ", e)); } } diff --git a/domain/src/main/java/org/mercury_im/messenger/core/store/message/MercuryMessageStoreFactory.java b/domain/src/main/java/org/mercury_im/messenger/core/store/message/MercuryMessageStoreFactory.java new file mode 100644 index 0000000..8cefc4f --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/core/store/message/MercuryMessageStoreFactory.java @@ -0,0 +1,8 @@ +package org.mercury_im.messenger.core.store.message; + +import org.mercury_im.messenger.entity.Account; + +public interface MercuryMessageStoreFactory { + + MercuryMessageStore createMessageStore(Account account); +} diff --git a/domain/src/main/java/org/mercury_im/messenger/core/store/MercuryRosterStore.java b/domain/src/main/java/org/mercury_im/messenger/core/store/roster/MercuryRosterStore.java similarity index 92% rename from domain/src/main/java/org/mercury_im/messenger/core/store/MercuryRosterStore.java rename to domain/src/main/java/org/mercury_im/messenger/core/store/roster/MercuryRosterStore.java index fb87a9d..7d9c1c8 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/store/MercuryRosterStore.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/store/roster/MercuryRosterStore.java @@ -1,9 +1,10 @@ -package org.mercury_im.messenger.core.store; +package org.mercury_im.messenger.core.store.roster; import org.jivesoftware.smack.roster.packet.RosterPacket; import org.jivesoftware.smack.roster.rosterstore.RosterStore; import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; +import org.mercury_im.messenger.core.SchedulersFacade; import org.mercury_im.messenger.core.data.repository.AccountRepository; import org.mercury_im.messenger.core.data.repository.PeerRepository; import org.mercury_im.messenger.entity.Account; @@ -37,24 +38,28 @@ public class MercuryRosterStore implements RosterStore { private final Map itemMap = new HashMap<>(); private String rosterVersion; + private final SchedulersFacade schedulers; - public MercuryRosterStore(UUID accountId, PeerRepository rosterRepository, AccountRepository accountRepository) { + public MercuryRosterStore(UUID accountId, PeerRepository rosterRepository, AccountRepository accountRepository, SchedulersFacade schedulers) { this.accountId = accountId; this.account = BehaviorSubject.create(); this.peerRepository = rosterRepository; this.accountRepository = accountRepository; + this.schedulers = schedulers; LOGGER.log(Level.INFO, "Construct Roster Store for " + accountId); subscribe(); } public void subscribe() { + // Subscribe database to behaviorSubject for quick access accountRepository.observeAccount(accountId) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.io()) + .subscribeOn(schedulers.getIoScheduler()) + .observeOn(schedulers.getIoScheduler()) .subscribe(account); + disposable.add(peerRepository.observeAllContactsOfAccount(accountId) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.computation()) + .subscribeOn(schedulers.getIoScheduler()) + .observeOn(schedulers.getIoScheduler()) .subscribe(contactsList -> { itemMap.clear(); for (Peer contactModel : contactsList) { @@ -67,8 +72,8 @@ public class MercuryRosterStore implements RosterStore { disposable.add(accountRepository.getAccount(accountId) .map(Account::getRosterVersion) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.computation()) + .subscribeOn(schedulers.getIoScheduler()) + .observeOn(schedulers.getIoScheduler()) .subscribe(this::setRosterVersion, error -> LOGGER.log(Level.WARNING, "An error occurred updating cached roster version", error))); @@ -132,7 +137,8 @@ public class MercuryRosterStore implements RosterStore { public boolean resetEntries(Collection items, String version) { LOGGER.log(Level.INFO, "Reset Entries: " + Arrays.toString(items.toArray())); // Update database - // TODO: Delete other contacts + disposable.add(peerRepository.deleteAllPeers(accountId).subscribe()); + for (RosterPacket.Item item : items) { writeEntryToDatabase(item); } diff --git a/domain/src/main/java/org/mercury_im/messenger/core/store/roster/MercuryRosterStoreFactory.java b/domain/src/main/java/org/mercury_im/messenger/core/store/roster/MercuryRosterStoreFactory.java new file mode 100644 index 0000000..3d704c6 --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/core/store/roster/MercuryRosterStoreFactory.java @@ -0,0 +1,8 @@ +package org.mercury_im.messenger.core.store.roster; + +import java.util.UUID; + +public interface MercuryRosterStoreFactory { + + MercuryRosterStore createRosterStore(UUID accountId); +} diff --git a/domain/src/main/java/org/mercury_im/messenger/core/usecase/RosterStoreBinder.java b/domain/src/main/java/org/mercury_im/messenger/core/usecase/RosterStoreBinder.java index 03bbf92..f078264 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/usecase/RosterStoreBinder.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/usecase/RosterStoreBinder.java @@ -10,14 +10,12 @@ import org.jivesoftware.smack.roster.SubscribeListener; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.FullJid; import org.jxmpp.jid.Jid; -import org.mercury_im.messenger.core.data.repository.AccountRepository; -import org.mercury_im.messenger.core.data.repository.PeerRepository; -import org.mercury_im.messenger.core.store.MercuryRosterStore; +import org.mercury_im.messenger.core.store.roster.MercuryRosterStore; +import org.mercury_im.messenger.core.store.roster.MercuryRosterStoreFactory; import org.mercury_im.messenger.core.xmpp.MercuryConnection; import java.util.Arrays; import java.util.Collection; -import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -25,20 +23,18 @@ import javax.inject.Inject; public class RosterStoreBinder { - private final AccountRepository accountRepository; - private final PeerRepository peerRepository; + private final MercuryRosterStoreFactory rosterStoreFactory; private final Logger LOGGER = Logger.getLogger(RosterStoreBinder.class.getName()); @Inject - public RosterStoreBinder(AccountRepository accountRepository, PeerRepository peerRepository) { - this.accountRepository = accountRepository; - this.peerRepository = peerRepository; + public RosterStoreBinder(MercuryRosterStoreFactory rosterStoreFactory) { + + this.rosterStoreFactory = rosterStoreFactory; } public void setRosterStoreOn(MercuryConnection connection) { - MercuryRosterStore store = - createRosterStore(connection.getAccount().getId(), accountRepository, peerRepository); + MercuryRosterStore store = rosterStoreFactory.createRosterStore(connection.getAccountId()); Roster roster = Roster.getInstanceFor(connection.getConnection()); roster.setRosterStore(store); roster.addSubscribeListener(new SubscribeListener() { @@ -111,8 +107,4 @@ public class RosterStoreBinder { } }); } - - private MercuryRosterStore createRosterStore(UUID accountId, AccountRepository accountRepository, PeerRepository peerRepository) { - return new MercuryRosterStore(accountId, peerRepository, accountRepository); - } } diff --git a/domain/src/main/java/org/mercury_im/messenger/core/util/ThreadUtils.java b/domain/src/main/java/org/mercury_im/messenger/core/util/ThreadUtils.java deleted file mode 100644 index 148f4a2..0000000 --- a/domain/src/main/java/org/mercury_im/messenger/core/util/ThreadUtils.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.mercury_im.messenger.core.util; - -/** - * Names for identifying scheduler instances during dependency injection. - */ -public class ThreadUtils { - /** - * Name for the database / io thread. - */ - public static final String SCHEDULER_IO = "DatabaseThread"; - - /** - * Name for the UI / main thread. - */ - public static final String SCHEDULER_UI = "UIThread"; - - public static final String SCHEDULER_NEW_THREAD = "NewThread"; -} diff --git a/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/accounts/AccountsViewModel.java b/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/accounts/AccountsViewModel.java index 61467b2..2fe00c9 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/accounts/AccountsViewModel.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/accounts/AccountsViewModel.java @@ -1,19 +1,16 @@ package org.mercury_im.messenger.core.viewmodel.accounts; +import org.mercury_im.messenger.core.SchedulersFacade; import org.mercury_im.messenger.core.data.repository.AccountRepository; import org.mercury_im.messenger.core.viewmodel.MercuryViewModel; -import org.mercury_im.messenger.entity.Account; -import org.mercury_im.messenger.core.util.ThreadUtils; import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager; import org.mercury_im.messenger.core.xmpp.state.ConnectionPoolState; +import org.mercury_im.messenger.entity.Account; import java.util.logging.Level; import java.util.logging.Logger; -import javax.inject.Named; - import io.reactivex.Observable; -import io.reactivex.Scheduler; public class AccountsViewModel implements MercuryViewModel { @@ -21,18 +18,15 @@ public class AccountsViewModel implements MercuryViewModel { private final MercuryConnectionManager connectionManager; private final AccountRepository accountRepository; - private final Scheduler ioScheduler; - private final Scheduler uiScheduler; + private final SchedulersFacade schedulers; public AccountsViewModel(MercuryConnectionManager connectionManager, AccountRepository accountRepository, - @Named(ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler, - @Named(ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) { + SchedulersFacade schedulers) { this.connectionManager = connectionManager; this.accountRepository = accountRepository; - this.ioScheduler = ioScheduler; - this.uiScheduler = uiScheduler; + this.schedulers = schedulers; } @@ -43,8 +37,8 @@ public class AccountsViewModel implements MercuryViewModel { public void onToggleAccountEnabled(Account account, boolean enabled) { account.setEnabled(enabled); addDisposable(accountRepository.upsertAccount(account) - .subscribeOn(ioScheduler) - .observeOn(uiScheduler) + .subscribeOn(schedulers.getIoScheduler()) + .observeOn(schedulers.getUiScheduler()) .subscribe( success -> logAccountToggledSuccess(success, enabled), error -> logAccountToggleError(account, enabled, error) diff --git a/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/accounts/LoginViewModel.java b/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/accounts/LoginViewModel.java index f24acfd..53edd1b 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/accounts/LoginViewModel.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/accounts/LoginViewModel.java @@ -4,27 +4,24 @@ import org.jivesoftware.smack.util.StringUtils; import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.stringprep.XmppStringprepException; +import org.mercury_im.messenger.core.SchedulersFacade; import org.mercury_im.messenger.core.account.error.PasswordError; import org.mercury_im.messenger.core.account.error.UsernameError; import org.mercury_im.messenger.core.data.repository.AccountRepository; -import org.mercury_im.messenger.core.viewmodel.MercuryViewModel; -import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.core.util.Optional; -import org.mercury_im.messenger.core.util.ThreadUtils; +import org.mercury_im.messenger.core.viewmodel.MercuryViewModel; import org.mercury_im.messenger.core.xmpp.MercuryConnection; import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager; import org.mercury_im.messenger.core.xmpp.exception.InvalidCredentialsException; import org.mercury_im.messenger.core.xmpp.exception.ServerUnreachableException; +import org.mercury_im.messenger.entity.Account; import java.util.logging.Level; import java.util.logging.Logger; import javax.inject.Inject; -import javax.inject.Named; import io.reactivex.Observable; -import io.reactivex.Scheduler; -import io.reactivex.schedulers.Schedulers; import io.reactivex.subjects.BehaviorSubject; public class LoginViewModel implements MercuryViewModel { @@ -34,8 +31,7 @@ public class LoginViewModel implements MercuryViewModel { private final MercuryConnectionManager connectionManager; private final AccountRepository accountRepository; - private final Scheduler ioScheduler; - private final Scheduler uiScheduler; + private final SchedulersFacade schedulers; private BehaviorSubject> loginUsernameError; private BehaviorSubject> loginPasswordError; @@ -48,12 +44,10 @@ public class LoginViewModel implements MercuryViewModel { @Inject public LoginViewModel(MercuryConnectionManager connectionManager, AccountRepository accountRepository, - @Named(ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler, - @Named(ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) { + SchedulersFacade schedulers) { this.connectionManager = connectionManager; this.accountRepository = accountRepository; - this.ioScheduler = ioScheduler; - this.uiScheduler = uiScheduler; + this.schedulers = schedulers; reset(); } @@ -129,8 +123,8 @@ public class LoginViewModel implements MercuryViewModel { .andThen(connection.login()) .andThen(connectionManager.registerConnection(connection)) .andThen(accountRepository.insertAccount(account)) - .subscribeOn(Schedulers.newThread()) - .observeOn(uiScheduler) + .subscribeOn(schedulers.getNewThread()) + .observeOn(schedulers.getUiScheduler()) .subscribe( this::onLoginSuccessful, this::onLoginFailed diff --git a/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/chat/ChatViewModel.java b/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/chat/ChatViewModel.java new file mode 100644 index 0000000..c359d24 --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/chat/ChatViewModel.java @@ -0,0 +1,20 @@ +package org.mercury_im.messenger.core.viewmodel.chat; + +import org.mercury_im.messenger.core.SchedulersFacade; +import org.mercury_im.messenger.core.data.repository.Repositories; +import org.mercury_im.messenger.core.viewmodel.MercuryViewModel; + +import javax.inject.Inject; + +public class ChatViewModel implements MercuryViewModel { + + private final Repositories repositories; + private final SchedulersFacade schedulers; + + @Inject + public ChatViewModel(Repositories repositories, + SchedulersFacade schedulers) { + this.repositories = repositories; + this.schedulers = schedulers; + } +} diff --git a/domain/src/main/java/org/mercury_im/messenger/core/xmpp/MercuryConnectionManager.java b/domain/src/main/java/org/mercury_im/messenger/core/xmpp/MercuryConnectionManager.java index 45246d8..dd84749 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/xmpp/MercuryConnectionManager.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/xmpp/MercuryConnectionManager.java @@ -2,15 +2,17 @@ package org.mercury_im.messenger.core.xmpp; import org.jivesoftware.smack.chat2.ChatManager; import org.jivesoftware.smackx.caps.EntityCapsManager; +import org.mercury_im.messenger.core.SchedulersFacade; import org.mercury_im.messenger.core.data.repository.AccountRepository; import org.mercury_im.messenger.core.data.repository.DirectChatRepository; import org.mercury_im.messenger.core.data.repository.MessageRepository; import org.mercury_im.messenger.core.data.repository.PeerRepository; import org.mercury_im.messenger.core.data.repository.Repositories; +import org.mercury_im.messenger.core.store.message.MercuryMessageStoreFactory; import org.mercury_im.messenger.core.xmpp.state.ConnectionPoolState; import org.mercury_im.messenger.entity.Account; -import org.mercury_im.messenger.core.store.MercuryEntityCapsStore; -import org.mercury_im.messenger.core.store.MercuryMessageStore; +import org.mercury_im.messenger.core.store.caps.MercuryEntityCapsStore; +import org.mercury_im.messenger.core.store.message.MercuryMessageStore; import org.mercury_im.messenger.core.usecase.RosterStoreBinder; import org.mercury_im.messenger.core.util.Optional; import org.mercury_im.messenger.core.xmpp.state.ConnectionState; @@ -39,12 +41,14 @@ public class MercuryConnectionManager { private static final Logger LOGGER = Logger.getLogger("ConnectionManager"); private final XmppConnectionFactory connectionFactory; + private final MercuryMessageStoreFactory messageStoreFactory; private final AccountRepository accountRepository; private final RosterStoreBinder rosterStoreBinder; private final MercuryEntityCapsStore entityCapsStore; private final PeerRepository peerRepository; private final DirectChatRepository directChatRepository; private final MessageRepository messageRepository; + private final SchedulersFacade schedulers; private final Map connectionsMap = new ConcurrentHashMap<>(); private final Map connectionDisposables = new ConcurrentHashMap<>(); @@ -61,7 +65,9 @@ public class MercuryConnectionManager { public MercuryConnectionManager(Repositories repositories, RosterStoreBinder rosterStoreBinder, MercuryEntityCapsStore entityCapsStore, - XmppConnectionFactory connectionFactory) { + MercuryMessageStoreFactory messageStoreFactory, + XmppConnectionFactory connectionFactory, + SchedulersFacade schedulers) { this.accountRepository = repositories.getAccountRepository(); this.rosterStoreBinder = rosterStoreBinder; this.entityCapsStore = entityCapsStore; @@ -69,14 +75,17 @@ public class MercuryConnectionManager { this.directChatRepository = repositories.getDirectChatRepository(); this.messageRepository = repositories.getMessageRepository(); this.connectionFactory = connectionFactory; + this.messageStoreFactory = messageStoreFactory; + this.schedulers = schedulers; EntityCapsManager.setPersistentCache(entityCapsStore); start(); } public void start() { - accountRepository.observeAllAccounts() - .subscribe(accounts -> doRegisterConnections(accounts)); + disposable.add(accountRepository.observeAllAccounts() + .subscribeOn(schedulers.getIoScheduler()) + .subscribe(this::doRegisterConnections)); } public List getConnections() { @@ -139,14 +148,14 @@ public class MercuryConnectionManager { public void bindConnection(MercuryConnection connection) { rosterStoreBinder.setRosterStoreOn(connection); - accountRepository.getAccount(connection.getAccountId()) - .subscribeOn(Schedulers.io()) + disposable.add(accountRepository.getAccount(connection.getAccountId()) + .subscribeOn(schedulers.getIoScheduler()) .subscribe(account -> { - MercuryMessageStore mercuryMessageStore = new MercuryMessageStore(account, peerRepository, directChatRepository, messageRepository); + MercuryMessageStore mercuryMessageStore = messageStoreFactory.createMessageStore(account); ChatManager chatManager = ChatManager.getInstanceFor(connection.getConnection()); chatManager.addIncomingListener(mercuryMessageStore); chatManager.addOutgoingListener(mercuryMessageStore); - }); + })); }