/**
*
*/
package by.istin.android.xcore.service;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.ResultReceiver;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import by.istin.android.xcore.ContextHolder;
import by.istin.android.xcore.error.IErrorHandler;
import by.istin.android.xcore.provider.ModelContract;
import by.istin.android.xcore.source.DataSourceRequest;
import by.istin.android.xcore.source.SyncDataSourceRequestEntity;
import by.istin.android.xcore.source.sync.helper.SyncHelper;
import by.istin.android.xcore.utils.AppUtils;
import by.istin.android.xcore.utils.Log;
/**
* @author IstiN
*
*/
public class SyncDataSourceService extends DataSourceService {
private static final Object sDbLockFlag = new Object();
private static final ExecutorService sSingleExecutor = Executors.newSingleThreadExecutor();
private static final Handler sHandler = new Handler(Looper.getMainLooper());
public static void execute(final Context context, final DataSourceRequest dataSourceRequest, final String processorKey, final String datasourceKey) {
SyncHelper.get(context).addSyncAccount();
StatusResultReceiver wrappedReceiver = createWrappedReceiver(context, dataSourceRequest, processorKey, datasourceKey, null);
execute(context, dataSourceRequest, processorKey, datasourceKey, wrappedReceiver, SyncDataSourceService.class);
}
public static void execute(final Context context, final DataSourceRequest dataSourceRequest, final String processorKey, final String datasourceKey, final StatusResultReceiver resultReceiver) {
SyncHelper.get(context).addSyncAccount();
StatusResultReceiver wrappedReceiver = createWrappedReceiver(context, dataSourceRequest, processorKey, datasourceKey, resultReceiver);
execute(context, dataSourceRequest, processorKey, datasourceKey, wrappedReceiver, SyncDataSourceService.class);
}
private static StatusResultReceiver createWrappedReceiver(final Context context, final DataSourceRequest dataSourceRequest, final String processorKey, final String datasourceKey, final StatusResultReceiver resultReceiver) {
return new StatusResultReceiver(sHandler) {
@Override
public void onStart(Bundle resultData) {
if (resultReceiver != null) {
resultReceiver.onStart(resultData);
}
}
@Override
protected void onCached(Bundle resultData) {
super.onCached(resultData);
if (resultReceiver != null) {
resultReceiver.onCached(resultData);
}
removeSyncEntity(context, dataSourceRequest);
}
@Override
public void onDone(Bundle resultData) {
if (resultReceiver != null) {
resultReceiver.onDone(resultData);
}
removeSyncEntity(context, dataSourceRequest);
}
@Override
public void onError(Exception exception) {
if (resultReceiver != null) {
resultReceiver.onError(exception);
}
IErrorHandler errorHandler = AppUtils.get(ContextHolder.getInstance().getContext(), IErrorHandler.SYSTEM_SERVICE_KEY);
if (errorHandler.isCanBeReSent(exception)) {
Log.xe(context, "save request for resubmit", exception);
markSyncEntityAsError(context, dataSourceRequest, datasourceKey, processorKey, exception);
} else {
Log.xe(context, "error", exception);
removeSyncEntity(context, dataSourceRequest);
}
}
};
}
@Override
protected void run(RequestExecutor.ExecuteRunnable runnable, final Intent intent, final DataSourceRequest dataSourceRequest, final Bundle bundle, final ResultReceiver resultReceiver) {
synchronized (sDbLockFlag) {
super.run(runnable, intent, dataSourceRequest, bundle, resultReceiver);
}
}
private static void markSyncEntityAsError(final Context context, final DataSourceRequest dataSourceRequest, final String datasourceKey, final String processorKey, Exception exception) {
sSingleExecutor.execute(new Runnable() {
@Override
public void run() {
synchronized (sDbLockFlag) {
ContentValues contentValues = SyncDataSourceRequestEntity.prepare(dataSourceRequest);
contentValues.put(SyncDataSourceRequestEntity.IS_ERROR, true);
contentValues.put(SyncDataSourceRequestEntity.DATASOURCE_KEY, datasourceKey);
contentValues.put(SyncDataSourceRequestEntity.PROCESSOR_KEY, processorKey);
context.getContentResolver().insert(ModelContract.getUri(SyncDataSourceRequestEntity.class), contentValues);
}
}
});
}
private static void removeSyncEntity(final Context context, final DataSourceRequest dataSourceRequest) {
sSingleExecutor.execute(new Runnable() {
@Override
public void run() {
synchronized (sDbLockFlag) {
context.getContentResolver().delete(ModelContract.getUri(SyncDataSourceRequestEntity.class, SyncDataSourceRequestEntity.generateId(dataSourceRequest)), null, null);
}
}
});
}
@Override
protected void onBeforeExecute(final Intent intent, final DataSourceRequest dataSourceRequest, ResultReceiver resultReceiver, Bundle bundle) {
final String processorKey = intent.getStringExtra(PROCESSOR_KEY);
final String datasourceKey = intent.getStringExtra(DATA_SOURCE_KEY);
sSingleExecutor.execute(new Runnable() {
@Override
public void run() {
synchronized (sDbLockFlag) {
ContentValues contentValues = SyncDataSourceRequestEntity.prepare(dataSourceRequest);
contentValues.put(SyncDataSourceRequestEntity.DATASOURCE_KEY, datasourceKey);
contentValues.put(SyncDataSourceRequestEntity.PROCESSOR_KEY, processorKey);
getContentResolver().insert(ModelContract.getUri(SyncDataSourceRequestEntity.class), contentValues);
}
}
});
}
@Override
protected RequestExecutor createExecutorService() {
return new RequestExecutor(1, new LinkedBlockingQueue<Runnable>());
}
}