View Javadoc
1   /*
2    * $Source$
3    * $Revision$
4    *
5    * Copyright (C) 2012 Tim Pizey
6    *
7    * Part of Melati (http://melati.org), a framework for the rapid
8    * development of clean, maintainable web applications.
9    *
10   * Melati is free software; Permission is granted to copy, distribute
11   * and/or modify this software under the terms either:
12   *
13   * a) the GNU General Public License as published by the Free Software
14   *    Foundation; either version 2 of the License, or (at your option)
15   *    any later version,
16   *
17   *    or
18   *
19   * b) any version of the Melati Software License, as published
20   *    at http://melati.org
21   *
22   * You should have received a copy of the GNU General Public License and
23   * the Melati Software License along with this program;
24   * if not, write to the Free Software Foundation, Inc.,
25   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26   * GNU General Public License and visit http://melati.org to obtain the
27   * Melati Software License.
28   *
29   * Feel free to contact the Developers of Melati (http://melati.org),
30   * if you would like to work out a different arrangement than the options
31   * outlined here.  It is our intention to allow Melati to be used by as
32   * wide an audience as possible.
33   *
34   * This program is distributed in the hope that it will be useful,
35   * but WITHOUT ANY WARRANTY; without even the implied warranty of
36   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37   * GNU General Public License for more details.
38   *
39   * Contact details for copyright holder:
40   *
41   *     Tim Pizey <timp At paneris.org>
42   */
43  package org.melati.template.freemarker;
44  
45  import java.io.FileNotFoundException;
46  import java.util.HashMap;
47  import java.util.Map;
48  
49  import org.apache.velocity.exception.ParseErrorException;
50  import org.apache.velocity.exception.ResourceNotFoundException;
51  import org.melati.poem.AccessPoemException;
52  import org.melati.template.AbstractTemplateEngine;
53  
54  import org.melati.MelatiConfig;
55  import org.melati.template.NotFoundException;
56  import org.melati.template.Template;
57  import org.melati.template.TemplateContext;
58  import org.melati.template.TemplateEngine;
59  import org.melati.template.TemplateEngineException;
60  import org.melati.template.velocity.VelocityTemplate;
61  import org.melati.util.MelatiBugMelatiException;
62  import org.melati.util.MelatiStringWriter;
63  import org.melati.util.MelatiWriter;
64  
65  import freemarker.ext.beans.BeansWrapper;
66  import freemarker.template.Configuration;
67  //import freemarker.template.DefaultObjectWrapper;
68  
69  /**
70   * Wrapper for the Freemarker Template Engine for use with Melati.
71   * @author timp
72   * @since 6 Mar 2012
73   *
74   */
75  public class FreemarkerTemplateEngine extends AbstractTemplateEngine implements TemplateEngine {
76  
77    /** The name of the engine. */
78    public static final String NAME = "freemarker";
79    
80    private Configuration config;
81  
82    /**
83     * @see org.melati.template.TemplateEngine#init(org.melati.MelatiConfig)
84     */
85    @Override
86    public void init(MelatiConfig melatiConfig) throws TemplateEngineException {
87      try {
88        config = new Configuration();
89        config.setClassForTemplateLoading(this.getClass(), "/"); // note first argument redundant
90        BeansWrapper bw = new BeansWrapper();
91        bw.setExposureLevel(BeansWrapper.EXPOSE_ALL);
92        config.setObjectWrapper(bw);
93        //config.setObjectWrapper(new DefaultObjectWrapper());
94      } catch (Exception e) {
95        throw new TemplateEngineException(e);
96      }
97  
98    }
99  
100   /**
101    * @see org.melati.template.TemplateEngine#getTemplateContext()
102    */
103   @Override
104   public TemplateContext getTemplateContext() throws TemplateEngineException {
105     Map<String, Object> context = new HashMap<String, Object>();
106     return new FreemarkerServletTemplateContext(context);
107   }
108 
109   /**
110    * @see org.melati.template.TemplateEngine#getName()
111    */
112   @Override
113   public String getName() {
114     return NAME;
115   }
116 
117   /**
118    * @see org.melati.template.TemplateEngine#templateExtension()
119    */
120   @Override
121   public String templateExtension() {
122     return ".fml";
123   }
124 
125   /**
126    * @see org.melati.template.TemplateEngine#template(java.lang.String)
127    */
128   @Override
129   public Template template(String templateName) throws NotFoundException {
130     freemarker.template.Template t;
131     try {
132       t = config.getTemplate(templateName);
133       return new FreemarkerTemplate(t);
134     } catch (FileNotFoundException e) {
135       if (templateName.endsWith(templateExtension())) {
136         // have a go at loading the velocity template and converting it, 
137         // which may entail its creation from wm
138         String velocityTemplateName = templateName.substring(0, templateName
139             .lastIndexOf(templateExtension()))
140             + ".vm";
141         try {
142           return new VelocityTemplate(velocityTemplateName);
143         } catch (ParseErrorException p) {
144           throw new MelatiBugMelatiException(
145               "Problem converting a Velocity template to a Freemarker template: " + velocityTemplateName,
146               p);
147         } catch (ResourceNotFoundException e2) {
148             throw new NotFoundException("Could not find template " + templateName + " or " + velocityTemplateName);
149         } 
150       } else throw new NotFoundException("Could not find template " + templateName, e);
151     } catch (Exception e) {
152       throw new TemplateEngineException(e);
153     }
154   }
155 
156 
157 
158   /**
159    * @see org.melati.template.TemplateEngine#expandTemplate(org.melati.util.MelatiWriter, java.lang.String, org.melati.template.TemplateContext)
160    */
161   @Override
162   public void expandTemplate(MelatiWriter out, String templateName, TemplateContext templateContext) throws NotFoundException {
163     expandTemplate(out, template(templateName), templateContext);
164   }
165 
166   /**
167    * Expand a {@link org.melati.template.Template} against the context.
168    * 
169    * @param out
170    *        a {@link MelatiWriter} to output on
171    * @param template
172    *        the {@link org.melati.template.Template} to expand
173    * @param templateContext
174    *        the {@link TemplateContext} to expand the template against
175    * @see org.melati.template.TemplateEngine#expandTemplate(org.melati.util.MelatiWriter, org.melati.template.Template, org.melati.template.TemplateContext)
176    */
177   @Override
178   public void expandTemplate(MelatiWriter out, Template template, TemplateContext templateContext) {
179     try {
180       template.write(out, templateContext);
181     } catch (TemplateEngineException problem) {
182       Exception underlying = problem.subException;
183       if (underlying instanceof AccessPoemException) {
184         throw (AccessPoemException)underlying;
185       }
186       throw problem;
187     } 
188 
189   }
190 
191   /**
192    * @see org.melati.template.TemplateEngine#expandedTemplate(org.melati.template.Template, org.melati.template.TemplateContext)
193    */
194   @Override
195   public String expandedTemplate(Template template, TemplateContext templateContext) {
196     MelatiStringWriter s = new MelatiStringWriter();
197     expandTemplate(s, template, templateContext);
198     return s.toString();
199   }
200 
201   /**
202    * @see org.melati.template.TemplateEngine#getStringWriter()
203    */
204   @Override
205   public MelatiStringWriter getStringWriter() {
206     return new MelatiStringWriter();
207   }
208 
209   /**
210    * Get the underlying engine.
211    * Only used by WebMacro, deprecated.
212    * 
213    * @see org.melati.template.TemplateEngine#getEngine()
214    * @return null - for Freemarker we do not expose this
215    */
216   @Override
217   public Object getEngine() {
218     return null;
219   }
220 
221 }