001/*
002 * Copyright 2002-2012 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 *      https://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.web.servlet.view.freemarker;
018
019import java.io.IOException;
020import java.util.List;
021import javax.servlet.ServletContext;
022
023import freemarker.cache.ClassTemplateLoader;
024import freemarker.cache.TemplateLoader;
025import freemarker.ext.jsp.TaglibFactory;
026import freemarker.template.Configuration;
027import freemarker.template.TemplateException;
028
029import org.springframework.beans.factory.InitializingBean;
030import org.springframework.context.ResourceLoaderAware;
031import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory;
032import org.springframework.web.context.ServletContextAware;
033
034/**
035 * JavaBean to configure FreeMarker for web usage, via the "configLocation"
036 * and/or "freemarkerSettings" and/or "templateLoaderPath" properties.
037 * The simplest way to use this class is to specify just a "templateLoaderPath";
038 * you do not need any further configuration then.
039 *
040 * <pre class="code">
041 * &lt;bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"&gt;
042 *   &lt;property name="templateLoaderPath"&gt;&lt;value&gt;/WEB-INF/freemarker/&lt;/value>&lt;/property&gt;
043 * &lt;/bean&gt;</pre>
044 *
045 * This bean must be included in the application context of any application
046 * using Spring's FreeMarkerView for web MVC. It exists purely to configure FreeMarker.
047 * It is not meant to be referenced by application components but just internally
048 * by FreeMarkerView. Implements FreeMarkerConfig to be found by FreeMarkerView without
049 * depending on the bean name the configurer. Each DispatcherServlet can define its
050 * own FreeMarkerConfigurer if desired.
051 *
052 * <p>Note that you can also refer to a preconfigured FreeMarker Configuration
053 * instance, for example one set up by FreeMarkerConfigurationFactoryBean, via
054 * the "configuration" property. This allows to share a FreeMarker Configuration
055 * for web and email usage, for example.
056 *
057 * <p>This configurer registers a template loader for this package, allowing to
058 * reference the "spring.ftl" macro library (contained in this package and thus
059 * in spring.jar) like this:
060 *
061 * <pre class="code">
062 * &lt;#import "/spring.ftl" as spring/&gt;
063 * &lt;@spring.bind "person.age"/&gt;
064 * age is ${spring.status.value}</pre>
065 *
066 * Note: Spring's FreeMarker support requires FreeMarker 2.3 or higher.
067 *
068 * @author Darren Davison
069 * @author Rob Harrop
070 * @since 03.03.2004
071 * @see #setConfigLocation
072 * @see #setFreemarkerSettings
073 * @see #setTemplateLoaderPath
074 * @see #setConfiguration
075 * @see org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean
076 * @see FreeMarkerView
077 */
078public class FreeMarkerConfigurer extends FreeMarkerConfigurationFactory
079                implements FreeMarkerConfig, InitializingBean, ResourceLoaderAware, ServletContextAware {
080
081        private Configuration configuration;
082
083        private TaglibFactory taglibFactory;
084
085
086        /**
087         * Set a preconfigured Configuration to use for the FreeMarker web config, e.g. a
088         * shared one for web and email usage, set up via FreeMarkerConfigurationFactoryBean.
089         * If this is not set, FreeMarkerConfigurationFactory's properties (inherited by
090         * this class) have to be specified.
091         * @see org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean
092         */
093        public void setConfiguration(Configuration configuration) {
094                this.configuration = configuration;
095        }
096
097        /**
098         * Initialize the {@link TaglibFactory} for the given ServletContext.
099         */
100        @Override
101        public void setServletContext(ServletContext servletContext) {
102                this.taglibFactory = new TaglibFactory(servletContext);
103        }
104
105
106        /**
107         * Initialize FreeMarkerConfigurationFactory's Configuration
108         * if not overridden by a preconfigured FreeMarker Configuation.
109         * <p>Sets up a ClassTemplateLoader to use for loading Spring macros.
110         * @see #createConfiguration
111         * @see #setConfiguration
112         */
113        @Override
114        public void afterPropertiesSet() throws IOException, TemplateException {
115                if (this.configuration == null) {
116                        this.configuration = createConfiguration();
117                }
118        }
119
120        /**
121         * This implementation registers an additional ClassTemplateLoader
122         * for the Spring-provided macros, added to the end of the list.
123         */
124        @Override
125        protected void postProcessTemplateLoaders(List<TemplateLoader> templateLoaders) {
126                templateLoaders.add(new ClassTemplateLoader(FreeMarkerConfigurer.class, ""));
127                logger.info("ClassTemplateLoader for Spring macros added to FreeMarker configuration");
128        }
129
130
131        /**
132         * Return the Configuration object wrapped by this bean.
133         */
134        @Override
135        public Configuration getConfiguration() {
136                return this.configuration;
137        }
138
139        /**
140         * Return the TaglibFactory object wrapped by this bean.
141         */
142        @Override
143        public TaglibFactory getTaglibFactory() {
144                return this.taglibFactory;
145        }
146
147}