/** * */ package by.istin.android.xcore.service; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; import by.istin.android.xcore.provider.ModelContract; import by.istin.android.xcore.source.DataSourceRequest; import by.istin.android.xcore.source.DataSourceRequestEntity; import by.istin.android.xcore.utils.CursorUtils; import by.istin.android.xcore.utils.Holder; import by.istin.android.xcore.utils.StringUtil; /** * @author IstiN * */ public class DataSourceService extends AbstractExecutorService { private final Object mDbLockFlag = new Object(); public static void execute(Context context, DataSourceRequest dataSourceRequest, String processorKey, String dataSourceKey) { execute(context, dataSourceRequest, processorKey, dataSourceKey, DataSourceService.class); } public static void execute(Context context, DataSourceRequest dataSourceRequest, String processorKey, String dataSourceKey, StatusResultReceiver resultReceiver) { execute(context, dataSourceRequest, processorKey, dataSourceKey, resultReceiver, DataSourceService.class); } public static Intent createStartIntent(Context context, DataSourceRequest dataSourceRequest, String processorKey, String dataSourceKey, StatusResultReceiver resultReceiver) { return createStartIntent(context, dataSourceRequest, processorKey, dataSourceKey, resultReceiver, DataSourceService.class); } @Override protected void run(final RequestExecutor.ExecuteRunnable runnable, Intent intent, DataSourceRequest dataSourceRequest, Bundle bundle, ResultReceiver resultReceiver) { runnable.sendStatus(StatusResultReceiver.Status.START, bundle); boolean isCacheable = dataSourceRequest.isCacheable(); boolean isForceUpdateData = dataSourceRequest.isForceUpdateData(); boolean isAlreadyCached = false; Holder<Long> requestIdHolder = new Holder<Long>(); synchronized (mDbLockFlag) { if (isCacheable && !isForceUpdateData) { long requestId = DataSourceRequestEntity.generateId(dataSourceRequest); requestIdHolder.set(requestId); isAlreadyCached = CacheRequestHelper.cacheIfNotCached(this, dataSourceRequest, requestId); } if (!isAlreadyCached) { //String requestParentUri = dataSourceRequest.getRequestParentUri(); //TODO something wrong, idea was check current request uri /*if (!StringUtil.isEmpty(requestParentUri)) { getContentResolver().delete(ModelContract.getUri(DataSourceRequestEntity.class), DataSourceRequestEntity.PARENT_URI + "=?", new String[]{requestParentUri}); }*/ //is it right? getContentResolver().delete(ModelContract.getUri(DataSourceRequestEntity.class), DataSourceRequestEntity.PARENT_URI + "=?", new String[]{dataSourceRequest.getUri()}); } } if (isAlreadyCached) { if (isExecuteJoinedRequestsSuccessful(runnable, intent, dataSourceRequest, bundle)) { runnable.sendStatus(StatusResultReceiver.Status.CACHED, bundle); } return; } try { final String processorKey = intent.getStringExtra(PROCESSOR_KEY); final String dataSourceKey = intent.getStringExtra(DATA_SOURCE_KEY); execute(this, isCacheable, processorKey, dataSourceKey, dataSourceRequest, bundle); if (isExecuteJoinedRequestsSuccessful(runnable, intent, dataSourceRequest, bundle)) { runnable.sendStatus(StatusResultReceiver.Status.DONE, bundle); } } catch (Exception e) { if (!requestIdHolder.isNull()) { synchronized (mDbLockFlag) { getContentResolver().delete(ModelContract.getUri(DataSourceRequestEntity.class, requestIdHolder.get()), null, null); } } try { bundle.putSerializable(StatusResultReceiver.ERROR_KEY, e); runnable.sendStatus(StatusResultReceiver.Status.ERROR, bundle); } catch (RuntimeException e1) { bundle.remove(StatusResultReceiver.ERROR_KEY); runnable.sendStatus(StatusResultReceiver.Status.ERROR, bundle); } } } private boolean isExecuteJoinedRequestsSuccessful(final RequestExecutor.ExecuteRunnable parentRunnable, Intent intent, DataSourceRequest dataSourceRequest, Bundle statusBundle) { DataSourceRequest joinedRequest = dataSourceRequest.getJoinedRequest(); if (joinedRequest != null) { ErrorRedirectExecuteRunnable redirectRunnable = new ErrorRedirectExecuteRunnable(parentRunnable); String joinedDataSource = dataSourceRequest.getJoinedDataSourceKey(); String joinedProcessor = dataSourceRequest.getJoinedProcessorKey(); Intent joinIntent = new Intent(); joinIntent.putExtra(DATA_SOURCE_KEY, joinedDataSource); joinIntent.putExtra(PROCESSOR_KEY, joinedProcessor); run(redirectRunnable, joinIntent, joinedRequest, statusBundle, null); if (redirectRunnable.isError) { return false; } } return true; } private class ErrorRedirectExecuteRunnable extends RequestExecutor.ExecuteRunnable { private final RequestExecutor.ExecuteRunnable parentRunnable; private boolean isError = false; public ErrorRedirectExecuteRunnable(RequestExecutor.ExecuteRunnable parentRunnable) { super(new ResultReceiver(new Handler(DataSourceService.this.getMainLooper()))); this.parentRunnable = parentRunnable; } @Override public String createKey() { //used only like redirect to parent request return null; } @Override protected void onDone() { //used only like redirect to parent request } @Override public void run() { //used only like redirect to parent request } @Override public void sendStatus(StatusResultReceiver.Status status, Bundle bundle) { if (status == StatusResultReceiver.Status.ERROR) { parentRunnable.sendStatus(status, bundle); isError = true; } } public boolean isError() { return isError; } } }