package com.jdroid.android.exception;
import com.jdroid.android.application.AbstractApplication;
import com.jdroid.android.context.UsageStats;
import com.jdroid.android.utils.LocalizationUtils;
import com.jdroid.java.collections.Lists;
import com.jdroid.java.exception.AbstractException;
import com.jdroid.java.exception.ConnectionException;
import com.jdroid.java.exception.ErrorCode;
import com.jdroid.java.exception.ErrorCodeException;
import com.jdroid.java.exception.UnexpectedException;
import com.jdroid.java.utils.LoggerUtils;
import com.jdroid.java.utils.ReflectionUtils;
import com.jdroid.java.utils.StringUtils;
import org.slf4j.Logger;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.List;
public class DefaultExceptionHandler implements ExceptionHandler {
private final static Logger LOGGER = LoggerUtils.getLogger(DefaultExceptionHandler.class);
private static final String MAIN_THREAD_NAME = "main";
private UncaughtExceptionHandler wrappedExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
private UncaughtExceptionHandler defaultExceptionHandler;
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
Boolean mainThread = thread.getName().equals(MAIN_THREAD_NAME);
if (mainThread) {
handleMainThreadException(thread, throwable);
} else {
handleWorkerThreadException(throwable);
}
}
protected void handleMainThreadException(Thread thread, Throwable throwable) {
try {
try {
UsageStats.setLastCrashTimestamp();
List<String> tags = getThrowableTags(throwable, null);
AbstractApplication.get().getAnalyticsSender().trackFatalException(throwable, tags);
} catch (Exception e) {
wrappedExceptionHandler.uncaughtException(thread, e);
}
wrappedExceptionHandler.uncaughtException(thread, throwable);
} catch (Exception e) {
LOGGER.error("Error when trying to handle an exception", e);
defaultExceptionHandler.uncaughtException(thread, throwable);
}
}
protected void handleWorkerThreadException(Throwable throwable) {
try {
logHandledException(throwable);
} catch (Exception e) {
logHandledExceptionSafe("Error when trying to handle an exception", e);
}
}
public void logHandledException(String errorMessage) {
logHandledException(new UnexpectedException(errorMessage));
}
@Override
public void logHandledException(Throwable throwable) {
logHandledException(null, throwable);
}
@Override
public void logHandledException(String errorMessage, Throwable throwable) {
if (throwable instanceof ConnectionException) {
if (errorMessage == null) {
errorMessage = "Connection error";
}
LOGGER.warn(errorMessage, throwable);
} else {
Boolean trackable = true;
Throwable throwableToLog = throwable;
int priorityLevel = AbstractException.NORMAL_PRIORITY;
if (throwable instanceof AbstractException) {
AbstractException abstractException = (AbstractException)throwable;
trackable = abstractException.isTrackable();
throwableToLog = abstractException.getThrowableToLog();
priorityLevel = abstractException.getPriorityLevel();
}
if (errorMessage == null) {
errorMessage = throwableToLog.getMessage();
if (errorMessage == null) {
errorMessage = "Error";
}
}
if (trackable) {
LOGGER.error(errorMessage, throwableToLog);
List<String> tags = getThrowableTags(throwable, priorityLevel);
AbstractApplication.get().getAnalyticsSender().trackHandledException(throwableToLog, tags);
} else {
LOGGER.warn(errorMessage);
}
}
}
private void logHandledExceptionSafe(String errorMessage, Throwable throwable) {
LOGGER.error(errorMessage, throwable);
AbstractApplication.get().getAnalyticsSender().trackHandledException(throwable, getDefaultThrowableTags());
}
protected List<String> getDefaultThrowableTags() {
return Lists.newArrayList();
}
public static Boolean matchAnyErrorCode(Throwable throwable, ErrorCode... errorCodes) {
List<ErrorCode> errorCodesList = Lists.newArrayList(errorCodes);
if (throwable instanceof ErrorCodeException) {
ErrorCodeException errorCodeException = (ErrorCodeException)throwable;
return errorCodesList.contains(errorCodeException.getErrorCode());
}
return false;
}
protected List<String> getThrowableTags(Throwable throwable, Integer priorityLevel) {
List<String> tags = Lists.newArrayList();
if (priorityLevel != null) {
tags.add("level" + String.format("%02d", priorityLevel));
}
return tags;
}
public static void addTags(Throwable throwable, List<String> tags) {
if (!Lists.isNullOrEmpty(tags)) {
StringBuilder builder = new StringBuilder();
builder.append(StringUtils.join(tags, " "));
if (throwable.getMessage() != null) {
builder.append(" ");
builder.append(throwable.getMessage());
}
try {
ReflectionUtils.set(throwable, "detailMessage", builder.toString());
} catch (Exception e) {
// do nothing
}
}
}
@Override
public void logWarningException(String errorMessage, Throwable throwable) {
if (throwable instanceof ConnectionException) {
logHandledException(throwable);
} else {
logHandledException(new WarningException(errorMessage, throwable));
}
}
@Override
public void logWarningException(String errorMessage) {
logHandledException(new WarningException(errorMessage));
}
@Override
public void logIgnoreStackTraceWarningException(String errorMessage) {
logHandledException(new WarningException(errorMessage, true));
}
@Override
public void setDefaultExceptionHandler(UncaughtExceptionHandler uncaughtExceptionHandler) {
defaultExceptionHandler = uncaughtExceptionHandler;
}
public static void setMessageOnConnectionTimeout(RuntimeException runtimeException, int resId) {
setMessageOnConnectionTimeout(runtimeException, LocalizationUtils.getString(resId));
}
public static void setMessageOnConnectionTimeout(RuntimeException runtimeException, String text) {
if (runtimeException instanceof ConnectionException) {
ConnectionException connectionException = (ConnectionException)runtimeException;
if (connectionException.isReadTimeout()) {
connectionException.setDescription(text);
}
}
}
}