From b56b451a4beea693f37b925f9386a41227ddf5d0 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 11 May 2020 16:31:07 +0200 Subject: [PATCH] Wip --- .../messenger/MercuryImApplication.java | 3 +- .../account/AccountsRecyclerViewAdapter.java | 2 +- .../messenger/ui/account/LoginViewModel.java | 11 +++ .../org/mercury_im/messenger/Messenger.java | 44 +--------- .../messenger/store/MercuryRosterStore.java | 17 ++-- .../messenger/usecase/AddAccount.java | 82 ------------------- .../messenger/usecase/AddAccountUseCase.java | 17 ---- .../messenger/usecase/LogIntoAccount.java | 6 +- .../messenger/usecase/RosterStoreBinder.java | 8 +- .../mercury_im/messenger/xmpp/CsiManager.java | 51 ++++++++++++ .../messenger/xmpp/MercuryConnection.java | 43 +++++++--- .../xmpp/MercuryConnectionManager.java | 7 +- .../InvalidCredentialsException.java | 10 +++ .../exception/ServerUnreachableException.java | 10 +++ .../smack/AddAccountUseCaseTest.java | 17 ---- libs/Smack | 2 +- 16 files changed, 142 insertions(+), 188 deletions(-) delete mode 100644 domain/src/main/java/org/mercury_im/messenger/usecase/AddAccount.java delete mode 100644 domain/src/main/java/org/mercury_im/messenger/usecase/AddAccountUseCase.java create mode 100644 domain/src/main/java/org/mercury_im/messenger/xmpp/CsiManager.java create mode 100644 domain/src/main/java/org/mercury_im/messenger/xmpp/exception/InvalidCredentialsException.java create mode 100644 domain/src/main/java/org/mercury_im/messenger/xmpp/exception/ServerUnreachableException.java delete mode 100644 domain/src/test/java/org/mercury_im/messenger/learning_tests/smack/AddAccountUseCaseTest.java diff --git a/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java b/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java index 480082c..09b439e 100644 --- a/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java +++ b/app/src/main/java/org/mercury_im/messenger/MercuryImApplication.java @@ -10,6 +10,7 @@ import org.mercury_im.messenger.di.component.DaggerAppComponent; import org.mercury_im.messenger.di.module.AppModule; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.service.MercuryConnectionService; +import org.mercury_im.messenger.xmpp.CsiManager; import java.util.List; @@ -56,7 +57,7 @@ public class MercuryImApplication extends Application { } private void setupClientStateIndication() { - clientStateHandler.addClientStateListener(messenger); + clientStateHandler.addClientStateListener(new CsiManager(messenger.getConnectionManager())); registerActivityLifecycleCallbacks(clientStateHandler); } diff --git a/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsRecyclerViewAdapter.java b/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsRecyclerViewAdapter.java index 97dc0e9..79688ba 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsRecyclerViewAdapter.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/account/AccountsRecyclerViewAdapter.java @@ -116,7 +116,7 @@ public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter { + connection.connect().login(); + }) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe() + ); disposable.add(messenger.addAccount() .execute(account) .subscribeOn(Schedulers.newThread()) diff --git a/domain/src/main/java/org/mercury_im/messenger/Messenger.java b/domain/src/main/java/org/mercury_im/messenger/Messenger.java index 1e53829..30cd819 100644 --- a/domain/src/main/java/org/mercury_im/messenger/Messenger.java +++ b/domain/src/main/java/org/mercury_im/messenger/Messenger.java @@ -1,11 +1,6 @@ package org.mercury_im.messenger; -import org.jivesoftware.smack.SmackException; -import org.jivesoftware.smackx.csi.ClientStateIndicationManager; import org.mercury_im.messenger.data.repository.Repositories; -import org.mercury_im.messenger.usecase.AddAccount; -import org.mercury_im.messenger.usecase.RosterStoreBinder; -import org.mercury_im.messenger.xmpp.MercuryConnection; import org.mercury_im.messenger.xmpp.MercuryConnectionManager; import java.util.logging.Level; @@ -18,7 +13,7 @@ import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; @Singleton -public class Messenger implements ClientStateListener { +public class Messenger { public static final String TAG = "MercuryIM"; private static final Logger LOGGER = Logger.getLogger(Messenger.class.getName()); @@ -46,41 +41,4 @@ public class Messenger implements ClientStateListener { .subscribe(connectionManager::registerConnections)); } - public AddAccount addAccount() { - return new AddAccount(repositories.getAccountRepository(), this.connectionManager); - } - - // CSI - - @Override - public void onClientInForeground() { - LOGGER.log(Level.INFO, "CSI: active"); - for (MercuryConnection connection : connectionManager.getConnections()) { - tryCsiActive(connection); - } - } - - @Override - public void onClientInBackground() { - LOGGER.log(Level.INFO, "CSI: inactive"); - for (MercuryConnection connection : connectionManager.getConnections()) { - tryCsiInactive(connection); - } - } - - private void tryCsiActive(MercuryConnection connection) { - try { - ClientStateIndicationManager.active(connection.getConnection()); - } catch (SmackException.NotConnectedException | InterruptedException e) { - LOGGER.log(Level.WARNING, "Sending CSI state 'active' failed.", e); - } - } - - private void tryCsiInactive(MercuryConnection connection) { - try { - ClientStateIndicationManager.inactive(connection.getConnection()); - } catch (SmackException.NotConnectedException | InterruptedException e) { - LOGGER.log(Level.WARNING, "Sending CSI state 'inactive' failed.", e); - } - } } diff --git a/domain/src/main/java/org/mercury_im/messenger/store/MercuryRosterStore.java b/domain/src/main/java/org/mercury_im/messenger/store/MercuryRosterStore.java index 63e9450..3972d00 100644 --- a/domain/src/main/java/org/mercury_im/messenger/store/MercuryRosterStore.java +++ b/domain/src/main/java/org/mercury_im/messenger/store/MercuryRosterStore.java @@ -16,6 +16,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -28,21 +29,21 @@ public class MercuryRosterStore implements RosterStore { private final PeerRepository peerRepository; private final AccountRepository accountRepository; - private Account account; + private UUID accountId; private final CompositeDisposable disposable = new CompositeDisposable(); private final Map itemMap = new HashMap<>(); private String rosterVersion; - public MercuryRosterStore(Account account, PeerRepository rosterRepository, AccountRepository accountRepository) { - this.account = account; + public MercuryRosterStore(UUID accountId, PeerRepository rosterRepository, AccountRepository accountRepository) { + this.accountId = accountId; this.peerRepository = rosterRepository; this.accountRepository = accountRepository; - LOGGER.log(Level.INFO, "Construct Roster Store for " + account.getId()); + LOGGER.log(Level.INFO, "Construct Roster Store for " + accountId); } public void subscribe() { - disposable.add(peerRepository.observeAllContactsOfAccount(account) + disposable.add(peerRepository.observeAllContactsOfAccount(accountId) .observeOn(Schedulers.computation()) .subscribe(contactsList -> { itemMap.clear(); @@ -96,7 +97,7 @@ public class MercuryRosterStore implements RosterStore { } private void writeEntryToDatabase(RosterPacket.Item item) { - disposable.add(peerRepository.getOrCreatePeer(account, item.getJid().asUnescapedString()) + disposable.add(peerRepository.getOrCreatePeer(accountId, item.getJid().asUnescapedString()) .map(peer -> toEntity(item, peer)) .flatMap(peerRepository::upsertPeer) .subscribe( @@ -139,7 +140,7 @@ public class MercuryRosterStore implements RosterStore { public boolean removeEntry(Jid bareJid, String version) { LOGGER.log(Level.INFO, "Remove entry " + bareJid.toString()); - disposable.add(peerRepository.deletePeer(account.getId(), bareJid.asEntityBareJidOrThrow().asEntityBareJidString()) + disposable.add(peerRepository.deletePeer(accountId, bareJid.asEntityBareJidOrThrow().asEntityBareJidString()) .subscribe( () -> LOGGER.log(Level.FINE, "Deletion of contact " + bareJid.toString() + " successful"), error -> LOGGER.log(Level.WARNING, "An error occurred deleting contact " + bareJid.toString(), error) @@ -185,7 +186,7 @@ public class MercuryRosterStore implements RosterStore { } public Peer toEntity(RosterPacket.Item item, Peer peer) { - peer.setAccount(account); + peer.setAccount(accountRepository.getAccount(accountId).blockingGet()); peer.setAddress(item.getJid().asEntityBareJidOrThrow().asEntityBareJidString()); peer.setName(item.getName()); if (item.getItemType() != null) { diff --git a/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccount.java b/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccount.java deleted file mode 100644 index 87d0b46..0000000 --- a/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccount.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.mercury_im.messenger.usecase; - -import org.mercury_im.messenger.data.repository.AccountRepository; -import org.mercury_im.messenger.entity.Account; -import org.mercury_im.messenger.xmpp.MercuryConnection; -import org.mercury_im.messenger.xmpp.MercuryConnectionManager; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.reactivex.Completable; -import io.reactivex.Single; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -public class AddAccount { - - private static final Logger LOGGER = Logger.getLogger(AddAccount.class.getName()); - - private final AccountRepository accountRepository; - private final MercuryConnectionManager connectionManager; - - private final CompositeDisposable disposable = new CompositeDisposable(); - - public AddAccount(AccountRepository accountRepository, MercuryConnectionManager connectionManager) { - this.accountRepository = accountRepository; - this.connectionManager = connectionManager; - } - - public Completable execute(Account account) { - return loginAndStoreAccountIfSuccessful(account); - } - - private Completable loginAndStoreAccountIfSuccessful(Account account) { - LOGGER.log(Level.INFO, "loginAndStoreIfSuccessful"); - return logIntoAccount(account).flatMap(connection -> - insertEnabledAccountIntoDatabase(account).flatMap(insertedAccount -> - updateAccountIdInConnectionSingle(insertedAccount, connection))) - .map(this::addConnectionToMessenger) - .ignoreElement(); - } - - private Single logIntoAccount(Account account) { - return getOrCreateConnectionSingle(account) - .doAfterSuccess(con -> LogIntoAccount.with(con).executeAndPossiblyThrow()) - .subscribeOn(Schedulers.io()); - } - - private Single getOrCreateConnectionSingle(Account account) { - return Single.fromCallable(() -> getOrCreateConnection(account)); - } - - private MercuryConnection getOrCreateConnection(Account account) { - MercuryConnection connection = connectionManager.getConnection(account); - if (connection == null) { - connection = new MercuryConnection(accountRepository, account); - } - return connection; - } - - private Single insertEnabledAccountIntoDatabase(Account account) { - account.setEnabled(true); - return accountRepository.upsertAccount(account); - } - - private Completable addConnectionToMessenger(MercuryConnection connection) { - return Completable.fromAction(() -> connectionManager.registerConnection(connection)); - } - - private Single updateAccountIdInConnectionSingle(Account account, MercuryConnection connection) { - return Single.fromCallable(() -> { - updateAccountIdInConnection(account, connection); - return connection; - }); - } - - private void updateAccountIdInConnection(Account account, MercuryConnection connection) { - if (connection != null) { - connection.getAccount().setId(account.getId()); - } - } -} diff --git a/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccountUseCase.java b/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccountUseCase.java deleted file mode 100644 index 6316d3d..0000000 --- a/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccountUseCase.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.mercury_im.messenger.usecase; - -import io.reactivex.Completable; - -public interface AddAccountUseCase { - - AddAccountTask create(); - - Completable execute(AddAccountTask task); - - interface AddAccountTask { - - void setAddress(String address); - - void setPassword(String password); - } -} diff --git a/domain/src/main/java/org/mercury_im/messenger/usecase/LogIntoAccount.java b/domain/src/main/java/org/mercury_im/messenger/usecase/LogIntoAccount.java index a3b74da..00662fd 100644 --- a/domain/src/main/java/org/mercury_im/messenger/usecase/LogIntoAccount.java +++ b/domain/src/main/java/org/mercury_im/messenger/usecase/LogIntoAccount.java @@ -50,14 +50,14 @@ public class LogIntoAccount { doAuthenticateIfNecessary(); return ConnectionResult.success; } catch (SASLErrorException e) { - LOGGER.log(Level.WARNING, "SASL Error while connecting to account " + connection.getAccount().getAddress(), e); + LOGGER.log(Level.WARNING, "SASL Error while connecting to account " + connection.getAccountId(), e); return ConnectionResult.credential_error; } catch (SmackException.ConnectionException e) { - LOGGER.log(Level.WARNING, "Connectivity error while connecting to account " + connection.getAccount().getAddress(), e); + LOGGER.log(Level.WARNING, "Connectivity error while connecting to account " + connection.getAccountId(), e); return ConnectionResult.server_error; } catch (IOException | XMPPException | SmackException | InterruptedException e) { - LOGGER.log(Level.WARNING, "Error connecting to account " + connection.getAccount().getAddress(), e); + LOGGER.log(Level.WARNING, "Error connecting to account " + connection.getAccountId(), e); return ConnectionResult.other_error; } } diff --git a/domain/src/main/java/org/mercury_im/messenger/usecase/RosterStoreBinder.java b/domain/src/main/java/org/mercury_im/messenger/usecase/RosterStoreBinder.java index 795916f..5874272 100644 --- a/domain/src/main/java/org/mercury_im/messenger/usecase/RosterStoreBinder.java +++ b/domain/src/main/java/org/mercury_im/messenger/usecase/RosterStoreBinder.java @@ -7,6 +7,8 @@ import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.store.MercuryRosterStore; import org.mercury_im.messenger.xmpp.MercuryConnection; +import java.util.UUID; + import javax.inject.Inject; public class RosterStoreBinder { @@ -22,12 +24,12 @@ public class RosterStoreBinder { public void setRosterStoreOn(MercuryConnection connection) { MercuryRosterStore store = - createRosterStore(connection.getAccount(), accountRepository, peerRepository); + createRosterStore(connection.getAccountId(), accountRepository, peerRepository); Roster roster = Roster.getInstanceFor(connection.getConnection()); roster.setRosterStore(store); } - private MercuryRosterStore createRosterStore(Account account, AccountRepository accountRepository, PeerRepository peerRepository) { - return new MercuryRosterStore(account, peerRepository, accountRepository); + 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/xmpp/CsiManager.java b/domain/src/main/java/org/mercury_im/messenger/xmpp/CsiManager.java new file mode 100644 index 0000000..f380595 --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/xmpp/CsiManager.java @@ -0,0 +1,51 @@ +package org.mercury_im.messenger.xmpp; + +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smackx.csi.ClientStateIndicationManager; +import org.mercury_im.messenger.ClientStateListener; + +import java.util.logging.Level; +import java.util.logging.Logger; + +public class CsiManager implements ClientStateListener { + + private final MercuryConnectionManager connectionManager; + private static final Logger LOGGER = Logger.getLogger(CsiManager.class.getName()); + + public CsiManager(MercuryConnectionManager connectionManager) { + this.connectionManager = connectionManager; + + } + + @Override + public void onClientInForeground() { + LOGGER.log(Level.INFO, "CSI: active"); + for (MercuryConnection connection : connectionManager.getConnections()) { + tryCsiActive(connection); + } + } + + @Override + public void onClientInBackground() { + LOGGER.log(Level.INFO, "CSI: inactive"); + for (MercuryConnection connection : connectionManager.getConnections()) { + tryCsiInactive(connection); + } + } + + private void tryCsiActive(MercuryConnection connection) { + try { + ClientStateIndicationManager.active(connection.getConnection()); + } catch (SmackException.NotConnectedException | InterruptedException e) { + LOGGER.log(Level.WARNING, "Sending CSI state 'active' failed.", e); + } + } + + private void tryCsiInactive(MercuryConnection connection) { + try { + ClientStateIndicationManager.inactive(connection.getConnection()); + } catch (SmackException.NotConnectedException | InterruptedException e) { + LOGGER.log(Level.WARNING, "Sending CSI state 'inactive' failed.", e); + } + } +} diff --git a/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnection.java b/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnection.java index 4899dfa..f291867 100644 --- a/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnection.java +++ b/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnection.java @@ -5,19 +5,18 @@ import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; -import org.mercury_im.messenger.data.repository.AccountRepository; +import org.jivesoftware.smack.sasl.SASLErrorException; import org.mercury_im.messenger.entity.Account; -import org.mercury_im.messenger.util.Optional; +import org.mercury_im.messenger.xmpp.exception.InvalidCredentialsException; +import org.mercury_im.messenger.xmpp.exception.ServerUnreachableException; import org.mercury_im.messenger.xmpp.state.ConnectionState; import org.mercury_im.messenger.xmpp.state.ConnectivityState; import java.io.IOException; import java.util.UUID; -import java.util.logging.Level; import java.util.logging.Logger; import io.reactivex.Observable; -import io.reactivex.disposables.CompositeDisposable; import io.reactivex.subjects.BehaviorSubject; import lombok.Getter; @@ -46,19 +45,43 @@ public class MercuryConnection { return state; } - public void connect() throws InterruptedException, XMPPException, SmackException, IOException { + public MercuryConnection connect() throws ServerUnreachableException { if (getConnection().isConnected()) { - return; + return this; } - ((AbstractXMPPConnection) getConnection()).connect(); + doConnect(); + return this; } - public void login() throws InterruptedException, IOException, SmackException, XMPPException { + private MercuryConnection doConnect() throws ServerUnreachableException { + AbstractXMPPConnection connection = (AbstractXMPPConnection) getConnection(); + try { + connection.connect(); + return this; + } catch (SmackException.EndpointConnectionException e) { + connection.disconnect(); + throw new ServerUnreachableException("Cannot connect to server " + connection.getXMPPServiceDomain().asUnescapedString(), e); + } catch (IOException | InterruptedException | XMPPException | SmackException e) { + throw new AssertionError("Unexpected exception.", e); + } + } + + public void login() throws ServerUnreachableException, InvalidCredentialsException { if (getConnection().isAuthenticated()) { return; } - connect(); - ((AbstractXMPPConnection) getConnection()).login(); + doLogin(); + } + + private void doLogin() throws InvalidCredentialsException, ServerUnreachableException { + try { + connect(); + ((AbstractXMPPConnection) getConnection()).login(); + } catch (SASLErrorException e) { + throw new InvalidCredentialsException("Credentials of account " + accountId + " are invalid.", e); + } catch (InterruptedException | XMPPException | SmackException | IOException e) { + throw new AssertionError("Unexpected exception.", e); + } } private final ConnectionListener connectionListener = new ConnectionListener() { diff --git a/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnectionManager.java b/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnectionManager.java index 1c808b4..a1d5f87 100644 --- a/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnectionManager.java +++ b/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnectionManager.java @@ -101,11 +101,14 @@ public class MercuryConnectionManager { return connections.get(id); } + public MercuryConnection createConnection(Account account) { + return new MercuryConnection(connectionFactory.createConnection(account), account); + } + public void registerConnections(List accounts) { for (Account account : accounts) { if (!connections.containsKey(account.getId())) { - MercuryConnection connection = new MercuryConnection( - connectionFactory.createConnection(account), account); + MercuryConnection connection = createConnection(account); registerConnection(connection); } } diff --git a/domain/src/main/java/org/mercury_im/messenger/xmpp/exception/InvalidCredentialsException.java b/domain/src/main/java/org/mercury_im/messenger/xmpp/exception/InvalidCredentialsException.java new file mode 100644 index 0000000..b15b0f4 --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/xmpp/exception/InvalidCredentialsException.java @@ -0,0 +1,10 @@ +package org.mercury_im.messenger.xmpp.exception; + +public class InvalidCredentialsException extends Exception { + + private static final long serialVersionUID = 1L; + + public InvalidCredentialsException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/domain/src/main/java/org/mercury_im/messenger/xmpp/exception/ServerUnreachableException.java b/domain/src/main/java/org/mercury_im/messenger/xmpp/exception/ServerUnreachableException.java new file mode 100644 index 0000000..4d505b2 --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/xmpp/exception/ServerUnreachableException.java @@ -0,0 +1,10 @@ +package org.mercury_im.messenger.xmpp.exception; + +public class ServerUnreachableException extends Exception { + + private static final long serialVersionUID = 1L; + + public ServerUnreachableException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/domain/src/test/java/org/mercury_im/messenger/learning_tests/smack/AddAccountUseCaseTest.java b/domain/src/test/java/org/mercury_im/messenger/learning_tests/smack/AddAccountUseCaseTest.java deleted file mode 100644 index cf41f75..0000000 --- a/domain/src/test/java/org/mercury_im/messenger/learning_tests/smack/AddAccountUseCaseTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.mercury_im.messenger.learning_tests.smack; - -import org.junit.Test; -import org.mercury_im.messenger.usecase.AddAccountUseCase; - -import java.util.UUID; - -public class AddAccountUseCaseTest { - - @Test - public void test() { - AddAccountUseCase useCase; - AddAccountUseCase.AddAccountTask task; - - System.out.println(UUID.randomUUID()); - } -} diff --git a/libs/Smack b/libs/Smack index a71ce2c..e797108 160000 --- a/libs/Smack +++ b/libs/Smack @@ -1 +1 @@ -Subproject commit a71ce2ca36faab3bd026dc492b0b8ab8266440d9 +Subproject commit e79710840be6d6b3301e078a23688eafaa06013c