001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2022 microBean™.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
014 * implied.  See the License for the specific language governing
015 * permissions and limitations under the License.
016 */
017package org.microbean.loader.spi;
018
019import java.lang.reflect.GenericArrayType;
020import java.lang.reflect.ParameterizedType;
021import java.lang.reflect.Type;
022
023import java.util.ServiceLoader;
024
025import org.microbean.loader.api.Loader;
026
027import org.microbean.path.Path;
028
029/**
030 * A service provider of {@link Value}s that might be suitable for a
031 * {@link Loader} implementation to return.
032 *
033 * <p>{@link Provider} instances are subordinate to {@link
034 * org.microbean.loader.DefaultLoader}.</p>
035 *
036 * <p>Any {@link Provider} implementation must have a {@code public}
037 * constructor that has no arguments.</p>
038 *
039 * @author <a href="https://about.me/lairdnelson"
040 * target="_parent">Laird Nelson</a>
041 *
042 * @see #get(Loader, Path)
043 *
044 * @see AbstractProvider
045 *
046 * @see org.microbean.loader.DefaultLoader
047 */
048@FunctionalInterface
049public interface Provider {
050
051
052  /*
053   * Instance methods.
054   */
055
056
057  /**
058   * Returns a {@link Type} representing the <em>lower type bound</em>
059   * of all possible {@linkplain Value values} {@linkplain
060   * #get(Loader, Path) supplied} by this {@link Provider}.
061   *
062   * <p>Often the value returned by implementations of this method is
063   * no more specific than the lowest possible type, which is {@code
064   * null}, meaning that the {@link Provider} has a chance of
065   * {@linkplain #get(Loader, Path) producing} a {@link Value} for any
066   * requested type.</p>
067   *
068   * <p>A return value of, for example, {@link String String.class}
069   * indicates that the {@link Provider} may satisfy requests for
070   * {@link String String.class}, or any of its supertypes (such as
071   * {@link CharSequence} or {@link Object}), but cannot satisfy
072   * requests for {@link Integer Integer.class}, for example.</p>
073   *
074   * <p>A return value of {@link Object Object.class} would be
075   * extremely unusual and would indicate a maximally opaque type,
076   * i.e. only requests for <em>exactly</em> {@link Object
077   * Object.class} have the possibility of being satisfied by this
078   * {@link Provider}.  Such a return value is possible, but rarely
079   * used, and {@link Provider} implementations are urged to consider
080   * returning a different {@link Type}.</p>
081   *
082   * <p>Note that this method is used solely to help eliminate types
083   * from consideration, not permit them.  That is, although {@link
084   * Provider} may indicate via an implementation of this method that
085   * a given {@link Type} is suitable, it is not thereby obliged to
086   * return a {@link Value} corresponding to it from its {@link
087   * #get(Loader, Path) get(Loader, Path)} method implementation.</p>
088   *
089   * <p>The default implementation of this method returns {@code
090   * null}.  Many {@link Provider} implementations will choose not to
091   * override this method.</p>
092   *
093   * @return a {@link Type} representing the lower type bound of all
094   * possible {@linkplain Value values} {@linkplain #get(Loader, Path)
095   * supplied} by this {@link Provider}, or {@code null} to indicate
096   * the lowest possible type bound
097   *
098   * @nullability This method always does, and overrides often may,
099   * return {@code null}.
100   *
101   * @idempotency This method is, and overrides of this method must
102   * be, idempotent and deterministic.
103   *
104   * @threadsafety This method is, and overrides of this method must
105   * be, safe for concurrent use by multiple threads.
106   */
107  public default Type lowerBound() {
108    return null; // the lowest possible type, assignable to all others
109  }
110
111  /**
112   * Returns a {@link Value} suitable for the supplied {@link Loader}
113   * and {@link Path}, <strong>or {@code null} if there is no such
114   * {@link Value} now and if there never will be such a {@link
115   * Value}</strong> for the supplied arguments.
116   *
117   * <p>In addition to the other requirements described here, the
118   * following assertions will be (and must be) true when this method
119   * is called in the normal course of events:</p>
120   *
121   * <ul>
122   *
123   * <li>{@code assert absolutePath.isAbsolute();}</li>
124   *
125   * <li>{@code assert
126   * absolutePath.startsWith(requestor.absolutePath());}</li>
127   *
128   * <li>{@code assert
129   * !absolutePath.equals(requestor.absolutePath());}</li>
130   *
131   * </ul>
132   *
133   * <p>If any caller does not honor these requirements, undefined
134   * behavior may result.</p>
135   *
136   * @param requestor the {@link Loader} seeking a {@link Value};
137   * must not be {@code null}
138   *
139   * @param absolutePath an {@linkplain Path#absolute() absolute
140   * <code>Path</code>} for which the supplied {@link Loader} is
141   * seeking a value; must not be {@code null}
142   *
143   * @return a {@link Value} more or less suitable for the combination
144   * of the supplied {@link Loader} and {@link Path}, <strong>or
145   * {@code null} if there is no such {@link Value} now and if there
146   * never will be such a {@link Value}</strong> for the supplied
147   * arguments
148   *
149   * @exception NullPointerException if either {@code requestor} or
150   * {@code absolutePath} is {@code null}
151   *
152   * @exception IllegalArgumentException if {@code absolutePath}
153   * {@linkplain Path#absolute() is not absolute}, or if {@link
154   * Path#startsWith(Path)
155   * !absolutePath.startsWith(requestor.absolutePath())}, or if {@link
156   * Path#equals(Object)
157   * absolutePath.equals(requestor.absolutePath())}
158   *
159   * @nullability Implementations of this method may return {@code
160   * null}.
161   *
162   * @threadsafety Implementations of this method must be safe for
163   * concurrent use by multiple threads.
164   *
165   * @idempotency Implementations of this method must be idempotent
166   * but are not assumed to be deterministic.
167   */
168  public Value<?> get(final Loader<?> requestor, final Path<? extends Type> absolutePath);
169
170}