Save This Page
Home » struts-2.0.11.2-src » org.apache » struts2 » components » template » [javadoc | source]
    1   /*
    2    * $Id: FreemarkerTemplateEngine.java 560894 2007-07-30 09:05:32Z rgielen $
    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   package org.apache.struts2.components.template;
   22   
   23   import java.io.IOException;
   24   import java.io.Writer;
   25   import java.util;
   26   
   27   import javax.servlet.ServletContext;
   28   import javax.servlet.http.HttpServletRequest;
   29   import javax.servlet.http.HttpServletResponse;
   30   
   31   import org.apache.commons.logging.Log;
   32   import org.apache.commons.logging.LogFactory;
   33   import org.apache.struts2.ServletActionContext;
   34   import org.apache.struts2.StrutsConstants;
   35   import org.apache.struts2.views.freemarker.FreemarkerManager;
   36   
   37   import com.opensymphony.xwork2.inject.Inject;
   38   import com.opensymphony.xwork2.util.ClassLoaderUtil;
   39   import com.opensymphony.xwork2.ActionContext;
   40   import com.opensymphony.xwork2.ActionInvocation;
   41   import com.opensymphony.xwork2.util.ValueStack;
   42   
   43   import freemarker.template;
   44   
   45   /**
   46    * Freemarker based template engine.
   47    */
   48   public class FreemarkerTemplateEngine extends BaseTemplateEngine {
   49       static Class bodyContent = null;
   50       private FreemarkerManager freemarkerManager;
   51   
   52       private final HashMap<String, freemarker.template.Template> templates = new HashMap<String, freemarker.template.Template>();
   53       private final HashSet<String> missingTemplates = new HashSet<String>();
   54       private boolean freemarkerCaching = false;
   55   
   56       static {
   57           try {
   58               bodyContent = ClassLoaderUtil.loadClass("javax.servlet.jsp.tagext.BodyContent",
   59                       FreemarkerTemplateEngine.class);
   60           } catch (ClassNotFoundException e) {
   61               // this is OK -- this just means JSP isn't even being used here, which is perfectly fine.
   62               // we need this class in environments that use JSP to know when to wrap the writer
   63               // and ignore flush() calls. In JSP, it is illegal for a BodyContent writer to be flushed(),
   64               // so we have to take caution here.
   65           }
   66       }
   67   
   68       private static final Log LOG = LogFactory.getLog(FreemarkerTemplateEngine.class);
   69   
   70       @Inject
   71       public void setFreemarkerManager(FreemarkerManager mgr) {
   72           this.freemarkerManager = mgr;
   73       }
   74       
   75       public void renderTemplate(TemplateRenderingContext templateContext) throws Exception {
   76           // get the various items required from the stack
   77           ValueStack stack = templateContext.getStack();
   78           Map context = stack.getContext();
   79           ServletContext servletContext = (ServletContext) context.get(ServletActionContext.SERVLET_CONTEXT);
   80           HttpServletRequest req = (HttpServletRequest) context.get(ServletActionContext.HTTP_REQUEST);
   81           HttpServletResponse res = (HttpServletResponse) context.get(ServletActionContext.HTTP_RESPONSE);
   82   
   83           // prepare freemarker
   84           Configuration config = freemarkerManager.getConfiguration(servletContext);
   85   
   86           // get the list of templates we can use
   87           List<Template> templates = templateContext.getTemplate().getPossibleTemplates(this);
   88   
   89           // find the right template
   90           freemarker.template.Template template = null;
   91           String templateName = null;
   92           Exception exception = null;
   93           for (Template t : templates) {
   94               templateName = getFinalTemplateName(t);
   95               if (freemarkerCaching) {
   96                   if (!isTemplateMissing(templateName)) {
   97                       try {
   98                           template = findInCache(templateName);  // look in cache first
   99                           if (template == null) {
  100                               // try to load, and if it works, stop at the first one
  101                               template = config.getTemplate(templateName);
  102                               addToCache(templateName, template);
  103                           }
  104                           break;
  105                       } catch (IOException e) {
  106                           addToMissingTemplateCache(templateName);
  107                           if (exception == null) {
  108                               exception = e;
  109                           }
  110                       }
  111                   }
  112               } else {
  113                   try {
  114                       // try to load, and if it works, stop at the first one
  115                       template = config.getTemplate(templateName);
  116                       break;
  117                   } catch (IOException e) {
  118                       if (exception == null) {
  119                           exception = e;
  120                       }
  121                   }
  122               }
  123           }
  124   
  125           if (template == null) {
  126               LOG.error("Could not load template " + templateContext.getTemplate());
  127               if (exception != null) {
  128                   throw exception;
  129               } else {
  130                   return;
  131               }
  132           }
  133   
  134           if (LOG.isDebugEnabled()) {
  135               LOG.debug("Rendering template " + templateName);
  136           }
  137   
  138           ActionInvocation ai = ActionContext.getContext().getActionInvocation();
  139   
  140           Object action = (ai == null) ? null : ai.getAction();
  141           SimpleHash model = freemarkerManager.buildTemplateModel(stack, action, servletContext, req, res, config.getObjectWrapper());
  142   
  143           model.put("tag", templateContext.getTag());
  144           model.put("themeProperties", getThemeProps(templateContext.getTemplate()));
  145   
  146           // the BodyContent JSP writer doesn't like it when FM flushes automatically --
  147           // so let's just not do it (it will be flushed eventually anyway)
  148           Writer writer = templateContext.getWriter();
  149           if (bodyContent != null && bodyContent.isAssignableFrom(writer.getClass())) {
  150               final Writer wrapped = writer;
  151               writer = new Writer() {
  152                   public void write(char cbuf[], int off, int len) throws IOException {
  153                       wrapped.write(cbuf, off, len);
  154                   }
  155   
  156                   public void flush() throws IOException {
  157                       // nothing!
  158                   }
  159   
  160                   public void close() throws IOException {
  161                       wrapped.close();
  162                   }
  163               };
  164           }
  165   
  166           try {
  167               stack.push(templateContext.getTag());
  168               template.process(model, writer);
  169           } finally {
  170               stack.pop();
  171           }
  172       }
  173   
  174       protected String getSuffix() {
  175           return "ftl";
  176       }
  177   
  178       protected void addToMissingTemplateCache(String templateName) {
  179           synchronized(missingTemplates) {
  180               missingTemplates.add(templateName);
  181           }
  182       }
  183   
  184       protected boolean isTemplateMissing(String templateName) {
  185           synchronized(missingTemplates) {
  186               return missingTemplates.contains(templateName);
  187           }
  188       }
  189   
  190       protected void addToCache(String templateName,
  191           freemarker.template.Template template) {
  192           synchronized(templates) {
  193               templates.put(templateName, template);
  194           }
  195       }
  196   
  197       protected freemarker.template.Template findInCache(String templateName) {
  198           synchronized(templates) {
  199               return templates.get(templateName);
  200           }
  201       }
  202   
  203       /**
  204        * Enables or disables Struts caching of Freemarker templates. By default disabled.
  205        * Set struts.freemarker.templatesCache=true to enable cache
  206        * @param cacheTemplates "true" if the template engine should cache freemarker template
  207        * internally
  208        */
  209       @Inject(StrutsConstants.STRUTS_FREEMARKER_TEMPLATES_CACHE)
  210       public void setCacheTemplates(String cacheTemplates) {
  211           freemarkerCaching = "true".equals(cacheTemplates);
  212       }
  213   }

Save This Page
Home » struts-2.0.11.2-src » org.apache » struts2 » components » template » [javadoc | source]