chromium/base/android/java/src/org/chromium/base/supplier/UnownedUserDataSupplier.java

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.base.supplier;

import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;

import org.chromium.base.UnownedUserData;
import org.chromium.base.UnownedUserDataHost;
import org.chromium.base.UnownedUserDataKey;
import org.chromium.base.lifetime.DestroyChecker;
import org.chromium.base.lifetime.Destroyable;

/**
 * UnownedUserDataSupplier handles the combined lifecycle management for {@link UnownedUserData} and
 * {@link DestroyableObservableSupplier}. It can be constructed anywhere but needs to be attached
 * before it's accessible via {@link UnownedUserDataHost}. When destroyed, UnownedUserDataSupplier
 * is detached from all hosts.
 *
 * <p>A functional implementation with best practices is defined in {@link
 * UnownedUserDataSupplierTest}.
 *
 * <p>Classes that hold a reference to to the concrete implementation of this class are also in
 * charge of its lifecycle. {@link #destroy} should be called when the application is shutting down.
 * This will detach the {@link UnownedUserDataSupplier}, but it won't destroy the supplied object.
 *
 * <p>In practice, UnownedUserDataSupplier owners should declare and assign the supplier inline.
 * This allows interop between other supplier implementations as well as use in activity
 * constructors before {@link WindowAndroid} is created. See the example below:
 *
 * <pre>{@code
 * UnownedUserDataSupplier<Foo> mFooSupplier = new FooSupplier();
 * ...
 * // Sometime after WindowAndroid has been created.
 * mFooSupplier.attach(mWindowAndroid.getUnownedUserDataHost());
 * }</pre>
 *
 * @param <E> The type of the data to be Supplied and stored in UnownedUserData.
 * @see UnownedUserDataHost for more details on ownership and typical usage.
 * @see UnownedUserDataKey for information about the type of key that is required.
 * @see UnownedUserData for the marker interface used for this type of data.
 */
public abstract class UnownedUserDataSupplier<E> extends ObservableSupplierImpl<E>
        implements Destroyable, UnownedUserData {
    private final UnownedUserDataKey<UnownedUserDataSupplier<E>> mUudKey;
    private final DestroyChecker mDestroyChecker = new DestroyChecker();

    /**
     * Constructs an UnownedUserDataSupplier.
     * @param uudKey The {@link UnownedUserDataKey}, which is defined in subclasses.
     */
    protected UnownedUserDataSupplier(
            @NonNull UnownedUserDataKey<? extends UnownedUserDataSupplier<E>> uudKey) {
        mUudKey = (UnownedUserDataKey<UnownedUserDataSupplier<E>>) uudKey;
    }

    /**
     * Attach to the specified host.
     * @param host The host to attach the supplier to.
     */
    public void attach(@NonNull UnownedUserDataHost host) {
        mDestroyChecker.checkNotDestroyed();
        mUudKey.attachToHost(host, this);
    }

    @Override
    @CallSuper
    public void destroy() {
        mDestroyChecker.destroy();
        mUudKey.detachFromAllHosts(this);
    }
}