package org.mercury_im.messenger.usecase; import org.jivesoftware.smack.AbstractXMPPConnection; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.sasl.SASLErrorException; import org.mercury_im.messenger.Messenger; import org.mercury_im.messenger.data.repository.AccountRepository; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.IAccount; import org.mercury_im.messenger.xmpp.MercuryConnection; import java.io.IOException; 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()); public enum ConnectionResult { success, credential_error, server_error, other_error } private Account account; private MercuryConnection connection; private final AccountRepository accountRepository; private final Messenger messenger; private final CompositeDisposable disposable = new CompositeDisposable(); public AddAccount(AccountRepository accountRepository, Messenger messenger) { this.accountRepository = accountRepository; this.messenger = messenger; this.account = new IAccount(); } public AddAccount setAddress(String address) { this.account.setAddress(address); return this; } public AddAccount setPassword(String password) { this.account.setPassword(password); return this; } public Completable execute() { return loginAndStoreAccountIfSuccessful(); } public Completable loginAndStoreAccountIfSuccessful() { return logIntoAccount() .andThen(insertEnabledAccountIntoDatabase()).ignoreElement() .andThen(addConnectionToMessenger()); } private Single insertEnabledAccountIntoDatabase() { account.setEnabled(true); return accountRepository.upsertAccount(account) .map(this::updateAccount); } private Completable addConnectionToMessenger() { return Completable.fromAction(() -> messenger.addConnection(connection)); } private Account updateAccount(Account account) { this.account = account; updateAccountIdInConnection(account); return account; } private void updateAccountIdInConnection(Account account) { if (connection != null) { connection.getAccount().setId(account.getId()); } } private Completable logIntoAccount() { return Completable.fromAction( () -> { getOrCreateConnection(); doAuthenticateIfNecessary(); }) .subscribeOn(Schedulers.io()); } private void getOrCreateConnection() { connection = messenger.getConnection(account); if (connection == null) { connection = new MercuryConnection(account); } } private ConnectionResult authenticateIfNecessary() { try { doAuthenticateIfNecessary(); return ConnectionResult.success; } catch (SASLErrorException e) { LOGGER.log(Level.WARNING, "SASL Error while connecting to account " + account.getAddress(), e); return ConnectionResult.credential_error; } catch (SmackException.ConnectionException e) { LOGGER.log(Level.WARNING, "Connectivity error while connecting to account " + account.getAddress(), e); return ConnectionResult.server_error; } catch (IOException | XMPPException | SmackException | InterruptedException e) { LOGGER.log(Level.WARNING, "Error connecting to account " + account.getAddress(), e); return ConnectionResult.other_error; } } private void doAuthenticateIfNecessary() throws InterruptedException, XMPPException, SmackException, IOException { if (!connection.getConnection().isAuthenticated()) { ((AbstractXMPPConnection) connection.getConnection()).connect().login(); } } }