001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2025–2026 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.bean;
015
016import javax.lang.model.AnnotatedConstruct;
017
018import org.microbean.assign.Annotated;
019
020import org.microbean.construct.Domain;
021
022/**
023 * A supplier of {@link References} objects.
024 *
025 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
026 *
027 * @see #references(Annotated)
028 *
029 * @see #reference(Annotated)
030 *
031 * @see References
032 */
033// TODO: not crazy about the circular dependencies, but they're no worse than, say, a sealed class
034public interface ReferencesSelector {
035
036  /**
037   * Destroys the supplied contextual reference if and only if it meets the conditions for destruction.
038   *
039   * @param r a contextual reference; may be {@code null} in which case {@code false} will be returned
040   *
041   * @return {@code true} if and only if destruction occurred
042   *
043   * @exception DestructionException if an error occurs
044   */
045  public boolean destroy(final Object r); // e.g. CDI's Instance#destroy(Object); works only on normal- and @Dependent-scoped objects
046
047  // I don't like this at all. But you need something that can make, e.g., AnnotatedConstructs, so that you can call the other
048  // methods in this interface. Every other type can be acquired at runtime via a ReferencesSelector, but you need a
049  // Domain to kick start the process.
050  /**
051   * Returns a non-{@code null} {@link Domain} that can be used to furnish {@link javax.lang.model.AnnotatedConstruct}s.
052   *
053   * <p>Implementations of this method must be safe for concurrent use by multiple threads.</p>
054   *
055   * <h4>Design Note</h4>
056   *
057   * <p>Without this method, componenents using a {@link ReferencesSelector} will have to arrange to have their own
058   * {@link Domain} somehow. Inconveniently, this is the only type in the system that cannot be acquired by an
059   * invocation of the {@link #references(Annotated)} method, since you need a {@link Domain} to make an {@link
060   * Annotated Annotated&lt;? extends AnnotatedConstruct&gt;}.</p>
061   *
062   * @return a non-{@code null} {@link Domain}
063   *
064   * @see Domain
065   */
066  public Domain domain();
067
068  /**
069   * Returns a non-{@code null}, determinate, contextual reference appropriate for the supplied {@link Bean}.
070   *
071   * <p>Implementations of this method must be safe for concurrent use by multiple threads.</p>
072   *
073   * <p>Implementations of this method must, directly or indirectly, must ensure that ultimately the supplied {@link
074   * Bean}'s {@linkplain Bean#factory() affiliated <code>Factory</code>} is the mechanism used, and no other is used, to
075   * {@linkplain Factory#create(Creation) create} any contextual instance underlying the contextual reference to be
076   * returned.</p>
077   *
078   * @param <R> the contextual reference type
079   *
080   * @param bean a non-{@code null} {@link Bean}
081   *
082   * @return a non-{@code null}, determinate, contextual reference appropriate for the supplied {@link Bean}
083   *
084   * @exception NullPointerException if {@code bean} is {@code null}
085   *
086   * @exception IllegalArgumentException if {@code bean} is unsuitable in any way
087   */
088  // Experimental. Needed because you might grab a pile of Beans, then filter them yourself according to external
089  // criteria, and then want references for them. I'm slightly sour on this because up to this point you don't need
090  // Beans to implement ReferencesSelector at all. Maybe this needs to be a different interface, but then you're still
091  // faced with the issue that fundamentally this method returns a contextual reference, and that *is* the domain of
092  // ReferencesSelector.
093  //
094  // You could do reference(Predicate) but that's TOO generic.
095  public <R> R reference(final Bean<R> bean);
096
097  /**
098   * Returns a non-{@code null}, determinate {@link References} capable of locating contextual references compatible
099   * with the supplied {@link Annotated Annotated&lt;? extends AnnotatedConstruct&gt;}.
100   *
101   * @param <R> the contextual reference type
102   *
103   * @param aac a non-{@code null} {@link Annotated Annotated&lt;? extends AnnotatedConstruct&gt;} describing the
104   * putative contextual reference; must represent {@code <R>}
105   *
106   * @return a non-{@code null}, determinate {@link References}
107   *
108   * @exception NullPointerException if {@code aac} is {@code null}
109   *
110   * @exception IllegalArgumentException if {@code aac} is unsuitable in any way
111   *
112   * @see References
113   *
114   * @see Annotated#of(AnnotatedConstruct)
115   */
116  public <R> References<R> references(final Annotated<? extends AnnotatedConstruct> aac);
117
118  /**
119   * Returns a non-{@code null}, determinate {@link References} capable of locating contextual references compatible
120   * with the supplied {@link AnnotatedConstruct}.
121   *
122   * @param <R> the contextual reference type
123   *
124   * @param ac a non-{@code null} {@link AnnotatedConstruct} describing the putative contextual reference; must represent
125   * {@code <R>}
126   *
127   * @return a non-{@code null}, determinate {@link References}
128   *
129   * @exception NullPointerException if {@code ac} is {@code null}
130   *
131   * @exception IllegalArgumentException if {@code ac} is unsuitable in any way
132   *
133   * @see References
134   *
135   * @see Annotated#of(AnnotatedConstruct)
136   *
137   * @deprecated Please use the {@link #references(Annotated)} method instead.
138   */
139  @Deprecated
140  public default <R> References<R> references(final AnnotatedConstruct ac) {
141    return references(Annotated.of(ac));
142  }
143
144  /**
145   * A convenience method that acquires and returns what is presumed, possibly incorrectly, to be the sole contextual
146   * reference compatible with the supplied {@link AnnotatedConstruct}.
147   *
148   * @param <R> the contextual reference type
149   *
150   * @param ac a non-{@code null} {@link AnnotatedConstruct} describing the putative contextual reference; must
151   * represent {@code <R>}
152   *
153   * @return a non-{@code null}, determinate contextual reference
154   *
155   * @exception NullPointerException if {@code ac} is {@code null}
156   *
157   * @exception UnsatisfiedResolutionException if there is no compatible contextual reference
158   *
159   * @exception AmbiguousResolutionException if there is more than one compatible contextual reference
160   *
161   * @see #references(Annotated)
162   *
163   * @see Annotated#of(AnnotatedConstruct)
164   *
165   * @see References#get()
166   *
167   * @deprecated Please use the {@link #reference(Annotated)} method instead.
168   */
169  @Deprecated
170  public default <R> R reference(final AnnotatedConstruct ac) {
171    return this.<R>reference(Annotated.of(ac));
172  }
173
174  /**
175   * A convenience method that acquires and returns what is presumed, possibly incorrectly, to be the sole contextual
176   * reference compatible with the supplied {@link Annotated Annotated&lt;? extends AnnotatedConstruct&gt;}.
177   *
178   * @param <R> the contextual reference type
179   *
180   * @param aac a non-{@code null} {@link Annotated Annotated&lt;? extends AnnotatedConstruct&gt;} describing the
181   * putative contextual reference; must represent {@code <R>}
182   *
183   * @return a non-{@code null}, determinate contextual reference
184   *
185   * @exception NullPointerException if {@code aac} is {@code null}
186   *
187   * @exception UnsatisfiedResolutionException if there is no compatible contextual reference
188   *
189   * @exception AmbiguousResolutionException if there is more than one compatible contextual reference
190   *
191   * @see #references(Annotated)
192   *
193   * @see References#get()
194   */
195  public default <R> R reference(final Annotated<? extends AnnotatedConstruct> aac) {
196    return this.<R>references(aac).get();
197  }
198
199}