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}