001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2023–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 java.lang.constant.Constable;
017import java.lang.constant.ConstantDesc;
018import java.lang.constant.DynamicConstantDesc;
019import java.lang.constant.MethodHandleDesc;
020
021import java.util.Optional;
022
023import static java.lang.constant.ConstantDescs.BSM_INVOKE;
024
025/**
026 * A creator and destroyer of contextual instances of a particular type.
027 *
028 * @param <I> the type of the contextual instances this {@link Factory} creates and destroys
029 *
030 * @author <a href="https://about.me/lairdnelson/" target="_top">Laird Nelson</a>
031 */
032@FunctionalInterface
033public interface Factory<I> extends Aggregate, Constable {
034
035  /**
036   * Creates a new contextual instance, possibly using the supplied {@link Request}, if it is non-{@code null}, to
037   * acquire its {@linkplain #dependencies() dependencies}.
038   *
039   * <p>Implementations of this method must not call {@link #singleton()}.</p>
040   *
041   * <p>Implementations of this method should consider calling {@link Creation#created(Object)} on the supplied {@link
042   * Request} with the contextual instance about to be returned.</p>
043   *
044   * @param r a {@link Request} responsible for the demand for creation and used for {@linkplain ReferenceSelector
045   * acquiring any needed dependencies}; <strong>may be {@code null}</strong> in early, uncommon bootstrap-like
046   * situations
047   *
048   * @return a new contextual instance, or {@code null}
049   *
050   * @exception CreationException if an error occurs
051   *
052   * @see Request
053   *
054   * @see ReferenceSelector
055   *
056   * @see Creation
057   */
058  public I create(final Request<I> r);
059
060  /**
061   * Returns the sole contextual instance of this {@link Factory}'s type, if there is one, or {@code null} in the very
062   * common case that there is not.
063   *
064   * <p>The default implementation of this method returns {@code null}.</p>
065   *
066   * <p>Overrides of this method should not call {@link #create(Request)}.</p>
067   *
068   * <p>Overrides of this method must be idempotent and must return a determinate value.</p>
069   *
070   * @return the sole contextual instance of this {@link Factory}'s type, or (commonly) {@code null}
071   */
072  public default I singleton() {
073    return null;
074  }
075
076  /**
077   * Returns {@code true} if this {@link Factory} implementation destroys its {@linkplain #create(Request) created}
078   * contextual instances in some way, or {@code false} if it does not.
079   *
080   * <p>The default implementation of this method returns {@code true}.</p>
081   *
082   * <p>Overrides of this method must be idempotent and return a determinate value.</p>
083   *
084   * @return {@code true} if this {@link Factory} implementation destroys its {@linkplain #create(Request) created}
085   * contextual instances in some way; {@code false} otherwise
086   *
087   * @see #destroy(Object, Request)
088   */
089  public default boolean destroys() {
090    return true;
091  }
092
093  /**
094   * Destroys the supplied contextual instance.
095   *
096   * @param i the contextual instance; may be {@code null} if this {@link Factory} suports returning {@code null} from
097   * its {@link #create(Request)} method
098   *
099   * @param creationRequest the {@link Request} that was {@linkplain #create(Request) present at creation time}; may be
100   * {@code null} if it was {@code null} at creation time
101   */
102  // MUST be idempotent
103  // If i is an AutoCloseable, MUST be idempotent
104  public default void destroy(final I i, final Request<I> creationRequest) {
105    if (i instanceof AutoCloseable ac) {
106      try {
107        ac.close();
108      } catch (final RuntimeException | Error re) {
109        throw re;
110      } catch (final InterruptedException e) {
111        Thread.currentThread().interrupt();
112        throw new DestructionException(e.getMessage(), e);
113      } catch (final Exception e) {
114        throw new DestructionException(e.getMessage(), e);
115      }
116    }
117  }
118
119  /**
120   * Returns an {@link Optional} containing the nominal descriptor for this instance, if one can be constructed, or an
121   * {@linkplain Optional#isEmpty() empty <code>Optional</code>} if one cannot be constructed.
122   *
123   * <p>The default implementation of this method returns an {@link Optional} that contains a dynamic constant
124   * representing an invocation of the implementation's constructor that takes no arguments.  <strong>The resolution of
125   * this dynamic constant is undefined if the implementation does not declare such a constructor.</strong></p>
126   *
127   * @return an {@link Optional} containing the nominal descriptor for this instance, if one can be constructed, or an
128   * {@linkplain Optional#isEmpty() empty <code>Optional</code>} if one cannot be constructed
129   *
130   * @microbean.threadsafety This method is safe for concurrent use by multiple threads.
131   *
132   * @microbean.idempotency This method is neither idempotent nor deterministic.
133   */
134  @Override // Constable
135  public default Optional<? extends ConstantDesc> describeConstable() {
136    return this.getClass()
137      .describeConstable()
138      .map(classDesc -> DynamicConstantDesc.of(BSM_INVOKE,
139                                               MethodHandleDesc.ofConstructor(classDesc)));
140  }
141
142}