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