001/* 002 * Copyright 2002-2016 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.groovy; 018 019import java.io.BufferedWriter; 020import java.io.IOException; 021import java.util.Locale; 022import java.util.Map; 023import javax.servlet.http.HttpServletRequest; 024import javax.servlet.http.HttpServletResponse; 025 026import groovy.text.Template; 027import groovy.text.markup.MarkupTemplateEngine; 028 029import org.springframework.beans.BeansException; 030import org.springframework.beans.factory.BeanFactoryUtils; 031import org.springframework.beans.factory.NoSuchBeanDefinitionException; 032import org.springframework.context.ApplicationContext; 033import org.springframework.context.ApplicationContextException; 034import org.springframework.web.servlet.view.AbstractTemplateView; 035import org.springframework.web.util.NestedServletException; 036 037/** 038 * An {@link AbstractTemplateView} subclass based on Groovy XML/XHTML markup templates. 039 * 040 * <p>Spring's Groovy Markup Template support requires Groovy 2.3.1 and higher. 041 * 042 * @author Brian Clozel 043 * @author Rossen Stoyanchev 044 * @since 4.1 045 * @see GroovyMarkupViewResolver 046 * @see GroovyMarkupConfigurer 047 * @see <a href="http://groovy-lang.org/templating.html#_the_markuptemplateengine"> 048 * Groovy Markup Template engine documentation</a> 049 */ 050public class GroovyMarkupView extends AbstractTemplateView { 051 052 private MarkupTemplateEngine engine; 053 054 055 /** 056 * Set the MarkupTemplateEngine to use in this view. 057 * <p>If not set, the engine is auto-detected by looking up a single 058 * {@link GroovyMarkupConfig} bean in the web application context and using 059 * it to obtain the configured {@code MarkupTemplateEngine} instance. 060 * @see GroovyMarkupConfig 061 */ 062 public void setTemplateEngine(MarkupTemplateEngine engine) { 063 this.engine = engine; 064 } 065 066 /** 067 * Invoked at startup. 068 * If no {@link #setTemplateEngine(MarkupTemplateEngine) templateEngine} has 069 * been manually set, this method looks up a {@link GroovyMarkupConfig} bean 070 * by type and uses it to obtain the Groovy Markup template engine. 071 * @see GroovyMarkupConfig 072 * @see #setTemplateEngine(groovy.text.markup.MarkupTemplateEngine) 073 */ 074 @Override 075 protected void initApplicationContext(ApplicationContext context) { 076 super.initApplicationContext(); 077 if (this.engine == null) { 078 setTemplateEngine(autodetectMarkupTemplateEngine()); 079 } 080 } 081 082 /** 083 * Autodetect a MarkupTemplateEngine via the ApplicationContext. 084 * Called if a MarkupTemplateEngine has not been manually configured. 085 */ 086 protected MarkupTemplateEngine autodetectMarkupTemplateEngine() throws BeansException { 087 try { 088 return BeanFactoryUtils.beanOfTypeIncludingAncestors(getApplicationContext(), 089 GroovyMarkupConfig.class, true, false).getTemplateEngine(); 090 } 091 catch (NoSuchBeanDefinitionException ex) { 092 throw new ApplicationContextException("Expected a single GroovyMarkupConfig bean in the current " + 093 "Servlet web application context or the parent root context: GroovyMarkupConfigurer is " + 094 "the usual implementation. This bean may have any name.", ex); 095 } 096 } 097 098 099 @Override 100 public boolean checkResource(Locale locale) throws Exception { 101 try { 102 this.engine.resolveTemplate(getUrl()); 103 } 104 catch (IOException ex) { 105 return false; 106 } 107 return true; 108 } 109 110 @Override 111 protected void renderMergedTemplateModel(Map<String, Object> model, 112 HttpServletRequest request, HttpServletResponse response) throws Exception { 113 114 Template template = getTemplate(getUrl()); 115 template.make(model).writeTo(new BufferedWriter(response.getWriter())); 116 } 117 118 /** 119 * Return a template compiled by the configured Groovy Markup template engine 120 * for the given view URL. 121 */ 122 protected Template getTemplate(String viewUrl) throws Exception { 123 try { 124 return this.engine.createTemplateByPath(viewUrl); 125 } 126 catch (ClassNotFoundException ex) { 127 Throwable cause = (ex.getCause() != null ? ex.getCause() : ex); 128 throw new NestedServletException( 129 "Could not find class while rendering Groovy Markup view with name '" + 130 getUrl() + "': " + ex.getMessage() + "'", cause); 131 } 132 } 133 134}