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   /**
187    * Render a String in a MarkupLanguage specific way, limiting it's length.
188    * Render to a supplied MelatiWriter.
189    *
190    * @param s - the string to be rendered
191    * @param writer - the MelatiWriter to render this String to
192    * @param limit - the lenght to trim the string to
193    * @throws IOException - if there is a problem during rendering
194    */
195   protected void render(String s, int limit, MelatiWriter writer)
196       throws IOException {
197     render(s.length() < limit + 3 ? s : s.substring(0, limit) + "...", writer);
198   }
199 
200   /**
201    * Render a String in a MarkupLanguage specific way
202    * to a supplied MelatiWriter.
203    *
204    * @param s - the string to be rendered
205    * @param writer - the MelatiWriter to render this String to
206    * @throws IOException - if there is a problem during rendering
207    */
208   protected abstract void render(String s, MelatiWriter writer) throws IOException;
209 
210   /**
211    * Render a Field Object in a MarkupLanguage specific way, 
212    * rendering to supplied MelatiWriter.
213    *
214    * @param field - the Field to be rendered
215    * @param writer - the MelatiWriter to render this Object to
216    * @throws IOException - if there is a problem during rendering
217    */
218   protected void render(Field field, MelatiWriter writer) throws IOException {
219     render(field, DateFormat.MEDIUM, FIELD_POSSIBILITIES_LIMIT, writer);
220   }
221 
222   /**
223    * Render a Field Object in a MarkupLanguage specific way, 
224    * rendering to supplied MelatiWriter.
225    *
226    * @param field - the Field to be rendered
227    * @param style - a style to format this Field.
228    * @see org.melati.poem.DatePoemType#stringOfCooked
229    *              (java.lang.Object,org.melati.poem.PoemLocale, int)
230    * @param limit - the length to trim the rendered string to
231    * @param writer - the MelatiWriter to render this Object to
232    * @throws IOException - if there is a problem during rendering
233    */
234   protected void render(Field field, int style, int limit, MelatiWriter writer)
235       throws IOException {
236     render(field.getCookedString(locale, style), limit, writer);
237   }
238 
239 
240   /**
241    * {@inheritDoc}
242    * @see org.melati.template.MarkupLanguage#renderedStart(org.melati.poem.Field)
243    */
244   public String renderedStart(Field field)
245       throws IOException {
246     MelatiStringWriter sw = getStringWriter();
247     renderStart(field, sw);
248     return sw.toString();
249   }
250 
251 
252   protected void renderStart(Field field, MelatiWriter writer)
253       throws IOException {
254     render(field, DateFormat.MEDIUM, 50, writer);
255   }
256 
257   /**
258    * Render an Object in a MarkupLanguage specific way, rendering to
259    * the <code>MelatiWriter</code> supplied by <code>melati.getWriter()</code>.
260    *
261    * @param o - the Object to be rendered
262    * @throws IOException - if there is a problem during rendering
263    * @throws TemplateEngineException - if there is a problem with the
264    *                                   ServletTemplateEngine
265    */
266   protected void render(Object o) throws IOException {
267     MelatiWriter writer = melati.getWriter();
268     render(o, writer);
269   }
270 
271   /**
272    * Render an Object in a MarkupLanguage specific way, rendering to
273    * a supplied Writer.
274    *
275    * NOTE The context always contains objects with the names melati, object and  ml  
276    *
277    * @param o - the Object to be rendered
278    * @param writer - the MelatiWriter to render this Object to
279    */
280   protected void render(Object o, MelatiWriter writer) throws IOException {
281     if (o == null)
282       throw new NullPointerException();
283     else {
284         TemplateContext vars =
285           melati.getTemplateEngine().getTemplateContext(melati);
286         Template templet =
287           templetLoader.templet(melati.getTemplateEngine(), this, o.getClass());
288         vars.put("object", o);
289         // Not happy but 
290         if (o instanceof Field) vars.put("field", o);
291         vars.put("melati", melati);
292         vars.put("ml", melati.getMarkupLanguage());
293         expandTemplet(templet, vars, writer);
294     }
295   }
296 
297 
298   //
299   // =========
300   //  Widgets
301   // =========
302   //
303   
304   /**
305    * {@inheritDoc}
306    * @see org.melati.template.MarkupLanguage#input(org.melati.poem.Field)
307    */
308   public String input(Field field)
309       throws TemplateEngineException,
310              IOException, NotFoundException {
311     return input(field, null, "", false);
312   }
313 
314   /**
315    * {@inheritDoc}
316    * @see org.melati.template.MarkupLanguage#inputAs(org.melati.poem.Field, java.lang.String)
317    */
318   public String inputAs(Field field, String templetName)
319       throws TemplateEngineException,
320              IOException, NotFoundException {
321     return input(field, templetName, "", false);
322   }
323 
324   /**
325    * {@inheritDoc}
326    * @see org.melati.template.MarkupLanguage#searchInput(org.melati.poem.Field, java.lang.String)
327    */
328   public String searchInput(Field field, String nullValue)
329       throws TemplateEngineException,
330              IOException, NotFoundException{
331     return input(field, null, nullValue, true);
332   }
333 
334   protected String input(Field field,
335                          String templetName,
336                          String nullValue,
337                          boolean overrideNullable)
338        throws IOException, NotFoundException {
339 
340     Template templet;
341     templet =
342       templetName == null ?
343         templetLoader.templet(melati.getTemplateEngine(), this, field) :
344         templetLoader.templet(melati.getTemplateEngine(), this, templetName);
345 
346     TemplateContext vars =
347         melati.getTemplateEngine().getTemplateContext(melati);
348 
349     if (overrideNullable) {
350       field = field.withNullable(true);
351       vars.put("nullValue", nullValue);
352     }
353 
354     vars.put("melati", melati);
355     vars.put("ml", melati.getMarkupLanguage());
356     vars.put("object", field);
357     vars.put("field", field);
358     MelatiStringWriter sw = getStringWriter();
359     melati.getTemplateEngine().expandTemplate(sw, templet,vars);
360     
361     return sw.toString(); 
362   }
363 
364   
365   /**
366    * Interpolate a templet and write it out.
367    * 
368    * @param templet {@link Template} to interpolate
369    * @param tc {@link TemplateContext} against which to instantiate variables
370    * @param out {@link MelatiWriter} to write results to 
371    * @throws TemplateEngineException if something unexpected happens
372    */
373   protected void expandTemplet(Template templet, TemplateContext tc,
374                                MelatiWriter out) throws IOException {
375     melati.getTemplateEngine().expandTemplate(out, templet, tc);
376   }
377 }
378 
379