View Javadoc
1   /*
2    * $Source$
3    * $Revision$
4    *
5    * Copyright (C) 2006 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   *     http://paneris.org/~timp
43   */
44  
45  package org.melati.template;
46  
47  import java.text.DateFormat;
48  
49  import org.melati.Melati;
50  import org.melati.poem.Field;
51  import org.melati.poem.PoemLocale;
52  import org.melati.util.MelatiStringWriter;
53  import org.melati.util.MelatiWriter;
54  
55  /**
56   * MarkupLanguage provides a variety of methods for rendering objects in a
57   * template.  
58   *
59   * Each object to be rendered has 3 methods:
60   * 1 - String rendered(Object o) - this will render the object to a String
61   * 2 - void render(Object o) - renders the object to melati.getWriter()
62   * 3 - void render(Object o, MelatiWriter w) - render the object to w.
63   *
64   * When this class was written it was thought that for maximum 
65   * efficiency one should render the object direct to the output stream using
66   * method (2) above.  
67   * However now all but (1) is deprecated. 
68   */
69  
70  public abstract class AbstractMarkupLanguage implements MarkupLanguage {
71  
72    protected TempletLoader templetLoader = null;
73    protected Melati melati = null;
74    protected PoemLocale locale = null;
75  
76    /** The maximum number of field possibilities to render.  */
77    public static final int FIELD_POSSIBILITIES_LIMIT = 10000;
78    /** The maximum number of date field possibilities to render.  */
79    public static final int DATE_FIELD_POSSIBILITIES_LIMIT = 50;
80  
81    private String name;
82  
83    /**
84     * Construct a Markup Language object.
85     *
86     * @param name - the name associated with this markup language.
87     *    This is used to determine where to load
88     *    templates from ie 'html' templates are
89     *    found in the 'html' directory.
90     * @param melati - the melati currently in use
91     * @param templetLoader - the template loader in use
92     *       (taken from org.melati.MelatiConfig.properties)
93     * @param locale - the locale in use
94     *    (taken from org.melati.MelatiConfig.properties)
95     */
96    public AbstractMarkupLanguage(String name,
97                          Melati melati,
98                          TempletLoader templetLoader,
99                          PoemLocale locale) {
100     this.name = name;
101     this.melati = melati;
102     this.templetLoader = templetLoader;
103     this.locale = locale;
104   }
105 
106   /**
107    * Construct a new MarkupLanguage given a new name and an
108    * existing MarkupLanguage.
109    *
110    * @param name - the name of the new MarkupLanguage
111    * @param other - the Markup Language to base this one upon
112    */
113   protected AbstractMarkupLanguage(String name, AbstractMarkupLanguage other) {
114     this(name, other.melati, other.templetLoader, other.locale);
115   }
116 
117   /**
118    * {@inheritDoc}
119    * @see org.melati.template.MarkupLanguage#getName()
120    */
121   public String getName() {
122     return name;
123   }
124 
125   /**
126    * Name and locale.
127    * {@inheritDoc}
128    * @see java.lang.Object#toString()
129    */
130   public String toString() {
131     return getName() + "/" + locale.toString();
132   }
133   
134   private MelatiStringWriter getStringWriter() {
135     return (MelatiStringWriter)melati.getStringWriter();
136   }
137 
138   /**
139    * {@inheritDoc}
140    * @see org.melati.template.MarkupLanguage#rendered(java.lang.String, int)
141    */
142   public String rendered(String s, int limit) {
143     MelatiStringWriter sw = getStringWriter();
144     render(s,limit,sw);
145     return sw.toString();
146   }
147 
148   /**
149    * {@inheritDoc}
150    * @see org.melati.template.MarkupLanguage#rendered(org.melati.poem.Field, int, int)
151    */
152   public String rendered(Field<?> field, int style, int limit)
153       throws TemplateEngineException {
154     MelatiStringWriter sw = getStringWriter();
155     render(field, style, limit, sw);
156     return sw.toString();
157   }
158 
159   /**
160    * {@inheritDoc}
161    * @see org.melati.template.MarkupLanguage#rendered(org.melati.poem.Field, int)
162    */
163   public String rendered(Field<?> field, int style)
164       throws TemplateEngineException {
165     MelatiStringWriter sw = getStringWriter();
166     render(field, style, FIELD_POSSIBILITIES_LIMIT, sw);
167     return sw.toString();
168   }
169 
170   /**
171    * {@inheritDoc}
172    * @see org.melati.template.MarkupLanguage#rendered(java.lang.Object)
173    */
174   public String rendered(Object o) {
175     MelatiStringWriter sw = getStringWriter();
176     if (o instanceof String)
177       render((String)o, sw);
178     else if (o instanceof Field) 
179       render((Field<?>)o, sw);
180     else
181       render(o, sw);
182     return sw.toString();
183   }
184 
185   /**
186    * {@inheritDoc}
187    * @see org.melati.template.MarkupLanguage#renderedMarkup(java.lang.String)
188    */
189   public String renderedMarkup(String s) {
190     MelatiStringWriter sw = getStringWriter();
191     renderMarkup(s, sw);
192     return sw.toString();    
193   }
194 
195   /**
196    * Render a String in a MarkupLanguage specific way, limiting it's length.
197    * Render to a supplied MelatiWriter.
198    *
199    * @param s - the string to be rendered
200    * @param writer - the MelatiWriter to render this String to
201    * @param limit - the length to trim the string to
202    */
203   protected void render(String s, int limit, MelatiWriter writer) {
204     render(s.length() < limit + 3 ? s : s.substring(0, limit) + "...", writer);
205   }
206 
207   /**
208    * Render a String in a MarkupLanguage specific way
209    * to a supplied MelatiWriter.
210    *
211    * @param s - the string to be rendered
212    * @param writer - the MelatiWriter to render this String to
213    */
214   protected abstract void render(String s, MelatiWriter writer);
215   
216   /**
217    * Render a markup fragment in a MarkupLanguage specific way
218    * to a supplied MelatiWriter.
219    *
220    * @param s - the fragment to be rendered
221    * @param writer - the MelatiWriter to render this String to
222    */
223   protected abstract void renderMarkup(String s, MelatiWriter writer);
224 
225   /**
226    * Render a Field Object in a MarkupLanguage specific way, 
227    * rendering to supplied MelatiWriter.
228    *
229    * @param field - the Field to be rendered
230    * @param writer - the MelatiWriter to render this Object to
231    */
232   protected void render(Field<?> field, MelatiWriter writer) {
233     render(field, DateFormat.MEDIUM, FIELD_POSSIBILITIES_LIMIT, writer);
234   }
235 
236   /**
237    * Render a Field Object in a MarkupLanguage specific way, 
238    * rendering to supplied MelatiWriter.
239    *
240    * @param field - the Field to be rendered
241    * @param style - a style to format this Field.
242    * @see org.melati.poem.DatePoemType#stringOfCooked
243    *              (java.lang.Object,org.melati.poem.PoemLocale, int)
244    * @param limit - the length to trim the rendered string to
245    * @param writer - the MelatiWriter to render this Object to
246    */
247   protected void render(Field<?> field, int style, int limit, MelatiWriter writer) {
248     render(field.getCookedString(locale, style), limit, writer);
249   }
250 
251 
252   /**
253    * {@inheritDoc}
254    * @see org.melati.template.MarkupLanguage#renderedStart(org.melati.poem.Field)
255    */
256   public String renderedStart(Field<?> field) {
257     MelatiStringWriter sw = getStringWriter();
258     renderStart(field, sw);
259     return sw.toString();
260   }
261   
262 
263   protected void renderStart(Field<?> field, MelatiWriter writer) {
264     render(field, DateFormat.MEDIUM, DATE_FIELD_POSSIBILITIES_LIMIT, writer);
265   }
266 
267   /**
268    * Render an Object in a MarkupLanguage specific way, rendering to
269    * the <code>MelatiWriter</code> supplied by <code>melati.getWriter()</code>.
270    *
271    * @param o - the Object to be rendered
272    * @throws TemplateEngineException - if there is a problem with the
273    *                                   ServletTemplateEngine
274    */
275   protected void render(Object o) {
276     MelatiWriter writer = melati.getWriter();
277     render(o, writer);
278   }
279 
280   /**
281    * Render an Object in a MarkupLanguage specific way, rendering to
282    * a supplied Writer.
283    *
284    * NOTE The context always contains objects with the names melati, object and  ml  
285    *
286    * @param o - the Object to be rendered
287    * @param writer - the MelatiWriter to render this Object to
288    */
289   protected void render(Object o, MelatiWriter writer) {
290     if (o == null)
291       throw new NullPointerException();
292     else {
293         TemplateContext vars =
294           melati.getTemplateEngine().getTemplateContext();
295         Template templet =
296           templetLoader.templet(melati.getTemplateEngine(), this, o.getClass());
297         vars.put("object", o);
298         vars.put("melati", melati);
299         vars.put("ml", melati.getMarkupLanguage());
300         expandTemplet(templet, vars, writer);
301     }
302   }
303 
304 
305   //
306   // =========
307   //  Widgets
308   // =========
309   //
310   
311   /**
312    * {@inheritDoc}
313    * @see org.melati.template.MarkupLanguage#input(org.melati.poem.Field)
314    */
315   public String input(Field<?> field)
316       throws TemplateEngineException,
317              NotFoundException {
318     return input(field, null, "", false);
319   }
320 
321   /**
322    * {@inheritDoc}
323    * @see org.melati.template.MarkupLanguage#inputAs(org.melati.poem.Field, java.lang.String)
324    */
325   public String inputAs(Field<?> field, String templetName)
326       throws TemplateEngineException,
327              NotFoundException {
328     return input(field, templetName, "", false);
329   }
330 
331   /**
332    * {@inheritDoc}
333    * @see org.melati.template.MarkupLanguage#searchInput(org.melati.poem.Field, java.lang.String)
334    */
335   public String searchInput(Field<?> field, String nullValue)
336       throws TemplateEngineException,
337              NotFoundException{
338     return input(field, null, nullValue, true);
339   }
340 
341   protected String input(Field<?> field,
342                          String templetName,
343                          String nullValue,
344                          boolean overrideNullable)
345        throws NotFoundException {
346 
347     Template templet;
348     if (templetName == null) 
349       templet = templetLoader.templet(melati.getTemplateEngine(), this, field) ;
350     else
351       templet = templetLoader.templet(melati.getTemplateEngine(), this, templetName);
352 
353     TemplateContext vars =
354         melati.getTemplateEngine().getTemplateContext();
355 
356     if (overrideNullable) {
357       field = field.withNullable(true);
358       vars.put("nullValue", nullValue);
359     }
360 
361     vars.put("melati", melati);
362     vars.put("ml", melati.getMarkupLanguage());
363     vars.put("object", field);
364     vars.put("field", field);
365     MelatiStringWriter sw = getStringWriter();
366     melati.getTemplateEngine().expandTemplate(sw, templet,vars);
367     
368     return sw.toString(); 
369   }
370 
371   
372   /**
373    * Interpolate a templet and write it out.
374    * 
375    * @param templet {@link Template} to interpolate
376    * @param tc {@link TemplateContext} against which to instantiate variables
377    * @param out {@link MelatiWriter} to write results to 
378    */
379   protected void expandTemplet(Template templet, TemplateContext tc,
380                                MelatiWriter out) {
381     melati.getTemplateEngine().expandTemplate(out, templet, tc);
382   }
383 }
384 
385