org.microbean.bean.Factory Maven / Gradle / Ivy
Show all versions of microbean-bean Show documentation
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
*
* Copyright © 2023–2024 microBean™.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.microbean.bean;
import java.lang.constant.Constable;
import java.lang.constant.ConstantDesc;
import java.lang.constant.DynamicConstantDesc;
import java.lang.constant.MethodHandleDesc;
import java.util.Optional;
import static java.lang.constant.ConstantDescs.BSM_INVOKE;
/**
* A creator and destroyer of contextual instances of a particular type.
*
* @param the type of the contextual instances this {@link Factory} creates and destroys
*
* @author Laird Nelson
*/
@FunctionalInterface
public interface Factory extends Aggregate, Constable {
/**
* Creates a new contextual instance, possibly using the supplied {@link Request}, if it is non-{@code null}, to
* acquire its {@linkplain #dependencies() dependencies}.
*
* Implementations of this method must not call {@link #singleton()}.
*
* Implementations of this method should consider calling {@link Creation#created(Object)} on the supplied {@link
* Request} with the contextual instance about to be returned.
*
* @param r a {@link Request} responsible for the demand for creation and used for {@linkplain ReferenceSelector
* acquiring any needed dependencies}; may be {@code null} in early, uncommon bootstrap-like
* situations
*
* @return a new contextual instance, or {@code null}
*
* @exception CreationException if an error occurs
*
* @see Request
*
* @see ReferenceSelector
*
* @see Creation
*/
public I create(final Request r);
/**
* Returns the sole contextual instance of this {@link Factory}'s type, if there is one, or {@code null} in the very
* common case that there is not.
*
* The default implementation of this method returns {@code null}.
*
* Overrides of this method should not call {@link #create(Request)}.
*
* Overrides of this method must be idempotent and must return a determinate value.
*
* @return the sole contextual instance of this {@link Factory}'s type, or (commonly) {@code null}
*/
public default I singleton() {
return null;
}
/**
* Returns {@code true} if this {@link Factory} implementation destroys its {@linkplain #create(Request) created}
* contextual instances in some way, or {@code false} if it does not.
*
* The default implementation of this method returns {@code true}.
*
* Overrides of this method must be idempotent and return a determinate value.
*
* @return {@code true} if this {@link Factory} implementation destroys its {@linkplain #create(Request) created}
* contextual instances in some way; {@code false} otherwise
*
* @see #destroy(Object, Request)
*/
public default boolean destroys() {
return true;
}
// MUST be idempotent
// If i is an AutoCloseable, MUST be idempotent
//
// TODO: rename back to destroy()
public default void destroy(final I i, final Request creationRequest) {
if (i instanceof AutoCloseable ac) {
try {
ac.close();
} catch (final RuntimeException | Error re) {
throw re;
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
throw new DestructionException(e.getMessage(), e);
} catch (final Exception e) {
throw new DestructionException(e.getMessage(), e);
}
}
}
/**
* Returns an {@link Optional} containing the nominal descriptor for this instance, if one can be constructed, or an
* {@linkplain Optional#isEmpty() empty Optional
} if one cannot be constructed.
*
* The default implementation of this method returns an {@link Optional} that contains a dynamic constant
* representing an invocation of the implementation's constructor that takes no arguments. The resolution of
* this dynamic constant is undefined if the implementation does not declare such a constructor.
*
* @return an {@link Optional} containing the nominal descriptor for this instance, if one can be constructed, or an
* {@linkplain Optional#isEmpty() empty Optional
} if one cannot be constructed
*
* @threadsafety This method is safe for concurrent use by multiple threads.
*
* @idempotency This method is neither idempotent nor deterministic.
*/
@Override // Constable
public default Optional extends ConstantDesc> describeConstable() {
return this.getClass()
.describeConstable()
.map(classDesc -> DynamicConstantDesc.of(BSM_INVOKE,
MethodHandleDesc.ofConstructor(classDesc)));
}
}