001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2025 microBean™.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
006 * the License. You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
012 * specific language governing permissions and limitations under the License.
013 */
014package org.microbean.reference;
015
016/**
017 * An interface whose implementations can register contextual instances for idempotent destruction at some later point.
018 *
019 * <p>This interface is often used by implementors of systems of dependent object destruction, and normally by no other
020 * kinds of users.</p>
021 *
022 * <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
023 *
024 * @see #register(Object, Destructor)
025 */
026// Needed by "dependent"/"none" scopes/lifecycle managers.
027// Not used by "normal" factories etc.
028//
029// TODO: the package feels wrong, but stashing it in microbean-scopelet, alongside NoneScopelet, doesn't let
030// microbean-reference's Request implement it
031//
032// TODO: maybe could move it to microbean-reference? microbean-scopelet depends on microbean-reference already?
033public interface DestructorRegistry {
034
035  /**
036   * <dfn>Registers</dfn> the supplied contextual instance such that at some future moment, or perhaps not at all, the
037   * supplied {@link Destructor} will be {@linkplain Destructor#destroy() run} to destroy it idempotently, and returns
038   * {@code true} if and only if the registration was successful.
039   *
040   * @param instance a contextual instance; may be {@code null} in which case no action will be taken and {@code false}
041   * will be returned
042   *
043   * @param destructor a {@link Destructor}; may be {@code null} in which case no action will be taken and {@code false}
044   * will be returned
045   *
046   * @return {@code true} if and only if registration was successful; {@code false} otherwise
047   *
048   * @see Destructor
049   */
050  public boolean register(final Object instance, final Destructor destructor);
051
052  /**
053   * An interface indicating that an implementation is capable of <dfn>destroying</dfn> an object that it opaquely
054   * references such that the destroyed object will no longer be suitable for use.
055   *
056   * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
057   *
058   * @see #destroy()
059   *
060   * @see DestructorRegistry#register(Object, Destructor)
061   */
062  @FunctionalInterface
063  public static interface Destructor {
064
065    /**
066     * Destroys an object that this implementation opaquely references such that the destroyed object will no longer be
067     * suitable for use.
068     *
069     * <p>Implementations of this method must be safe for concurrent use by multiple threads.</p>
070     *
071     * <p>Implementations of this method must be idempotent, performing no action if destruction of the implicit object
072     * has already taken place.</p>
073     *
074     * @see DestructorRegistry#register(Object, Destructor)
075     */
076    public void destroy();
077
078  }
079
080}