001package arez.component; 002 003import arez.Arez; 004import arez.Locator; 005import grim.annotations.OmitType; 006import java.util.HashMap; 007import java.util.Map; 008import java.util.function.Function; 009import javax.annotation.Nonnull; 010import javax.annotation.Nullable; 011import static org.realityforge.braincheck.Guards.*; 012 013/** 014 * An Locator implementation where you can register a function-per type to be resolved. 015 */ 016@OmitType( unless = "arez.enable_references" ) 017public final class TypeBasedLocator 018 implements Locator 019{ 020 /** 021 * Factory methods for looking entities up by type. 022 */ 023 @Nonnull 024 private final Map<Class<?>, Function<Object, ?>> _findByIdFunctions = new HashMap<>(); 025 026 /** 027 * Register a function that will find entities of specified type by id. 028 * This must not be invoked if another function has already been registered for type. 029 * 030 * @param <T> the type of the entity. 031 * @param type the type of the entity. 032 * @param findByIdFunction the function that looks up the entity by id. 033 */ 034 public <T> void registerLookup( @Nonnull final Class<T> type, @Nonnull final Function<Object, T> findByIdFunction ) 035 { 036 if ( Arez.shouldCheckApiInvariants() ) 037 { 038 apiInvariant( () -> !_findByIdFunctions.containsKey( type ), 039 () -> "Arez-0188: Attempting to register lookup function for type " + type + 040 " when a function for type already exists." ); 041 } 042 _findByIdFunctions.put( type, findByIdFunction ); 043 } 044 045 @Nullable 046 @Override 047 @SuppressWarnings( "unchecked" ) 048 public <T> T findById( @Nonnull final Class<T> type, @Nonnull final Object id ) 049 { 050 final Function<Object, ?> function = _findByIdFunctions.get( type ); 051 if ( null != function ) 052 { 053 return (T) function.apply( id ); 054 } 055 else 056 { 057 return null; 058 } 059 } 060}