Use DI for store injection

This commit is contained in:
Paul Schaub 2020-06-09 21:52:53 +02:00
parent 3b9042b95e
commit d22b0b3472
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
30 changed files with 364 additions and 192 deletions

View File

@ -1,20 +1,23 @@
package org.mercury_im.messenger.android.di.component; package org.mercury_im.messenger.android.di.component;
import org.mercury_im.messenger.android.MercuryImApplication; 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.core.di.module.XmppTcpConnectionFactoryModule;
import org.mercury_im.messenger.data.di.RepositoryModule; 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.android.di.module.AppModule;
import org.mercury_im.messenger.core.di.module.ViewModelModule; import org.mercury_im.messenger.core.di.module.ViewModelModule;
import org.mercury_im.messenger.android.service.MercuryConnectionService; 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.MainActivity;
import org.mercury_im.messenger.android.ui.account.AndroidAccountsViewModel; 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.account.AndroidLoginViewModel;
import org.mercury_im.messenger.android.ui.chat.ChatActivity; 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.ChatInputFragment;
import org.mercury_im.messenger.android.ui.chat.ChatInputViewModel; 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.chatlist.ChatListViewModel;
import org.mercury_im.messenger.android.ui.roster.contacts.ContactListViewModel; import org.mercury_im.messenger.android.ui.roster.contacts.ContactListViewModel;
import org.mercury_im.messenger.android.ui.roster.contacts.detail.ContactDetailActivity; import org.mercury_im.messenger.android.ui.roster.contacts.detail.ContactDetailActivity;
@ -34,10 +37,13 @@ import dagger.Component;
@Component( @Component(
modules = { modules = {
AppModule.class, AppModule.class,
AndroidPersistenceModule.class, AndroidDatabaseModule.class,
AndroidSchedulersModule.class,
RepositoryModule.class, RepositoryModule.class,
ViewModelModule.class, ViewModelModule.class,
XmppTcpConnectionFactoryModule.class XmppTcpConnectionFactoryModule.class,
RxMercuryMessageStoreFactoryModule.class,
RxMercuryRosterStoreFactoryModule.class
}) })
public interface AppComponent { public interface AppComponent {
@ -62,7 +68,7 @@ public interface AppComponent {
void inject(ContactListViewModel contactListViewModel); void inject(ContactListViewModel contactListViewModel);
void inject(ChatViewModel chatViewModel); void inject(AndroidChatViewModel androidChatViewModel);
void inject(ChatInputViewModel chatInputViewModel); void inject(ChatInputViewModel chatInputViewModel);
@ -85,6 +91,5 @@ public interface AppComponent {
void inject(MercuryConnectionService service); void inject(MercuryConnectionService service);
void inject(MercuryEntityCapsStore store); void inject(MercuryEntityCapsStore store);
} }

View File

@ -2,18 +2,13 @@ package org.mercury_im.messenger.android.di.module;
import android.app.Application; 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.BuildConfig;
import org.mercury_im.messenger.data.model.Models;
import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import dagger.Module; import dagger.Module;
import dagger.Provides; 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.Persistable;
import io.requery.android.sqlite.DatabaseSource; import io.requery.android.sqlite.DatabaseSource;
import io.requery.reactivex.ReactiveEntityStore; import io.requery.reactivex.ReactiveEntityStore;
@ -23,7 +18,7 @@ import io.requery.sql.EntityDataStore;
import io.requery.sql.TableCreationMode; import io.requery.sql.TableCreationMode;
@Module @Module
public class AndroidPersistenceModule { public class AndroidDatabaseModule {
@Provides @Provides
@Singleton @Singleton
@ -36,18 +31,4 @@ public class AndroidPersistenceModule {
Configuration configuration = source.getConfiguration(); Configuration configuration = source.getConfiguration();
return ReactiveSupport.toReactiveStore(new EntityDataStore<>(configuration)); 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();
}
} }

View File

@ -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();
}
}

View File

@ -6,10 +6,12 @@ import androidx.lifecycle.ViewModel;
import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.android.MercuryImApplication; 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.Messenger;
import org.mercury_im.messenger.core.data.repository.DirectChatRepository; 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.MessageRepository;
import org.mercury_im.messenger.core.data.repository.PeerRepository; 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.chat.DirectChat;
import org.mercury_im.messenger.entity.contact.Peer; import org.mercury_im.messenger.entity.contact.Peer;
import org.mercury_im.messenger.entity.message.Message; 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.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
public class ChatViewModel extends ViewModel { public class AndroidChatViewModel extends ViewModel implements MercuryAndroidViewModel<ChatViewModel> {
private final CompositeDisposable disposable = new CompositeDisposable(); 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 @Inject
PeerRepository contactRepository; PeerRepository contactRepository;
@ -49,7 +54,7 @@ public class ChatViewModel extends ViewModel {
private MutableLiveData<String> contactDisplayName = new MutableLiveData<>(); private MutableLiveData<String> contactDisplayName = new MutableLiveData<>();
private MutableLiveData<DirectChat> chat = new MutableLiveData<>(); private MutableLiveData<DirectChat> chat = new MutableLiveData<>();
public ChatViewModel() { public AndroidChatViewModel() {
super(); super();
MercuryImApplication.getApplication().getAppComponent().inject(this); MercuryImApplication.getApplication().getAppComponent().inject(this);
} }
@ -78,7 +83,7 @@ public class ChatViewModel extends ViewModel {
disposable.add(messageRepository.observeMessages(chat) disposable.add(messageRepository.observeMessages(chat)
.subscribe(messageList -> { .subscribe(messageList -> {
LOGGER.log(Level.INFO, "NEW MESSAGES."); 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))); error -> LOGGER.log(Level.SEVERE, "Error subscribing to messages", error)));
} }
@ -108,13 +113,13 @@ public class ChatViewModel extends ViewModel {
messageRepository.findMessagesWithBody(chat.getValue(), query); messageRepository.findMessagesWithBody(chat.getValue(), query);
disposable.add(observable.subscribe(messages -> disposable.add(observable.subscribe(messages ->
ChatViewModel.this.messages.setValue(messages))); AndroidChatViewModel.this.messages.setValue(messages)));
} }
public Completable requestMamMessages() { public Completable requestMamMessages() {
/* /*
return Completable.fromAction(() -> { return Completable.fromAction(() -> {
ChatModel chatModel = ChatViewModel.this.chat.getValue(); ChatModel chatModel = AndroidChatViewModel.this.chat.getValue();
if (chatModel == null) { if (chatModel == null) {
return; return;
} }
@ -139,4 +144,9 @@ public class ChatViewModel extends ViewModel {
disposable.add(messenger.sendMessage(getContact().getValue(), body) disposable.add(messenger.sendMessage(getContact().getValue(), body)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe()); .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe());
} }
@Override
public ChatViewModel getCommonViewModel() {
return commonViewModel;
}
} }

View File

@ -43,7 +43,7 @@ public class ChatActivity extends AppCompatActivity
private final MessagesRecyclerViewAdapter recyclerViewAdapter = new MessagesRecyclerViewAdapter(); private final MessagesRecyclerViewAdapter recyclerViewAdapter = new MessagesRecyclerViewAdapter();
private ChatViewModel chatViewModel; private AndroidChatViewModel androidChatViewModel;
private final CompositeDisposable disposable = new CompositeDisposable(); private final CompositeDisposable disposable = new CompositeDisposable();
@ -79,10 +79,10 @@ public class ChatActivity extends AppCompatActivity
getSupportActionBar().setSubtitle(jid.asUnescapedString()); getSupportActionBar().setSubtitle(jid.asUnescapedString());
accountId = UUID.fromString(savedInstanceState.getString(EXTRA_ACCOUNT)); accountId = UUID.fromString(savedInstanceState.getString(EXTRA_ACCOUNT));
chatViewModel = new ViewModelProvider(this).get(ChatViewModel.class); androidChatViewModel = new ViewModelProvider(this).get(AndroidChatViewModel.class);
chatViewModel.init(accountId, jid); androidChatViewModel.init(accountId, jid);
// Listen for updates to contact information and messages // Listen for updates to contact information and messages
observeViewModel(chatViewModel); observeViewModel(androidChatViewModel);
} }
toolbar.setOnClickListener(new View.OnClickListener() { 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, viewModel.getContactDisplayName().observe(this,
name -> getSupportActionBar().setTitle(name)); name -> getSupportActionBar().setTitle(name));
@ -128,14 +128,14 @@ public class ChatActivity extends AppCompatActivity
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_debug: case R.id.action_debug:
Peer peer = chatViewModel.getContact().getValue(); Peer peer = androidChatViewModel.getContact().getValue();
Toast.makeText(this, "subscription: " + peer.getSubscriptionDirection().toString() + Toast.makeText(this, "subscription: " + peer.getSubscriptionDirection().toString() +
" isApproved: " + peer.isSubscriptionApproved() + " isPending: " + peer.isSubscriptionPending(), Toast.LENGTH_SHORT).show(); " isApproved: " + peer.isSubscriptionApproved() + " isPending: " + peer.isSubscriptionPending(), Toast.LENGTH_SHORT).show();
break; break;
// menu_chat // menu_chat
case R.id.action_delete_contact: case R.id.action_delete_contact:
chatViewModel.deleteContact(); androidChatViewModel.deleteContact();
break; break;
case R.id.action_call: case R.id.action_call:
case R.id.action_clear_history: case R.id.action_clear_history:
@ -188,7 +188,7 @@ public class ChatActivity extends AppCompatActivity
return; return;
} }
chatViewModel.sendMessage(msg); androidChatViewModel.sendMessage(msg);
} }
@Override @Override
@ -199,7 +199,7 @@ public class ChatActivity extends AppCompatActivity
@Override @Override
public boolean onQueryTextChange(String query) { public boolean onQueryTextChange(String query) {
chatViewModel.queryTextChanged(query); androidChatViewModel.queryTextChanged(query);
return false; return false;
} }

View File

@ -8,8 +8,8 @@ import androidx.lifecycle.ViewModel;
import org.mercury_im.messenger.android.MercuryImApplication; import org.mercury_im.messenger.android.MercuryImApplication;
import org.mercury_im.messenger.core.Messenger; import org.mercury_im.messenger.core.Messenger;
import org.mercury_im.messenger.data.repository.XmppAccountRepository; import org.mercury_im.messenger.data.repository.RxAccountRepository;
import org.mercury_im.messenger.data.repository.XmppPeerRepository; import org.mercury_im.messenger.data.repository.RxPeerRepository;
import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.entity.contact.Peer; import org.mercury_im.messenger.entity.contact.Peer;
@ -24,10 +24,10 @@ import lombok.Getter;
public class ContactListViewModel extends ViewModel { public class ContactListViewModel extends ViewModel {
@Inject @Inject
XmppPeerRepository xmppContactRepository; RxPeerRepository xmppContactRepository;
@Inject @Inject
XmppAccountRepository accountRepository; RxAccountRepository accountRepository;
@Inject @Inject
@Getter @Getter

View File

@ -3,8 +3,6 @@ plugins {
id 'application' id 'application'
} }
group 'org.mercury_im'
version '1.0'
mainClassName = "org.mercury_im.messenger.cli.MercuryCli" mainClassName = "org.mercury_im.messenger.cli.MercuryCli"
repositories { repositories {

View File

@ -51,7 +51,6 @@ public class MercuryCli {
public MercuryCli() { public MercuryCli() {
createCliComponent(); createCliComponent();
userInterface = ConsoleUserInterface.isSupported() ? new ConsoleUserInterface() : new ScannerUserInterface(); userInterface = ConsoleUserInterface.isSupported() ? new ConsoleUserInterface() : new ScannerUserInterface();
//connectionStateDisposable = messenger.getConnectionCenter().observeConnectionPoolState().subscribe(System.out::println);
} }
private void loginDialog() { private void loginDialog() {

View File

@ -1,9 +1,11 @@
package org.mercury_im.messenger.cli.di.component; package org.mercury_im.messenger.cli.di.component;
import org.mercury_im.messenger.cli.MercuryCli; import org.mercury_im.messenger.cli.MercuryCli;
import org.mercury_im.messenger.cli.X509WorkaroundConnectionFactory; import org.mercury_im.messenger.cli.di.module.CliDatabaseModule;
import org.mercury_im.messenger.cli.di.module.CliPersistenceModule; import org.mercury_im.messenger.cli.di.module.CliSchedulersModule;
import org.mercury_im.messenger.cli.di.module.X509WorkaroundConnectionFactoryModule; 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.core.di.module.ViewModelModule;
import org.mercury_im.messenger.data.di.RepositoryModule; import org.mercury_im.messenger.data.di.RepositoryModule;
@ -14,10 +16,13 @@ import dagger.Component;
@Singleton @Singleton
@Component( @Component(
modules = { modules = {
CliPersistenceModule.class, CliDatabaseModule.class,
CliSchedulersModule.class,
RepositoryModule.class, RepositoryModule.class,
ViewModelModule.class, ViewModelModule.class,
X509WorkaroundConnectionFactoryModule.class X509WorkaroundConnectionFactoryModule.class,
RxMercuryMessageStoreFactoryModule.class,
RxMercuryRosterStoreFactoryModule.class
}) })
public interface CliComponent { public interface CliComponent {

View File

@ -1,7 +1,7 @@
package org.mercury_im.messenger.cli.di.module; package org.mercury_im.messenger.cli.di.module;
import org.h2.jdbcx.JdbcDataSource; 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 org.mercury_im.messenger.data.model.Models;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -24,9 +24,7 @@ import io.requery.sql.SchemaModifier;
import io.requery.sql.TableCreationMode; import io.requery.sql.TableCreationMode;
@Module @Module
public class CliPersistenceModule { public class CliDatabaseModule {
private static Scheduler scheduler = Schedulers.newThread();
@Provides @Provides
@Singleton @Singleton
@ -50,17 +48,4 @@ public class CliPersistenceModule {
return ReactiveSupport.toReactiveStore(new EntityDataStore<>(configuration)); 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;
}
} }

View File

@ -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();
}
}

View File

@ -1,6 +1,5 @@
package org.mercury_im.messenger.data.repository; 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.core.data.repository.EntityCapsRepository;
import org.mercury_im.messenger.data.mapping.EntityCapsMapping; import org.mercury_im.messenger.data.mapping.EntityCapsMapping;
import org.mercury_im.messenger.data.model.EntityCapsModel; import org.mercury_im.messenger.data.model.EntityCapsModel;
@ -10,12 +9,11 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import io.reactivex.Completable; import io.reactivex.Completable;
import io.reactivex.Maybe; import io.reactivex.Maybe;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.Scheduler; import io.reactivex.Single;
import io.requery.Persistable; import io.requery.Persistable;
import io.requery.reactivex.ReactiveEntityStore; import io.requery.reactivex.ReactiveEntityStore;
import io.requery.reactivex.ReactiveResult; import io.requery.reactivex.ReactiveResult;
@ -77,4 +75,10 @@ public class RxEntityCapsRepository extends RequeryRepository implements EntityC
return data().upsert(entityCapsMapping.toModel(entityCapsRecord)) return data().upsert(entityCapsMapping.toModel(entityCapsRecord))
.ignoreElement(); .ignoreElement();
} }
@Override
public Single<Integer> deleteAllEntityCapsRecords() {
return data().delete().from(EntityCapsModel.class)
.get().single();
}
} }

View File

@ -11,6 +11,7 @@ dependencies {
api "org.igniterealtime.smack:smack-extensions:$smackExtensionsVersion" api "org.igniterealtime.smack:smack-extensions:$smackExtensionsVersion"
api "org.igniterealtime.smack:smack-im:$smackImVersion" api "org.igniterealtime.smack:smack-im:$smackImVersion"
api "org.igniterealtime.smack:smack-tcp:$smackTcpVersion" api "org.igniterealtime.smack:smack-tcp:$smackTcpVersion"
api "org.igniterealtime.smack:smack-openpgp:$smackOpenpgpVersion"
testImplementation "org.igniterealtime.smack:smack-java7:$smackJava7Version" testImplementation "org.igniterealtime.smack:smack-java7:$smackJava7Version"

View File

@ -1,6 +1,5 @@
package org.mercury_im.messenger.core; package org.mercury_im.messenger.core;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.chat2.ChatManager; import org.jivesoftware.smack.chat2.ChatManager;
@ -10,11 +9,11 @@ import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException; import org.jxmpp.stringprep.XmppStringprepException;
import org.mercury_im.messenger.core.data.repository.Repositories; 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.ConnectionNotFoundException;
import org.mercury_im.messenger.core.exception.ContactAlreadyAddedException; import org.mercury_im.messenger.core.exception.ContactAlreadyAddedException;
import org.mercury_im.messenger.core.xmpp.MercuryConnection; import org.mercury_im.messenger.core.xmpp.MercuryConnection;
import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager; import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager;
import org.mercury_im.messenger.entity.contact.Peer;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
@ -25,7 +24,6 @@ import javax.inject.Singleton;
import io.reactivex.Completable; import io.reactivex.Completable;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
@Singleton @Singleton
public class Messenger { public class Messenger {
@ -35,17 +33,17 @@ public class Messenger {
private final MercuryConnectionManager connectionManager; private final MercuryConnectionManager connectionManager;
private final Repositories repositories; private final Repositories repositories;
private final SchedulersFacade schedulers;
private CompositeDisposable disposable = new CompositeDisposable(); private CompositeDisposable disposable = new CompositeDisposable();
static {
//SmackConfiguration.DEBUG = true;
}
@Inject @Inject
public Messenger(Repositories repositories, MercuryConnectionManager connectionManager) { public Messenger(Repositories repositories,
MercuryConnectionManager connectionManager,
SchedulersFacade schedulers) {
this.repositories = repositories; this.repositories = repositories;
this.connectionManager = connectionManager; this.connectionManager = connectionManager;
this.schedulers = schedulers;
performInitialLogin(); performInitialLogin();
} }
@ -56,7 +54,7 @@ public class Messenger {
public void performInitialLogin() { public void performInitialLogin() {
LOGGER.log(Level.INFO, "Perform initial login."); LOGGER.log(Level.INFO, "Perform initial login.");
disposable.add(repositories.getAccountRepository().observeAllAccounts().firstOrError() disposable.add(repositories.getAccountRepository().observeAllAccounts().firstOrError()
.subscribeOn(Schedulers.io()) .subscribeOn(schedulers.getIoScheduler())
.subscribe(connectionManager::doRegisterConnections)); .subscribe(connectionManager::doRegisterConnections));
} }

View File

@ -1,7 +1,5 @@
package org.mercury_im.messenger.core; package org.mercury_im.messenger.core;
import org.mercury_im.messenger.core.util.ThreadUtils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -10,19 +8,35 @@ import lombok.Getter;
public class SchedulersFacade { 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 @Getter
private final Scheduler io; private final Scheduler ioScheduler;
@Getter @Getter
private final Scheduler ui; private final Scheduler uiScheduler;
@Getter @Getter
private final Scheduler newThread; private final Scheduler newThread;
@Inject @Inject
public SchedulersFacade(@Named(value = ThreadUtils.SCHEDULER_IO) Scheduler io, public SchedulersFacade(@Named(value = SCHEDULER_IO) Scheduler ioScheduler,
@Named(value = ThreadUtils.SCHEDULER_UI) Scheduler ui, @Named(value = SCHEDULER_UI) Scheduler uiScheduler,
@Named(value = ThreadUtils.SCHEDULER_NEW_THREAD) Scheduler newThread) { @Named(value = SCHEDULER_NEW_THREAD) Scheduler newThread) {
this.io = io; this.ioScheduler = ioScheduler;
this.ui = ui; this.uiScheduler = uiScheduler;
this.newThread = newThread; this.newThread = newThread;
} }
} }

View File

@ -7,6 +7,7 @@ import java.util.Map;
import io.reactivex.Completable; import io.reactivex.Completable;
import io.reactivex.Maybe; import io.reactivex.Maybe;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.Single;
public interface EntityCapsRepository { public interface EntityCapsRepository {
@ -17,4 +18,6 @@ public interface EntityCapsRepository {
Maybe<EntityCapsRecord> maybeGetEntityCapsRecord(String nodeVer); Maybe<EntityCapsRecord> maybeGetEntityCapsRecord(String nodeVer);
Completable insertEntityCapsRecord(EntityCapsRecord entityCapsRecord); Completable insertEntityCapsRecord(EntityCapsRecord entityCapsRecord);
Single<Integer> deleteAllEntityCapsRecords();
} }

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -1,9 +1,11 @@
package org.mercury_im.messenger.core.di.module; 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.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.AccountsViewModel;
import org.mercury_im.messenger.core.viewmodel.accounts.LoginViewModel; 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 org.mercury_im.messenger.core.xmpp.MercuryConnectionManager;
import javax.inject.Named; import javax.inject.Named;
@ -20,17 +22,21 @@ public class ViewModelModule {
@Singleton @Singleton
static LoginViewModel provideLoginViewModel(MercuryConnectionManager connectionManager, static LoginViewModel provideLoginViewModel(MercuryConnectionManager connectionManager,
AccountRepository accountRepository, AccountRepository accountRepository,
@Named(ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler, SchedulersFacade schedulers) {
@Named(ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) { return new LoginViewModel(connectionManager, accountRepository, schedulers);
return new LoginViewModel(connectionManager, accountRepository, ioScheduler, uiScheduler);
} }
@Provides @Provides
@Singleton @Singleton
static AccountsViewModel provideAccountsViewModel(MercuryConnectionManager connectionManager, static AccountsViewModel provideAccountsViewModel(MercuryConnectionManager connectionManager,
AccountRepository accountRepository, AccountRepository accountRepository,
@Named(ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler, SchedulersFacade schedulers) {
@Named(ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) { return new AccountsViewModel(connectionManager, accountRepository, schedulers);
return new AccountsViewModel(connectionManager, accountRepository, ioScheduler, uiScheduler); }
@Provides
@Singleton
static ChatViewModel provideChatViewModel(Repositories repositories, SchedulersFacade schedulers) {
return new ChatViewModel(repositories, schedulers);
} }
} }

View File

@ -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.util.PacketParserUtils;
import org.jivesoftware.smack.xml.XmlPullParser; import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smackx.caps.cache.EntityCapsPersistentCache; import org.jivesoftware.smackx.caps.cache.EntityCapsPersistentCache;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo; 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.core.data.repository.EntityCapsRepository;
import org.mercury_im.messenger.entity.caps.EntityCapsRecord; import org.mercury_im.messenger.entity.caps.EntityCapsRecord;
import org.mercury_im.messenger.core.logging.Tags; 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 CompositeDisposable disposable = new CompositeDisposable();
private final EntityCapsRepository repository; private final EntityCapsRepository repository;
private final SchedulersFacade schedulers;
@Inject @Inject
public MercuryEntityCapsStore(EntityCapsRepository entityCapsRepository) { public MercuryEntityCapsStore(EntityCapsRepository entityCapsRepository,
SchedulersFacade schedulers) {
this.repository = entityCapsRepository; this.repository = entityCapsRepository;
this.schedulers = schedulers;
} }
@Override @Override
@ -37,7 +41,9 @@ public class MercuryEntityCapsStore implements EntityCapsPersistentCache {
record.setNodeVer(nodeVer); record.setNodeVer(nodeVer);
record.setXml(info.toXML().toString()); record.setXml(info.toXML().toString());
disposable.add(repository.insertEntityCapsRecord(record).subscribe()); disposable.add(repository.insertEntityCapsRecord(record)
.subscribeOn(schedulers.getIoScheduler())
.subscribe());
} }
@Override @Override
@ -46,6 +52,7 @@ public class MercuryEntityCapsStore implements EntityCapsPersistentCache {
EntityCapsRecord defaultIfEmpty = new EntityCapsRecord(); EntityCapsRecord defaultIfEmpty = new EntityCapsRecord();
EntityCapsRecord record = repository.maybeGetEntityCapsRecord(nodeVer) EntityCapsRecord record = repository.maybeGetEntityCapsRecord(nodeVer)
.defaultIfEmpty(defaultIfEmpty) .defaultIfEmpty(defaultIfEmpty)
.subscribeOn(schedulers.getIoScheduler())
.blockingGet(); .blockingGet();
if (record == defaultIfEmpty) { if (record == defaultIfEmpty) {
return null; return null;
@ -66,6 +73,8 @@ public class MercuryEntityCapsStore implements EntityCapsPersistentCache {
@Override @Override
public void emptyCache() { public void emptyCache() {
LOGGER.log(Level.INFO, "MercuryEntityCapsStore: emptyCache."); LOGGER.log(Level.INFO, "MercuryEntityCapsStore: emptyCache.");
// Not needed? disposable.add(repository.deleteAllEntityCapsRecords()
.subscribeOn(schedulers.getIoScheduler())
.subscribe());
} }
} }

View File

@ -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.IncomingChatMessageListener;
import org.jivesoftware.smack.chat2.OutgoingChatMessageListener; import org.jivesoftware.smack.chat2.OutgoingChatMessageListener;
import org.jivesoftware.smack.packet.MessageBuilder; import org.jivesoftware.smack.packet.MessageBuilder;
import org.jivesoftware.smackx.delay.packet.DelayInformation; import org.jivesoftware.smackx.delay.packet.DelayInformation;
import org.jxmpp.jid.EntityBareJid; 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.DirectChatRepository;
import org.mercury_im.messenger.core.data.repository.MessageRepository; 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.PeerRepository;
@ -16,9 +17,13 @@ import java.util.Date;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import io.reactivex.disposables.CompositeDisposable; import javax.inject.Inject;
import io.reactivex.schedulers.Schedulers; import javax.inject.Singleton;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
@Singleton
public class MercuryMessageStore implements IncomingChatMessageListener, OutgoingChatMessageListener { public class MercuryMessageStore implements IncomingChatMessageListener, OutgoingChatMessageListener {
private static final Logger LOGGER = Logger.getLogger(MercuryMessageStore.class.getName()); 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 MessageRepository messageRepository;
private final DirectChatRepository directChatRepository; private final DirectChatRepository directChatRepository;
private final PeerRepository peerRepository; private final PeerRepository peerRepository;
private final SchedulersFacade schedulers;
private Account account; private Account account;
private CompositeDisposable disposable = new CompositeDisposable(); private CompositeDisposable disposable = new CompositeDisposable();
@Inject
public MercuryMessageStore(Account account, public MercuryMessageStore(Account account,
PeerRepository peerRepository, PeerRepository peerRepository,
DirectChatRepository directChatRepository, DirectChatRepository directChatRepository,
MessageRepository messageRepository) { MessageRepository messageRepository,
SchedulersFacade schedulers) {
this.account = account; this.account = account;
this.peerRepository = peerRepository; this.peerRepository = peerRepository;
this.directChatRepository = directChatRepository; this.directChatRepository = directChatRepository;
this.messageRepository = messageRepository; this.messageRepository = messageRepository;
this.schedulers = schedulers;
} }
@Override @Override
@ -54,11 +63,7 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin
if (smackMessage.getBody() != null) { if (smackMessage.getBody() != null) {
message.setBody(smackMessage.getBody()); message.setBody(smackMessage.getBody());
} }
disposable.add(peerRepository.getOrCreatePeer(account, from.asEntityBareJidString()) disposable.add(writeMessageToStore(from.asEntityBareJidString(), message));
.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)));
} }
@Override @Override
@ -73,9 +78,14 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin
if (smackMessage.getBody() != null) { if (smackMessage.getBody() != null) {
message.setBody(smackMessage.getBody().getMessage()); 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(directChatRepository::getOrCreateChatWithPeer)
.flatMap(chat -> messageRepository.insertMessage(chat, message)) .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));
} }
} }

View File

@ -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);
}

View File

@ -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.packet.RosterPacket;
import org.jivesoftware.smack.roster.rosterstore.RosterStore; import org.jivesoftware.smack.roster.rosterstore.RosterStore;
import org.jxmpp.jid.Jid; import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate; 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.AccountRepository;
import org.mercury_im.messenger.core.data.repository.PeerRepository; import org.mercury_im.messenger.core.data.repository.PeerRepository;
import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.Account;
@ -37,24 +38,28 @@ public class MercuryRosterStore implements RosterStore {
private final Map<String, RosterPacket.Item> itemMap = new HashMap<>(); private final Map<String, RosterPacket.Item> itemMap = new HashMap<>();
private String rosterVersion; 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.accountId = accountId;
this.account = BehaviorSubject.create(); this.account = BehaviorSubject.create();
this.peerRepository = rosterRepository; this.peerRepository = rosterRepository;
this.accountRepository = accountRepository; this.accountRepository = accountRepository;
this.schedulers = schedulers;
LOGGER.log(Level.INFO, "Construct Roster Store for " + accountId); LOGGER.log(Level.INFO, "Construct Roster Store for " + accountId);
subscribe(); subscribe();
} }
public void subscribe() { public void subscribe() {
// Subscribe database to behaviorSubject for quick access
accountRepository.observeAccount(accountId) accountRepository.observeAccount(accountId)
.subscribeOn(Schedulers.io()) .subscribeOn(schedulers.getIoScheduler())
.observeOn(Schedulers.io()) .observeOn(schedulers.getIoScheduler())
.subscribe(account); .subscribe(account);
disposable.add(peerRepository.observeAllContactsOfAccount(accountId) disposable.add(peerRepository.observeAllContactsOfAccount(accountId)
.subscribeOn(Schedulers.io()) .subscribeOn(schedulers.getIoScheduler())
.observeOn(Schedulers.computation()) .observeOn(schedulers.getIoScheduler())
.subscribe(contactsList -> { .subscribe(contactsList -> {
itemMap.clear(); itemMap.clear();
for (Peer contactModel : contactsList) { for (Peer contactModel : contactsList) {
@ -67,8 +72,8 @@ public class MercuryRosterStore implements RosterStore {
disposable.add(accountRepository.getAccount(accountId) disposable.add(accountRepository.getAccount(accountId)
.map(Account::getRosterVersion) .map(Account::getRosterVersion)
.subscribeOn(Schedulers.io()) .subscribeOn(schedulers.getIoScheduler())
.observeOn(Schedulers.computation()) .observeOn(schedulers.getIoScheduler())
.subscribe(this::setRosterVersion, .subscribe(this::setRosterVersion,
error -> LOGGER.log(Level.WARNING, "An error occurred updating cached roster version", error))); 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<RosterPacket.Item> items, String version) { public boolean resetEntries(Collection<RosterPacket.Item> items, String version) {
LOGGER.log(Level.INFO, "Reset Entries: " + Arrays.toString(items.toArray())); LOGGER.log(Level.INFO, "Reset Entries: " + Arrays.toString(items.toArray()));
// Update database // Update database
// TODO: Delete other contacts disposable.add(peerRepository.deleteAllPeers(accountId).subscribe());
for (RosterPacket.Item item : items) { for (RosterPacket.Item item : items) {
writeEntryToDatabase(item); writeEntryToDatabase(item);
} }

View File

@ -0,0 +1,8 @@
package org.mercury_im.messenger.core.store.roster;
import java.util.UUID;
public interface MercuryRosterStoreFactory {
MercuryRosterStore createRosterStore(UUID accountId);
}

View File

@ -10,14 +10,12 @@ import org.jivesoftware.smack.roster.SubscribeListener;
import org.jxmpp.jid.BareJid; import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.FullJid; import org.jxmpp.jid.FullJid;
import org.jxmpp.jid.Jid; import org.jxmpp.jid.Jid;
import org.mercury_im.messenger.core.data.repository.AccountRepository; import org.mercury_im.messenger.core.store.roster.MercuryRosterStore;
import org.mercury_im.messenger.core.data.repository.PeerRepository; import org.mercury_im.messenger.core.store.roster.MercuryRosterStoreFactory;
import org.mercury_im.messenger.core.store.MercuryRosterStore;
import org.mercury_im.messenger.core.xmpp.MercuryConnection; import org.mercury_im.messenger.core.xmpp.MercuryConnection;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -25,20 +23,18 @@ import javax.inject.Inject;
public class RosterStoreBinder { public class RosterStoreBinder {
private final AccountRepository accountRepository; private final MercuryRosterStoreFactory rosterStoreFactory;
private final PeerRepository peerRepository;
private final Logger LOGGER = Logger.getLogger(RosterStoreBinder.class.getName()); private final Logger LOGGER = Logger.getLogger(RosterStoreBinder.class.getName());
@Inject @Inject
public RosterStoreBinder(AccountRepository accountRepository, PeerRepository peerRepository) { public RosterStoreBinder(MercuryRosterStoreFactory rosterStoreFactory) {
this.accountRepository = accountRepository;
this.peerRepository = peerRepository; this.rosterStoreFactory = rosterStoreFactory;
} }
public void setRosterStoreOn(MercuryConnection connection) { public void setRosterStoreOn(MercuryConnection connection) {
MercuryRosterStore store = MercuryRosterStore store = rosterStoreFactory.createRosterStore(connection.getAccountId());
createRosterStore(connection.getAccount().getId(), accountRepository, peerRepository);
Roster roster = Roster.getInstanceFor(connection.getConnection()); Roster roster = Roster.getInstanceFor(connection.getConnection());
roster.setRosterStore(store); roster.setRosterStore(store);
roster.addSubscribeListener(new SubscribeListener() { 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);
}
} }

View File

@ -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";
}

View File

@ -1,19 +1,16 @@
package org.mercury_im.messenger.core.viewmodel.accounts; 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.data.repository.AccountRepository;
import org.mercury_im.messenger.core.viewmodel.MercuryViewModel; 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.MercuryConnectionManager;
import org.mercury_im.messenger.core.xmpp.state.ConnectionPoolState; 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.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.inject.Named;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.Scheduler;
public class AccountsViewModel implements MercuryViewModel { public class AccountsViewModel implements MercuryViewModel {
@ -21,18 +18,15 @@ public class AccountsViewModel implements MercuryViewModel {
private final MercuryConnectionManager connectionManager; private final MercuryConnectionManager connectionManager;
private final AccountRepository accountRepository; private final AccountRepository accountRepository;
private final Scheduler ioScheduler; private final SchedulersFacade schedulers;
private final Scheduler uiScheduler;
public AccountsViewModel(MercuryConnectionManager connectionManager, public AccountsViewModel(MercuryConnectionManager connectionManager,
AccountRepository accountRepository, AccountRepository accountRepository,
@Named(ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler, SchedulersFacade schedulers) {
@Named(ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) {
this.connectionManager = connectionManager; this.connectionManager = connectionManager;
this.accountRepository = accountRepository; this.accountRepository = accountRepository;
this.ioScheduler = ioScheduler; this.schedulers = schedulers;
this.uiScheduler = uiScheduler;
} }
@ -43,8 +37,8 @@ public class AccountsViewModel implements MercuryViewModel {
public void onToggleAccountEnabled(Account account, boolean enabled) { public void onToggleAccountEnabled(Account account, boolean enabled) {
account.setEnabled(enabled); account.setEnabled(enabled);
addDisposable(accountRepository.upsertAccount(account) addDisposable(accountRepository.upsertAccount(account)
.subscribeOn(ioScheduler) .subscribeOn(schedulers.getIoScheduler())
.observeOn(uiScheduler) .observeOn(schedulers.getUiScheduler())
.subscribe( .subscribe(
success -> logAccountToggledSuccess(success, enabled), success -> logAccountToggledSuccess(success, enabled),
error -> logAccountToggleError(account, enabled, error) error -> logAccountToggleError(account, enabled, error)

View File

@ -4,27 +4,24 @@ import org.jivesoftware.smack.util.StringUtils;
import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException; 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.PasswordError;
import org.mercury_im.messenger.core.account.error.UsernameError; import org.mercury_im.messenger.core.account.error.UsernameError;
import org.mercury_im.messenger.core.data.repository.AccountRepository; 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.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.MercuryConnection;
import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager; 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.InvalidCredentialsException;
import org.mercury_im.messenger.core.xmpp.exception.ServerUnreachableException; 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.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.Scheduler;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject; import io.reactivex.subjects.BehaviorSubject;
public class LoginViewModel implements MercuryViewModel { public class LoginViewModel implements MercuryViewModel {
@ -34,8 +31,7 @@ public class LoginViewModel implements MercuryViewModel {
private final MercuryConnectionManager connectionManager; private final MercuryConnectionManager connectionManager;
private final AccountRepository accountRepository; private final AccountRepository accountRepository;
private final Scheduler ioScheduler; private final SchedulersFacade schedulers;
private final Scheduler uiScheduler;
private BehaviorSubject<Optional<UsernameError>> loginUsernameError; private BehaviorSubject<Optional<UsernameError>> loginUsernameError;
private BehaviorSubject<Optional<PasswordError>> loginPasswordError; private BehaviorSubject<Optional<PasswordError>> loginPasswordError;
@ -48,12 +44,10 @@ public class LoginViewModel implements MercuryViewModel {
@Inject @Inject
public LoginViewModel(MercuryConnectionManager connectionManager, public LoginViewModel(MercuryConnectionManager connectionManager,
AccountRepository accountRepository, AccountRepository accountRepository,
@Named(ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler, SchedulersFacade schedulers) {
@Named(ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) {
this.connectionManager = connectionManager; this.connectionManager = connectionManager;
this.accountRepository = accountRepository; this.accountRepository = accountRepository;
this.ioScheduler = ioScheduler; this.schedulers = schedulers;
this.uiScheduler = uiScheduler;
reset(); reset();
} }
@ -129,8 +123,8 @@ public class LoginViewModel implements MercuryViewModel {
.andThen(connection.login()) .andThen(connection.login())
.andThen(connectionManager.registerConnection(connection)) .andThen(connectionManager.registerConnection(connection))
.andThen(accountRepository.insertAccount(account)) .andThen(accountRepository.insertAccount(account))
.subscribeOn(Schedulers.newThread()) .subscribeOn(schedulers.getNewThread())
.observeOn(uiScheduler) .observeOn(schedulers.getUiScheduler())
.subscribe( .subscribe(
this::onLoginSuccessful, this::onLoginSuccessful,
this::onLoginFailed this::onLoginFailed

View File

@ -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;
}
}

View File

@ -2,15 +2,17 @@ package org.mercury_im.messenger.core.xmpp;
import org.jivesoftware.smack.chat2.ChatManager; import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smackx.caps.EntityCapsManager; 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.AccountRepository;
import org.mercury_im.messenger.core.data.repository.DirectChatRepository; 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.MessageRepository;
import org.mercury_im.messenger.core.data.repository.PeerRepository; import org.mercury_im.messenger.core.data.repository.PeerRepository;
import org.mercury_im.messenger.core.data.repository.Repositories; 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.core.xmpp.state.ConnectionPoolState;
import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.core.store.MercuryEntityCapsStore; import org.mercury_im.messenger.core.store.caps.MercuryEntityCapsStore;
import org.mercury_im.messenger.core.store.MercuryMessageStore; import org.mercury_im.messenger.core.store.message.MercuryMessageStore;
import org.mercury_im.messenger.core.usecase.RosterStoreBinder; import org.mercury_im.messenger.core.usecase.RosterStoreBinder;
import org.mercury_im.messenger.core.util.Optional; import org.mercury_im.messenger.core.util.Optional;
import org.mercury_im.messenger.core.xmpp.state.ConnectionState; 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 static final Logger LOGGER = Logger.getLogger("ConnectionManager");
private final XmppConnectionFactory connectionFactory; private final XmppConnectionFactory connectionFactory;
private final MercuryMessageStoreFactory messageStoreFactory;
private final AccountRepository accountRepository; private final AccountRepository accountRepository;
private final RosterStoreBinder rosterStoreBinder; private final RosterStoreBinder rosterStoreBinder;
private final MercuryEntityCapsStore entityCapsStore; private final MercuryEntityCapsStore entityCapsStore;
private final PeerRepository peerRepository; private final PeerRepository peerRepository;
private final DirectChatRepository directChatRepository; private final DirectChatRepository directChatRepository;
private final MessageRepository messageRepository; private final MessageRepository messageRepository;
private final SchedulersFacade schedulers;
private final Map<UUID, MercuryConnection> connectionsMap = new ConcurrentHashMap<>(); private final Map<UUID, MercuryConnection> connectionsMap = new ConcurrentHashMap<>();
private final Map<UUID, Disposable> connectionDisposables = new ConcurrentHashMap<>(); private final Map<UUID, Disposable> connectionDisposables = new ConcurrentHashMap<>();
@ -61,7 +65,9 @@ public class MercuryConnectionManager {
public MercuryConnectionManager(Repositories repositories, public MercuryConnectionManager(Repositories repositories,
RosterStoreBinder rosterStoreBinder, RosterStoreBinder rosterStoreBinder,
MercuryEntityCapsStore entityCapsStore, MercuryEntityCapsStore entityCapsStore,
XmppConnectionFactory connectionFactory) { MercuryMessageStoreFactory messageStoreFactory,
XmppConnectionFactory connectionFactory,
SchedulersFacade schedulers) {
this.accountRepository = repositories.getAccountRepository(); this.accountRepository = repositories.getAccountRepository();
this.rosterStoreBinder = rosterStoreBinder; this.rosterStoreBinder = rosterStoreBinder;
this.entityCapsStore = entityCapsStore; this.entityCapsStore = entityCapsStore;
@ -69,14 +75,17 @@ public class MercuryConnectionManager {
this.directChatRepository = repositories.getDirectChatRepository(); this.directChatRepository = repositories.getDirectChatRepository();
this.messageRepository = repositories.getMessageRepository(); this.messageRepository = repositories.getMessageRepository();
this.connectionFactory = connectionFactory; this.connectionFactory = connectionFactory;
this.messageStoreFactory = messageStoreFactory;
this.schedulers = schedulers;
EntityCapsManager.setPersistentCache(entityCapsStore); EntityCapsManager.setPersistentCache(entityCapsStore);
start(); start();
} }
public void start() { public void start() {
accountRepository.observeAllAccounts() disposable.add(accountRepository.observeAllAccounts()
.subscribe(accounts -> doRegisterConnections(accounts)); .subscribeOn(schedulers.getIoScheduler())
.subscribe(this::doRegisterConnections));
} }
public List<MercuryConnection> getConnections() { public List<MercuryConnection> getConnections() {
@ -139,14 +148,14 @@ public class MercuryConnectionManager {
public void bindConnection(MercuryConnection connection) { public void bindConnection(MercuryConnection connection) {
rosterStoreBinder.setRosterStoreOn(connection); rosterStoreBinder.setRosterStoreOn(connection);
accountRepository.getAccount(connection.getAccountId()) disposable.add(accountRepository.getAccount(connection.getAccountId())
.subscribeOn(Schedulers.io()) .subscribeOn(schedulers.getIoScheduler())
.subscribe(account -> { .subscribe(account -> {
MercuryMessageStore mercuryMessageStore = new MercuryMessageStore(account, peerRepository, directChatRepository, messageRepository); MercuryMessageStore mercuryMessageStore = messageStoreFactory.createMessageStore(account);
ChatManager chatManager = ChatManager.getInstanceFor(connection.getConnection()); ChatManager chatManager = ChatManager.getInstanceFor(connection.getConnection());
chatManager.addIncomingListener(mercuryMessageStore); chatManager.addIncomingListener(mercuryMessageStore);
chatManager.addOutgoingListener(mercuryMessageStore); chatManager.addOutgoingListener(mercuryMessageStore);
}); }));
} }