001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2023–2026 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.scopelet;
015
016import java.lang.System.Logger;
017
018import java.lang.constant.Constable;
019import java.lang.constant.ConstantDesc;
020import java.lang.constant.DynamicConstantDesc;
021
022import java.util.Optional;
023
024import org.microbean.bean.Creation;
025import org.microbean.bean.Destruction;
026import org.microbean.bean.Factory;
027
028import org.microbean.reference.DestructorRegistry;
029
030import static java.lang.constant.ConstantDescs.BSM_INVOKE;
031
032import static java.lang.constant.MethodHandleDesc.ofConstructor;
033
034import static java.lang.System.getLogger;
035
036import static java.lang.System.Logger.Level.WARNING;
037
038/**
039 * A {@link Scopelet} implementation that does not cache objects at all.
040 *
041 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
042 */
043public class NoneScopelet extends Scopelet<NoneScopelet> implements Constable {
044
045
046  /*
047   * Static fields.
048   */
049
050
051  private static final Logger LOGGER = getLogger(NoneScopelet.class.getName());
052
053
054  /*
055   * Constructors.
056   */
057
058
059  /**
060   * Creates a new {@link NoneScopelet}.
061   */
062  public NoneScopelet() {
063    super();
064  }
065
066
067  /*
068   * Instance methods.
069   */
070
071
072  /**
073   * Checks to see if this {@link Scopelet} {@linkplain #active() is active} and then returns a contextual instance
074   * {@linkplain Factory#create(Creation) created by the supplied <code>Factory</code>}.
075   *
076   * <p>This method (and its overrides) may return {@code null}.</p>
077   *
078   * <p>If the supplied {@link Factory} is {@code null}, this method will (and its overrides must) return {@code null}.
079   *
080   * @param ignoredBeanId an identifier; ignored by the default implementation; may be {@code null}
081   *
082   * @param factory a {@link Factory}; may be {@code null} in which case {@code null} will and must be returned
083   *
084   * @param creation a {@link Creation}, typically the one in effect that is causing this method to be invoked in the
085   * first place; may be {@code null}; most commonly also an instance of {@link DestructorRegistry}
086   *
087   * @return a contextual instance, or {@code null}
088   *
089   * @exception InactiveScopeletException if this {@link Scopelet} {@linkplain #active() is not active}
090   *
091   * @exception ClassCastException if destruction is called for, {@code creation} is non-{@code null}, and {@code
092   * creation} does not implement {@link Destruction}, a requirement of its contract
093   *
094   * @see DestructorRegistry
095   *
096   * @see Creation
097   *
098   * @see Destruction
099   *
100   * @see Factory#destroys()
101   */
102  // All parameters are nullable.
103  // Non-final to permit subclasses to, e.g., add logging.
104  @Override // Scopelet<NoneScopelet>
105  public <I> I instance(final Object ignoredBeanId, final Factory<I> factory, final Creation<I> creation) {
106    if (!this.active()) {
107      throw new InactiveScopeletException();
108    } else if (factory == null) {
109      return null;
110    }
111    final I returnValue = factory.create(creation);
112    if (factory.destroys()) {
113      if (creation instanceof DestructorRegistry dr && creation instanceof Destruction d) {
114        dr.register(returnValue, () -> factory.destroy(returnValue, d));
115      } else if (LOGGER.isLoggable(WARNING)) {
116        LOGGER.log(WARNING, "Dependent objects will not be destroyed");
117      }
118    }
119    return returnValue;
120  }
121
122  @Override // Constable
123  public Optional<? extends ConstantDesc> describeConstable() {
124    return Optional.of(DynamicConstantDesc.of(BSM_INVOKE, ofConstructor(this.getClass().describeConstable().orElseThrow())));
125  }
126
127}