BaseCancelable.java :  » Facebook » pombook » com » pomty » pombook » gallery » Android Open Source

Android Open Source » Facebook » pombook 
pombook » com » pomty » pombook » gallery » BaseCancelable.java
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.pomty.pombook.gallery;

import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;

/**
 * An abstract class for the interface <code>Cancelable</code>. Subclass can
 * simply override the <code>execute()</code> function to provide an
 * implementation of <code>Cancelable</code>.
 */
public abstract class BaseCancelable<T> implements Cancelable<T> {

    /**
     * The state of the task, possible transitions are:
     * <pre>
     *     INITIAL -> CANCELED
     *     EXECUTING -> COMPLETE, CANCELING, ERROR, CANCELED
     *     CANCELING -> CANCELED
     * </pre>
     * When the task stop, it must be end with one of the following states:
     * COMPLETE, CANCELED, or ERROR;
     */
    private static final int STATE_INITIAL = (1 << 0);
    private static final int STATE_EXECUTING = (1 << 1);
    private static final int STATE_CANCELING = (1 << 2);
    private static final int STATE_CANCELED = (1 << 3);
    private static final int STATE_ERROR = (1 << 4);
    private static final int STATE_COMPLETE = (1 << 5);

    private int mState = STATE_INITIAL;

    private Throwable mError;
    private T mResult;
    private Cancelable<?> mCurrentTask;

    protected abstract T execute() throws Exception;

    /**
     * Frees the result (which is not null) when the task has been canceled.
     */
    protected void freeCanceledResult(T result) {
        // Do nothing by default;
    }

    private boolean isInStates(int states) {
        return (states & mState) != 0;
    }

    private T handleTerminalStates() throws ExecutionException {
        if (mState == STATE_CANCELED) {
            throw new CancellationException();
        }
        if (mState == STATE_ERROR) {
            throw new ExecutionException(mError);
        }
        if (mState == STATE_COMPLETE) return mResult;
        throw new IllegalStateException();
    }

    public synchronized void await() throws InterruptedException {
        while (!isInStates(STATE_COMPLETE | STATE_CANCELED | STATE_ERROR)) {
            wait();
        }
    }

    public final T get() throws InterruptedException, ExecutionException {
        synchronized (this) {
            if (mState != STATE_INITIAL) {
                await();
                return handleTerminalStates();
            }
            mState = STATE_EXECUTING;
        }
        try {
            mResult = execute();
        } catch (CancellationException e) {
            mState = STATE_CANCELED;
        } catch (InterruptedException e) {
            mState = STATE_CANCELED;
        } catch (Throwable error) {
            synchronized (this) {
                if (mState != STATE_CANCELING) {
                    mError = error;
                    mState = STATE_ERROR;
                }
            }
        }
        synchronized (this) {
            if (mState == STATE_CANCELING) mState = STATE_CANCELED;
            if (mState == STATE_EXECUTING) mState = STATE_COMPLETE;
            notifyAll();
            if (mState == STATE_CANCELED && mResult != null) {
                freeCanceledResult(mResult);
            }
            return handleTerminalStates();
        }
    }

    /**
     * Requests the task to be canceled.
     *
     * @return true if the task is running and has not been canceled; false
     *     otherwise
     */

    public synchronized boolean requestCancel() {
        if (mState == STATE_INITIAL) {
            mState = STATE_CANCELED;
            notifyAll();
            return false;
        }
        if (mState == STATE_EXECUTING) {
            if (mCurrentTask != null) mCurrentTask.requestCancel();
            mState = STATE_CANCELING;
            return true;
        }
        return false;
    }

    /**
     * Runs a <code>Cancelable</code> subtask. This method is helpful, if the
     * task can be composed of several cancelable tasks. By using this function,
     * it will pass <code>requestCancel</code> message to those subtasks.
     *
     * @param <T> the return type of the sub task
     * @param cancelable the sub task
     * @return the result of the subtask
     */
    protected <T> T runSubTask(Cancelable<T> cancelable)
            throws InterruptedException, ExecutionException {
        synchronized (this) {
            if (mCurrentTask != null) {
                throw new IllegalStateException(
                        "cannot two subtasks at the same time");
            }
            if (mState == STATE_CANCELING) throw new CancellationException();
            mCurrentTask = cancelable;
        }
        try {
            return cancelable.get();
        } finally {
            synchronized (this) {
                mCurrentTask = null;
            }
        }
    }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.