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.api;
018
019import java.lang.reflect.ParameterizedType;
020import java.lang.reflect.Type;
021import java.lang.reflect.TypeVariable;
022
023import java.util.List;
024import java.util.Objects;
025import java.util.ServiceLoader;
026
027import org.microbean.development.annotation.EntryPoint;
028import org.microbean.development.annotation.Experimental;
029import org.microbean.development.annotation.OverridingDiscouraged;
030
031import org.microbean.invoke.OptionalSupplier;
032
033import org.microbean.path.Path;
034import org.microbean.path.Path.Element;
035
036import org.microbean.qualifier.Qualifier;
037import org.microbean.qualifier.Qualifiers;
038
039import org.microbean.type.JavaType.Token;
040
041/**
042 * An {@link OptionalSupplier} that {@linkplain #get() supplies} an
043 * environmental object, and can {@linkplain #load(Path) load} others.
044 *
045 * <p><strong>Note:</strong> {@link Loader} implementations are
046 * expected to be immutable with respect to the methods exposed by
047 * this interface.  All methods in this interface that have a {@link
048 * Loader}-typed return type require their implementations to return a
049 * <em>new</em> {@link Loader}.</p>
050 *
051 * <p>The presence of the {@link
052 * OverridingDiscouraged @OverridingDiscouraged} annotation on a
053 * method means that undefined behavior may result if an
054 * implementation of this interface provides an alternate
055 * implementation of the method in question.</p>
056 *
057 * @param <T> the type of environmental objects this {@link Loader}
058 * {@linkplain #get() supplies}
059 *
060 * @author <a href="https://about.me/lairdnelson"
061 * target="_parent">Laird Nelson</a>
062 *
063 * @see #loader()
064 *
065 * @see OptionalSupplier#get()
066 *
067 * @see #load(Path)
068 */
069public interface Loader<T> extends OptionalSupplier<T> {
070
071  /**
072   * Returns the {@link Loader} that is the parent of this {@link
073   * Loader}.
074   *
075   * <p>The {@linkplain #root() root <code>Loader</code>} is defined
076   * to be the only one whose {@link #parent()} method returns itself.
077   * It follows that in general a {@link Loader} implementation should
078   * not return {@code this}.  See {@link #isRoot()} for details.</p>
079   *
080   * @return the {@link Loader} that is the parent of this {@link
081   * Loader}; not {@code this} in almost all circumstances
082   *
083   * @nullability Implementations of this method must not return
084   * {@code null}.
085   *
086   * @idempotency Implementations of this method must be idempotent
087   * and deterministic.
088   *
089   * @threadsafety Implementations of this method must be safe for
090   * concurrent use by multiple threads.
091   *
092   * @see #root()
093   *
094   * @see #isRoot()
095   *
096   * @see #loader()
097   */
098  public Loader<?> parent();
099
100  /**
101   * Returns the {@link Path} with which this {@link Loader} was
102   * created.
103   *
104   * <p>The {@link Path} that is returned by an implementation of this
105   * method is not guaranteed to be {@linkplain Path#absolute()
106   * absolute}.</p>
107   *
108   * <p>The {@link Path} that is returned by an implementation of this
109   * method must be {@linkplain Path#equals(Object) equal} to a
110   * {@linkplain #transliterate(Path) transliterated} version of the
111   * {@link Path} that was supplied to the {@link #load(Path)} method
112   * of this {@link Loader}'s {@linkplain #parent() parent} that
113   * resulted in this {@link Loader}'s creation.</p>
114   *
115   * @return the non-{@code null} {@link Path} with which this {@link
116   * Loader} was created
117   *
118   * @nullability Implementations of this method must not return
119   * {@code null}.
120   *
121   * @threadsafety Implementations of this method must be safe for
122   * concurrent use by multiple threads.
123   *
124   * @idempotency Implementations of this method must be idempotent
125   * and deterministic.
126   *
127   * @see #parent()
128   *
129   * @see #load(Path)
130   *
131   * @see #absolutePath()
132   *
133   * @see #absolutePath(Path)
134   */
135  public Path<? extends Type> path(); // must be absolute
136
137  /**
138   * Experimental; do not use.
139   *
140   * @return an {@linkplain Path#absolute() absolute
141   * <code>Path</code>}
142   *
143   * @exception NullPointerException if {@link #path()} or {@link
144   * #parent()} is implemented incorrectly
145   *
146   * @nullability This method does not, and its overrides must not,
147   * return {@code null}.
148   *
149   * @idempotency This method is, and its overrides must be,
150   * idempotent and deterministic.
151   *
152   * @threadsafety This method is, and its overrides must be, safe for
153   * concurrent use by multiple threads.
154   *
155   * @see #absolutePath(Path)
156   */
157  @Experimental
158  public default Path<? extends Type> absolutePath() {
159    return this.absolutePath(this.path());
160  }
161
162  /**
163   * Returns an {@linkplain Path#absolute() absolute} {@link Path} representing the
164   *
165   * @param <P> the type of the path
166   *
167   * @param path a {@link Path}; must not be {@code null}
168   *
169   * @return an {@linkplain Path#absolute() absolute
170   * <code>Path</code>}
171   *
172   * @exception NullPointerException if {@code path} is {@code null}
173   * or if #parent()} is implemented incorrectly
174   *
175   * @nullability This method does not, and its (discouraged)
176   * overrides must not, return {@code null}.
177   *
178   * @idempotency This method is, and its (discouraged) overrides must
179   * be, idempotent and deterministic.
180   *
181   * @threadsafety This method is, and its (discouraged) overrides
182   * must be, safe for concurrent use by multiple threads.
183   */
184  @Experimental
185  @OverridingDiscouraged
186  public default <P> Path<P> absolutePath(final Path<P> path) {
187    return path.absolute() ? path : this.parent().absolutePath().plus(path);
188  }
189
190  /**
191   * Uses the addressing information encoded in the supplied {@link
192   * Path} to load and return the {@link Loader} logically found at
193   * that location, following additional contractual requirements
194   * defined below.
195   *
196   * <p>Any {@link Loader} returned by an implementation of this
197   * method:</p>
198   *
199   * <ul>
200   *
201   * <li>must not be {@code null}</li>
202   *
203   * <li>must implement its {@link #get() get()} method and its {@link
204   * #determinism() determinism()} method to indicate the transitory
205   * or permanent presence or absence of any value it might
206   * {@linkplain #get() supply}</li>
207   *
208   * </ul>
209   *
210   * <p>The default implementations of all other methods in this
211   * interface named {@code load} call this method.</p>
212   *
213   * @param <U> the type of the environmental object the returned
214   * {@link Loader} can {@linkplain #get() supply}
215   *
216   * @param path the {@link Path} (perhaps only partially) identifying
217   * the {@link Loader} to load; must not be {@code null}; may be
218   * {@linkplain Path#absolute() absolute} or relative (in which case
219   * it will be {@linkplain Path#plus(Path) appended} to {@linkplain
220   * #path() this <code>Loader</code>'s <code>Path</code>})
221   *
222   * @return a {@link Loader} for the supplied {@link Path}; must not
223   * be {@code null}, but may implement its {@link #get() get()}
224   * method and its {@link #determinism() determinism()} method to
225   * indicate the transitory or permanent presence or absence of any
226   * value it might {@linkplain #get() supply}
227   *
228   * @exception NullPointerException if {@code path} is {@code null}
229   *
230   * @exception ClassCastException if the implementation is
231   * implemented improperly
232   *
233   * @see #get()
234   *
235   * @see #determinism()
236   */
237  @EntryPoint
238  public <U> Loader<U> load(final Path<? extends Type> path);
239
240  /**
241   * Builds a {@link Path} from the supplied arguments, calls the
242   * {@link #load(Path)} method and returns its result.
243   *
244   * @param <U> the type of environmental objects the returned {@link Loader}
245   * {@linkplain #get() will supply}
246   *
247   * @param qualifiers the path's {@link Qualifiers}; must not be
248   * {@code null}
249   *
250   * @param type the path's {@link Type}; must not be {@code null}
251   *
252   * @return a {@link Loader}
253   *
254   * @exception NullPointerException if any argument is {@code null}
255   *
256   * @nullability This method does not, and its (discouraged)
257   * overrides must not, return {@code null}.
258   *
259   * @idempotency No guarantees are made about idempotency or
260   * determinism with respect to this method or its (discouraged)
261   * overrides.
262   *
263   * @threadsafety This method is, and its (discouraged) overrides
264   * must be, safe for concurrent use by multiple threads.
265   *
266   * @see Path#of(Qualifiers, Element)
267   *
268   * @see Element#of(Object, String)
269   *
270   * @see #load(Path)
271   */
272  @OverridingDiscouraged
273  @SuppressWarnings("unchecked")
274  public default <U> Loader<U> load(final Qualifiers<? extends String, ?> qualifiers, final Type type) {
275    if (type instanceof Class<?> c) {
276      return this.load(qualifiers, (Class<U>)c);
277    }
278    return this.load(Path.of(qualifiers, Element.of(type, "")));
279  }
280
281  /**
282   * Builds a {@link Path} from the supplied arguments, calls the
283   * {@link #load(Path)} method and returns its result.
284   *
285   * @param <U> the type of environmental objects the returned {@link Loader}
286   * {@linkplain #get() will supply}
287   *
288   * @param type the path's {@link Type}; must not be {@code null}
289   *
290   * @return a {@link Loader}
291   *
292   * @exception NullPointerException if any argument is {@code null}
293   *
294   * @nullability This method does not, and its (discouraged)
295   * overrides must not, return {@code null}.
296   *
297   * @idempotency No guarantees are made about idempotency or
298   * determinism with respect to this method or its (discouraged)
299   * overrides.
300   *
301   * @threadsafety This method is, and its (discouraged) overrides
302   * must be, safe for concurrent use by multiple threads.
303   *
304   * @see Path#of(Object)
305   *
306   * @see #load(Path)
307   */
308  @OverridingDiscouraged
309  @SuppressWarnings("unchecked")
310  public default <U> Loader<U> load(final Type type) {
311    if (type instanceof Class<?> c) {
312      return this.load((Class<U>)c);
313    }
314    return this.load(Path.of(type));
315  }
316
317  /**
318   * Builds a {@link Path} from the supplied arguments, calls the
319   * {@link #load(Path)} method and returns its result.
320   *
321   * @param <U> the type of environmental objects the returned {@link Loader}
322   * {@linkplain #get() will supply}
323   *
324   * @param type the path's {@link Type}; must not be {@code null}
325   *
326   * @param name the {@linkplain Element#name() name} of the last
327   * {@link Element} in the {@link Path}; must not be {@code null}
328   *
329   * @return a {@link Loader}
330   *
331   * @exception NullPointerException if any argument is {@code null}
332   *
333   * @nullability This method does not, and its (discouraged)
334   * overrides must not, return {@code null}.
335   *
336   * @idempotency No guarantees are made about idempotency or
337   * determinism with respect to this method or its (discouraged)
338   * overrides.
339   *
340   * @threadsafety This method is, and its (discouraged) overrides
341   * must be, safe for concurrent use by multiple threads.
342   *
343   * @see #load(Path)
344   */
345  @OverridingDiscouraged
346  @SuppressWarnings("unchecked")
347  public default <U> Loader<U> load(final Type type, final String name) {
348    if (type instanceof Class<?> c) {
349      return this.load((Class<U>)c, name);
350    }
351    return this.load(Path.of(type, name));
352  }
353
354  /**
355   * Builds a {@link Path} from the supplied arguments, calls the
356   * {@link #load(Path)} method and returns its result.
357   *
358   * @param <U> the type of environmental objects the returned {@link Loader}
359   * {@linkplain #get() will supply}
360   *
361   * @param type the path's {@link Type}; must not be {@code null}
362   *
363   * @param names the sequence of names forming the {@link Path}; must
364   * not be {@code null}
365   *
366   * @return a {@link Loader}
367   *
368   * @exception NullPointerException if any argument is {@code null}
369   *
370   * @nullability This method does not, and its (discouraged)
371   * overrides must not, return {@code null}.
372   *
373   * @idempotency No guarantees are made about idempotency or
374   * determinism with respect to this method or its (discouraged)
375   * overrides.
376   *
377   * @threadsafety This method is, and its (discouraged) overrides
378   * must be, safe for concurrent use by multiple threads.
379   *
380   * @see #load(Path)
381   */
382  @OverridingDiscouraged
383  @SuppressWarnings("unchecked")
384  public default <U> Loader<U> load(final Type type, final String... names) {
385    if (type instanceof Class<?> c) {
386      return this.load((Class<U>)c, names);
387    }
388    return this.load(Path.of(type, names));
389  }
390
391  /**
392   * Builds a {@link Path} from the supplied arguments, calls the
393   * {@link #load(Path)} method and returns its result.
394   *
395   * @param <U> the type of environmental objects the returned {@link Loader}
396   * {@linkplain #get() will supply}
397   *
398   * @param type the path's {@link Type}; must not be {@code null}
399   *
400   * @param names the sequence of names forming the {@link Path}; must
401   * not be {@code null}
402   *
403   * @return a {@link Loader}
404   *
405   * @exception NullPointerException if any argument is {@code null}
406   *
407   * @nullability This method does not, and its (discouraged)
408   * overrides must not, return {@code null}.
409   *
410   * @idempotency No guarantees are made about idempotency or
411   * determinism with respect to this method or its (discouraged)
412   * overrides.
413   *
414   * @threadsafety This method is, and its (discouraged) overrides
415   * must be, safe for concurrent use by multiple threads.
416   *
417   * @see #load(Path)
418   */
419  @OverridingDiscouraged
420  @SuppressWarnings("unchecked")
421  public default <U> Loader<U> load(final Type type, final List<? extends String> names) {
422    if (type instanceof Class<?> c) {
423      return this.load((Class<U>)c, names);
424    }
425    return this.load(Path.of(type, names));
426  }
427
428  /**
429   * Builds a {@link Path} from the supplied arguments, calls the
430   * {@link #load(Path)} method and returns its result.
431   *
432   * @param <U> the type of environmental objects the returned {@link Loader}
433   * {@linkplain #get() will supply}
434   *
435   * @param qualifiers the path's {@link Qualifiers}; must not be
436   * {@code null}
437   *
438   * @param type a {@link Token} representing the path's {@link Type};
439   * must not be {@code null}
440   *
441   * @return a {@link Loader}
442   *
443   * @exception NullPointerException if any argument is {@code null}
444   *
445   * @nullability This method does not, and its (discouraged)
446   * overrides must not, return {@code null}.
447   *
448   * @idempotency No guarantees are made about idempotency or
449   * determinism with respect to this method or its (discouraged)
450   * overrides.
451   *
452   * @threadsafety This method is, and its (discouraged) overrides
453   * must be, safe for concurrent use by multiple threads.
454   *
455   * @see #load(Path)
456   */
457  @OverridingDiscouraged
458  public default <U> Loader<U> load(final Qualifiers<? extends String, ?> qualifiers, final Token<U> type) {
459    return this.load(qualifiers, type.type());
460  }
461
462  /**
463   * Builds a {@link Path} from the supplied arguments, calls the
464   * {@link #load(Path)} method and returns its result.
465   *
466   * @param <U> the type of environmental objects the returned {@link Loader}
467   * {@linkplain #get() will supply}
468   *
469   * @param type a {@link Token} representing the path's {@link Type};
470   * must not be {@code null}
471   *
472   * @return a {@link Loader}
473   *
474   * @exception NullPointerException if any argument is {@code null}
475   *
476   * @nullability This method does not, and its (discouraged)
477   * overrides must not, return {@code null}.
478   *
479   * @idempotency No guarantees are made about idempotency or
480   * determinism with respect to this method or its (discouraged)
481   * overrides.
482   *
483   * @threadsafety This method is, and its (discouraged) overrides
484   * must be, safe for concurrent use by multiple threads.
485   *
486   * @see #load(Path)
487   */
488  @OverridingDiscouraged
489  public default <U> Loader<U> load(final Token<U> type) {
490    return this.load(type.type());
491  }
492
493  /**
494   * Builds a {@link Path} from the supplied arguments, calls the
495   * {@link #load(Path)} method and returns its result.
496   *
497   * @param <U> the type of environmental objects the returned {@link Loader}
498   * {@linkplain #get() will supply}
499   *
500   * @param type a {@link Token} representing the path's {@link Type};
501   * must not be {@code null}
502   *
503   * @param name the {@linkplain Element#name() name} of the last
504   * {@link Element} in the {@link Path}; must not be {@code null}
505   *
506   * @return a {@link Loader}
507   *
508   * @exception NullPointerException if any argument is {@code null}
509   *
510   * @nullability This method does not, and its (discouraged)
511   * overrides must not, return {@code null}.
512   *
513   * @idempotency No guarantees are made about idempotency or
514   * determinism with respect to this method or its (discouraged)
515   * overrides.
516   *
517   * @threadsafety This method is, and its (discouraged) overrides
518   * must be, safe for concurrent use by multiple threads.
519   *
520   * @see #load(Path)
521   */
522  @OverridingDiscouraged
523  public default <U> Loader<U> load(final Token<U> type, final String name) {
524    return this.load(type.type(), name);
525  }
526
527  /**
528   * Builds a {@link Path} from the supplied arguments, calls the
529   * {@link #load(Path)} method and returns its result.
530   *
531   * @param <U> the type of environmental objects the returned {@link Loader}
532   * {@linkplain #get() will supply}
533   *
534   * @param type a {@link Token} representing the path's {@link Type};
535   * must not be {@code null}
536   *
537   * @param names the sequence of names forming the {@link Path}; must
538   * not be {@code null}
539   *
540   * @return a {@link Loader}
541   *
542   * @exception NullPointerException if any argument is {@code null}
543   *
544   * @nullability This method does not, and its (discouraged)
545   * overrides must not, return {@code null}.
546   *
547   * @idempotency No guarantees are made about idempotency or
548   * determinism with respect to this method or its (discouraged)
549   * overrides.
550   *
551   * @threadsafety This method is, and its (discouraged) overrides
552   * must be, safe for concurrent use by multiple threads.
553   *
554   * @see #load(Path)
555   */
556  @OverridingDiscouraged
557  public default <U> Loader<U> load(final Token<U> type, final String... names) {
558    return this.load(type.type(), names);
559  }
560
561  /**
562   * Builds a {@link Path} from the supplied arguments, calls the
563   * {@link #load(Path)} method and returns its result.
564   *
565   * @param <U> the type of environmental objects the returned {@link Loader}
566   * {@linkplain #get() will supply}
567   *
568   * @param type a {@link Token} representing the path's {@link Type};
569   * must not be {@code null}
570   *
571   * @param names the sequence of names forming the {@link Path}; must
572   * not be {@code null}
573   *
574   * @return a {@link Loader}
575   *
576   * @exception NullPointerException if any argument is {@code null}
577   *
578   * @nullability This method does not, and its (discouraged)
579   * overrides must not, return {@code null}.
580   *
581   * @idempotency No guarantees are made about idempotency or
582   * determinism with respect to this method or its (discouraged)
583   * overrides.
584   *
585   * @threadsafety This method is, and its (discouraged) overrides
586   * must be, safe for concurrent use by multiple threads.
587   *
588   * @see #load(Path)
589   */
590  @OverridingDiscouraged
591  public default <U> Loader<U> load(final Token<U> type, final List<? extends String> names) {
592    return this.load(type.type(), names);
593  }
594
595  /**
596   * Builds a {@link Path} from the supplied arguments, calls the
597   * {@link #load(Path)} method and returns its result.
598   *
599   * @param <U> the type of environmental objects the returned {@link Loader}
600   * {@linkplain #get() will supply}
601   *
602   * @param qualifiers the path's {@link Qualifiers}; must not be
603   * {@code null}
604   *
605   * @param type a {@link Class} serving as the path's {@link Type};
606   * must not be {@code null}
607   *
608   * @return a {@link Loader}
609   *
610   * @exception NullPointerException if any argument is {@code null}
611   *
612   * @nullability This method does not, and its (discouraged)
613   * overrides must not, return {@code null}.
614   *
615   * @idempotency No guarantees are made about idempotency or
616   * determinism with respect to this method or its (discouraged)
617   * overrides.
618   *
619   * @threadsafety This method is, and its (discouraged) overrides
620   * must be, safe for concurrent use by multiple threads.
621   *
622   * @see #load(Path)
623   */
624  @OverridingDiscouraged
625  public default <U> Loader<U> load(final Qualifiers<? extends String, ?> qualifiers, Class<U> type) {
626    return this.load(Path.of(qualifiers, Element.of(type, "")));
627  }
628
629  /**
630   * Builds a {@link Path} from the supplied arguments, calls the
631   * {@link #load(Path)} method and returns its result.
632   *
633   * @param <U> the type of environmental objects the returned {@link Loader}
634   * {@linkplain #get() will supply}
635   *
636   * @param type a {@link Class} serving as the path's {@link Type};
637   * must not be {@code null}
638   *
639   * @return a {@link Loader}
640   *
641   * @exception NullPointerException if any argument is {@code null}
642   *
643   * @nullability This method does not, and its (discouraged)
644   * overrides must not, return {@code null}.
645   *
646   * @idempotency No guarantees are made about idempotency or
647   * determinism with respect to this method or its (discouraged)
648   * overrides.
649   *
650   * @threadsafety This method is, and its (discouraged) overrides
651   * must be, safe for concurrent use by multiple threads.
652   *
653   * @see #load(Path)
654   */
655  @OverridingDiscouraged
656  public default <U> Loader<U> load(final Class<U> type) {
657    return this.load(Path.of(type));
658  }
659
660  /**
661   * Builds a {@link Path} from the supplied arguments, calls the
662   * {@link #load(Path)} method and returns its result.
663   *
664   * @param <U> the type of environmental objects the returned {@link Loader}
665   * {@linkplain #get() will supply}
666   *
667   * @param type a {@link Class} serving as the path's {@link Type};
668   * must not be {@code null}
669   *
670   * @param name the {@linkplain Element#name() name} of the last
671   * {@link Element} in the {@link Path}; must not be {@code null}
672   *
673   * @return a {@link Loader}
674   *
675   * @exception NullPointerException if any argument is {@code null}
676   *
677   * @nullability This method does not, and its (discouraged)
678   * overrides must not, return {@code null}.
679   *
680   * @idempotency No guarantees are made about idempotency or
681   * determinism with respect to this method or its (discouraged)
682   * overrides.
683   *
684   * @threadsafety This method is, and its (discouraged) overrides
685   * must be, safe for concurrent use by multiple threads.
686   *
687   * @see #load(Path)
688   */
689  @OverridingDiscouraged
690  public default <U> Loader<U> load(final Class<U> type, final String name) {
691    return this.load(Path.of(type, name));
692  }
693
694  /**
695   * Builds a {@link Path} from the supplied arguments, calls the
696   * {@link #load(Path)} method and returns its result.
697   *
698   * @param <U> the type of environmental objects the returned {@link Loader}
699   * {@linkplain #get() will supply}
700   *
701   * @param type a {@link Class} serving as the path's {@link Type};
702   * must not be {@code null}
703   *
704   * @param names the sequence of names forming the {@link Path}; must
705   * not be {@code null}
706   *
707   * @return a {@link Loader}
708   *
709   * @exception NullPointerException if any argument is {@code null}
710   *
711   * @nullability This method does not, and its (discouraged)
712   * overrides must not, return {@code null}.
713   *
714   * @idempotency No guarantees are made about idempotency or
715   * determinism with respect to this method or its (discouraged)
716   * overrides.
717   *
718   * @threadsafety This method is, and its (discouraged) overrides
719   * must be, safe for concurrent use by multiple threads.
720   *
721   * @see #load(Path)
722   */
723  @OverridingDiscouraged
724  public default <U> Loader<U> load(final Class<U> type, final String... names) {
725    return this.load(Path.of(type, names));
726  }
727
728  /**
729   * Builds a {@link Path} from the supplied arguments, calls the
730   * {@link #load(Path)} method and returns its result.
731   *
732   * @param <U> the type of environmental objects the returned {@link Loader}
733   * {@linkplain #get() will supply}
734   *
735   * @param type a {@link Class} serving as the path's {@link Type};
736   * must not be {@code null}
737   *
738   * @param names the sequence of names forming the {@link Path}; must
739   * not be {@code null}
740   *
741   * @return a {@link Loader}
742   *
743   * @exception NullPointerException if any argument is {@code null}
744   *
745   * @nullability This method does not, and its (discouraged)
746   * overrides must not, return {@code null}.
747   *
748   * @idempotency No guarantees are made about idempotency or
749   * determinism with respect to this method or its (discouraged)
750   * overrides.
751   *
752   * @threadsafety This method is, and its (discouraged) overrides
753   * must be, safe for concurrent use by multiple threads.
754   *
755   * @see #load(Path)
756   */
757  @OverridingDiscouraged
758  public default <U> Loader<U> load(final Class<U> type, final List<? extends String> names) {
759    return this.load(Path.of(type, names));
760  }
761
762  /**
763   * Returns an ancestral {@link Loader}, derived from and possibly
764   * identical to this {@link Loader}, that is suitable for a
765   * {@linkplain #transliterate(Path) transliterated} and {@linkplain
766   * Path#absolute() absolute} version of the supplied {@code path},
767   * particularly for cases where, during the execution of the {@link
768   * #load(Path)} method, a {@link Loader} must be supplied to some
769   * other class.
770   *
771   * <p>The returned {@link Loader} must be one whose {@link #path()}
772   * method returns the {@linkplain Path#size() longest} {@link Path}
773   * that is a parent of an {@linkplain Path#absolute() absolute}
774   * version of the ({@linkplain #transliterate(Path) transliterated})
775   * supplied {@code path}.  In many cases {@code this} will be
776   * returned.</p>
777   *
778   * <p>Typically only classes implementing this interface will need
779   * to call this method.  Most users will have no need to call this
780   * method directly.</p>
781   *
782   * <p>Overriding of this method is <strong>very strongly</strong>
783   * discouraged.</p>
784   *
785   * @param path the {@link Path} in question; must not be {@code
786   * null}
787   *
788   * @return an ancestral {@link Loader}, derived from and possibly
789   * identical to this {@link Loader}, that is suitable for a
790   * {@linkplain #transliterate(Path) transliterated} and {@linkplain
791   * Path#absolute() absolute} version of the supplied {@code path},
792   * particularly for cases where, during the execution of the {@link
793   * #load(Path)} method, a {@link Loader} must be supplied to some
794   * other class; never {@code null}
795   *
796   * @exception NullPointerException if {@code path} is {@code null}
797   *
798   * @nullability The default implementation of this method does not,
799   * and its (discouraged) overrides must not, return {@code null}.
800   *
801   * @threadsafety The default implementation of this method is, and
802   * its (discouraged) overrides must be, safe for concurrent use by
803   * multiple threads.
804   *
805   * @idempotency The default implementation of this method is, and
806   * its (discouraged) overrides must be, idempotent and
807   * deterministic.
808   *
809   * @see #transliterate(Path)
810   *
811   * @see #root()
812   */
813  @OverridingDiscouraged
814  public default Loader<?> loaderFor(Path<? extends Type> path) {
815    Objects.requireNonNull(path, "path");
816    final Loader<?> parent = this.parent();
817    if (this != parent) {
818      final Path<? extends Type> absolutePath = this.absolutePath();
819      assert absolutePath.absolute() : "!absolutePath.absolute(): " + absolutePath;
820      assert absolutePath.transliterated();
821      if (!path.absolute()) {
822        path = absolutePath.plus(path);
823        assert path.absolute();
824      }
825      path = this.transliterate(path);
826      // TODO: note that this does not take a Path's top-level
827      // qualifiers into account.  Maybe that's on purpose?
828      if (absolutePath.startsWith(path)) {
829        // This Loader's absolute path (e.g. /a/b/c/d) begins with
830        // path (e.g. /a/b or /a/b/c/d), and so could also equal its
831        // sequence of path elements (e.g. if path is also /a/b/c/d).
832        // We don't care about the equals case, only the
833        // starts-with-but-not-equal case.
834        final int absolutePathSize = absolutePath.size();
835        final int pathSize = path.size();
836        if (absolutePathSize > pathSize) {
837          // This Loader's absolute path(e.g. /a/b/c/d) begins with
838          // path (e.g. /a/b) and does not have the same sequence of
839          // path elements.
840          return parent.loaderFor(path); // NOTE: recursive call
841        }
842      } else {
843        return this.root();
844      }
845    }
846    return this;
847  }
848
849  /**
850   * <em>Transliterates</em> the supplied {@linkplain Path#absolute()
851   * absolute <code>Path</code>} into some other {@link Path}, whose
852   * meaning is the same, but whose representation may be different,
853   * that will be used instead.
854   *
855   * <p>The {@link Path} that is returned may be the {@link Path} that
856   * was supplied.  This may happen, for example, if {@linkplain
857   * Path#transliterated() the path has already been transliterated},
858   * or if the path identifies a transliteration request.</p>
859   *
860   * <p>Path transliteration is needed because the {@link
861   * Element#name() name()} components of {@link Element}s may
862   * unintentionally clash when two components are combined into a
863   * single application.</p>
864   *
865   * <p>Path transliteration must occur during the execution of any
866   * implementation of the {@link #load(Path)} method, such that the
867   * {@link Path} supplied to that method, once it has been verified
868   * to be {@linkplain Path#absolute() absolute}, is supplied to an
869   * implementation of this method. The {@link Path} returned by an
870   * implementation of this method must then be used during the rest
871   * of the invocation of the {@link #load(Path)} method, as if it had
872   * been supplied in the first place.</p>
873   *
874   * <p>Behavior resulting from any other usage of an implementation
875   * of this method is undefined.</p>
876   *
877   * <p>The default implementation of this method uses the
878   * configuration system itself to find a transliterated {@link Path}
879   * corresponding to the supplied {@link Path}, returning the
880   * supplied {@code path} itself if no transliteration can take
881   * place.  Infinite loops are avoided except as noted below.</p>
882   *
883   * <p>Overrides of this method <strong>must not call {@link
884   * #loaderFor(Path)}</strong> or an infinite loop may
885   * result.</p>
886   *
887   * <p>Overrides of this method <strong>must not call {@link
888   * #load(Path)} with the supplied {@code path}</strong> or an infinite
889   * loop may result.</p>
890   *
891   * <p>An implementation of {@link Loader} will find {@link
892   * Path#transliterate(java.util.function.BiFunction)} particularly
893   * useful in implementing this method.</p>
894   *
895   * <p>Most users will have no need to call this method directly.</p>
896   *
897   * @param <U> the type of the supplied and returned {@link Path}s
898   *
899   * @param path an {@linkplain Path#absolute() absolute
900   * <code>Path</code>}; must not be null
901   *
902   * @return the transliterated {@link Path}; never {@code null};
903   * possibly the supplied {@code path} itself
904   *
905   * @exception NullPointerException if {@code path} is {@code null}
906   *
907   * @exception IllegalArgumentException if {@code path} returns
908   * {@code false} from its {@link Path#absolute() absolute()}
909   * method
910   *
911   * @nullability The default implementation of this method does not,
912   * and its (discouraged) overrides must not, return {@code null}.
913   *
914   * @threadsafety The default implementation of this method is, and
915   * its (discouraged) overrides must be, safe for concurrent use by
916   * multiple threads.
917   *
918   * @idempotency The default implementation of this method is, and
919   * its (discouraged) overrides must be, idempotent and
920   * deterministic.
921   *
922   * @see Path#absolute()
923   *
924   * @see Path#transliterate(java.util.function.BiFunction)
925   *
926   * @see #loaderFor(Path)
927   *
928   * @see #load(Path)
929   */
930  @OverridingDiscouraged
931  public default <U extends Type> Path<U> transliterate(final Path<U> path) {
932    if (path.transliterated()) {
933      return path;
934    } else if (path.lastElement().name().equals("org.microbean.loader.api.transliteration") &&
935               path.lastElement().qualified() instanceof ParameterizedType ptype &&
936               ptype.getRawType() instanceof Class<?> c &&
937               Path.class.isAssignableFrom(c)) {
938      // (All of these tests are to check: is the supplied Path a
939      // transliteration request?)
940      //
941      // The last element's type should be a parameterized type
942      // representing Path<Something>.  The last element's qualifiers
943      // will also contain a "path" key with the original Path being
944      // transliterated, but we don't need to check that.
945      //
946      // In such a case: mark the transliteration request itself as
947      // already transliterated to kill off infinite loops.
948      return path.transliterate();
949    }
950    final ParameterizedType ptype = (ParameterizedType)new Token<Path<U>>() {}.type();
951    final Element<ParameterizedType> e = Element.of(Qualifiers.of(Qualifier.<String, Path<U>>of("path", path)), ptype, "org.microbean.loader.api.transliteration");
952    // Note that we transliterate the transliteration request itself
953    // with a no-op: this marks the request itself as already
954    // transliterated, which should kill off any infinite loops.
955    final Path<ParameterizedType> transliterationRequest = Path.root().plus(e).transliterate();
956    assert transliterationRequest.absolute();
957    Path<U> returnValue = this.<Path<U>>load(transliterationRequest).orElse(path);
958    if (returnValue == null) {
959      // null is not a permitted return value for this method,
960      // although it may be a valid value from a provider.  Treat it
961      // as absent by simply marking the supplied path as already
962      // transliterated.
963      returnValue = path.transliterate();
964    } else if (!returnValue.transliterated()) {
965      returnValue = returnValue.transliterate();
966    }
967    return returnValue;
968  }
969
970  /**
971   * Returns {@code true} if and only if this {@link Loader} is the
972   * root {@link Loader}, which occurs only when the return value of
973   * {@link #parent() this.parent() == this}.
974   *
975   * <p>Overrides of this method are <strong>strongly</strong>
976   * discouraged.</p>
977   *
978   * <p>Most users will have no need to call this method directly.</p>
979   *
980   * @return {@code true} if and only if this {@link Loader} is the
981   * root {@link Loader}
982   *
983   * @idempotency This method is, and its (discouraged) overrides must
984   * be, idempotent and deterministic.
985   *
986   * @threadsafety This method is, and its (discouraged) overrides
987   * must be, safe for concurrent use by multiple threads.
988   *
989   * @see #parent()
990   */
991  @OverridingDiscouraged
992  public default boolean isRoot() {
993    return this.parent() == this;
994  }
995
996  /**
997   * Returns the root {@link Loader}, which is the {@link Loader}
998   * whose {@link #parent()} method returns iteself.
999   *
1000   * <p>Overrides of this method are <strong>strongly</strong>
1001   * discouraged.</p>
1002   *
1003   * <p>Most users will have no need to call this method directly.</p>
1004   *
1005   * @return the root {@link Loader}
1006   *
1007   * @nullability This method does not, and its (discouraged)
1008   * overrides must not, return {@code null}.
1009   *
1010   * @idempotency This method is, and its (discouraged) overrides must
1011   * be, idempotent and deterministic.
1012   *
1013   * @threadsafety This method is, and its (discouraged) overrides
1014   * must be, safe for concurrent use by multiple threads.
1015   *
1016   * @see #isRoot()
1017   *
1018   * @see #parent()
1019   *
1020   * @see Path#root()
1021   */
1022  @OverridingDiscouraged
1023  public default Loader<?> root() {
1024    Loader<?> root = this;
1025    Loader<?> parent = root.parent();
1026    while (parent != null && parent != root) {
1027      // (Strictly speaking, Loader::parent should NEVER be null.)
1028      root = parent;
1029      parent = root.parent();
1030    }
1031    assert root.path().isRoot();
1032    assert root.parent() == root;
1033    assert this == root ? true : !this.path().isRoot();
1034    return root;
1035  }
1036
1037  /**
1038   * Casts this {@link Loader} appropriately and returns it, usually
1039   * so that an implementation's implementation-specific methods can
1040   * be accessed.
1041   *
1042   * @param <L> the {@link Loader} subclass
1043   *
1044   * @param loaderSubclass a {@link Class} representing a subclass of
1045   * {@link Loader}; must not be {@code null}
1046   *
1047   * @return this {@link Loader}
1048   *
1049   * @exception NullPointerException if {@code loaderSubclass} is
1050   * {@code null}
1051   *
1052   * @exception ClassCastException if the cast could not be performed
1053   *
1054   * @nullability This method does not, and its (discouraged)
1055   * overrides must not, return {@code null}.
1056   *
1057   * @idempotency This method is, and its (discouraged) overrides must
1058   * be, idempotent and deterministic.
1059   *
1060   * @threadsafety This method is, and its (discouraged) overrides
1061   * must be, safe for concurrent use by multiple threads.
1062   */
1063  @OverridingDiscouraged
1064  public default <L extends Loader<?>> L as(final Class<L> loaderSubclass) {
1065    return loaderSubclass.cast(this);
1066  }
1067
1068  /**
1069   * Bootstraps and returns a {@link Loader}.
1070   *
1071   * <p>If this method has been called before, its prior result is
1072   * returned.</p>
1073   *
1074   * <p>Otherwise, first, the <em>root {@link Loader}</em> is located
1075   * using Java's built-in {@link ServiceLoader}.  The first of the
1076   * {@link Loader} instances it discovers is used and all others are
1077   * ignored.  Note that the {@link ServiceLoader} discovery process
1078   * is non-deterministic.  Normally there is only one such {@link
1079   * Loader} provided by an implementation of this API.</p>
1080   *
1081   * <p>The root {@link Loader} that is loaded via this mechanism is
1082   * subject to the following restrictions:</p>
1083   *
1084   * <ul>
1085   *
1086   * <li>It must return a {@link Path} from its {@link #path()}
1087   * implementation that is {@linkplain Path#equals(Object) equal to}
1088   * {@link Path#root() Path.root()}.</li>
1089   *
1090   * <li>It must return a {@link Path} from its {@link
1091   * #absolutePath()} implementation that is {@linkplain
1092   * Path#equals(Object) equal to} {@link Path#root()
1093   * Path.root()}.</li>
1094   *
1095   * <li>It must return itself ({@code this}) from its {@link
1096   * #parent()} implementation.</li>
1097   *
1098   * <li>It must return {@code true} from its {@link #isRoot()}
1099   * implementation.</li>
1100   *
1101   * <li>It must return itself ({@code this}) from its {@link #root()}
1102   * method.</li>
1103   *
1104   * <li>It must return {@link Determinism#PRESENT} from its {@link
1105   * #determinism() determinism()} method.</li>
1106   *
1107   * <li>It must return itself ({@code this}) from its {@link #get()
1108   * get()} method.</li>
1109   *
1110   * </ul>
1111   *
1112   * <p>Next, this root {@link Loader} is used to {@linkplain
1113   * #load(Path) find} the <em>{@link Loader} of record</em>, which in
1114   * most cases is simply itself.</p>
1115   *
1116   * <p>The {@link Loader} of record is subject to the following
1117   * restrictions (which are compatible with the overwhelmingly common
1118   * case of its also being the root {@link Loader}):</p>
1119   *
1120   * <ul>
1121   *
1122   * <li>It must return a {@link Path} from its {@link #path()}
1123   * implementation that is equal to {@link Path#root() Path.root()}
1124   * (same as above).</li>
1125   *
1126   * <li>It must return a {@link Path} from its {@link
1127   * #absolutePath()} implementation that is equal to {@link
1128   * Path#root() Path.root()} (same as above).</li>
1129   *
1130   * <li>It must return {@link Determinism#PRESENT} from its {@link
1131   * #determinism() determinism()} method (same as above).</li>
1132   *
1133   * <li>It must return the root {@link Loader} from its {@link
1134   * #parent()} implementation (which may be itself ({@code
1135   * this})).</li>
1136   *
1137   * <li>It must return a {@link Loader} implementation, often itself
1138   * ({@code this}), from its {@link #get() get()} method.</li>
1139   *
1140   * </ul>
1141   *
1142   * <p>An {@link IllegalStateException} will be thrown if an
1143   * implementation of the {@link Loader} interface does not honor the
1144   * requirements above.</p>
1145   *
1146   * <p>This method is the primary entry point for end users of this
1147   * framework.</p>
1148   *
1149   * @return a non-{@code null} {@link Loader} that can be used to
1150   * acquire environmental objects that abides by the requirements and
1151   * restrictions above
1152   *
1153   * @exception IllegalStateException if any of the requirements and
1154   * restrictions above is violated
1155   *
1156   * @exception java.util.ServiceConfigurationError if the root {@link
1157   * Loader} could not be loaded for any reason
1158   *
1159   * @exception NoClassDefFoundError if the root {@link Loader} could
1160   * not be loaded for any reason
1161   */
1162  @EntryPoint
1163  public static Loader<?> loader() {
1164    final class LoaderOfRecord {
1165      private static final Loader<?> INSTANCE;
1166      static {
1167        final Loader<?> rootLoader =
1168          ServiceLoader.load(Loader.class, Loader.class.getClassLoader()).findFirst().orElseThrow();
1169        if (rootLoader.determinism() != Determinism.PRESENT) {
1170          throw new IllegalStateException("rootLoader.determinism() != PRESENT: " + rootLoader.determinism());
1171        } else if (!rootLoader.path().isRoot()) {
1172          throw new IllegalStateException("!rootLoader.path().isRoot(): " + rootLoader.path());
1173        } else if (!rootLoader.absolutePath().isRoot()) {
1174          throw new IllegalStateException("!rootLoader.absolutePath().isRoot(): " + rootLoader.absolutePath());
1175        } else if (rootLoader.parent() != rootLoader) {
1176          throw new IllegalStateException("rootLoader.parent() != rootLoader: " + rootLoader.parent() + "; rootLoader: " + rootLoader);
1177        } else if (rootLoader.get() != rootLoader) {
1178          throw new IllegalStateException("rootLoader.get() != rootLoader: " + rootLoader.get() + "; rootLoader: " + rootLoader);
1179        } else if (!rootLoader.isRoot()) {
1180          throw new IllegalStateException("!rootLoader.isRoot()");
1181        } else if (rootLoader.root() != rootLoader) {
1182          throw new IllegalStateException("rootLoader.root() != rootLoader: " + rootLoader.root() + "; rootLoader: " + rootLoader);
1183        }
1184        INSTANCE = rootLoader.<Loader<?>>load(Path.of(new Token<Loader<?>>() {}.type())).orElse(rootLoader);
1185        if (INSTANCE.determinism() != Determinism.PRESENT) {
1186          throw new IllegalStateException("INSTANCE.determinism() != PRESENT: " + INSTANCE.determinism());
1187        } else if (!INSTANCE.path().isRoot()) {
1188          throw new IllegalStateException("!INSTANCE.path().isRoot(): " + INSTANCE.path());
1189        } else if (!INSTANCE.absolutePath().isRoot()) {
1190          throw new IllegalStateException("!INSTANCE.absolutePath().isRoot(): " + INSTANCE.absolutePath());
1191        } else if (INSTANCE.parent() != rootLoader) {
1192          throw new IllegalStateException("INSTANCE.parent() != rootLoader: " + INSTANCE.parent());
1193        } else if (!(INSTANCE.get() instanceof Loader)) {
1194          throw new IllegalStateException("!(INSTANCE.get() instanceof Loader): " + INSTANCE.get());
1195        }
1196      }
1197    };
1198    return LoaderOfRecord.INSTANCE;
1199  }
1200
1201}