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