16859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert/*
26859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert * Copyright (C) 2010 The Android Open Source Project
36859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert *
46859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
56859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert * you may not use this file except in compliance with the License.
66859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert * You may obtain a copy of the License at
76859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert *
86859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert *      http://www.apache.org/licenses/LICENSE-2.0
96859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert *
106859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
116859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
126859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert * See the License for the specific language governing permissions and
146859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert * limitations under the License.
156859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert */
166859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
176859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringertpackage com.android.quicksearchbox.util;
186859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
196859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringertimport android.util.Log;
206859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
216859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringertimport java.util.ArrayList;
226859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringertimport java.util.List;
236859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
246859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert/**
256859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert * Abstract base class for a one-place cache that holds a value that is produced
266859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert * asynchronously.
276859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert *
286859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert * @param <A> The type of the data held in the cache.
296859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert */
30e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodpublic abstract class CachedLater<A> implements NowOrLater<A> {
316859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
326859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    private static final String TAG = "QSB.AsyncCache";
3313b4f2dc4b339790c2b9b0220be47c8e77fd61eaMathew Inwood    private static final boolean DBG = false;
346859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
356859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    private final Object mLock = new Object();
366859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
376859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    private A mValue;
386859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
39e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood    private boolean mCreating;
406859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    private boolean mValid;
416859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
42e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood    private List<Consumer<? super A>> mWaitingConsumers;
436859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
446859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    /**
456859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     * Creates the object to store in the cache. This method must call
466859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     * {@link #store} when it's done.
476859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     * This method must not block.
486859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     */
496859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    protected abstract void create();
506859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
516859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    /**
526859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     * Saves a new value to the cache.
536859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     */
546859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    protected void store(A value) {
557f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert        if (DBG) Log.d(TAG, "store()");
56e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood        List<Consumer<? super A>> waitingConsumers;
576859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        synchronized (mLock) {
586859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            mValue = value;
596859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            mValid = true;
607f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert            mCreating = false;
616859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            waitingConsumers = mWaitingConsumers;
626859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            mWaitingConsumers = null;
636859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        }
646859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        if (waitingConsumers != null) {
65e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood            for (Consumer<? super A> consumer : waitingConsumers) {
666859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert                if (DBG) Log.d(TAG, "Calling consumer: " + consumer);
676859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert                consumer.consume(value);
686859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            }
696859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        }
706859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    }
716859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
726859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    /**
736859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     * Gets the value.
746859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     *
756859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     * @param consumer A consumer that will be given the cached value.
766859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     *        The consumer may be called synchronously, or asynchronously on
776859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     *        an unspecified thread.
786859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     */
79e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood    public void getLater(Consumer<? super A> consumer) {
807f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert        if (DBG) Log.d(TAG, "getLater()");
816859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        boolean valid;
826859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        A value;
836859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        synchronized (mLock) {
846859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            valid = mValid;
856859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            value = mValue;
866859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            if (!valid) {
87e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood                if (mWaitingConsumers == null) {
88e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood                    mWaitingConsumers = new ArrayList<Consumer<? super A>>();
89e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood                }
906859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert                mWaitingConsumers.add(consumer);
916859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            }
926859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        }
936859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        if (valid) {
947f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert            if (DBG) Log.d(TAG, "valid, calling consumer synchronously");
956859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            consumer.consume(value);
966859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        } else {
97e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood            boolean create = false;
98e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood            synchronized (mLock) {
99e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood                if (!mCreating) {
100e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood                    mCreating = true;
101e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood                    create = true;
102e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood                }
103e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood            }
1047f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert            if (create) {
1057f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert                if (DBG) Log.d(TAG, "not valid, calling create()");
1067f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert                create();
1077f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert            } else {
1087f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert                if (DBG) Log.d(TAG, "not valid, already creating");
1097f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert            }
1106859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        }
1116859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    }
1126859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
1136859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    /**
1146859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     * Clears the cache.
1156859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert     */
1166859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    public void clear() {
1177f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert        if (DBG) Log.d(TAG, "clear()");
1186859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        synchronized (mLock) {
1196859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            mValue = null;
1206859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            mValid = false;
1216859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        }
1226859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    }
1236859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert
124e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood    public boolean haveNow() {
125e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood        synchronized (mLock) {
126e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood            return mValid;
127e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood        }
128e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood    }
129e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood
130e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood    public synchronized A getNow() {
131e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood        synchronized (mLock) {
132e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood            if (!haveNow()) {
133e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood                throw new IllegalStateException("getNow() called when haveNow() is false");
134e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood            }
135e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood            return mValue;
136e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood        }
137e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood    }
138e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood
1396859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert}
140