1 /* 2 * $Id: FreeMarkerAttributeRenderer.java 821299 2009-10-03 12:15:05Z apetrelli $ 3 * 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 package org.apache.tiles.freemarker.renderer; 23 24 import java.io.IOException; 25 import java.util.Enumeration; 26 import java.util.HashMap; 27 import java.util.Map; 28 29 import javax.servlet.ServletConfig; 30 import javax.servlet.ServletContext; 31 import javax.servlet.ServletException; 32 import javax.servlet.http.HttpServletRequest; 33 import javax.servlet.http.HttpServletResponse; 34 35 import org.apache.tiles.Attribute; 36 import org.apache.tiles.context.TilesRequestContext; 37 import org.apache.tiles.freemarker.FreeMarkerTilesException; 38 import org.apache.tiles.freemarker.servlet.TilesFreemarkerServlet; 39 import org.apache.tiles.impl.InvalidTemplateException; 40 import org.apache.tiles.renderer.impl.AbstractTypeDetectingAttributeRenderer; 41 import org.apache.tiles.servlet.context.ExternalWriterHttpServletResponse; 42 import org.apache.tiles.servlet.context.ServletTilesRequestContext; 43 import org.apache.tiles.servlet.context.ServletUtil; 44 import org.apache.tiles.util.IteratorEnumeration; 45 46 /** 47 * FreeMarker renderer for rendering FreeMarker templates as Tiles attributes. 48 * It is only usable under a Servlet environment, because it uses 49 * {@link TilesFreemarkerServlet} internally to forward the request.<br/> 50 * To initialize it correctly, call {@link #setParameter(String, String)} for all the 51 * parameters that you want to set, and then call {@link #commit()}. 52 * 53 * @version $Rev: 821299 $ $Date: 2009-10-03 14:15:05 +0200 (sab, 03 ott 2009) $ 54 * @since 2.2.0 55 */ 56 public class FreeMarkerAttributeRenderer extends AbstractTypeDetectingAttributeRenderer { 57 58 /** 59 * The servlet that is used to forward the request to. 60 */ 61 private AttributeValueFreemarkerServlet servlet; 62 63 /** 64 * The initialization parameters. 65 */ 66 private Map<String, String> params = new HashMap<String, String>(); 67 68 /** 69 * Sets a parameter for the internal servlet. 70 * 71 * @param key The name of the parameter. 72 * @param value The value of the parameter. 73 * @since 2.2.0 74 */ 75 public void setParameter(String key, String value) { 76 params.put(key, value); 77 } 78 79 /** 80 * Commits the parameters and makes this renderer ready for the use. 81 * 82 * @since 2.2.0 83 */ 84 public void commit() { 85 servlet = new AttributeValueFreemarkerServlet(); 86 try { 87 servlet.init(new InitParamsServletConfig()); 88 } catch (ServletException e) { 89 throw new FreeMarkerTilesException( 90 "Cannot initialize internal servlet", e); 91 } 92 } 93 94 /** {@inheritDoc} */ 95 @Override 96 public void write(Object value, Attribute attribute, 97 TilesRequestContext request) throws IOException { 98 if (value != null) { 99 if (value instanceof String) { 100 ServletTilesRequestContext servletRequest = ServletUtil.getServletRequest(request); 101 HttpServletRequest httpRequest = servletRequest.getRequest(); 102 HttpServletResponse httpResponse = servletRequest.getResponse(); 103 servlet.setValue((String) value); 104 try { 105 servlet.doGet(httpRequest, 106 new ExternalWriterHttpServletResponse(httpResponse, 107 request.getPrintWriter())); 108 } catch (ServletException e) { 109 throw new FreeMarkerTilesException("Exception when rendering a FreeMarker attribute", e); 110 } 111 } else { 112 throw new InvalidTemplateException( 113 "Cannot render a template that is not a string: " 114 + value.toString()); 115 } 116 } else { 117 throw new InvalidTemplateException("Cannot render a null template"); 118 } 119 } 120 121 /** {@inheritDoc} */ 122 public boolean isRenderable(Object value, Attribute attribute, 123 TilesRequestContext request) { 124 if (value instanceof String) { 125 String string = (String) value; 126 return string.startsWith("/") && string.endsWith(".ftl"); 127 } 128 return false; 129 } 130 131 /** 132 * Extends {@link TilesFreemarkerServlet} to use the attribute value as the template name. 133 * 134 * @since 2.2.0 135 */ 136 private static class AttributeValueFreemarkerServlet extends TilesFreemarkerServlet { 137 138 /** 139 * Holds the value that should be used as the template name. 140 */ 141 private ThreadLocal<String> valueHolder = new ThreadLocal<String>(); 142 143 /** 144 * Sets the value to use as the template name. 145 * 146 * @param value The template name. 147 * @since 2.2.0 148 */ 149 public void setValue(String value) { 150 valueHolder.set(value); 151 } 152 153 /** {@inheritDoc} */ 154 @Override 155 protected String requestUrlToTemplatePath(HttpServletRequest request) { 156 return valueHolder.get(); 157 } 158 } 159 160 /** 161 * Implements {@link ServletConfig} to initialize the internal servlet using parameters 162 * set through {@link FreeMarkerAttributeRenderer#setParameter(String, String)}. 163 * 164 * @version $Rev: 821299 $ $Date: 2009-10-03 14:15:05 +0200 (sab, 03 ott 2009) $ 165 * @since 2.2.0 166 */ 167 private class InitParamsServletConfig implements ServletConfig { 168 169 /** {@inheritDoc} */ 170 public String getInitParameter(String name) { 171 return params.get(name); 172 } 173 174 /** {@inheritDoc} */ 175 @SuppressWarnings("unchecked") 176 public Enumeration getInitParameterNames() { 177 return new IteratorEnumeration(params.keySet().iterator()); 178 } 179 180 /** {@inheritDoc} */ 181 public ServletContext getServletContext() { 182 return ServletUtil.getServletContext(applicationContext); 183 } 184 185 /** {@inheritDoc} */ 186 public String getServletName() { 187 return "FreeMarker Attribute Renderer"; 188 } 189 } 190 }