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}