/**
* Copyright (c) 2013, Redsolution LTD. All rights reserved.
*
* This file is part of Xabber project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License, Version 3.
*
* Xabber is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License,
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.xabber.android.data.connection;
import android.support.annotation.NonNull;
import android.util.Log;
import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.account.AccountErrorEvent;
import com.xabber.android.data.account.AccountItem;
import com.xabber.android.data.log.AndroidLoggingHandler;
import com.xabber.android.data.log.LogManager;
import org.greenrobot.eventbus.EventBus;
import org.jivesoftware.smack.AbstractXMPPConnection;
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.DNSUtil;
import org.jivesoftware.smack.util.dns.dnsjava.DNSJavaResolver;
import org.jivesoftware.smack.util.dns.minidns.MiniDnsResolver;
import java.io.IOException;
import java.util.logging.Level;
import de.measite.minidns.AbstractDNSClient;
class ConnectionThread {
@NonNull
private final XMPPTCPConnection connection;
@SuppressWarnings("WeakerAccess")
@NonNull
final ConnectionItem connectionItem;
private Thread thread;
ConnectionThread(@NonNull XMPPTCPConnection connection, @NonNull ConnectionItem connectionItem) {
this.connection = connection;
this.connectionItem = connectionItem;
createNewThread();
}
private void createNewThread() {
LogManager.i(this, "Creating new connection thread");
thread = new Thread(new Runnable() {
@Override
public void run() {
if (NetworkManager.isNetworkAvailable()) {
connectAndLogin();
} else {
connectionItem.updateState(ConnectionState.waiting);
LogManager.i(this, "No network connection");
}
}
});
thread.setPriority(Thread.MIN_PRIORITY);
thread.setDaemon(true);
}
/**
*
* @return true if connection thread started, false if already running - nothing changed
*/
boolean start() {
if (thread.getState() == Thread.State.TERMINATED) {
LogManager.i(this, "Connection thread is finished, creating new one...");
createNewThread();
}
if (thread.getState() == Thread.State.NEW) {
LogManager.i(this, "Connection thread is new, starting...");
thread.start();
return true;
} else {
LogManager.i(this, "Connection thread is running already");
return false;
}
}
@SuppressWarnings("WeakerAccess")
void connectAndLogin() {
AndroidLoggingHandler.reset(new AndroidLoggingHandler());
java.util.logging.Logger.getLogger(XMPPTCPConnection.class.getName()).setLevel(Level.FINEST);
java.util.logging.Logger.getLogger(AbstractDNSClient.class.getName()).setLevel(Level.FINEST);
java.util.logging.Logger.getLogger(AbstractXMPPConnection.class.getName()).setLevel(Level.FINEST);
java.util.logging.Logger.getLogger(DNSUtil.class.getName()).setLevel(Level.FINEST);
switch (SettingsManager.connectionDnsResolver()) {
case dnsJavaResolver:
LogManager.i(this, "Use DNS Java resolver");
DNSJavaResolver.setup();
break;
case miniDnsResolver:
LogManager.i(this, "Use Mini DNS resolver");
MiniDnsResolver.setup();
break;
}
try {
LogManager.i(this, "Trying to connect and login...");
if (!connection.isConnected()) {
connectionItem.updateState(ConnectionState.connecting);
connection.connect();
} else {
LogManager.i(this, "Already connected");
}
if (!connection.isAuthenticated()) {
connection.login();
} else {
LogManager.i(this, "Already authenticated");
}
} catch (SASLErrorException e) {
LogManager.exception(this, e);
AccountErrorEvent accountErrorEvent = new AccountErrorEvent(connectionItem.getAccount(),
AccountErrorEvent.Type.AUTHORIZATION, e.getMessage());
com.xabber.android.data.account.AccountManager.getInstance().addAccountError(accountErrorEvent);
com.xabber.android.data.account.AccountManager.getInstance().setEnabled(connectionItem.getAccount(), false);
EventBus.getDefault().postSticky(accountErrorEvent);
// catching RuntimeExceptions seems to be strange, but we got a lot of error coming from
// Smack or mini DSN client inside of Smack.
} catch (XMPPException | SmackException | IOException | RuntimeException e) {
LogManager.exception(this, e);
if (!((AccountItem)connectionItem).isSuccessfulConnectionHappened()) {
LogManager.i(this, "There was no successful connection, disabling account");
AccountErrorEvent accountErrorEvent = new AccountErrorEvent(connectionItem.getAccount(),
AccountErrorEvent.Type.CONNECTION, Log.getStackTraceString(e));
com.xabber.android.data.account.AccountManager.getInstance().addAccountError(accountErrorEvent);
com.xabber.android.data.account.AccountManager.getInstance().setEnabled(connectionItem.getAccount(), false);
EventBus.getDefault().postSticky(accountErrorEvent);
}
} catch (InterruptedException e) {
LogManager.exception(this, e);
}
LogManager.i(this, "Connection thread finished");
}
@Override
public String toString() {
return getClass().getSimpleName() + ": " + connectionItem.getAccount();
}
}