001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.inject;
018
019import java.util.function.*;
020
021/**
022 * Extends {@link BeanStore} with methods for adding beans.
023 *
024 * <p>
025 * This interface provides write operations for bean stores, allowing beans to be added
026 * either as direct instances or as suppliers for lazy initialization.
027 *
028 * <h5 class='section'>Example:</h5>
029 * <p class='bjava'>
030 *    WritableBeanStore <jv>beanStore</jv> = ...;
031 *
032 *    <jc>// Add unnamed bean</jc>
033 *    <jv>beanStore</jv>.addBean(MyService.<jk>class</jk>, <jk>new</jk> MyService());
034 *
035 *    <jc>// Add named bean</jc>
036 *    <jv>beanStore</jv>.addBean(MyService.<jk>class</jk>, <jk>new</jk> MyService(), <js>"primary"</js>);
037 *
038 *    <jc>// Add bean supplier for lazy initialization</jc>
039 *    <jv>beanStore</jv>.addSupplier(MyService.<jk>class</jk>, () -&gt; <jk>new</jk> MyService());
040 *
041 *    <jc>// Add named bean supplier</jc>
042 *    <jv>beanStore</jv>.addSupplier(MyService.<jk>class</jk>, () -&gt; <jk>new</jk> MyService(), <js>"secondary"</js>);
043 *
044 *    <jc>// Clear all beans</jc>
045 *    <jv>beanStore</jv>.clear();
046 * </p>
047 *
048 * <h5 class='section'>See Also:</h5><ul>
049 *    <li class='jc'>{@link BeanStore} - Read-only bean lookup interface
050 * </ul>
051 */
052@SuppressWarnings({
053   "resource" // Fluent methods return the store itself (an AutoCloseable); callers chaining registrations must not be flagged for not closing each returned reference.
054})
055public interface WritableBeanStore extends BeanStore, AutoCloseable {
056
057   /**
058    * Same as {@link #addBean(Class,Object)} but returns the bean instead of this object for fluent calls.
059    *
060    * @param <T> The bean type.
061    * @param beanType The bean type.
062    * @param bean The bean instance.  Can be <jk>null</jk> (stored as an explicit <jk>null</jk> binding, distinct from no binding at all).
063    * @return The bean.
064    */
065   default <T> T add(Class<T> beanType, T bean) {
066      addBean(beanType, bean);
067      return bean;
068   }
069
070   /**
071    * Same as {@link #addBean(Class,Object,String)} but returns the bean instead of this object for fluent calls.
072    *
073    * @param <T> The bean type.
074    * @param beanType The bean type.
075    * @param bean The bean instance.  Can be <jk>null</jk> (stored as an explicit <jk>null</jk> binding, distinct from no binding at all).
076    * @param name The bean name.  Can be <jk>null</jk> for unnamed beans.
077    * @return The bean.
078    */
079   default <T> T add(Class<T> beanType, T bean, String name) {
080      addBean(beanType, bean, name);
081      return bean;
082   }
083
084   /**
085    * Adds an unnamed bean of the specified type to this store.
086    *
087    * @param <T> The bean type.
088    * @param beanType The bean type.
089    * @param bean The bean instance.  Can be <jk>null</jk> (stored as an explicit <jk>null</jk> binding, distinct from no binding at all).
090    * @return This object for method chaining.
091    */
092   <T> WritableBeanStore addBean(Class<T> beanType, T bean);
093
094   /**
095    * Adds a named bean of the specified type to this store.
096    *
097    * @param <T> The bean type.
098    * @param beanType The bean type.
099    * @param bean The bean instance.  Can be <jk>null</jk> (stored as an explicit <jk>null</jk> binding, distinct from no binding at all).
100    * @param name The bean name.  Can be <jk>null</jk> for unnamed beans.
101    * @return This object for method chaining.
102    */
103   <T> WritableBeanStore addBean(Class<T> beanType, T bean, String name);
104
105   /**
106    * Adds a supplier for an unnamed bean of the specified type to this store.
107    *
108    * <p>
109    * The supplier will be invoked lazily when the bean is first requested.
110    *
111    * @param <T> The bean type.
112    * @param beanType The bean type.
113    * @param supplier The bean supplier.  Must not be <jk>null</jk>.
114    * @return This object for method chaining.
115    */
116   <T> WritableBeanStore addSupplier(Class<T> beanType, Supplier<T> supplier);
117
118   /**
119    * Adds a supplier for a named bean of the specified type to this store.
120    *
121    * <p>
122    * The supplier will be invoked lazily when the bean is first requested.
123    *
124    * @param <T> The bean type.
125    * @param beanType The bean type.
126    * @param supplier The bean supplier.  Must not be <jk>null</jk>.
127    * @param name The bean name.  Can be <jk>null</jk> for unnamed beans.
128    * @return This object for method chaining.
129    */
130   <T> WritableBeanStore addSupplier(Class<T> beanType, Supplier<T> supplier, String name);
131
132   /**
133    * Adds a fallback supplier for an unnamed bean of the specified type to this store.
134    *
135    * <p>
136    * Default suppliers are consulted only after regular {@linkplain #addBean(Class,Object) entries} and the regular {@linkplain BasicBeanStore#BasicBeanStore(BeanStore) parent}
137    * chain have been searched.  They serve as a "use this if nothing else has provided one" hook,
138    * useful for memoizer-backed framework defaults that should not shadow explicit user
139    * registrations or beans inherited from an overriding parent (e.g. a Spring application context).
140    *
141    * @param <T> The bean type.
142    * @param beanType The bean type.
143    * @param supplier The bean supplier.  Must not be <jk>null</jk>.
144    * @return This object for method chaining.
145    */
146   <T> WritableBeanStore addDefaultSupplier(Class<T> beanType, Supplier<T> supplier);
147
148   /**
149    * Adds a fallback supplier for a named bean of the specified type to this store.
150    *
151    * <p>
152    * Default suppliers are consulted only after regular {@linkplain #addBean(Class,Object,String) entries} and the regular
153    * parent chain have been searched.  See {@link #addDefaultSupplier(Class,Supplier)}.
154    *
155    * @param <T> The bean type.
156    * @param beanType The bean type.
157    * @param supplier The bean supplier.  Must not be <jk>null</jk>.
158    * @param name The bean name.  Can be <jk>null</jk> for unnamed beans.
159    * @return This object for method chaining.
160    */
161   <T> WritableBeanStore addDefaultSupplier(Class<T> beanType, Supplier<T> supplier, String name);
162
163   /**
164    * Removes all beans from this store.
165    *
166    * <p>
167    * This operation only affects this store and does not affect any parent stores
168    * that may be associated with this store.
169    *
170    * @return This object for method chaining.
171    */
172   WritableBeanStore clear();
173
174   /**
175    * Returns <jk>true</jk> if this store has a {@linkplain #addDefaultSupplier(Class,Supplier) default supplier}
176    * registered locally for the specified unnamed bean type.
177    *
178    * <p>
179    * This is intended for callers that need to distinguish "framework default present" from "any binding
180    * exists" — for example, REST initialization uses this signal to skip types that are managed by an
181    * internal memoizer.  Parent and overriding-parent stores are <i>not</i> consulted.
182    *
183    * @param beanType The bean type to check.
184    * @return <jk>true</jk> if a default supplier for the unnamed bean type is registered on this store.
185    */
186   boolean hasDefaultSupplier(Class<?> beanType);
187
188   /**
189    * Returns <jk>true</jk> if this store has a {@linkplain #addDefaultSupplier(Class,Supplier,String) default supplier}
190    * registered locally for the specified bean type and name.
191    *
192    * <p>
193    * See {@link #hasDefaultSupplier(Class)} for the rationale.  Parent and overriding-parent stores are
194    * <i>not</i> consulted.
195    *
196    * @param beanType The bean type to check.
197    * @param name The bean name.  Can be <jk>null</jk> for unnamed beans.
198    * @return <jk>true</jk> if a default supplier for the bean type and name is registered on this store.
199    */
200   boolean hasDefaultSupplier(Class<?> beanType, String name);
201
202   /**
203    * Registers a default implementation class for the specified bean type.
204    *
205    * <p>
206    * Type bindings are consulted by callers (notably {@link BeanInstantiator} and the various REST
207    * memoizers) when resolving the impl class to instantiate for <c>beanType</c>.  This is the
208    * type-binding analogue of {@link #addDefaultSupplier(Class,Supplier) addDefaultSupplier}: it
209    * provides a deferred-construction default that can be overridden by later resolution steps
210    * (e.g. an annotation override).
211    *
212    * @param <T> The bean type.
213    * @param beanType The bean type to bind.
214    * @param implType The implementation class to instantiate when this type is resolved.
215    * @return This object for method chaining.
216    */
217   <T> WritableBeanStore addBeanType(Class<T> beanType, Class<? extends T> implType);
218
219   /**
220    * Registers a configuration class and its {@link Bean}-annotated members.
221    *
222    * @param configType The configuration type.
223    * @return This object.
224    */
225   WritableBeanStore registerConfiguration(Class<?> configType);
226
227   /**
228    * Registers multiple configuration classes.
229    *
230    * @param configTypes The configuration types.  Can be <jk>null</jk>, in which case no action is taken.
231    * @return This object.
232    */
233   default WritableBeanStore registerConfigurations(Class<?>... configTypes) {
234      if (configTypes != null)
235         for (var c : configTypes)
236            registerConfiguration(c);
237      return this;
238   }
239
240   /**
241    * Pushes the supplied {@link BeanStore} onto this store's overlay stack.
242    *
243    * <p>
244    * The pushed frame becomes the top-priority lookup target for subsequent bean resolution &mdash; it sits above
245    * any pre-existing {@code overridingParent} setting, this store's local entries, the regular parent chain, and
246    * the default-supplier tier.  Frames are popped in LIFO order via {@link #popOverlay(Snapshot)}.
247    *
248    * <p>
249    * This is the framework primitive behind <b>Mode OVERLAY</b> of the test-injection model: a long-lived SUT's
250    * bean store has a per-test overlay pushed at {@code @BeforeEach}, then popped at {@code @AfterEach}, so
251    * subsequent tests see the original beans again with no rebuild cost.
252    *
253    * <h5 class='section'>Composition with {@code overridingParent}:</h5>
254    * <p>
255    * When this store was constructed with an
256    * {@linkplain BasicBeanStore#BasicBeanStore(BeanStore, BeanStore) overriding parent} <i>and</i> has overlays
257    * pushed on top, the overlay stack wins (it is "more recent").  Both are still consulted before local entries
258    * and the regular parent.
259    *
260    * @param overlay The bean store to layer on top.  Must not be <jk>null</jk>.
261    * @return A {@link Snapshot} that must be passed back to {@link #popOverlay(Snapshot)} to remove the frame.
262    * @throws NullPointerException If {@code overlay} is <jk>null</jk>.
263    * @since 10.0.0
264    */
265   Snapshot pushOverlay(BeanStore overlay);
266
267   /**
268    * Removes the overlay frame identified by the supplied {@link Snapshot}.
269    *
270    * <p>
271    * Pops must be issued in <b>LIFO</b> order &mdash; the supplied snapshot must identify the current top-of-stack
272    * frame.  Out-of-order pops, pops on an empty stack, and pops of a snapshot produced by a different store all
273    * throw {@link IllegalStateException} with a descriptive message.  These are programming errors, surfaced loudly
274    * rather than silently degraded.
275    *
276    * @param snapshot The snapshot returned by a prior {@link #pushOverlay(BeanStore)} call.  Must not be
277    *    <jk>null</jk>.
278    * @throws NullPointerException If {@code snapshot} is <jk>null</jk>.
279    * @throws IllegalStateException If the snapshot was produced by a different store, the overlay stack is empty,
280    *    or the snapshot does not identify the top-of-stack frame (LIFO violation).
281    * @since 10.0.0
282    */
283   void popOverlay(Snapshot snapshot);
284
285   /**
286    * Closes this bean store, invoking pre-destroy callbacks.
287    *
288    * @throws BeanCreationException on shutdown failures.
289    */
290   @Override
291   void close() throws BeanCreationException;
292}
293