/** * 2011 Foxykeep (http://datadroid.foxykeep.com) * <p> * Licensed under the Beerware License : <br /> * As long as you retain this notice you can do whatever you want with this stuff. If we meet some * day, and you think this stuff is worth it, you can buy me a beer in return */ package com.foxykeep.datadroid.service; import com.foxykeep.datadroid.exception.ConnectionException; import com.foxykeep.datadroid.exception.CustomRequestException; import com.foxykeep.datadroid.exception.DataException; import com.foxykeep.datadroid.requestmanager.Request; import com.foxykeep.datadroid.requestmanager.RequestManager; import com.foxykeep.datadroid.util.DataDroidLog; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.ResultReceiver; /** * This class is the superclass of all the worker services you'll create. * * @author Foxykeep */ public abstract class RequestService extends MultiThreadedIntentService { /** * Interface to implement by your operations * * @author Foxykeep */ public interface Operation { /** * Execute the request and returns a {@link Bundle} containing the data to return. * * @param context The context to use for your operation. * @param request The request to execute. * @return A {@link Bundle} containing the data to return. If no data to return, null. * @throws ConnectionException Thrown when a connection error occurs. It will be propagated * to the {@link RequestManager} as a * {@link RequestManager#ERROR_TYPE_CONNEXION}. * @throws DataException Thrown when a problem occurs while managing the data of the * webservice. It will be propagated to the {@link RequestManager} as a * {@link RequestManager#ERROR_TYPE_DATA}. * @throws CustomRequestException Any other exception you may have to throw. A call to * {@link RequestService#onCustomRequestException(Request, * CustomRequestException)} will be made with the Exception thrown. */ public Bundle execute(Context context, Request request) throws ConnectionException, DataException, CustomRequestException; } private static final String LOG_TAG = RequestService.class.getSimpleName(); public static final String INTENT_EXTRA_RECEIVER = "com.foxykeep.datadroid.extra.receiver"; public static final String INTENT_EXTRA_REQUEST = "com.foxykeep.datadroid.extra.request"; private static final int SUCCESS_CODE = 0; public static final int ERROR_CODE = -1; /** * Proxy method for {@link #sendResult(ResultReceiver, Bundle, int)} when the work is a * success. * * @param receiver The result receiver received inside the {@link Intent}. * @param data A {@link Bundle} with the data to send back. */ private void sendSuccess(ResultReceiver receiver, Bundle data) { sendResult(receiver, data, SUCCESS_CODE); } /** * Proxy method for {@link #sendResult(ResultReceiver, Bundle, int)} when the work is a failure * due to the network. * * @param receiver The result receiver received inside the {@link Intent}. * @param exception The {@link ConnectionException} triggered. */ private void sendConnexionFailure(ResultReceiver receiver, ConnectionException exception) { Bundle data = new Bundle(); data.putInt(RequestManager.RECEIVER_EXTRA_ERROR_TYPE, RequestManager.ERROR_TYPE_CONNEXION); data.putInt(RequestManager.RECEIVER_EXTRA_CONNECTION_ERROR_STATUS_CODE, exception.getStatusCode()); sendResult(receiver, data, ERROR_CODE); } /** * Proxy method for {@link #sendResult(ResultReceiver, Bundle, int)} when the work is a failure * due to the data (parsing for example). * * @param receiver The result receiver received inside the {@link Intent}. */ private void sendDataFailure(ResultReceiver receiver) { Bundle data = new Bundle(); data.putInt(RequestManager.RECEIVER_EXTRA_ERROR_TYPE, RequestManager.ERROR_TYPE_DATA); sendResult(receiver, data, ERROR_CODE); } /** * Proxy method for {@link #sendResult(ResultReceiver, Bundle, int)} when the work is a failure * due to {@link CustomRequestException} being thrown. * * @param receiver The result receiver received inside the {@link Intent}. * @param data A {@link Bundle} the data to send back. */ private void sendCustomFailure(ResultReceiver receiver, Bundle data) { if (data == null) { data = new Bundle(); } data.putInt(RequestManager.RECEIVER_EXTRA_ERROR_TYPE, RequestManager.ERROR_TYPE_CUSTOM); sendResult(receiver, data, ERROR_CODE); } /** * Method used to send back the result to the {@link RequestManager}. * * @param receiver The result receiver received inside the {@link Intent}. * @param data A {@link Bundle} the data to send back. * @param code The success/error code to send back. */ private void sendResult(ResultReceiver receiver, Bundle data, int code) { DataDroidLog.d(LOG_TAG, "sendResult : " + ((code == SUCCESS_CODE) ? "Success" : "Failure")); if (receiver != null) { if (data == null) { data = new Bundle(); } receiver.send(code, data); } } @Override protected final void onHandleIntent(Intent intent) { Request request = intent.getParcelableExtra(INTENT_EXTRA_REQUEST); request.setClassLoader(getClassLoader()); ResultReceiver receiver = intent.getParcelableExtra(INTENT_EXTRA_RECEIVER); Operation operation = getOperationForType(request.getRequestType()); try { sendSuccess(receiver, operation.execute(this, request)); } catch (ConnectionException e) { DataDroidLog.e(LOG_TAG, "ConnectionException", e); sendConnexionFailure(receiver, e); } catch (DataException e) { DataDroidLog.e(LOG_TAG, "DataException", e); sendDataFailure(receiver); } catch (CustomRequestException e) { DataDroidLog.e(LOG_TAG, "Custom Exception", e); sendCustomFailure(receiver, onCustomRequestException(request, e)); } catch (RuntimeException e) { DataDroidLog.e(LOG_TAG, "RuntimeException", e); sendDataFailure(receiver); } } /** * Get the {@link Operation} corresponding to the given request type. * * @param requestType The request type (extracted from {@link Request}). * @return The corresponding {@link Operation}. */ public abstract Operation getOperationForType(int requestType); /** * Call if a {@link CustomRequestException} is thrown by an {@link Operation}. You may return a * Bundle containing data to return to the {@link RequestManager}. * <p> * Default implementation return null. You may want to override this method in your * implementation of {@link RequestService} to execute specific action and/or return specific * data. * * @param request The {@link Request} which execution threw the exception. * @param exception The {@link CustomRequestException} thrown. * @return A {@link Bundle} containing data to return to the {@link RequestManager}. Default * implementation return null. */ protected Bundle onCustomRequestException(Request request, CustomRequestException exception) { return null; } }