001package io.jstach.opt.spring;
002
003import java.util.List;
004import java.util.ServiceLoader;
005
006import org.springframework.core.env.Environment;
007
008import io.jstach.jstachio.Template;
009import io.jstach.jstachio.TemplateInfo;
010import io.jstach.jstachio.spi.JStachioConfig;
011import io.jstach.jstachio.spi.JStachioExtensionProvider;
012import io.jstach.jstachio.spi.JStachioTemplateFinder;
013
014/**
015 * JStachio services based on Spring notably the {@link #provideConfig() config} and
016 * {@link #provideTemplateFinder() template finding}.
017 *
018 * @apiNote Although this is an extension it is not designed to be loaded by the
019 * {@link ServiceLoader}.
020 * @author agentgt
021 *
022 */
023public class SpringJStachioExtension implements JStachioExtensionProvider {
024
025        private final Environment environment;
026
027        private final List<Template<?>> templates;
028
029        /**
030         * Constructor for injection
031         * @param environment springs environment to be used for {@link JStachioConfig}
032         * @param templates templates found via spring
033         */
034        public SpringJStachioExtension(@SuppressWarnings("exports") Environment environment, List<Template<?>> templates) {
035                super();
036                this.environment = environment;
037                this.templates = templates;
038        }
039
040        /**
041         * {@inheritDoc} The config comes from Spring {@link Environment} abstraction.
042         */
043        @Override
044        public JStachioConfig provideConfig() {
045                return prop -> environment.getProperty(prop);
046        }
047
048        /**
049         * {@inheritDoc} The provided template finder instead of using reflection delegates to
050         * the templates wired in via spring.
051         */
052        @Override
053        public JStachioTemplateFinder provideTemplateFinder() {
054
055                return new JStachioTemplateFinder() {
056
057                        @Override
058                        public TemplateInfo findTemplate(Class<?> modelType) throws Exception {
059                                /*
060                                 * TODO should we do reflection based lookup if this fails?
061                                 */
062                                for (var t : templates) {
063                                        if (t.supportsType(modelType)) {
064                                                return t;
065                                        }
066                                }
067                                throw new RuntimeException("template not found for type: " + modelType);
068                        }
069
070                        @Override
071                        public boolean supportsType(Class<?> modelType) {
072                                for (var t : templates) {
073                                        if (t.supportsType(modelType)) {
074                                                return true;
075                                        }
076                                }
077                                return false;
078                        }
079                };
080
081        }
082
083}