All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.octo.android.robospice.request.RequestProcessor Maven / Gradle / Ivy

There is a newer version: 1.4.14
Show newest version
package com.octo.android.robospice.request;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;

import roboguice.util.temp.Ln;
import android.content.Context;

import com.octo.android.robospice.SpiceService;
import com.octo.android.robospice.networkstate.NetworkStateChecker;
import com.octo.android.robospice.persistence.CacheManager;
import com.octo.android.robospice.request.listener.RequestCancellationListener;
import com.octo.android.robospice.request.listener.RequestListener;
import com.octo.android.robospice.request.listener.SpiceServiceListener;
import com.octo.android.robospice.request.notifier.RequestListenerNotifier;
import com.octo.android.robospice.request.notifier.SpiceServiceListenerNotifier;

/**
 * Delegate class of the {@link SpiceService}, easier to test than an Android
 * {@link android.app.Service}.
 * @author jva
 */
public class RequestProcessor {
    // ============================================================================================
    // ATTRIBUTES
    // ============================================================================================

    private final Map, Set>> mapRequestToRequestListener = Collections.synchronizedMap(new LinkedHashMap, Set>>());
    private final RequestProgressManager requestProgressManager;
    private final RequestRunner requestRunner;
    private final CacheManager cacheManager;
    private boolean isStopped;

    // ============================================================================================
    // CONSTRUCTOR
    // ============================================================================================

    /**
     * Build a request processor using a custom. This feature has been
     * implemented follwing a feature request from Riccardo Ciovati.
     * @param context
     *            the context on which {@link SpiceRequest} will provide their
     *            results.
     * @param cacheManager
     *            the {@link CacheManager} that will be used to retrieve
     *            requests' result and store them.
     * @param executorService
     *            a custom {@link ExecutorService} that will be used to execute
     *            {@link SpiceRequest} .
     * @param requestProcessorListener
     *            a listener of the {@link RequestProcessor}, it will be
     *            notified when no more requests are left, typically allowing
     *            the {@link SpiceService} to stop itself.
     */
    public RequestProcessor(final Context context, final CacheManager cacheManager, final ExecutorService executorService, final RequestProcessorListener requestProcessorListener,
        final NetworkStateChecker networkStateChecker, final RequestListenerNotifier requestListenerNotifier, final SpiceServiceListenerNotifier spiceServiceListenerNotifier) {

        this.cacheManager = cacheManager;
        this.requestProgressManager = new RequestProgressManager(requestProcessorListener, mapRequestToRequestListener, requestListenerNotifier, spiceServiceListenerNotifier);
        this.requestRunner = new RequestRunner(context, cacheManager, executorService, requestProgressManager, networkStateChecker);
    }

    // ============================================================================================
    // PUBLIC
    // ============================================================================================
    public void addRequest(final CachedSpiceRequest request, final Set> listRequestListener) {
        if (isStopped) {
            Ln.d("Dropping request : " + request + " as processor is stopped.");
            return;
        }

        Ln.d("Adding request to queue " + hashCode() + ": " + request + " size is " + mapRequestToRequestListener.size());

        if (request.isCancelled()) {
            synchronized (mapRequestToRequestListener) {
                for (final CachedSpiceRequest cachedSpiceRequest : mapRequestToRequestListener.keySet()) {
                    if (cachedSpiceRequest.equals(request)) {
                        cachedSpiceRequest.cancel();
                        requestProgressManager.notifyListenersOfRequestCancellation(request);
                        return;
                    }
                }
            }
        }

        boolean aggregated = false;
        Set> listRequestListenerForThisRequest = mapRequestToRequestListener.get(request);

        if (listRequestListenerForThisRequest == null) {
            if (request.isProcessable()) {
                Ln.d("Adding entry for type %s and cacheKey %s.", request.getResultType(), request.getRequestCacheKey());
                listRequestListenerForThisRequest = Collections.synchronizedSet(new HashSet>());
                this.mapRequestToRequestListener.put(request, listRequestListenerForThisRequest);
            }
        } else {
            Ln.d("Request for type %s and cacheKey %s already exists.", request.getResultType(), request.getRequestCacheKey());
            aggregated = true;
        }

        if (listRequestListener != null && listRequestListenerForThisRequest != null) {
            listRequestListenerForThisRequest.addAll(listRequestListener);
        }

        if (aggregated) {
            requestProgressManager.notifyListenersOfRequestAggregated(request, listRequestListener);
            return;
        }

        if (request.isProcessable()) {
            requestProgressManager.notifyListenersOfRequestAdded(request, listRequestListener);
        } else {
            if (listRequestListenerForThisRequest == null) {
                requestProgressManager.notifyListenersOfRequestNotFound(request, listRequestListener);
            }
            requestProgressManager.notifyOfRequestProcessed(request, listRequestListener);
            // we have to return if request is not processable.
            // fix bug https://github.com/octo-online/robospice/issues/215
            return;
        }

        final RequestCancellationListener requestCancellationListener = new RequestCancellationListener() {

            @Override
            public void onRequestCancelled() {
                requestProgressManager.notifyListenersOfRequestCancellation(request);
                mapRequestToRequestListener.remove(request);
            }
        };
        request.setRequestCancellationListener(requestCancellationListener);

        if (request.isCancelled()) {
            requestProgressManager.notifyListenersOfRequestCancellation(request);
            mapRequestToRequestListener.remove(request);
            return;
        } else {
            requestRunner.executeRequest(request);
        }
    }

    /**
     * Disable request listeners notifications for a specific request.
* All listeners associated to this request won't be called when request * will finish.
* @param request * Request on which you want to disable listeners * @param listRequestListener * the collection of listeners associated to request not to be * notified */ public void dontNotifyRequestListenersForRequest(final CachedSpiceRequest request, final Collection> listRequestListener) { requestProgressManager.dontNotifyRequestListenersForRequest(request, listRequestListener); } public boolean removeDataFromCache(final Class clazz, final Object cacheKey) { return cacheManager.removeDataFromCache(clazz, cacheKey); } public void removeAllDataFromCache(final Class clazz) { cacheManager.removeAllDataFromCache(clazz); } public void removeAllDataFromCache() { cacheManager.removeAllDataFromCache(); } public boolean isFailOnCacheError() { return requestRunner.isFailOnCacheError(); } public void setFailOnCacheError(final boolean failOnCacheError) { requestRunner.setFailOnCacheError(failOnCacheError); } @Override public String toString() { final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append('['); stringBuilder.append(getClass().getName()); stringBuilder.append(" : "); stringBuilder.append(" request count= "); stringBuilder.append(mapRequestToRequestListener.keySet().size()); stringBuilder.append(", listeners per requests = ["); for (final Map.Entry, Set>> entry : mapRequestToRequestListener.entrySet()) { stringBuilder.append(entry.getKey().getClass().getName()); stringBuilder.append(":"); stringBuilder.append(entry.getKey()); stringBuilder.append(" --> "); if (entry.getValue() == null) { stringBuilder.append(entry.getValue()); } else { stringBuilder.append(entry.getValue().size()); } } stringBuilder.append(']'); stringBuilder.append(']'); return stringBuilder.toString(); } public void addSpiceServiceListener(final SpiceServiceListener spiceServiceListener) { requestProgressManager.addSpiceServiceListener(spiceServiceListener); } public void removeSpiceServiceListener(final SpiceServiceListener spiceServiceListener) { requestProgressManager.removeSpiceServiceListener(spiceServiceListener); } public void shouldStop() { isStopped = true; requestRunner.shouldStop(); } public boolean isStopped() { return isStopped; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy