diff --git a/app/src/main/java/org/mercury_im/messenger/di/component/AppComponent.java b/app/src/main/java/org/mercury_im/messenger/di/component/AppComponent.java index d37dd20..8c8f752 100644 --- a/app/src/main/java/org/mercury_im/messenger/di/component/AppComponent.java +++ b/app/src/main/java/org/mercury_im/messenger/di/component/AppComponent.java @@ -4,7 +4,6 @@ import org.mercury_im.messenger.MercuryImApplication; import org.mercury_im.messenger.data.di.RepositoryModule; import org.mercury_im.messenger.di.module.AndroidPersistenceModule; import org.mercury_im.messenger.di.module.AppModule; -import org.mercury_im.messenger.di.module.MercuryModule; import org.mercury_im.messenger.service.MercuryConnectionService; import org.mercury_im.messenger.ui.MainActivity; import org.mercury_im.messenger.ui.chat.ChatActivity; @@ -30,8 +29,7 @@ import dagger.Component; modules = { AppModule.class, AndroidPersistenceModule.class, - RepositoryModule.class, - MercuryModule.class + RepositoryModule.class }) public interface AppComponent { diff --git a/app/src/main/java/org/mercury_im/messenger/ui/login/LoginActivity.java b/app/src/main/java/org/mercury_im/messenger/ui/login/LoginActivity.java index 82d9c7d..fc28124 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/login/LoginActivity.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/login/LoginActivity.java @@ -1,7 +1,6 @@ package org.mercury_im.messenger.ui.login; import android.os.Bundle; -import android.util.Log; import android.view.KeyEvent; import android.view.inputmethod.EditorInfo; import android.widget.Button; @@ -14,7 +13,6 @@ import androidx.lifecycle.ViewModelProvider; import com.google.android.material.textfield.TextInputEditText; import org.mercury_im.messenger.MercuryImApplication; -import org.mercury_im.messenger.Messenger; import org.mercury_im.messenger.R; import org.mercury_im.messenger.account.error.PasswordError; import org.mercury_im.messenger.account.error.UsernameError; @@ -54,42 +52,42 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito viewModel = new ViewModelProvider(this).get(LoginViewModel.class); observeViewModel(); setupTextInputFields(); - mSignInView.setOnClickListener(view -> viewModel.loginDetailsEntered()); + mSignInView.setOnClickListener(view -> viewModel.login()); } private void observeViewModel() { observeUsernameError(); observePasswordError(); finishOnceLoginWasSuccessful(); - displayCredentials(viewModel.getAccount()); + enableLoginButtonOncePossible(); } private void observeUsernameError() { viewModel.getUsernameError().observe(this, usernameError -> { - Optional errorMessage = getUsernameError(usernameError); - if (errorMessage.isPresent()) { - mUsernameView.setError(errorMessage.getItem()); - } + mUsernameView.setError(usernameError.isError() ? usernameError.getErrorMessage() : null); }); } private void observePasswordError() { viewModel.getPasswordError().observe(this, passwordError -> { - Optional errorMessage = getPasswordError(passwordError); - if (errorMessage.isPresent()) { - mPasswordView.setError(errorMessage.getItem()); - } + mPasswordView.setError(passwordError.isError() ? passwordError.getErrorMessage() : null); }); } private void finishOnceLoginWasSuccessful() { - viewModel.getSigninSuccessful().observe(this, successful -> { + viewModel.isLoginSuccessful().observe(this, successful -> { if (Boolean.TRUE.equals(successful)) { finish(); } }); } + private void enableLoginButtonOncePossible() { + viewModel.isLoginEnabled().observe(this, isEnabled -> { + mSignInView.setEnabled(isEnabled); + }); + } + private Optional getUsernameError(UsernameError usernameError) { switch (usernameError) { case none: @@ -130,8 +128,8 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito mUsernameView.setText(accountEvent.getAddress()); } - if (accountEvent.getAuthentication() != null) { - mPasswordView.setText(accountEvent.getAuthentication().getPassword()); + if (accountEvent.getPassword() != null) { + mPasswordView.setText(accountEvent.getPassword()); } }); } @@ -143,16 +141,14 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito mUsernameView.addTextChangedListener(new TextChangedListener() { @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { - viewModel.onUsernameInputChanged(charSequence.toString()); - Log.d(Messenger.TAG, "onTextChanged"); + viewModel.setUsername(charSequence.toString()); } }); mPasswordView.addTextChangedListener(new TextChangedListener() { @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { - viewModel.onPasswordInputChanged(charSequence.toString()); - Log.d(Messenger.TAG, "onTextChanged"); + viewModel.setPassword(charSequence.toString()); } }); } @@ -169,7 +165,7 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito case R.id.password: if (actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_NULL) { - viewModel.loginDetailsEntered(); + viewModel.login(); return true; } } diff --git a/app/src/main/java/org/mercury_im/messenger/ui/login/LoginViewModel.java b/app/src/main/java/org/mercury_im/messenger/ui/login/LoginViewModel.java index c4afcb1..138ae70 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/login/LoginViewModel.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/login/LoginViewModel.java @@ -1,140 +1,138 @@ package org.mercury_im.messenger.ui.login; -import android.text.TextUtils; -import android.util.Log; +import android.app.Application; +import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; - -import io.reactivex.Single; -import io.reactivex.observers.DisposableSingleObserver; import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.stringprep.XmppStringprepException; import org.mercury_im.messenger.MercuryImApplication; -import org.mercury_im.messenger.account.error.PasswordError; -import org.mercury_im.messenger.account.error.UsernameError; -import org.mercury_im.messenger.data.repository.AccountRepository; +import org.mercury_im.messenger.Messenger; +import org.mercury_im.messenger.R; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.IAccount; -import org.mercury_im.messenger.entity.PasswordAuthentication; import javax.inject.Inject; -public class LoginViewModel extends ViewModel { +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; - @Inject - AccountRepository accountRepository; +public class LoginViewModel extends AndroidViewModel { - // @Inject - // ConnectionCenter connectionCenter; + private MutableLiveData usernameError = new MutableLiveData<>(new Error()); + private MutableLiveData passwordError = new MutableLiveData<>(new Error()); + private MutableLiveData loginEnabled = new MutableLiveData<>(false); + private MutableLiveData loginSuccessful = new MutableLiveData<>(false); - private String username; + private EntityBareJid username; private String password; - private MutableLiveData usernameError = new MutableLiveData<>(UsernameError.none); - private MutableLiveData passwordError = new MutableLiveData<>(PasswordError.none); + @Inject + Messenger messenger; - private MutableLiveData account = new MutableLiveData<>(); - - private MutableLiveData signinSuccessful = new MutableLiveData<>(); - - public LoginViewModel() { - super(); - MercuryImApplication.getApplication().getAppComponent().inject(this); - init(new IAccount()); + public LoginViewModel(@NonNull Application application) { + super(application); + ((MercuryImApplication) application).getAppComponent().inject(this); } - public LiveData getSigninSuccessful() { - return signinSuccessful; + public void setUsername(String username) { + if (username == null || username.isEmpty()) { + usernameError.setValue(new Error(getApplication().getResources().getString(R.string.error_field_required))); + this.username = null; + updateLoginEnabled(); + return; + } + + try { + this.username = JidCreate.entityBareFrom(username); + updateLoginEnabled(); + } catch (XmppStringprepException e) { + usernameError.setValue(new Error(getApplication().getResources().getString(R.string.error_invalid_username))); + this.username = null; + updateLoginEnabled(); + } } - public void onUsernameInputChanged(String input) { - this.username = input; + public void setPassword(String password) { + this.password = password; + updateLoginEnabled(); + if (password == null || password.isEmpty()) { + passwordError.setValue(new Error(getApplication().getResources().getString(R.string.error_field_required))); + } } - public void onPasswordInputChanged(String input) { - this.password = input; - } - - public LiveData getUsernameError() { - return usernameError; - } - - public LiveData getPasswordError() { - return passwordError; - } - - /** - * Try to parse the input string into a {@link EntityBareJid} and return it. - * Return null on failure. - * @param input input string - * @return valid username or null - */ - private EntityBareJid asValidUsernameOrNull(String input) { - return JidCreate.entityBareFromOrNull(input); - } - - private boolean isPasswordValid(String password) { - return !password.isEmpty(); - } - - public void init(@NonNull Account account) { - this.account.setValue(account); - } - - public MutableLiveData getAccount() { - return account; + private void updateLoginEnabled() { + loginEnabled.setValue(username != null && !(password == null || password.isEmpty())); } public void login() { - Account account = getAccount().getValue(); - if (account != null && account.getAddress() != null - && !TextUtils.isEmpty(account.getAuthentication().getPassword())) { - accountRepository.upsertAccount(account); - } + Account account = new IAccount(); + account.setAddress(username.asUnescapedString()); + account.setPassword(password); + account.setEnabled(true); + loginEnabled.setValue(false); + messenger.addAccount().enableAccountAndLogin(account) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .map(result -> { + switch (result) { + case success: + loginSuccessful.setValue(true); + break; + case credential_error: + passwordError.setValue(new Error(getApplication().getResources().getString(R.string.error_incorrect_password))); + loginEnabled.setValue(true); + break; + case server_error: + case other_error: + Toast.makeText(getApplication(), "A connection error occurred", Toast.LENGTH_LONG); + loginEnabled.setValue(true); + } + return true; + }) + .ignoreElement() + .subscribe(); } - public void loginDetailsEntered() { - boolean loginIntact = true; - if (username.isEmpty()) { - usernameError.postValue(UsernameError.emptyUsername); - loginIntact = false; + public LiveData getPasswordError() { + return passwordError; + } + + public LiveData getUsernameError() { + return usernameError; + } + + public LiveData isLoginSuccessful() { + return loginSuccessful; + } + + public LiveData isLoginEnabled() { + return loginEnabled; + } + + public static class Error { + + private String message; + + public Error() { + } - EntityBareJid bareJid = asValidUsernameOrNull(username); - if (bareJid == null) { - usernameError.postValue(UsernameError.invalidUsername); - loginIntact = false; + public Error(String errorMessage) { + this.message = errorMessage; } - if (!isPasswordValid(password)) { - passwordError.postValue(PasswordError.invalidPassword); - loginIntact = false; + public boolean isError() { + return message != null; } - if (loginIntact) { - Account account = new IAccount(); - account.setEnabled(true); - account.setAddress(bareJid.toString()); - account.setAuthentication(new PasswordAuthentication(password)); - Single insert = accountRepository.upsertAccount(account); - insert.subscribe( - new DisposableSingleObserver() { - @Override - public void onSuccess(Account inserted) { - // connectionCenter.createConnection(account); - signinSuccessful.setValue(true); - } - - @Override - public void onError(Throwable e) { - Log.e("Mercury", "Could not insert new Account data.", e); - } - }); - + public String getErrorMessage() { + return message; } } } diff --git a/core-old/build.gradle b/core-old/build.gradle index 03b0732..348a34c 100644 --- a/core-old/build.gradle +++ b/core-old/build.gradle @@ -8,7 +8,7 @@ sourceSets { dependencies { - api project(':entity') // Entities + api project(':entity') // Smack // Not all of those are needed, but it may be a good idea to define those versions explicitly @@ -37,6 +37,7 @@ dependencies { // JUnit for testing testImplementation "junit:junit:$junitVersion" + compile project(path: ':data') } sourceCompatibility = "8" diff --git a/core-old/src/main/java/org/mercury_im/messenger/core/stores/EntityCapsStore.java b/core-old/src/main/java/org/mercury_im/messenger/core/stores/EntityCapsStore.java index 9d41c30..ff67a9d 100644 --- a/core-old/src/main/java/org/mercury_im/messenger/core/stores/EntityCapsStore.java +++ b/core-old/src/main/java/org/mercury_im/messenger/core/stores/EntityCapsStore.java @@ -4,8 +4,8 @@ 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.xmpp.model.EntityCapsModel; -import org.mercury_im.messenger.xmpp.repository.EntityCapsRepository; +import org.mercury_im.messenger.data.model.EntityCapsModel; +import org.mercury_im.messenger.data.repository.XmppEntityCapsRepository; import java.io.StringReader; @@ -23,13 +23,13 @@ public class EntityCapsStore implements EntityCapsPersistentCache { private static final Logger LOGGER = Logger.getLogger(EntityCapsStore.class.getName()); - private final EntityCapsRepository entityCapsRepository; + private final XmppEntityCapsRepository entityCapsRepository; private final Map discoverInfoMap = new HashMap<>(); private final CompositeDisposable disposable = new CompositeDisposable(); @Inject - public EntityCapsStore(EntityCapsRepository entityCapsRepository) { + public EntityCapsStore(XmppEntityCapsRepository entityCapsRepository) { this.entityCapsRepository = entityCapsRepository; populateFromDatabase(); } diff --git a/data/src/main/java/org/mercury_im/messenger/data/di/RepositoryModule.java b/data/src/main/java/org/mercury_im/messenger/data/di/RepositoryModule.java index bc16ffe..9d2a91e 100644 --- a/data/src/main/java/org/mercury_im/messenger/data/di/RepositoryModule.java +++ b/data/src/main/java/org/mercury_im/messenger/data/di/RepositoryModule.java @@ -10,7 +10,7 @@ import org.mercury_im.messenger.data.repository.GroupChatRepository; import org.mercury_im.messenger.data.repository.MessageRepository; import org.mercury_im.messenger.data.repository.PeerRepository; import org.mercury_im.messenger.data.repository.DirectChatRepository; -import org.mercury_im.messenger.data.repository.EntityCapsRepository; +import org.mercury_im.messenger.data.repository.XmppEntityCapsRepository; import org.mercury_im.messenger.data.repository.Repositories; import org.mercury_im.messenger.data.repository.XmppAccountRepository; import org.mercury_im.messenger.data.repository.XmppDirectChatRepository; @@ -89,11 +89,11 @@ public class RepositoryModule { @Provides @Singleton - static EntityCapsRepository provideCapsRepository( + static XmppEntityCapsRepository provideCapsRepository( ReactiveEntityStore data, @Named(value = ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler, @Named(value = ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) { - return new EntityCapsRepository(data, ioScheduler, uiScheduler); + return new XmppEntityCapsRepository(data, ioScheduler, uiScheduler); } @Provides diff --git a/data/src/main/java/org/mercury_im/messenger/data/mapping/AccountMapping.java b/data/src/main/java/org/mercury_im/messenger/data/mapping/AccountMapping.java index 25034c2..e3976fe 100644 --- a/data/src/main/java/org/mercury_im/messenger/data/mapping/AccountMapping.java +++ b/data/src/main/java/org/mercury_im/messenger/data/mapping/AccountMapping.java @@ -3,7 +3,6 @@ package org.mercury_im.messenger.data.mapping; import org.mercury_im.messenger.data.model.AccountModel; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.IAccount; -import org.mercury_im.messenger.entity.PasswordAuthentication; import javax.inject.Inject; @@ -27,7 +26,7 @@ public class AccountMapping extends AbstractMapping { @Override public AccountModel mapToModel(Account entity, AccountModel model) { model.setAddress(entity.getAddress()); - model.setPassword(entity.getAuthentication().getPassword()); + model.setPassword(entity.getPassword()); model.setEnabled(entity.isEnabled()); return model; @@ -37,7 +36,7 @@ public class AccountMapping extends AbstractMapping { public Account mapToEntity(AccountModel model, Account entity) { entity.setId(model.getId()); entity.setAddress(model.getAddress()); - entity.setAuthentication(new PasswordAuthentication(model.getPassword())); + entity.setPassword(model.getPassword()); entity.setEnabled(model.isEnabled()); return entity; diff --git a/data/src/main/java/org/mercury_im/messenger/data/repository/EntityCapsRepository.java b/data/src/main/java/org/mercury_im/messenger/data/repository/XmppEntityCapsRepository.java similarity index 84% rename from data/src/main/java/org/mercury_im/messenger/data/repository/EntityCapsRepository.java rename to data/src/main/java/org/mercury_im/messenger/data/repository/XmppEntityCapsRepository.java index feccee5..e7073ed 100644 --- a/data/src/main/java/org/mercury_im/messenger/data/repository/EntityCapsRepository.java +++ b/data/src/main/java/org/mercury_im/messenger/data/repository/XmppEntityCapsRepository.java @@ -9,10 +9,10 @@ import io.reactivex.Scheduler; import io.requery.Persistable; import io.requery.reactivex.ReactiveEntityStore; -public class EntityCapsRepository extends RequeryRepository { +public class XmppEntityCapsRepository extends RequeryRepository { @Inject - public EntityCapsRepository( + public XmppEntityCapsRepository( ReactiveEntityStore data, @Named(value = ThreadUtils.SCHEDULER_IO) Scheduler subscriberScheduler, @Named(value = ThreadUtils.SCHEDULER_UI) Scheduler observerScheduler) { diff --git a/data/src/main/java/org/mercury_im/messenger/data/repository/XmppGroupChatRepository.java b/data/src/main/java/org/mercury_im/messenger/data/repository/XmppGroupChatRepository.java index fec5567..98ece17 100644 --- a/data/src/main/java/org/mercury_im/messenger/data/repository/XmppGroupChatRepository.java +++ b/data/src/main/java/org/mercury_im/messenger/data/repository/XmppGroupChatRepository.java @@ -74,8 +74,8 @@ public class XmppGroupChatRepository @Override public Single getOrCreateGroupChat(Account account, String roomAddress) { return getGroupChatByRoomAddress(account, roomAddress) - .switchIfEmpty(Single - .just((GroupChat) new IGroupChat() { + .switchIfEmpty( + Single.just((GroupChat) new IGroupChat() { { setAccount(account); setRoomAddress(roomAddress); diff --git a/data/src/test/java/org/mercury_im/messenger/data/repository/AccountRepositoryTest.java b/data/src/test/java/org/mercury_im/messenger/data/repository/AccountRepositoryTest.java index 7d5f288..c63d6cf 100644 --- a/data/src/test/java/org/mercury_im/messenger/data/repository/AccountRepositoryTest.java +++ b/data/src/test/java/org/mercury_im/messenger/data/repository/AccountRepositoryTest.java @@ -6,21 +6,6 @@ import org.mercury_im.messenger.data.di.InMemoryDatabaseComponent; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.IAccount; import org.mercury_im.messenger.entity.PasswordAuthentication; -import org.mercury_im.messenger.entity.chat.DirectChat; -import org.mercury_im.messenger.entity.chat.IDirectChat; -import org.mercury_im.messenger.entity.contact.IPeer; -import org.mercury_im.messenger.entity.contact.Peer; -import org.mercury_im.messenger.entity.message.IMessage; -import org.mercury_im.messenger.entity.message.IPayloadContainer; -import org.mercury_im.messenger.entity.message.Message; -import org.mercury_im.messenger.entity.message.PayloadContainer; -import org.mercury_im.messenger.entity.message.content.TextPayload; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.List; import javax.inject.Inject; @@ -28,8 +13,6 @@ import io.reactivex.disposables.CompositeDisposable; import io.requery.Persistable; import io.requery.reactivex.ReactiveEntityStore; -import static junit.framework.TestCase.assertEquals; - public class AccountRepositoryTest { @Inject diff --git a/domain/.gitignore b/domain/.gitignore index 796b96d..60bf954 100644 --- a/domain/.gitignore +++ b/domain/.gitignore @@ -1 +1,2 @@ /build +testcredentials.properties diff --git a/domain/build.gradle b/domain/build.gradle index 608afd2..7b7739b 100644 --- a/domain/build.gradle +++ b/domain/build.gradle @@ -4,6 +4,16 @@ dependencies { implementation project(':entity') + // Smack + // Not all of those are needed, but it may be a good idea to define those versions explicitly + api "org.igniterealtime.smack:smack-core:$smackCoreVersion" + api "org.igniterealtime.smack:smack-experimental:$smackExperimentalVersion" + api "org.igniterealtime.smack:smack-extensions:$smackExtensionsVersion" + api "org.igniterealtime.smack:smack-im:$smackImVersion" + api "org.igniterealtime.smack:smack-tcp:$smackTcpVersion" + + testImplementation "org.igniterealtime.smack:smack-java7:$smackJava7Version" + // RxJava2 implementation "io.reactivex.rxjava2:rxjava:$rxJava2Version" diff --git a/domain/src/main/java/org/mercury_im/messenger/MessageCenter.java b/domain/src/main/java/org/mercury_im/messenger/MessageCenter.java index fe5ab2c..995f780 100644 --- a/domain/src/main/java/org/mercury_im/messenger/MessageCenter.java +++ b/domain/src/main/java/org/mercury_im/messenger/MessageCenter.java @@ -1,6 +1,6 @@ package org.mercury_im.messenger; -import org.mercury_im.messenger.transport.listener.IncomingDirectMessageListener; +import org.mercury_im.messenger.listener.IncomingDirectMessageListener; import org.mercury_im.messenger.entity.chat.Chat; import org.mercury_im.messenger.entity.message.Message; 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 a23d1e7..22cde18 100644 --- a/domain/src/main/java/org/mercury_im/messenger/Messenger.java +++ b/domain/src/main/java/org/mercury_im/messenger/Messenger.java @@ -2,7 +2,8 @@ package org.mercury_im.messenger; import org.mercury_im.messenger.data.repository.Repositories; import org.mercury_im.messenger.entity.Account; -import org.mercury_im.messenger.transport.connection.ConnectionMethod; +import org.mercury_im.messenger.usecase.AddAccount; +import org.mercury_im.messenger.xmpp.MercuryConnection; import java.util.HashMap; import java.util.Map; @@ -13,28 +14,23 @@ public class Messenger { public static final String TAG = "MercuryIM"; - private final Map connections = new HashMap<>(); - - private final Repositories repositories; + private final Map connections = new HashMap<>(); + private Repositories repositories; @Inject public Messenger(Repositories repositories) { this.repositories = repositories; } - public void addConnection(ConnectionMethod connection) { + public void addConnection(MercuryConnection connection) { connections.put(connection.getAccount().getId(), connection); } - public ConnectionMethod getConnection(Account account) { + public MercuryConnection getConnection(Account account) { return connections.get(account.getId()); } - public void appInUse() { - - } - - public void appInBackground() { - + public AddAccount addAccount() { + return new AddAccount(repositories.getAccountRepository(), this); } } diff --git a/domain/src/main/java/org/mercury_im/messenger/di/module/MercuryModule.java b/domain/src/main/java/org/mercury_im/messenger/di/module/MercuryModule.java deleted file mode 100644 index d54d541..0000000 --- a/domain/src/main/java/org/mercury_im/messenger/di/module/MercuryModule.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.mercury_im.messenger.di.module; - -import org.mercury_im.messenger.Messenger; -import org.mercury_im.messenger.data.repository.Repositories; - -import javax.inject.Singleton; - -import dagger.Module; -import dagger.Provides; - -@Module -public class MercuryModule { - - /* - @Provides - @Singleton - static Messenger provideMessenger(Repositories repositories) { - return new Messenger(repositories); - } - - */ - -} diff --git a/domain/src/main/java/org/mercury_im/messenger/exception/IllegalUsernameException.java b/domain/src/main/java/org/mercury_im/messenger/exception/IllegalUsernameException.java new file mode 100644 index 0000000..6e084dc --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/exception/IllegalUsernameException.java @@ -0,0 +1,8 @@ +package org.mercury_im.messenger.exception; + +public class IllegalUsernameException extends RuntimeException { + + public IllegalUsernameException(Throwable cause) { + super(cause); + } +} diff --git a/domain/src/main/java/org/mercury_im/messenger/transport/listener/IncomingDirectMessageListener.java b/domain/src/main/java/org/mercury_im/messenger/listener/IncomingDirectMessageListener.java similarity index 84% rename from domain/src/main/java/org/mercury_im/messenger/transport/listener/IncomingDirectMessageListener.java rename to domain/src/main/java/org/mercury_im/messenger/listener/IncomingDirectMessageListener.java index 9e7a8d2..3facc87 100644 --- a/domain/src/main/java/org/mercury_im/messenger/transport/listener/IncomingDirectMessageListener.java +++ b/domain/src/main/java/org/mercury_im/messenger/listener/IncomingDirectMessageListener.java @@ -1,4 +1,4 @@ -package org.mercury_im.messenger.transport.listener; +package org.mercury_im.messenger.listener; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.chat.DirectChat; diff --git a/domain/src/main/java/org/mercury_im/messenger/transport/listener/IncomingGroupChatMessageListener.java b/domain/src/main/java/org/mercury_im/messenger/listener/IncomingGroupChatMessageListener.java similarity index 85% rename from domain/src/main/java/org/mercury_im/messenger/transport/listener/IncomingGroupChatMessageListener.java rename to domain/src/main/java/org/mercury_im/messenger/listener/IncomingGroupChatMessageListener.java index b6932f3..3fc9af3 100644 --- a/domain/src/main/java/org/mercury_im/messenger/transport/listener/IncomingGroupChatMessageListener.java +++ b/domain/src/main/java/org/mercury_im/messenger/listener/IncomingGroupChatMessageListener.java @@ -1,4 +1,4 @@ -package org.mercury_im.messenger.transport.listener; +package org.mercury_im.messenger.listener; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.chat.GroupChat; diff --git a/domain/src/main/java/org/mercury_im/messenger/transport/listener/TypingEventListener.java b/domain/src/main/java/org/mercury_im/messenger/listener/TypingEventListener.java similarity index 80% rename from domain/src/main/java/org/mercury_im/messenger/transport/listener/TypingEventListener.java rename to domain/src/main/java/org/mercury_im/messenger/listener/TypingEventListener.java index 7662eac..3d8e037 100644 --- a/domain/src/main/java/org/mercury_im/messenger/transport/listener/TypingEventListener.java +++ b/domain/src/main/java/org/mercury_im/messenger/listener/TypingEventListener.java @@ -1,4 +1,4 @@ -package org.mercury_im.messenger.transport.listener; +package org.mercury_im.messenger.listener; import org.mercury_im.messenger.entity.chat.Chat; import org.mercury_im.messenger.entity.event.TypingEvent; diff --git a/domain/src/main/java/org/mercury_im/messenger/transport/AccountChangedEvent.java b/domain/src/main/java/org/mercury_im/messenger/transport/AccountChangedEvent.java deleted file mode 100644 index 2628fcf..0000000 --- a/domain/src/main/java/org/mercury_im/messenger/transport/AccountChangedEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.mercury_im.messenger.transport; - -import org.mercury_im.messenger.entity.Account; - -public class AccountChangedEvent { - - private final Account account; - private final EventType eventType; - - public AccountChangedEvent(Account account, EventType eventType) { - this.account = account; - this.eventType = eventType; - } - - public Account getAccount() { - return account; - } - - public EventType getEventType() { - return eventType; - } - - public enum EventType { - enabled, - disabled - } -} diff --git a/domain/src/main/java/org/mercury_im/messenger/transport/AccountChangedHandler.java b/domain/src/main/java/org/mercury_im/messenger/transport/AccountChangedHandler.java deleted file mode 100644 index ad38e00..0000000 --- a/domain/src/main/java/org/mercury_im/messenger/transport/AccountChangedHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.mercury_im.messenger.transport; - -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.util.DiffUtil; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import javax.inject.Inject; - -import io.reactivex.disposables.CompositeDisposable; - -public class AccountChangedHandler { - - private final Messenger messenger; - private final AccountRepository accountRepository; - private final Map accounts = new HashMap<>(); - private final CompositeDisposable disposable = new CompositeDisposable(); - - @Inject - public AccountChangedHandler(Messenger messenger, AccountRepository accountRepository) { - this.messenger = messenger; - this.accountRepository = accountRepository; - //disposable.add(accountRepository.observeAllAccounts() - // .scan(new ArrayList<>(), this::calculateChangeEvents) - // .subscribe(this::onAccountsChanged)); - } - - private HashMap calculateChangeEvents(List accounts, List newAccounts) { - DiffUtil.Diff diff = DiffUtil.diff(accounts, newAccounts); - return null; - } - - private AccountChangedEvent calculateEvent(Account previous, Account next) { - if (previous == null && next == null) { - throw new IllegalArgumentException("Not both accounts can be null at the same time!"); - } - if (previous == null) { - if (next.isEnabled()) { - return new AccountChangedEvent(next, AccountChangedEvent.EventType.enabled); - } else { - return null; - } - } - if (next == null) { - if (previous.isEnabled()) { - return new AccountChangedEvent(previous, AccountChangedEvent.EventType.disabled); - } else { - return null; - } - } - if (previous.isEnabled()) { - if (next.isEnabled()) { - return null; - } else { - return new AccountChangedEvent(next, AccountChangedEvent.EventType.disabled); - } - } else { - if (next.isEnabled()) { - return new AccountChangedEvent(next, AccountChangedEvent.EventType.enabled); - } else { - return null; - } - } - } - - private void onAccountsChanged(List accounts, List newAccounts) { - DiffUtil.Diff diff = DiffUtil.diff(accounts, newAccounts); - - } -} diff --git a/domain/src/main/java/org/mercury_im/messenger/transport/ConnectionType.java b/domain/src/main/java/org/mercury_im/messenger/transport/ConnectionType.java deleted file mode 100644 index aa04e7f..0000000 --- a/domain/src/main/java/org/mercury_im/messenger/transport/ConnectionType.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.mercury_im.messenger.transport; - -public enum ConnectionType { - // Smack Connection Types from module transport_xmpp. - /** - * Underlying connection is a Smack XMPPTCPConnection. - */ - SMACK_TCP, - - /** - * Underlying connection is a Smack XMPPBOSHConnection. - * @deprecated Not yet implemented. - */ - SMACK_BOSH, - - /** - * Underlying connection is a Smack XMPPWebsocketConnection. - * @deprecated Not yet implemented. - */ - SMACK_WEBSOCKETS, - ; -} diff --git a/domain/src/main/java/org/mercury_im/messenger/transport/connection/AbstractConnectionMethod.java b/domain/src/main/java/org/mercury_im/messenger/transport/connection/AbstractConnectionMethod.java deleted file mode 100644 index 7d7383f..0000000 --- a/domain/src/main/java/org/mercury_im/messenger/transport/connection/AbstractConnectionMethod.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.mercury_im.messenger.transport.connection; - -import org.mercury_im.messenger.Messenger; -import org.mercury_im.messenger.entity.Account; - -public abstract class AbstractConnectionMethod - implements ConnectionMethod { - - protected final Account account; - protected final Messenger messenger; - - public AbstractConnectionMethod(Account account, Messenger messenger) { - this.account = account; - this.messenger = messenger; - } - - @Override - public Account getAccount() { - return account; - } - - @Override - public Messenger getMessenger() { - return messenger; - } -} diff --git a/domain/src/main/java/org/mercury_im/messenger/transport/connection/ConnectionFactory.java b/domain/src/main/java/org/mercury_im/messenger/transport/connection/ConnectionFactory.java deleted file mode 100644 index 7c9369a..0000000 --- a/domain/src/main/java/org/mercury_im/messenger/transport/connection/ConnectionFactory.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.mercury_im.messenger.transport.connection; - -import org.mercury_im.messenger.Messenger; -import org.mercury_im.messenger.entity.Account; - -public interface ConnectionFactory< - CM extends ConnectionMethod> { - - Messenger getMessenger(); - - CM provideConnection(Account account); - -} diff --git a/domain/src/main/java/org/mercury_im/messenger/transport/connection/ConnectionMethod.java b/domain/src/main/java/org/mercury_im/messenger/transport/connection/ConnectionMethod.java deleted file mode 100644 index f8c0fbb..0000000 --- a/domain/src/main/java/org/mercury_im/messenger/transport/connection/ConnectionMethod.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.mercury_im.messenger.transport.connection; - -import org.mercury_im.messenger.Messenger; -import org.mercury_im.messenger.transport.ConnectionType; -import org.mercury_im.messenger.entity.Account; - -import io.reactivex.Completable; - -public interface ConnectionMethod { - - Account getAccount(); - - Messenger getMessenger(); - - Completable connect(); - - ConnectionType getConnectionType(); -} diff --git a/domain/src/main/java/org/mercury_im/messenger/transport/connection/exception/ConnectionFailedException.java b/domain/src/main/java/org/mercury_im/messenger/transport/connection/exception/ConnectionFailedException.java deleted file mode 100644 index add6a2c..0000000 --- a/domain/src/main/java/org/mercury_im/messenger/transport/connection/exception/ConnectionFailedException.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.mercury_im.messenger.transport.connection.exception; - -public class ConnectionFailedException extends Exception { - - private static final long serialVersionUID = 1L; -} 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 new file mode 100644 index 0000000..61a6953 --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/usecase/AddAccount.java @@ -0,0 +1,132 @@ +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.jxmpp.jid.BareJid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.stringprep.XmppStringprepException; +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.exception.IllegalUsernameException; +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.schedulers.Schedulers; + +public class AddAccount { + + private static final Logger LOGGER = Logger.getLogger(AddAccount.class.getName()); + + private String username; + private String server; + private BareJid address; + private String password; + private Account account; + + private final AccountRepository accountRepository; + private final Messenger messenger; + + public AddAccount(AccountRepository accountRepository, Messenger messenger) { + this.accountRepository = accountRepository; + this.messenger = messenger; + } + + public void setAddress(String address) { + try { + this.address = JidCreate.entityBareFrom(address); + } catch (XmppStringprepException e) { + this.address = null; + throw new IllegalUsernameException(e); + } + } + + public boolean isAddressSet() { + return address != null; + } + + public void setPassword(String password) { + this.password = password; + } + + public boolean isPasswordSet() { + return password != null; + } + + public Single insertAccountIntoDatabase() { + Account account = new IAccount(); + account.setAddress(address.asUnescapedString()); + account.setPassword(password); + return accountRepository.insertAccount(account).doAfterSuccess(this::setAccount); + } + + private void setAccount(Account account) { + this.account = account; + } + + public Single enableAccountAndLogin(Account account) { + return enableAccount(account).andThen(login(account)); + } + + private Completable enableAccount(Account account) { + account.setEnabled(true); + return accountRepository.upsertAccount(account) + .doAfterSuccess(this::setAccount) + .ignoreElement(); + } + + private Single login(Account account) { + return Single.fromCallable(() -> { + MercuryConnection connection = getOrCreateConnection(account); + return authenticateIfNecessary(connection); + }).subscribeOn(Schedulers.io()); + } + + private MercuryConnection getOrCreateConnection(Account account) { + MercuryConnection connection = messenger.getConnection(account); + if (connection == null) { + connection = new MercuryConnection(account); + messenger.addConnection(connection); + } + return connection; + } + + private ConnectionResult authenticateIfNecessary(MercuryConnection connection) { + try { + doAuthenticateIfNecessary(connection); + 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(MercuryConnection connection) + throws InterruptedException, XMPPException, SmackException, IOException { + if (!connection.getConnection().isAuthenticated()) { + ((AbstractXMPPConnection) connection.getConnection()).connect().login(); + } + } + + public enum ConnectionResult { + success, + credential_error, + server_error, + other_error + } +} 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 new file mode 100644 index 0000000..98bfa96 --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnection.java @@ -0,0 +1,34 @@ +package org.mercury_im.messenger.xmpp; + +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.tcp.XMPPTCPConnection; +import org.jxmpp.stringprep.XmppStringprepException; +import org.mercury_im.messenger.entity.Account; + +public class MercuryConnection { + + private final Account account; + + private XMPPConnection connection; + + public MercuryConnection(Account account) { + this.account = account; + try { + this.connection = new XMPPTCPConnection(account.getAddress(), account.getPassword()); + } catch (XmppStringprepException e) { + throw new AssertionError("Account has invalid address: " + account.getAddress(), e); + } + } + + public Account getAccount() { + return account; + } + + public XMPPConnection getConnection() { + return connection; + } + + public void ensureAuthenticated() { + + } +} diff --git a/xmpp/src/main/java/org/mercury_im/messenger/domain/xmpp/XmppDirectMessageCenter.java b/domain/src/main/java/org/mercury_im/messenger/xmpp/XmppDirectMessageCenter.java similarity index 87% rename from xmpp/src/main/java/org/mercury_im/messenger/domain/xmpp/XmppDirectMessageCenter.java rename to domain/src/main/java/org/mercury_im/messenger/xmpp/XmppDirectMessageCenter.java index 6de84cc..ba8f8f4 100644 --- a/xmpp/src/main/java/org/mercury_im/messenger/domain/xmpp/XmppDirectMessageCenter.java +++ b/domain/src/main/java/org/mercury_im/messenger/xmpp/XmppDirectMessageCenter.java @@ -1,10 +1,9 @@ -package org.mercury_im.messenger.domain.xmpp; +package org.mercury_im.messenger.xmpp; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.chat2.Chat; import org.jivesoftware.smack.chat2.ChatManager; import org.jivesoftware.smack.chat2.IncomingChatMessageListener; -import org.jivesoftware.smackx.avatar.element.MetadataExtension; import org.jivesoftware.smackx.sid.element.OriginIdElement; import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.impl.JidCreate; @@ -20,9 +19,7 @@ import org.mercury_im.messenger.entity.chat.DirectChat; import org.mercury_im.messenger.entity.message.IMessage; import org.mercury_im.messenger.entity.message.IMessageMetadata; import org.mercury_im.messenger.entity.message.Message; -import org.mercury_im.messenger.entity.message.MessageMetadata; -import org.mercury_im.messenger.transport.listener.IncomingDirectMessageListener; -import org.mercury_im.messenger.transport.xmpp.XmppTcpConnectionMethod; +import org.mercury_im.messenger.listener.IncomingDirectMessageListener; import java.util.LinkedHashSet; import java.util.Set; @@ -56,8 +53,7 @@ public class XmppDirectMessageCenter this.directChatRepository = repositories.getDirectChatRepository(); this.messageRepository = repositories.getMessageRepository(); - XMPPConnection connection = ((XmppTcpConnectionMethod) getMessenger() - .getConnection(account)).getConnection(); + XMPPConnection connection = getMessenger().getConnection(account).getConnection(); ChatManager.getInstanceFor(connection).addIncomingListener(this); } @@ -102,8 +98,8 @@ public class XmppDirectMessageCenter } protected ChatManager getChatManager(DirectChat chat) { - XmppTcpConnectionMethod connectionMethod = (XmppTcpConnectionMethod) getMessenger().getConnection(chat.getAccount()); - return ChatManager.getInstanceFor(connectionMethod.getConnection()); + MercuryConnection mercuryConnection = getMessenger().getConnection(chat.getAccount()); + return ChatManager.getInstanceFor(mercuryConnection.getConnection()); } @Override diff --git a/domain/src/test/java/org/mercury_im/messenger/learning_tests/smack/XmppConnectionLoginBehaviorTest.java b/domain/src/test/java/org/mercury_im/messenger/learning_tests/smack/XmppConnectionLoginBehaviorTest.java new file mode 100644 index 0000000..2b62017 --- /dev/null +++ b/domain/src/test/java/org/mercury_im/messenger/learning_tests/smack/XmppConnectionLoginBehaviorTest.java @@ -0,0 +1,91 @@ +package org.mercury_im.messenger.learning_tests.smack; + +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.sasl.SASLErrorException; +import org.jivesoftware.smack.tcp.XMPPTCPConnection; +import org.jivesoftware.smack.util.stringencoder.Base64; +import org.jivesoftware.smack.util.stringencoder.java7.Java7Base64Encoder; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.junit.Assume.assumeTrue; + +/** + * Learning Test to study Smacks behavior during connection process. + */ +public class XmppConnectionLoginBehaviorTest { + + public static final String CREDENTIALS_PROPERTIES = "testcredentials.properties"; + + private static final Logger LOGGER = Logger.getLogger(XmppConnectionLoginBehaviorTest.class.getName()); + private static Properties testCredentials = null; + + @BeforeClass + public static void readProperties() { + Properties properties = new Properties(); + File propertiesFile = new File(CREDENTIALS_PROPERTIES); + if (!propertiesFile.exists() || !propertiesFile.isFile()) { + LOGGER.log(Level.WARNING, "Cannot find file domain/testcredentials.properties. Some tests will be skipped."); + return; + } + + try(FileReader reader = new FileReader(propertiesFile)) { + properties.load(reader); + } catch (IOException e) { + LOGGER.log(Level.WARNING, "Error reading properties file testcredentials.properties.", e); + return; + } + testCredentials = properties; + + Base64.setEncoder(Java7Base64Encoder.getInstance()); + } + + /* + * Connecting to an invalid host causes {@link org.jivesoftware.smack.SmackException.ConnectionException} + * to be thrown. + */ + @Test(expected = SmackException.ConnectionException.class) + public void invalidHostConnectionTest() throws IOException, InterruptedException, XMPPException, SmackException { + ignoreIfNoCredentials(); + new XMPPTCPConnection( + testCredentials.getProperty("invalidHostUsername"), + testCredentials.getProperty("invalidHostPassword")) + .connect().login(); + } + + /* + * Connecting with invalid user causes {@link SASLErrorException} to be thrown. + */ + @Test(expected = SASLErrorException.class) + public void invalidUserConnectionTest() throws IOException, InterruptedException, XMPPException, SmackException { + ignoreIfNoCredentials(); + new XMPPTCPConnection( + testCredentials.getProperty("invalidUserUsername"), + testCredentials.getProperty("invalidUserPassword")) + .connect().login(); + } + + /* + * Connecting with invalid password causes {@link SASLErrorException} to be thrown. + */ + @Test(expected = SASLErrorException.class) + public void invalidPasswordConnectionTest() throws IOException, InterruptedException, XMPPException, SmackException { + ignoreIfNoCredentials(); + new XMPPTCPConnection( + testCredentials.getProperty("invalidPasswordUsername"), + testCredentials.getProperty("invalidPasswordPassword")) + .connect().login(); + } + + private void ignoreIfNoCredentials() { + assumeTrue("Test ignored as domain/testcredentials.properties file not found.", testCredentials != null); + } +} diff --git a/domain/testcredentials.properties.example b/domain/testcredentials.properties.example new file mode 100644 index 0000000..2752843 --- /dev/null +++ b/domain/testcredentials.properties.example @@ -0,0 +1,11 @@ +#Server must not exist +invalidHostUsername=invalid@example.com +invalidHostPassword=invalid123 + +#User must not exist on a server that is reachable +invalidUserUsername= +invalidPassword= + +#User must exists, but password must be invalid +invalidPasswordUsername= +invalidPasswordPassword= diff --git a/entity/src/main/java/org/mercury_im/messenger/entity/Account.java b/entity/src/main/java/org/mercury_im/messenger/entity/Account.java index 3079838..cd7c66c 100644 --- a/entity/src/main/java/org/mercury_im/messenger/entity/Account.java +++ b/entity/src/main/java/org/mercury_im/messenger/entity/Account.java @@ -15,8 +15,14 @@ public interface Account { String getAddress(); + void setPassword(String password); + + String getPassword(); + + @Deprecated void setAuthentication(AuthMethod authentication); + @Deprecated AuthMethod getAuthentication(); void setEnabled(boolean enabled); diff --git a/entity/src/main/java/org/mercury_im/messenger/entity/IAccount.java b/entity/src/main/java/org/mercury_im/messenger/entity/IAccount.java index 9af4a5e..aadf418 100644 --- a/entity/src/main/java/org/mercury_im/messenger/entity/IAccount.java +++ b/entity/src/main/java/org/mercury_im/messenger/entity/IAccount.java @@ -4,6 +4,7 @@ public class IAccount implements Account { protected long id; protected String address; + protected String password; protected AuthMethod authentication; protected boolean enabled; @@ -28,6 +29,16 @@ public class IAccount implements Account { return address; } + @Override + public void setPassword(String password) { + this.password = password; + } + + @Override + public String getPassword() { + return password; + } + @Override public void setAuthentication(AuthMethod authentication) { this.authentication = authentication; diff --git a/settings.gradle b/settings.gradle index afa6a4f..1d606e1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,9 +1,7 @@ include ':entity', ':data', ':domain', - ':xmpp', ':app', - ':core-old', - ':view_entity' + ':core-old' includeBuild 'libs/Smack' diff --git a/view_entity/.gitignore b/view_entity/.gitignore deleted file mode 100644 index 796b96d..0000000 --- a/view_entity/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/view_entity/build.gradle b/view_entity/build.gradle deleted file mode 100644 index 7fa7473..0000000 --- a/view_entity/build.gradle +++ /dev/null @@ -1,8 +0,0 @@ -apply plugin: 'java-library' - -dependencies { - implementation project(':entity') -} - -sourceCompatibility = "8" -targetCompatibility = "8" diff --git a/view_entity/src/main/java/org/mercury_im/messenger/view/entity/ViewInterlocutor.java b/view_entity/src/main/java/org/mercury_im/messenger/view/entity/ViewInterlocutor.java deleted file mode 100644 index 56bc35e..0000000 --- a/view_entity/src/main/java/org/mercury_im/messenger/view/entity/ViewInterlocutor.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.mercury_im.messenger.view.entity; - -import org.mercury_im.messenger.entity.contact.SubscriptionMode; -import org.mercury_im.messenger.view.entity.definition.InterlocutorViewEntity; - -public class ViewInterlocutor implements InterlocutorViewEntity { - - private final String name; - private final String address; - private final String accountAddress; - private final SubscriptionMode subscriptionMode; - private final String lastActivity; - private final boolean isTyping; - private final String status; - private final A avatar; - - private ViewInterlocutor(String name, - String address, - String accountAddress, - SubscriptionMode subscriptionMode, - String lastActivity, - boolean isTyping, - String status, - A avatar) { - this.name = name; - this.address = address; - this.accountAddress = accountAddress; - this.subscriptionMode = subscriptionMode; - this.lastActivity = lastActivity; - this.isTyping = isTyping; - this.status = status; - this.avatar = avatar; - } - - @Override - public String getName() { - return name; - } - - @Override - public String getAddress() { - return address; - } - - @Override - public String getAccountAddress() { - return accountAddress; - } - - @Override - public SubscriptionMode getSubscriptionMode() { - return subscriptionMode; - } - - @Override - public String getLastActivity() { - return lastActivity; - } - - @Override - public boolean isTyping() { - return isTyping; - } - - @Override - public String getStatus() { - return status; - } - - public A getAvatar() { - return avatar; - } - - public static Builder builder() { - return new Builder<>(); - } - - private static class Builder { - - private String name; - private String address; - private String accountAddress; - private SubscriptionMode subscriptionMode; - private String lastActivity; - private boolean isTyping; - private String status; - private A avatar; - - public Builder setName(String name) { - this.name = name; - return this; - } - - public Builder setAddress(String address) { - this.address = address; - return this; - } - - public Builder setAccountAddress(String accountAddress) { - this.accountAddress = accountAddress; - return this; - } - - public Builder setSubscriptionMode(SubscriptionMode subscriptionMode) { - this.subscriptionMode = subscriptionMode; - return this; - } - - public Builder setLastActivity(String lastActivity) { - this.lastActivity = lastActivity; - return this; - } - - public Builder setIsTyping(boolean isTyping) { - this.isTyping = isTyping; - return this; - } - - public Builder setStatus(String status) { - this.status = status; - return this; - } - - public Builder setAvatar(A avatar) { - this.avatar = avatar; - return this; - } - - public ViewInterlocutor build() { - return new ViewInterlocutor<>(name, address, accountAddress, subscriptionMode, - lastActivity, isTyping, status, avatar); - } - } -} diff --git a/view_entity/src/main/java/org/mercury_im/messenger/view/entity/definition/InterlocutorViewEntity.java b/view_entity/src/main/java/org/mercury_im/messenger/view/entity/definition/InterlocutorViewEntity.java deleted file mode 100644 index 4187adb..0000000 --- a/view_entity/src/main/java/org/mercury_im/messenger/view/entity/definition/InterlocutorViewEntity.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.mercury_im.messenger.view.entity.definition; - -import org.mercury_im.messenger.entity.contact.SubscriptionMode; - -public interface InterlocutorViewEntity { - - String getName(); - - String getAddress(); - - String getAccountAddress(); - - SubscriptionMode getSubscriptionMode(); - - String getLastActivity(); - - boolean isTyping(); - - String getStatus(); -} diff --git a/xmpp/.gitignore b/xmpp/.gitignore deleted file mode 100644 index 796b96d..0000000 --- a/xmpp/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/xmpp/build.gradle b/xmpp/build.gradle deleted file mode 100644 index a0594e6..0000000 --- a/xmpp/build.gradle +++ /dev/null @@ -1,25 +0,0 @@ -apply plugin: 'java-library' - -dependencies { - implementation project(":entity") - implementation project(':domain') - - // RxJava2 - implementation "io.reactivex.rxjava2:rxjava:$rxJava2Version" - - // Dagger 2 for dependency injection - implementation "com.google.dagger:dagger:$daggerVersion" - annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion" - testAnnotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion" - - // Smack - // Not all of those are needed, but it may be a good idea to define those versions explicitly - api "org.igniterealtime.smack:smack-core:$smackCoreVersion" - api "org.igniterealtime.smack:smack-experimental:$smackExperimentalVersion" - api "org.igniterealtime.smack:smack-extensions:$smackExtensionsVersion" - api "org.igniterealtime.smack:smack-im:$smackImVersion" - api "org.igniterealtime.smack:smack-tcp:$smackTcpVersion" -} - -sourceCompatibility = "8" -targetCompatibility = "8" diff --git a/xmpp/src/main/java/org/mercury_im/messenger/transport/xmpp/XmppConnectionFactory.java b/xmpp/src/main/java/org/mercury_im/messenger/transport/xmpp/XmppConnectionFactory.java deleted file mode 100644 index 5f07e73..0000000 --- a/xmpp/src/main/java/org/mercury_im/messenger/transport/xmpp/XmppConnectionFactory.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.mercury_im.messenger.transport.xmpp; - -import org.jivesoftware.smack.ConnectionConfiguration; -import org.jivesoftware.smack.XMPPConnection; -import org.mercury_im.messenger.Messenger; -import org.mercury_im.messenger.transport.connection.ConnectionFactory; -import org.mercury_im.messenger.entity.Account; - -public abstract class XmppConnectionFactory - implements ConnectionFactory { - - protected final Messenger messenger; - - public XmppConnectionFactory(Messenger messenger) { - this.messenger = messenger; - } - - public Messenger getMessenger() { - return messenger; - } - - @Override - public XmppTcpConnectionMethod provideConnection(Account account) { - return new XmppTcpConnectionMethod(account, getMessenger(), createXmppConnection(getConfiguration(account))); - } - - protected abstract CF getConfiguration(Account account); - - protected abstract XMPPConnection createXmppConnection(CF connectionConfiguration); -} diff --git a/xmpp/src/main/java/org/mercury_im/messenger/transport/xmpp/XmppTcpConnectionFactory.java b/xmpp/src/main/java/org/mercury_im/messenger/transport/xmpp/XmppTcpConnectionFactory.java deleted file mode 100644 index 2fa9808..0000000 --- a/xmpp/src/main/java/org/mercury_im/messenger/transport/xmpp/XmppTcpConnectionFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.mercury_im.messenger.transport.xmpp; - -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.tcp.XMPPTCPConnection; -import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; -import org.jxmpp.jid.EntityBareJid; -import org.jxmpp.jid.impl.JidCreate; -import org.mercury_im.messenger.Messenger; -import org.mercury_im.messenger.entity.Account; -import org.mercury_im.messenger.entity.PasswordAuthentication; - -public class XmppTcpConnectionFactory extends XmppConnectionFactory { - - public XmppTcpConnectionFactory(Messenger messenger) { - super(messenger); - } - - @Override - protected XMPPTCPConnectionConfiguration getConfiguration(Account account) { - XMPPTCPConnectionConfiguration.Builder configBuilder = XMPPTCPConnectionConfiguration.builder(); - configBuilder.setConnectTimeout(20 * 1000); - - if (account.getAuthentication() instanceof PasswordAuthentication) { - PasswordAuthentication authPassword = (PasswordAuthentication) account.getAuthentication(); - EntityBareJid accountAddress = JidCreate.entityBareFromOrThrowUnchecked(account.getAddress()); - configBuilder.setXmppAddressAndPassword(accountAddress, authPassword.getPassword()); - } - - return configBuilder.build(); - } - - @Override - protected XMPPConnection createXmppConnection(XMPPTCPConnectionConfiguration configuration) { - return new XMPPTCPConnection(configuration); - } -} diff --git a/xmpp/src/main/java/org/mercury_im/messenger/transport/xmpp/XmppTcpConnectionMethod.java b/xmpp/src/main/java/org/mercury_im/messenger/transport/xmpp/XmppTcpConnectionMethod.java deleted file mode 100644 index 585008b..0000000 --- a/xmpp/src/main/java/org/mercury_im/messenger/transport/xmpp/XmppTcpConnectionMethod.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.mercury_im.messenger.transport.xmpp; - -import org.jivesoftware.smack.AbstractXMPPConnection; -import org.jivesoftware.smack.XMPPConnection; -import org.mercury_im.messenger.Messenger; -import org.mercury_im.messenger.transport.ConnectionType; -import org.mercury_im.messenger.transport.connection.AbstractConnectionMethod; -import org.mercury_im.messenger.entity.Account; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.reactivex.Completable; - -public class XmppTcpConnectionMethod extends AbstractConnectionMethod { - - private static final Logger LOGGER = Logger.getLogger(XmppTcpConnectionMethod.class.getName()); - - private XMPPConnection connection; - - public XmppTcpConnectionMethod(Account account, Messenger messenger, XMPPConnection connection) { - super(account, messenger); - this.connection = connection; - } - - @Override - public Completable connect() { - if (connection.isConnected()) { - return Completable.complete(); - } - - return Completable.fromAction( - () -> { - AbstractXMPPConnection con = (AbstractXMPPConnection) connection; - try { - con.connect(); - } catch (Exception e) { - LOGGER.log(Level.WARNING, "Exception while connecting to XMPP account " + account.getId(), e); - throw e; - } - - try { - con.login(); - } catch (Exception e) { - LOGGER.log(Level.WARNING, "Exception while logging into XMPP account " + account.getId(), e); - throw e; - } - }); - } - - public XMPPConnection getConnection() { - return connection; - } - - @Override - public ConnectionType getConnectionType() { - return ConnectionType.SMACK_TCP; - } -}