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}