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}