/** * */ package by.istin.android.xcore.service; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.IBinder; import android.os.Parcelable; import android.os.ResultReceiver; import java.io.Serializable; import java.util.ArrayList; import by.istin.android.xcore.ContextHolder; import by.istin.android.xcore.processor.IProcessor; import by.istin.android.xcore.service.RequestExecutor.ExecuteRunnable; import by.istin.android.xcore.service.assist.LIFOLinkedBlockingDeque; import by.istin.android.xcore.source.DataSourceRequest; import by.istin.android.xcore.source.IDataSource; import by.istin.android.xcore.utils.AppUtils; import by.istin.android.xcore.utils.Log; /** * @author IstiN * */ public abstract class AbstractExecutorService extends Service { private static final String ACTION_STOP = "stop"; protected static final String DATA_SOURCE_KEY = "dataSourceKey"; protected static final String PROCESSOR_KEY = "processorKey"; protected static final String RESULT_RECEIVER = "resultReceiver"; private RequestExecutor mRequestExecutor; public static void stop(Context context, ResultReceiver receiver, Class<? extends AbstractExecutorService> serviceClass) { Intent intent = new Intent(context, serviceClass); intent.putExtra(ACTION_STOP, true); intent.putExtra(RESULT_RECEIVER, receiver); context.startService(intent); } protected static void execute(Context context, DataSourceRequest dataSourceRequest, String processorKey, String dataSourceKey, Class<?> serviceClass) { execute(context, dataSourceRequest, processorKey, dataSourceKey, null, serviceClass); } protected static void execute(Context context, DataSourceRequest dataSourceRequest, String processorKey, String dataSourceKey, StatusResultReceiver resultReceiver, Class<?> serviceClass) { if (context == null) { context = ContextHolder.getInstance().getContext(); if (context == null) { return; } } Intent intent = createStartIntent(context, dataSourceRequest, processorKey, dataSourceKey, resultReceiver, serviceClass); if (intent == null) { return; } context.startService(intent); } protected static Intent createStartIntent(Context context, DataSourceRequest dataSourceRequest, String processorKey, String dataSourceKey, StatusResultReceiver resultReceiver, Class<?> serviceClass) { if (context == null) { context = ContextHolder.getInstance().getContext(); if (context == null) { return null; } } Intent intent = new Intent(context, serviceClass); intent.putExtra(DATA_SOURCE_KEY, dataSourceKey); intent.putExtra(PROCESSOR_KEY, processorKey); intent.putExtra(RESULT_RECEIVER, resultReceiver); dataSourceRequest.toIntent(intent); return intent; } /* (non-Javadoc) * @see android.app.Service#onBind(android.content.Intent) */ @Override public IBinder onBind(Intent intent) { return new ServiceBinder<AbstractExecutorService>(this); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { onHandleIntent(intent); } return super.onStartCommand(intent, flags, startId); } protected void onHandleIntent(final Intent intent) { final ResultReceiver resultReceiver = intent.getParcelableExtra(RESULT_RECEIVER); if (intent.getBooleanExtra(ACTION_STOP, false)) { Log.xd(this, "action stop"); if (mRequestExecutor != null) { mRequestExecutor.stop(resultReceiver); } else { resultReceiver.send(0, null); } stopSelf(); Log.xd(this, "action stop executor recreated"); return; } final DataSourceRequest dataSourceRequest = DataSourceRequest.fromIntent(intent); final Bundle bundle = new Bundle(); dataSourceRequest.toBundle(bundle); if (resultReceiver != null) { resultReceiver.send(StatusResultReceiver.Status.ADD_TO_QUEUE.ordinal(), bundle); } onBeforeExecute(intent, dataSourceRequest, resultReceiver, bundle); final RequestExecutor requestExecutor = getRequestExecutor(); requestExecutor.execute(new ExecuteRunnable(resultReceiver) { @Override public void run() { AbstractExecutorService.this.run(this, intent, dataSourceRequest, bundle, resultReceiver); } @Override public String createKey() { return dataSourceRequest.toUriParams(); } @Override protected void onDone() { if (requestExecutor.isEmpty()) { stopSelf(); Log.xd(AbstractExecutorService.this, "stop from run"); } } }); } protected abstract void run(ExecuteRunnable runnable, final Intent intent, final DataSourceRequest dataSourceRequest, final Bundle bundle, final ResultReceiver resultReceiver); protected RequestExecutor getRequestExecutor() { if (mRequestExecutor == null) { mRequestExecutor = createExecutorService(); } return mRequestExecutor; } @Override public void onDestroy() { mRequestExecutor = null; super.onDestroy(); } protected RequestExecutor createExecutorService() { return new RequestExecutor(RequestExecutor.DEFAULT_POOL_SIZE, new LIFOLinkedBlockingDeque<Runnable>()); } protected void onBeforeExecute(Intent intent, DataSourceRequest dataSourceRequest, ResultReceiver resultReceiver, Bundle bundle) { } @SuppressWarnings("unchecked") public static Object execute(Context context, boolean cacheable, String processorKey, String dataSourceKey, DataSourceRequest dataSourceRequest, Bundle bundle) throws Exception { final IProcessor processor = AppUtils.get(context, processorKey); final IDataSource dataSource = AppUtils.get(context, dataSourceKey); Object result = processor.execute(dataSourceRequest, dataSource, dataSource.getSource(dataSourceRequest)); if (cacheable) { processor.cache(context, dataSourceRequest, result); if (bundle == null) { return result; } if (result instanceof Parcelable) { bundle.putParcelable(StatusResultReceiver.RESULT_KEY, (Parcelable) result); } else if (result instanceof Parcelable[]) { bundle.putParcelableArray(StatusResultReceiver.RESULT_KEY, (Parcelable[]) result); } else if (result instanceof Serializable) { bundle.putSerializable(StatusResultReceiver.RESULT_KEY, (Serializable) result); } } else { if (bundle == null) { return result; } if (result instanceof Parcelable) { bundle.putParcelable(StatusResultReceiver.RESULT_KEY, (Parcelable) result); } else if (result instanceof Parcelable[]) { bundle.putParcelableArray(StatusResultReceiver.RESULT_KEY, (Parcelable[]) result); } else if (result instanceof Serializable) { bundle.putSerializable(StatusResultReceiver.RESULT_KEY, (Serializable) result); } } return result; } }