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}