View Javadoc
1   /*
2    * Copyright 2002-2014 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.web.servlet.view.groovy;
18  
19  import java.io.BufferedWriter;
20  import java.io.IOException;
21  import java.util.Locale;
22  import java.util.Map;
23  import javax.servlet.http.HttpServletRequest;
24  import javax.servlet.http.HttpServletResponse;
25  
26  import groovy.text.Template;
27  import groovy.text.markup.MarkupTemplateEngine;
28  
29  import org.springframework.beans.BeansException;
30  import org.springframework.beans.factory.BeanFactoryUtils;
31  import org.springframework.beans.factory.NoSuchBeanDefinitionException;
32  import org.springframework.context.ApplicationContext;
33  import org.springframework.context.ApplicationContextException;
34  import org.springframework.web.servlet.view.AbstractTemplateView;
35  import org.springframework.web.util.NestedServletException;
36  
37  /**
38   * An {@link org.springframework.web.servlet.view.AbstractTemplateView AbstractTemplateView}
39   * based on Groovy XML/XHTML markup templates.
40   *
41   * <p>Spring's Groovy Markup Template support requires Groovy 2.3.1 and higher.
42   *
43   * @author Brian Clozel
44   * @author Rossen Stoyanchev
45   * @since 4.1
46   * @see GroovyMarkupViewResolver
47   * @see GroovyMarkupConfigurer
48   * @see <a href="http://beta.groovy-lang.org/docs/groovy-2.3.2/html/documentation/markup-template-engine.html">
49   *     Groovy Markup Template engine documentation</a>
50   */
51  public class GroovyMarkupView extends AbstractTemplateView {
52  
53  	private MarkupTemplateEngine engine;
54  
55  
56  	/**
57  	 * Set the MarkupTemplateEngine to use in this view.
58  	 * <p>If not set, the engine is auto-detected by looking up up a single
59  	 * {@link GroovyMarkupConfig} bean in the web application context and using
60  	 * it to obtain the configured {@code MarkupTemplateEngine} instance.
61  	 * @see GroovyMarkupConfig
62  	 */
63  	public void setTemplateEngine(MarkupTemplateEngine engine) {
64  		this.engine = engine;
65  	}
66  
67  	@Override
68  	public boolean checkResource(Locale locale) throws Exception {
69  		try {
70  			this.engine.resolveTemplate(getUrl());
71  		}
72  		catch (IOException exception) {
73  			return false;
74  		}
75  		return true;
76  	}
77  
78  	/**
79  	 * Invoked at startup.
80  	 * If no {@link #setTemplateEngine(MarkupTemplateEngine) templateEngine} has
81  	 * been manually set, this method looks up a {@link GroovyMarkupConfig} bean
82  	 * by type and uses it to obtain the Groovy Markup template engine.
83  	 * @see GroovyMarkupConfig
84  	 * @see #setTemplateEngine(groovy.text.markup.MarkupTemplateEngine)
85  	 */
86  	@Override
87  	protected void initApplicationContext(ApplicationContext context) {
88  		super.initApplicationContext();
89  		if (this.engine == null) {
90  			setTemplateEngine(autodetectMarkupTemplateEngine());
91  		}
92  	}
93  
94  	/**
95  	 * Autodetect a MarkupTemplateEngine via the ApplicationContext.
96  	 * Called if a MarkupTemplateEngine has not been manually configured.
97  	 */
98  	protected MarkupTemplateEngine autodetectMarkupTemplateEngine() throws BeansException {
99  		try {
100 			return BeanFactoryUtils.beanOfTypeIncludingAncestors(getApplicationContext(),
101 					GroovyMarkupConfig.class, true, false).getTemplateEngine();
102 		}
103 		catch (NoSuchBeanDefinitionException ex) {
104 			throw new ApplicationContextException("Expected a single GroovyMarkupConfig bean in the current " +
105 					"Servlet web application context or the parent root context: GroovyMarkupConfigurer is " +
106 					"the usual implementation. This bean may have any name.", ex);
107 		}
108 	}
109 
110 
111 	@Override
112 	protected void renderMergedTemplateModel(Map<String, Object> model,
113 			HttpServletRequest request, HttpServletResponse response) throws Exception {
114 
115 		Template template = getTemplate(getUrl());
116 		template.make(model).writeTo(new BufferedWriter(response.getWriter()));
117 	}
118 
119 	/**
120 	 * Return a template compiled by the configured Groovy Markup template engine
121 	 * for the given view URL.
122 	 */
123 	protected Template getTemplate(String viewUrl) throws Exception {
124 		try {
125 			return this.engine.createTemplateByPath(viewUrl);
126 		}
127 		catch (ClassNotFoundException ex) {
128 			Throwable cause = (ex.getCause() != null ? ex.getCause() : ex);
129 			throw new NestedServletException("Could not find class while rendering Groovy Markup view with name '" +
130 					getUrl() + "': " + ex.getMessage() +  "'", cause);
131 		}
132 	}
133 
134 }