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.util.SequencedSet;
017
018/**
019 * An interface whose implementations {@linkplain #produce(Request) produce} possibly uninitialized contextual
020 * instances.
021 *
022 * <p>{@link Producer}s are used to implement {@link Factory} instances' {@link Factory#create(Request) create(Request)}
023 * and {@link Factory#destroy(Object, Request) destroy(Object, Request)} methods. Values returned from the {@link
024 * #produce(Request)} method are often supplied to {@link Initializer}s.</p>
025 *
026 * @param <I> the type of contextual instance
027 *
028 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
029 *
030 * @see #produce(Request)
031 *
032 * @see Factory#create(Request)
033 */
034// Subordinate to Factory<I> (really to Initializer<I>)
035// Akin to CDI's Producer.
036// Handles instance production and disposal, *including intercepted production*.
037//
038// Does NOT handle initialization; see for example
039// https://github.com/search?q=repo%3Aweld%2Fcore+%22.produce%28%29%22+language%3AJava&type=code. Obviously it may
040// acquire dependencies and supply them during production, but the point is it doesn't do field injection or initializer
041// method invocation.
042//
043// Does NOT handle post-initialization.
044// Does NOT handle business method interception.
045// Does NOT handle pre-disposal.
046// See also: InterceptingProducer
047@FunctionalInterface
048public interface Producer<I> extends Aggregate {
049
050  /**
051   * Disposes of the supplied contextual instance.
052   *
053   * <p>The default implementation of this method checks to see if {@code i} is an instance of {@link AutoCloseable},
054   * and, if so, calls {@link AutoCloseable#close() close()} on it, throwing any resulting exception as a {@link
055   * DestructionException}.</p>
056   *
057   * @param i a contextual instance {@linkplain #produce(Request) produced} by this {@link Producer}; may be {@code
058   * null}
059   *
060   * @param r the {@link Request} that was {@linkplain #produce(Request) present at production time}; must not be {@code
061   * null}
062   *
063   * @exception NullPointerException if {@code r} is {@code null}
064   *
065   * @exception DestructionException if {@code i} is an {@link AutoCloseable} instance, and if its {@link
066   * AutoCloseable#close() close()} method throws a checked exception
067   */
068  public default void dispose(final I i, final Request<I> r) {
069    if (i instanceof AutoCloseable ac) {
070      try {
071        ac.close();
072      } catch (final RuntimeException | Error e) {
073        throw e;
074      } catch (final InterruptedException e) {
075        Thread.currentThread().interrupt();
076        throw new DestructionException(e.getMessage(), e);
077      } catch (final Exception e) {
078        throw new DestructionException(e.getMessage(), e);
079      }
080    }
081  }
082
083  /**
084   * Produces a new contextual instance and returns it by calling the {@link #produce(SequencedSet)} method with the
085   * return value of an invocation of the {@link #assign(Request)} method with the supplied {@link Request}.
086   *
087   * @param r a {@link Request}; must not be {@code null}
088   *
089   * @return a new contextual instance, or {@code null}
090   *
091   * @exception NullPointerException if {@code r} is {@code null}
092   *
093   * @see #produce(SequencedSet)
094   *
095   * @see #assign(Request)
096   */
097  public default I produce(final Request<?> r) {
098    return this.produce(this.assign(r));
099  }
100
101  /**
102   * Produces a new contextual instance and returns it, possibly (often) making use of the supplied, dependent,
103   * contextual references.
104   *
105   * <p>Implementations of this method must not call {@link #produce(Request)} or an infinite loop may result.</p>
106   *
107   * @param assignments a {@link SequencedSet} of {@link Assignment}s this {@link Producer} needs to create the
108   * contextual instance; must not be {@code null}
109   *
110   * @return a new contextual instance, or {@code null}
111   *
112   * @exception NullPointerException if {@code dependentContextualReferences} is {@code null}
113   */
114  public I produce(final SequencedSet<? extends Assignment<?>> assignments);
115
116}