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.bean; 015 016import org.microbean.assign.AttributedType; 017 018import org.microbean.construct.Domain; 019 020/** 021 * A supplier of {@link References} objects. 022 * 023 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 024 * 025 * @see #references(AttributedType) 026 * 027 * @see #reference(AttributedType) 028 * 029 * @see References 030 */ 031// TODO: not crazy about the circular dependencies, but they're no worse than, say, a sealed class 032public interface ReferencesSelector { 033 034 /** 035 * Destroys the supplied contextual reference if and only if it meets the conditions for destruction. 036 * 037 * @param r a contextual reference; may be {@code null} in which case {@code false} will be returned 038 * 039 * @return {@code true} if and only if destruction occurred 040 * 041 * @exception DestructionException if an error occurs 042 */ 043 public boolean destroy(final Object r); // e.g. CDI's Instance#destroy(Object); works only on normal- and @Dependent-scoped objects 044 045 // I don't like this at all. But you need something that can make, e.g., TypeMirrors, so that you can create 046 // AttributedTypes, which you need to call the other methods in this interface. Every other type can be acquired at 047 // runtime via a ReferencesSelector, but you need a Domain to kick start the process. 048 /** 049 * Returns a {@link Domain} that can be used to produce {@link javax.lang.model.type.TypeMirror}s so that {@link 050 * AttributedType} instances used by the {@link #references(AttributedType)} and {@link #reference(AttributedType)} 051 * methods may be created. 052 * 053 * <p>Implementations of this method must not return {@code null}.</p> 054 * 055 * <p>Implementations of this method must be safe for concurrent use by multiple threads.</p> 056 * 057 * <p>Implementations of this method must return a determinate value.</p> 058 * 059 * <h4>Design Note</h4> 060 * 061 * <p>Without this method, componenents using a {@link ReferencesSelector} will have to arrange to have their own 062 * {@link Domain} somehow. Inconveniently, this is the only type in the system that cannot be acquired by an 063 * invocation of the {@link #references(AttributedType)} method, since you need a {@link Domain} to make an {@link 064 * AttributedType}.</p> 065 * 066 * @return a non-{@code null} {@link Domain} 067 */ 068 public Domain domain(); 069 070 /** 071 * Returns a contextual reference of the relevant type appropriate for the supplied {@link Bean}. 072 * 073 * <p>Implementations of this method must be safe for concurrent use by multiple threads.</p> 074 * 075 * <p>Implementations of this method must, directly or indirectly, use the supplied {@link Bean}'s {@linkplain 076 * Bean#factory() affiliated <code>Factory</code>} to {@linkplain Factory#create(Creation) create} any contextual 077 * instance underlying the contextual reference to be returned.</p> 078 * 079 * @param <R> the contextual reference type 080 * 081 * @param bean a {@link Bean}; must not be {@code null} 082 * 083 * @return a non-{@code null} contextual reference 084 * 085 * @exception NullPointerException if {@code bean} is {@code null} 086 * 087 * @exception IllegalArgumentException if {@code bean} is unsuitable in any way 088 */ 089 // Experimental. Needed because you might grab a pile of Beans, then filter them yourself according to external 090 // criteria, and then want references for them. I'm slightly sour on this because up to this point you don't need 091 // Beans to implement ReferencesSelector at all. Maybe this needs to be a different interface, but then you're still 092 // faced with the issue that fundamentally this method returns a contextual reference, and that *is* the domain of 093 // ReferencesSelector. 094 // 095 // You could do reference(Predicate) but that's TOO generic. 096 public <R> R reference(final Bean<R> bean); 097 098 /** 099 * Returns a {@link References} capable of locating contextual references of the relevant type. 100 * 101 * @param <R> the contextual reference type 102 * 103 * @param t an {@link AttributedType} describing the contextual reference type; must not be {@code null} 104 * 105 * @return a non-{@code null} {@link References} 106 * 107 * @exception NullPointerException if {@code t} is {@code null} 108 * 109 * @exception IllegalArgumentException if {@code t} is unsuitable in any way 110 * 111 * @see References 112 */ 113 public <R> References<R> references(final AttributedType t); 114 115 /** 116 * A convenience method that acquires and returns what is presumed, possibly incorrectly, to be the sole contextual 117 * reference of the relevant type. 118 * 119 * @param <R> the contextual reference type 120 * 121 * @param t an {@link AttributedType} describing the contextual reference type; must not be {@code null} 122 * 123 * @return a non-{@code null} contextual reference 124 * 125 * @exception NullPointerException if {@code t} is {@code null} 126 * 127 * @exception UnsatisfiedResolutionException if there is no contextual reference for the relevant type 128 * 129 * @exception AmbiguousResolutionException if there is more than one contextual reference for the relevant type 130 * 131 * @see #references(AttributedType) 132 * 133 * @see References#get() 134 */ 135 public default <R> R reference(final AttributedType t) { 136 return this.<R>references(t).get(); 137 } 138 139}