001package io.jstach.jstachio.spi; 002 003import org.eclipse.jdt.annotation.Nullable; 004 005/** 006 * An extension that is a factory that provides other extensions. 007 * 008 * All methods are optional (default) so that implementations can decide what particularly 009 * plugins/services they want to provide. 010 * 011 * This is extension is useful if there is configuration logic that needs to happen before 012 * creation. See {@link #init(JStachioConfig)} and {@link #provideConfig()}. 013 * 014 * @author agentgt 015 * @see JStachioExtensions 016 * @see JStachioExtension 017 */ 018public non-sealed interface JStachioExtensionProvider extends JStachioExtension { 019 020 /** 021 * Provide a filter or not. The final filter is a composite and becomes a filter 022 * chain. 023 * @return filter if this service provider provies one or <code>null</code> 024 */ 025 default @Nullable JStachioFilter provideFilter() { 026 return null; 027 } 028 029 /** 030 * Provide a config or not. The final config is a composite of all the found configs. 031 * <p> 032 * Specifically if multiple instances of {@link JStachioExtension} are found that 033 * return a nonnull they will be combined by looping through all of them to find a 034 * nonnull value for {@link JStachioConfig#getProperty(String)}. <strong>If no configs 035 * are provided or no services found {@link JStachioExtensions} instance will use the 036 * default config which uses {@link System#getProperties()}</strong>. 037 * 038 * @apiNote This method is called before {@link #init(JStachioConfig)} 039 * @return config if this service provides one or <code>null</code> 040 */ 041 default @Nullable JStachioConfig provideConfig() { 042 return null; 043 } 044 045 /** 046 * Provide a template finder or not. The final template finder is a composite of all 047 * the other ones found. See {@link JStachioTemplateFinder#order()} for ordering 048 * details. 049 * <p> 050 * <strong>If no template finders are provided then the default template finder that 051 * uses reflection and the ServiceLoader is used.</strong> 052 * @return template finder or not 053 */ 054 default @Nullable JStachioTemplateFinder provideTemplateFinder() { 055 return null; 056 } 057 058 /** 059 * Called before the extensions are used but after {@link #provideConfig()}. See 060 * {@link #provideConfig()} on how the config is consolidated to a single config. 061 * @param config the composite config never null 062 */ 063 default void init(JStachioConfig config) { 064 } 065 066 /** 067 * Creates a provider from an extension. If the extension is a provider than it is 068 * returned without wrapping. 069 * 070 * If the extension represent multiple types of extensions the returned provider will 071 * provide all of them. 072 * @param extension the extension to be wrapped. 073 * @return provider that will provide the extension 074 */ 075 public static JStachioExtensionProvider of(JStachioExtension extension) { 076 if (extension instanceof JStachioExtensionProvider p) { 077 return p; 078 } 079 JStachioFilter filter = null; 080 JStachioConfig config = null; 081 JStachioTemplateFinder finder = null; 082 if (extension instanceof JStachioFilter _filter) { 083 filter = _filter; 084 } 085 if (extension instanceof JStachioConfig _config) { 086 config = _config; 087 } 088 if (extension instanceof JStachioTemplateFinder _finder) { 089 finder = _finder; 090 } 091 return new ExtensionProvider(config, filter, finder); 092 } 093 094} 095 096record ExtensionProvider(@Nullable JStachioConfig config, @Nullable JStachioFilter filter, 097 @Nullable JStachioTemplateFinder finder) implements JStachioExtensionProvider { 098}