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