001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 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.ClassDesc; 017import java.lang.constant.Constable; 018import java.lang.constant.ConstantDesc; 019import java.lang.constant.DynamicConstantDesc; 020import java.lang.constant.MethodHandleDesc; 021 022import java.util.Optional; 023 024import org.microbean.assign.Aggregate; 025 026import static java.lang.constant.ConstantDescs.BSM_INVOKE; 027 028/** 029 * A source of (normally new) contextual instances. 030 * 031 * @param <I> the contextual instance type 032 * 033 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 034 * 035 * @see #create(Creation) 036 * 037 * @see Aggregate 038 */ 039public interface Factory<I> extends Aggregate, Constable { 040 041 /** 042 * Returns a (normally new) contextual instance, which may be {@code null}. 043 * 044 * @param creation a {@link Creation}; may be {@code null} 045 * 046 * @return a contextual instance, which may be {@code null} 047 * 048 * @see Creation 049 */ 050 public I create(final Creation<I> creation); 051 052 /** 053 * Returns an {@link Optional} containing the nominal descriptor for this instance, if one can be constructed, or an 054 * {@linkplain Optional#isEmpty() empty <code>Optional</code>} if one cannot be constructed. 055 * 056 * <p>The default implementation of this method returns an {@link Optional} that contains a dynamic constant 057 * representing an invocation of the implementation's constructor that takes no arguments. <strong>The resolution of 058 * this dynamic constant is undefined if the implementation does not declare such a constructor.</strong></p> 059 * 060 * @return an {@link Optional} containing the nominal descriptor for this instance, if one can be constructed, or an 061 * {@linkplain Optional#isEmpty() empty <code>Optional</code>} if one cannot be constructed 062 * 063 * @microbean.threadsafety This method is safe for concurrent use by multiple threads. 064 * 065 * @microbean.idempotency This method is neither idempotent nor deterministic. 066 */ 067 @Override // Constable 068 public default Optional<? extends ConstantDesc> describeConstable() { 069 return 070 Optional.of(DynamicConstantDesc.of(BSM_INVOKE, 071 MethodHandleDesc.ofConstructor(ClassDesc.of(this.getClass().getCanonicalName())))); 072 } 073 074 /** 075 * Destroys the supplied contextual instance. 076 * 077 * <p>The default implementation of this method {@linkplain AutoCloseable#close() closes} the supplied contextual 078 * instance if it is an instance of {@link AutoCloseable}, and {@linkplain AutoCloseable#close() closes} the supplied 079 * {@link Destruction} if it is non-{@code null}.</p> 080 * 081 * @param i the contextual instance to destroy; may be {@code null} in which case no action must be taken 082 * 083 * @param creation the object supplied to the {@link #create(Creation)} method represented here as a {@link 084 * Destruction}; may be {@code null}; must have an idempotent {@link AutoCloseable#close() close()} method 085 * 086 * @see #create(Creation) 087 * 088 * @see Destruction 089 * 090 * @see Creation 091 */ 092 @SuppressWarnings("try") 093 public default void destroy(final I i, final Destruction creation) { 094 if (creation == null) { 095 if (i instanceof AutoCloseable ac) { 096 try { 097 ac.close(); 098 } catch (final RuntimeException | Error e) { 099 throw e; 100 } catch (final InterruptedException e) { 101 Thread.currentThread().interrupt(); 102 throw new DestructionException(e.getMessage(), e); 103 } catch (final Exception e) { 104 throw new DestructionException(e.getMessage(), e); 105 } 106 } 107 } else if (!(creation instanceof Creation<I>)) { 108 throw new IllegalArgumentException("creation: " + creation); 109 } else if (creation instanceof AutoCloseable cac) { 110 try (cac) { 111 if (i instanceof AutoCloseable iac) { 112 iac.close(); 113 } 114 } catch (final RuntimeException | Error e) { 115 throw e; 116 } catch (final InterruptedException e) { 117 Thread.currentThread().interrupt(); 118 throw new DestructionException(e.getMessage(), e); 119 } catch (final Exception e) { 120 throw new DestructionException(e.getMessage(), e); 121 } 122 } else if (i instanceof AutoCloseable ac) { 123 try { 124 ac.close(); 125 } catch (final RuntimeException | Error e) { 126 throw e; 127 } catch (final InterruptedException e) { 128 Thread.currentThread().interrupt(); 129 throw new DestructionException(e.getMessage(), e); 130 } catch (final Exception e) { 131 throw new DestructionException(e.getMessage(), e); 132 } 133 } 134 } 135 136 /** 137 * Returns {@code true} if this {@link Factory} implementation {@linkplain #destroy(Object, Destruction) destroys} its 138 * {@linkplain #create(Creation) created} contextual instances in some way, or {@code false} if it does not. 139 * 140 * <p>The default implementation of this method returns {@code true}.</p> 141 * 142 * <p>Overrides of this method must be idempotent and return a determinate value.</p> 143 * 144 * @return {@code true} if this {@link Factory} implementation {@linkplain #destroy(Object, Destruction) destroys} its 145 * {@linkplain #create(Creation) created} contextual instances in some way; {@code false} otherwise 146 * 147 * @see #destroy(Object, Destruction) 148 */ 149 public default boolean destroys() { 150 return true; 151 } 152 153 /** 154 * Returns the sole contextual instance of this {@link Factory}'s type, if there is one, or {@code null} in the very 155 * common case that there is not. 156 * 157 * <p>The default implementation of this method returns {@code null}.</p> 158 * 159 * <p>Overrides of this method should not call {@link #create(Creation)}.</p> 160 * 161 * <p>Overrides of this method must be idempotent and must return a determinate value.</p> 162 * 163 * @return the sole contextual instance of this {@link Factory}'s type, or (commonly) {@code null} 164 */ 165 public default I singleton() { 166 return null; 167 } 168 169}