001/*
002 * Copyright 2012-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.autoconfigure.groovy.template;
018
019import java.security.CodeSource;
020import java.security.ProtectionDomain;
021
022import javax.annotation.PostConstruct;
023import javax.servlet.Servlet;
024
025import groovy.text.markup.MarkupTemplateEngine;
026import org.apache.commons.logging.Log;
027import org.apache.commons.logging.LogFactory;
028
029import org.springframework.beans.factory.ObjectProvider;
030import org.springframework.boot.autoconfigure.AutoConfigureAfter;
031import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
032import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
033import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
034import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
035import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
036import org.springframework.boot.autoconfigure.template.TemplateLocation;
037import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
038import org.springframework.boot.context.properties.ConfigurationProperties;
039import org.springframework.boot.context.properties.EnableConfigurationProperties;
040import org.springframework.context.ApplicationContext;
041import org.springframework.context.annotation.Bean;
042import org.springframework.context.annotation.Configuration;
043import org.springframework.context.i18n.LocaleContextHolder;
044import org.springframework.web.servlet.view.UrlBasedViewResolver;
045import org.springframework.web.servlet.view.groovy.GroovyMarkupConfig;
046import org.springframework.web.servlet.view.groovy.GroovyMarkupConfigurer;
047import org.springframework.web.servlet.view.groovy.GroovyMarkupViewResolver;
048
049/**
050 * Auto-configuration support for Groovy templates in MVC. By default creates a
051 * {@link MarkupTemplateEngine} configured from {@link GroovyTemplateProperties}, but you
052 * can override that by providing your own {@link GroovyMarkupConfig} or even a
053 * {@link MarkupTemplateEngine} of a different type.
054 *
055 * @author Dave Syer
056 * @author Andy Wilkinson
057 * @author Brian Clozel
058 * @since 1.1.0
059 */
060@Configuration
061@ConditionalOnClass(MarkupTemplateEngine.class)
062@AutoConfigureAfter(WebMvcAutoConfiguration.class)
063@EnableConfigurationProperties(GroovyTemplateProperties.class)
064public class GroovyTemplateAutoConfiguration {
065
066        private static final Log logger = LogFactory
067                        .getLog(GroovyTemplateAutoConfiguration.class);
068
069        @Configuration
070        @ConditionalOnClass(GroovyMarkupConfigurer.class)
071        public static class GroovyMarkupConfiguration {
072
073                private final ApplicationContext applicationContext;
074
075                private final GroovyTemplateProperties properties;
076
077                private final MarkupTemplateEngine templateEngine;
078
079                public GroovyMarkupConfiguration(ApplicationContext applicationContext,
080                                GroovyTemplateProperties properties,
081                                ObjectProvider<MarkupTemplateEngine> templateEngine) {
082                        this.applicationContext = applicationContext;
083                        this.properties = properties;
084                        this.templateEngine = templateEngine.getIfAvailable();
085                }
086
087                @PostConstruct
088                public void checkTemplateLocationExists() {
089                        if (this.properties.isCheckTemplateLocation() && !isUsingGroovyAllJar()) {
090                                TemplateLocation location = new TemplateLocation(
091                                                this.properties.getResourceLoaderPath());
092                                if (!location.exists(this.applicationContext)) {
093                                        logger.warn("Cannot find template location: " + location
094                                                        + " (please add some templates, check your Groovy "
095                                                        + "configuration, or set spring.groovy.template."
096                                                        + "check-template-location=false)");
097                                }
098                        }
099                }
100
101                /**
102                 * MarkupTemplateEngine could be loaded from groovy-templates or groovy-all.
103                 * Unfortunately it's quite common for people to use groovy-all and not actually
104                 * need templating support. This method check attempts to check the source jar so
105                 * that we can skip the {@code /template} folder check for such cases.
106                 * @return true if the groovy-all jar is used
107                 */
108                private boolean isUsingGroovyAllJar() {
109                        try {
110                                ProtectionDomain domain = MarkupTemplateEngine.class
111                                                .getProtectionDomain();
112                                CodeSource codeSource = domain.getCodeSource();
113                                if (codeSource != null
114                                                && codeSource.getLocation().toString().contains("-all")) {
115                                        return true;
116                                }
117                                return false;
118                        }
119                        catch (Exception ex) {
120                                return false;
121                        }
122                }
123
124                @Bean
125                @ConditionalOnMissingBean(GroovyMarkupConfig.class)
126                @ConfigurationProperties(prefix = "spring.groovy.template.configuration")
127                public GroovyMarkupConfigurer groovyMarkupConfigurer() {
128                        GroovyMarkupConfigurer configurer = new GroovyMarkupConfigurer();
129                        configurer.setResourceLoaderPath(this.properties.getResourceLoaderPath());
130                        configurer.setCacheTemplates(this.properties.isCache());
131                        if (this.templateEngine != null) {
132                                configurer.setTemplateEngine(this.templateEngine);
133                        }
134                        return configurer;
135                }
136
137        }
138
139        @Configuration
140        @ConditionalOnClass({ Servlet.class, LocaleContextHolder.class,
141                        UrlBasedViewResolver.class })
142        @ConditionalOnWebApplication(type = Type.SERVLET)
143        @ConditionalOnProperty(name = "spring.groovy.template.enabled", matchIfMissing = true)
144        public static class GroovyWebConfiguration {
145
146                private final GroovyTemplateProperties properties;
147
148                public GroovyWebConfiguration(GroovyTemplateProperties properties) {
149                        this.properties = properties;
150                }
151
152                @Bean
153                @ConditionalOnMissingBean(name = "groovyMarkupViewResolver")
154                public GroovyMarkupViewResolver groovyMarkupViewResolver() {
155                        GroovyMarkupViewResolver resolver = new GroovyMarkupViewResolver();
156                        this.properties.applyToMvcViewResolver(resolver);
157                        return resolver;
158                }
159
160        }
161
162}