001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2023–2024 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  // MUST be idempotent
094  // If i is an AutoCloseable, MUST be idempotent
095  //
096  // TODO: rename back to destroy()
097  public default void destroy(final I i, final Request<I> creationRequest) {
098    if (i instanceof AutoCloseable ac) {
099      try {
100        ac.close();
101      } catch (final RuntimeException | Error re) {
102        throw re;
103      } catch (final InterruptedException e) {
104        Thread.currentThread().interrupt();
105        throw new DestructionException(e.getMessage(), e);
106      } catch (final Exception e) {
107        throw new DestructionException(e.getMessage(), e);
108      }
109    }
110  }
111
112  /**
113   * Returns an {@link Optional} containing the nominal descriptor for this instance, if one can be constructed, or an
114   * {@linkplain Optional#isEmpty() empty <code>Optional</code>} if one cannot be constructed.
115   *
116   * <p>The default implementation of this method returns an {@link Optional} that contains a dynamic constant
117   * representing an invocation of the implementation's constructor that takes no arguments.  <strong>The resolution of
118   * this dynamic constant is undefined if the implementation does not declare such a constructor.</strong></p>
119   *
120   * @return 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   * @threadsafety This method is safe for concurrent use by multiple threads.
124   *
125   * @idempotency This method is neither idempotent nor deterministic.
126   */
127  @Override // Constable
128  public default Optional<? extends ConstantDesc> describeConstable() {
129    return this.getClass()
130      .describeConstable()
131      .map(classDesc -> DynamicConstantDesc.of(BSM_INVOKE,
132                                               MethodHandleDesc.ofConstructor(classDesc)));
133  }
134
135}