KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > dinamica > TemplateEngine


1 package dinamica;
2
3 import java.text.MessageFormat JavaDoc;
4 import java.util.ArrayList JavaDoc;
5 import java.util.HashMap JavaDoc;
6 import java.util.Iterator JavaDoc;
7 import java.io.PrintWriter JavaDoc;
8 import java.net.URLEncoder JavaDoc;
9 import java.sql.Types JavaDoc;
10 import javax.servlet.RequestDispatcher JavaDoc;
11 import javax.servlet.ServletContext JavaDoc;
12 import javax.servlet.http.*;
13 import java.util.Locale JavaDoc;
14 import electric.xml.*;
15
16 /**
17  * Core-level framework class: Text Generator.
18  * <br><br>
19  * Generates text output (html, xml, sql, etc) given
20  * a template with some special markers that will be replaced
21  * by data (supplied from recordsets). This class is used by the MVC mechanism of this framework
22  * and for general purpose text management.
23  * <br><br>
24  * This is a very powerfull class, it can generate html forms
25  * with its values ready to be edited, whole tables with one line
26  * of code, complete well written, portable SQL statements with one line of code,
27  * no matter how many fields or the type of each field, the statement will
28  * be formatted appropiately, without programmer effort.
29  * <br><br>
30  * It helps to COMPLETELY separate content from presentation, the
31  * templates are dynamically loaded and some labels are replaced with
32  * data provided by recordsets using very simple and effective logic.
33  * <br><br>
34  * Markers are represented by:
35  * <li> Field Markers: ${fld:FieldName}
36  * <li> Default Values Markers: ${def:DefaultValueName}
37  * <li> Sequence Markers: ${seq:nextval@SequenceName} - ${seq:currval@SequenceName}. This markers allows cross-database sequence expressions, the generation
38  * of the actual SEQUENCE SQL expression is determined by context parameters in WEB.XML (sequence-nextval and sequence-currval).
39  *
40  * <br><br>
41  * As you can see, the markers distingish themselves by a prefix which
42  * denotes its type of marker (fld, def or seq).
43  * <br><br>
44  * Field Markers can have an additional attribute (not valid for SQL generation)
45  * representing the output format, using any valid Java mask for dates and numbers.
46  * Example: {fld:FieldName@mask} - where "mask" would be the output format mask.<br>
47  * <br><br>
48  * Repeating blocks can also be generated and are conmmonly used for
49  * printing tables or filling HTML SELECT controls (ComboBox/ListBox). Example:
50  * <pre>
51  * &ltrepeat&gt
52  * &lttr&gt
53  * &lttd&gt${fld:col_1}&lt/td&gt
54  * &lttd>${fld:col_2}&lt/td&gt
55  * &lt/tr&gt
56  * &lt/repeat&gt
57  * </pre>
58  *
59  * This can be replaced using one line of code with the data
60  * values of each record in a recordset, default formats are applied
61  * unless you specify an output format for a specific field. Default formats
62  * are configured in WEB.XML, as context parameters (def-format-date and def-format-double).
63  * <br><br>
64  * This class also supports two advanced features: Special markers for <b>dynamic labes</b> ${lbl:KeyName} which are replaced
65  * according to a pre-selected language (ES, EN, IT, etc), this allows multi-language templates, and
66  * also supports <b>includes</b>, the ability to dynamically include the output of another MVC transaction, which allows
67  * composition of pages from smaller parts, using a special marker: ${inc:ModuleName}
68  * <br><br>
69  * Please consult the How-to documentation to learn all about this class and its
70  * role inside the framework.
71  * <br><br>
72  * Context parameters in WEB.XML used by this class:
73  * <xmp>
74  * <context-param>
75  * <param-name>def-format-date</param-name>
76  * <param-value>dd-MM-yyyy</param-value>
77  * <description>default format for dates</description>
78  * </context-param>
79  *
80  * <context-param>
81  * <param-name>sequence-nextval</param-name>
82  * <param-value>${seq}.NEXTVAL</param-value>
83  * <description>SQL expression to obtain the next sequence value - sequence name will be ${seq}</description>
84  * </context-param>
85  *
86  * <context-param>
87  * <param-name>sequence-currval</param-name>
88  * <param-value>${seq}.CURRVAL</param-value>
89  * <description>SQL expression to obtain the current sequence value - sequence name will be ${seq}</description>
90  * </context-param>
91  * </xmp>
92  *
93  * Creation date: 18/09/2003<br>
94  * Last Update: 18/09/2003<br>
95  * (c) 2003 Martin Cordova<br>
96  * This code is released under the LGPL license<br>
97  * @author Martin Cordova
98  */

99 public class TemplateEngine
100 {
101
102     /** template text */
103     private String JavaDoc _template = "";
104     
105
106     /** servlet request - used to generate many default values related to the request */
107     private HttpServletRequest _req = null;
108     
109     /** servlet context - used to read configuration from the context */
110     private ServletContext JavaDoc _ctx = null;
111     
112     /** custom defined Locale used for format masks in dates and numbers */
113     private Locale JavaDoc _locale = null;
114
115     /** callback object that implements the interface IRowEvent */
116     private IRowEvent _rowEvent = null;
117
118     /** template encoding -if available- */
119     private String JavaDoc _encoding = null;
120
121     /**
122      * Set template encoding - for information purporses only
123      * @param encoding Canonical name of character encoding (ISO-8859-1, etc)
124      */

125     public void setEncoding(String JavaDoc encoding)
126     {
127         _encoding = encoding;
128     }
129
130     /**
131      * Set reference to callback object that
132      * implements the IRowEvent interface
133      * @param obj Object that implements the IRowEvent interface
134      */

135     public void setRowEventObject(IRowEvent obj)
136     {
137         _rowEvent = obj;
138     }
139
140     /**
141      * Set custom LOCALE for formatting
142      * @param l Locale object
143      */

144     public void setLocale(Locale JavaDoc l) throws Throwable JavaDoc
145     {
146         _locale = l;
147         replaceLabels();
148     }
149
150     /**
151      * Set servlet request reference
152      * @param req HTTP Servlet Request object
153      */

154     public void setRequest(HttpServletRequest req)
155     {
156         _req = req;
157     }
158
159     /**
160      * Servlet oriented constructor
161      * @param ctx Servlet Context - will be used to read context parameters.
162      * @param req Servlet Request - will be used to produce default values, like userid or remote_addr.
163      * @param template Text template with markers
164      * @throws Throwable
165      */

166     public TemplateEngine(ServletContext JavaDoc ctx, HttpServletRequest req, String JavaDoc template)
167     {
168         _template = template;
169         _ctx = ctx;
170         _req = req;
171         
172         //patch june-28-2004 -avoid unnecessary replace calls for repeat sections
173
try {
174             replaceDefaultValues();
175             if (_req!=null && _ctx!=null) {
176                 replaceSessionAttributes();
177                 replaceRequestAttributes();
178             }
179         } catch (Throwable JavaDoc e) {}
180         
181     }
182
183     /**
184      * Generates SQL using the recordset values from the current record,
185      * substitutes the field markers with properly formatted values. Saves a lot
186      * of work with only one line of code. This method is smart enough as to generate
187      * well formatted values for Strings and portable formats for dates and timestamps,
188      * using the date/timestamp canonical syntax. Also special characters like single quote (') in
189      * Strings will be correctly escaped to avoid SQL syntax errors or SQL injection attacks.
190      * <br><br>
191      * This object must be created using a SQL template containing markers like ${fld:FieldName}, ${def:date} or ${seq:nextval@SeqName}
192      * @param rs Recordset containing at least one record, the record position must be valid
193      * @return Well formatted SQL with all the markers replaced by the corresponding values (only fld, def and seq markers are considered, no format masks allowed)
194      * @throws Throwable
195      */

196     public String JavaDoc getSql(Recordset rs) throws Throwable JavaDoc
197     {
198         
199         try
200         {
201         
202             if (rs!=null)
203             {
204                 /* get recordset metadata */
205                 HashMap JavaDoc flds = rs.getFields();
206             
207                 /* for each field try to replace value */
208                 Iterator JavaDoc i = flds.values().iterator();
209                 while (i.hasNext())
210                 {
211                 
212                     RecordsetField f = (RecordsetField)i.next();
213                     String JavaDoc fname = f.getName();
214                     Object JavaDoc value = rs.getValue(fname);
215                     String JavaDoc marker = "${fld:" + fname + "}";
216                 
217                     if (value==null)
218                     {
219                         _template = StringUtil.replace(_template, marker, "NULL");
220                     }
221                     else
222                     {
223                         switch (f.getType())
224                         {
225                             case Types.VARCHAR:
226                             case Types.CHAR:
227                             case Types.LONGVARCHAR:
228                                 String JavaDoc v = (String JavaDoc)value;
229                                 v = StringUtil.replace(v,"'","''");
230                                 _template = StringUtil.replace(_template, marker, "'" + v + "'");
231                                 break;
232                             
233                             case Types.DATE:
234                                 java.util.Date JavaDoc d = (java.util.Date JavaDoc)value;
235                                 _template = StringUtil.replace(_template, marker, "{d '" + StringUtil.formatDate(d, "yyyy-MM-dd") + "'}");
236                                 break;
237                             
238                             case Types.TIMESTAMP:
239                                 java.util.Date JavaDoc d1 = (java.util.Date JavaDoc)value;
240                                 _template = StringUtil.replace(_template, marker, "{ts '" + StringUtil.formatDate(d1, "yyyy-MM-dd HH:mm:ss:SSS") + "'}");
241                                 break;
242                             
243                             default:
244                                 String JavaDoc n = String.valueOf(value);
245                                 _template = StringUtil.replace(_template, marker, n);
246                                 break;
247                                 
248                         }
249                     }
250                 
251                 }
252             }
253                     
254             /* replace default values */
255             replaceDefaultValues();
256         
257             /* replace SEQUENCE and request/session markers */
258             if (_ctx!=null)
259             {
260                 replaceRequestAttributes();
261                 replaceSessionAttributes();
262                 
263                 ArrayList JavaDoc seqs = getMarkers("seq");
264         
265                 /* for each field marker set value */
266                 Iterator JavaDoc is = seqs.iterator();
267                 while (is.hasNext())
268                 {
269                     /* get next marker */
270                     Marker m = (Marker)is.next();
271                     String JavaDoc seqType = m.getName(); //sequence mode (nextval|currval)
272
String JavaDoc seqName = m.getExtraInfo(); //sequence object name
273
String JavaDoc marker = "${seq:" + seqType + "@" + seqName + "}";
274             
275                     /* get sequence configuration from context */
276                     String JavaDoc seqConfigParam = "sequence-" + seqType;
277                     String JavaDoc seqExpr = _ctx.getInitParameter(seqConfigParam);
278                 
279                     /* throw error if config not found */
280                     if (seqExpr==null || seqExpr.equals(""))
281                     {
282                         String JavaDoc args[] = {marker};
283                         String JavaDoc msg = Errors.SEQUENCE_BAD_CONFIGURATION;
284                         msg = MessageFormat.format(msg, args);
285                         throw new Throwable JavaDoc(msg);
286                     }
287                             
288                     /* replace sequence expression */
289                     String JavaDoc value = "";
290                     
291                     //patch for Resin 3.0.6 - Feb26-2004
292
if (seqExpr.indexOf("${seq}")<0)
293                         value = StringUtil.replace(seqExpr, "$[seq]", seqName);
294                     else
295                         value = StringUtil.replace(seqExpr, "${seq}", seqName);
296                     //end patch
297

298                     _template = StringUtil.replace(_template, marker, value);
299             
300                 }
301             }
302                 
303             return _template;
304         }
305         catch (Throwable JavaDoc e)
306         {
307             String JavaDoc msg = "[TemplateEngine].\n Template:" + _template + "\n";
308             String JavaDoc data = "";
309             if (rs!=null)
310             {
311                 data = rs.toString();
312                 System.err.println(msg + data);
313             }
314             throw e;
315         }
316          
317     }
318     
319     /**
320      * Replace default values present in the template, default values
321      * are special markers expressed in the form: ${def:valueName}<br>
322      * Implemented defaults are:<br>
323      * <li>${def:user} - HttpServletRequest.getPrincipal().getUserName(). If the user is not authenticated then returns an empty string ""
324      * <li>${def:date} - yyyy-MM-dd
325      * <li>${def:time} - HH:mm:ss
326      * <li>${def:timestamp} - yyyy-MM-dd HH:mm:ss:SSS
327      * <li>${def:host} - HttpServletRequest.getServerName()
328      * <li>${def:context} - HttpServletRequest.getContextPath()
329      * <li>${def:remoteaddr} - HttpServletRequest.getRemoteAddr()
330      * <li>${def:uri} - HttpServletRequest.getRequestURI()
331      * <li>${def:dateDMY} - dd-MM-yyyy
332      * <li>${def:dateMDY} - MM-dd-yyyy
333      * <br>
334      * All values extracted from HttpServletRequest will be replaced
335      * by an empty string "" if the request object is null. Use the method
336      * setRequest() to set the request object or the special constructor
337      * TemplateEngine(ServletContext ctx, HttpServletRequest req, String t) if you want to set
338      * the request object.
339      * <br>
340      * Default values can be used in every kind of template, SQL, HTML, XML, etc.
341      */

342     public void replaceDefaultValues() throws Throwable JavaDoc
343     {
344         
345         //patch june-22-2004 don't waste time
346
if (_template.indexOf("${def:")< 0 )
347             return;
348         
349         String JavaDoc markers[] = {
350                             "${def:user}",
351                             "${def:date}",
352                             "${def:time}",
353                             "${def:timestamp}",
354                             "${def:host}",
355                             "${def:context}",
356                             "${def:remoteaddr}",
357                             "${def:uri}",
358                             "${def:dateDMY}",
359                             "${def:dateMDY}",
360                             "${def:actionroot}"
361                             };
362                             
363         String JavaDoc values[] = new String JavaDoc[markers.length];
364         
365         String JavaDoc userid = null;
366         if (_req != null) userid = _req.getRemoteUser();
367         if (userid == null) userid = "";
368
369         java.util.Date JavaDoc d = new java.util.Date JavaDoc();
370         values[0] = userid;
371         values[1] = StringUtil.formatDate(d, "yyyy-MM-dd");
372         values[2] = StringUtil.formatDate(d, "HH:mm:ss");
373         values[3] = StringUtil.formatDate(d, "yyyy-MM-dd HH:mm:ss:SSS");
374         
375         if (_req!=null)
376             values[4] = _req.getServerName(); else values[4] = "";
377
378         if (_req!=null)
379             values[5] = _req.getContextPath(); else values[5] = "";
380
381         if (_req!=null)
382             values[6] = _req.getRemoteAddr(); else values[6] = "";
383
384         if (_req!=null)
385             values[7] = _req.getRequestURI(); else values[7] = "";
386
387         values[8] = StringUtil.formatDate(d, "dd-MM-yyyy");
388         values[9] = StringUtil.formatDate(d, "MM-dd-yyyy");
389
390         if (_req!=null)
391         {
392             String JavaDoc path = (String JavaDoc)_req.getAttribute("dinamica.action.path");
393             path = path.substring(0, path.lastIndexOf("/"));
394             values[10] = path;
395         }
396         else values[10] = "";
397         
398         for (int i=0;i<markers.length;i++)
399         {
400             _template = StringUtil.replace(_template,markers[i],values[i]);
401         }
402         
403     }
404     
405     /**
406      * Return current state of the internal template
407      */

408     public String JavaDoc toString()
409     {
410         return _template;
411     }
412
413     /**
414      * Returns a list of markers of a given type
415      * @param prefix The type of marker (fld, lbl, inc, seq)
416      * @return ArrayList containing Marker objects
417      * @throws Throwable
418      */

419     public ArrayList JavaDoc getMarkers(String JavaDoc prefix) throws Throwable JavaDoc
420     {
421         
422         /* test precondition */
423         if (prefix.length()!=3)
424         {
425             String JavaDoc args[] = {prefix};
426             String JavaDoc msg = Errors.INVALID_PREFIX;
427             msg = MessageFormat.format(msg, args);
428             throw new Throwable JavaDoc(msg);
429         }
430         
431         int pos = 0;
432         ArrayList JavaDoc l = new ArrayList JavaDoc();
433         
434         /* search markers */
435         while ( pos >= 0 )
436         {
437             int pos1 = 0;
438             int pos2 = 0;
439             int newPos = 0;
440             
441             /* find start of marker */
442             pos1 = _template.indexOf("${" + prefix + ":", pos);
443             if (pos1>=0)
444             {
445                 
446                 /* find end of marker */
447                 newPos = pos1 + 6;
448                 pos2 = _template.indexOf("}", newPos);
449                 
450                 if (pos2>0)
451                 {
452                     
453                     /* get marker string */
454                     String JavaDoc fld = _template.substring(newPos, pos2);
455                     Marker m = new Marker(fld,null,pos1,pos2);
456                     
457                     /* search for etra attribute (format or sequence name) */
458                     int pos3 = fld.indexOf("@");
459                     if (pos3>0)
460                     {
461                         
462                         String JavaDoc name = fld.substring(0, pos3);
463                         String JavaDoc extraInfo = fld.substring(pos3 + 1, fld.length());
464                         
465                         if ( (name.indexOf(" ")>=0) || (name.indexOf("\r")>=0) || (name.indexOf("\n")>=0) || (name.indexOf('\t')>=0) )
466                         {
467                             String JavaDoc args[] = {name};
468                             String JavaDoc msg = Errors.INVALID_MARKER;
469                             msg = MessageFormat.format(msg, args);
470                             throw new Throwable JavaDoc(msg);
471                         }
472
473
474                         m.setName(name);
475                         m.setExtraInfo(extraInfo);
476                     }
477                     
478                     l.add(m);
479                 }
480                 else
481                 {
482                     throw new Throwable JavaDoc( Errors.MARKER_UNCLOSED );
483                 }
484                 pos = pos2 + 1;
485             }
486             else
487             {
488                 pos = -1;
489             }
490         }
491         
492         return l;
493         
494     }
495
496     /**
497      * Replace all possible field markers with corresponding
498      * recordset field values from current record. This method
499      * is mainly used to populate forms
500      * @param rs Recordset with a valid record position
501      * @param nullValueExpr The string to represent null values ("" or &ampnbsp;)
502      * @throws Throwable
503      */

504     public void replace(Recordset rs, String JavaDoc nullValueExpr) throws Throwable JavaDoc
505     {
506         
507         /* parse the template and create list of field markers */
508         ArrayList JavaDoc flds = getMarkers("fld");
509
510         /* call internal replace method */
511         replace(rs, nullValueExpr, flds);
512         
513     }
514
515     /**
516      * Navigate all the recordset and replace the
517      * values of each record. This method is used to produce
518      * tables or fill controls like ComboBoxes or ListBoxes. It is
519      * suitable for any section of the template that must be repeated
520      * as many times as records are in the recordset
521      *
522      * @param rs Recordset
523      * @param nullValueExpr The string to represent null values ("" or &ampnbsp;) - when generating html tables it should be &ampnbsp;
524      * @param RepeatSectionTag A custom tag that encloses the repeatable section
525      * @throws Throwable
526      */

527     public void replace(Recordset rs, String JavaDoc nullValueExpr, String JavaDoc repeatSectionTag) throws Throwable JavaDoc
528     {
529         
530         dinamica.parser.FastTemplateEngine fte = new dinamica.parser.FastTemplateEngine();
531         
532         String JavaDoc section = null;
533         String JavaDoc repeatTemplate = null;
534         int pos1 = 0;
535         int pos2 = 0;
536         
537         String JavaDoc tagStart = "<" + repeatSectionTag + ">";
538         String JavaDoc tagEnd = "</" + repeatSectionTag + ">";
539         
540         /* find start of repeat section */
541         pos1 = _template.indexOf(tagStart);
542         if (pos1>=0)
543         {
544                 
545             /* find end of repeat section */
546             int newPos = pos1 + tagStart.length();
547             pos2 = _template.indexOf(tagEnd, newPos);
548                 
549             if (pos2>0)
550             {
551                 /* get section string */
552                 section = _template.substring(pos1, pos2 + tagEnd.length());
553                 repeatTemplate = _template.substring(newPos, pos2);
554
555                 /* buffer to contain generated text */
556                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
557                 
558                 /* navigate all recordset */
559                 if (rs.getRecordCount()>0)
560                 {
561                     
562                     // fast template engine
563
fte.setTemplate(repeatTemplate);
564                     ArrayList JavaDoc markers = fte.getMarkers();
565                     
566                     // rewind recordset
567
rs.top();
568                     
569                     /* for each record */
570                     while (rs.next())
571                     {
572                         
573                         setValues(fte, markers, rs, nullValueExpr);
574                         
575                         // get row
576
String JavaDoc row = fte.toString();
577                         
578                         /* row event available? */
579                         if (_rowEvent!=null)
580                         {
581                             row = _rowEvent.onNewRow( rs, row );
582                         }
583                             
584                         
585                         // append text
586
buf.append(row);
587                         
588                     }
589                     _template = StringUtil.replace(_template, section, buf.toString());
590                 }
591                 else
592                 {
593                     _template = StringUtil.replace(_template, section, "");
594                 }
595                 
596             }
597             else
598             {
599                 String JavaDoc args[] = {repeatSectionTag};
600                 String JavaDoc msg = Errors.REPEAT_TAG_NOT_CLOSED;
601                 msg = MessageFormat.format(msg, args);
602                 throw new Throwable JavaDoc(msg);
603             }
604
605         }
606         else
607         {
608             String JavaDoc args[] = {repeatSectionTag};
609             String JavaDoc msg = Errors.REPEAT_TAG_NOT_FOUND;
610             msg = MessageFormat.format(msg, args);
611             throw new Throwable JavaDoc(msg);
612         }
613         
614     }
615
616     
617     /**
618      * Internal method that factorizes most of the code
619      * that is common to all the overloaders
620      * @param rs Recordset
621      * @param nullValueExpr The string to represent null values ("" or &ampnbsp;) - when generating html tables it should be &ampnbsp;
622      * @param markers ArrayList containing the field markers
623      * @throws Throwable
624      */

625     void replace(Recordset rs, String JavaDoc nullValueExpr, ArrayList JavaDoc markers) throws Throwable JavaDoc
626     {
627
628         String JavaDoc strValue = null;
629         Object JavaDoc value = null;
630         String JavaDoc toReplace = null;
631         
632         /* get recordset fields */
633         HashMap JavaDoc rsFlds = rs.getFields();
634         
635         /* parse the template and create list of field markers */
636         ArrayList JavaDoc flds = markers;
637         
638         /* for each field marker set value */
639         Iterator JavaDoc i = flds.iterator();
640         while (i.hasNext())
641         {
642
643             String JavaDoc formatPluginName = null;
644             IFormatPlugin fmtObj = null;
645             FormatPluginParser fpp = null;
646
647             /* get next marker */
648             Marker m = (Marker)i.next();
649             String JavaDoc fName = m.getName();
650             String JavaDoc fFormat = m.getExtraInfo();
651             
652             /* determine if it is an special field (rowNumber/rowIndex) otherwise if the field exists */
653             boolean found = true;
654             boolean fakeField = false;
655             if (!fName.equals("_rowNumber") && !fName.equals("_rowIndex"))
656             {
657                 if (!rsFlds.containsKey(fName))
658                     found = false;
659             }
660             else
661             {
662                 fakeField = true;
663             }
664                             
665             
666             /* recordset contains this field? */
667             if (found)
668             {
669                 
670                 String JavaDoc defDateFmt = null;
671                 
672                 /* read default date format */
673                 defDateFmt = _ctx.getInitParameter("def-format-date");
674                 if (defDateFmt==null || defDateFmt.equals(""))
675                     defDateFmt = "dd-MM-yyyy";
676                 
677                 /* rebuild marker to replace by searched and replaced by corresponding value */
678                 if (fFormat!=null)
679                 {
680                     toReplace = "${fld:" + fName + "@" + fFormat + "}";
681                     
682                     //PATCH 2005-05-23 - get plugin name if available
683
if (fFormat.startsWith("class:"))
684                     {
685                         formatPluginName = fFormat.substring(6);
686                         fpp = new FormatPluginParser(formatPluginName);
687                         fmtObj = (IFormatPlugin)Thread.currentThread().getContextClassLoader().loadClass(fpp.getName()).newInstance();
688                     }
689                 }
690                 else
691                     toReplace = "${fld:" + fName + "}";
692                 
693                 /* get field value */
694                 value = rs.getValue(fName);
695                 
696                 //custom format??
697
if (fmtObj!=null)
698                 {
699                     strValue = fmtObj.format(fName, rs, _locale, fpp.getArgs());
700                 }
701                 else
702                 {
703                 
704                     /* apply appropiate null representation */
705                     if (value==null)
706                     {
707                         strValue=nullValueExpr;
708                     }
709                     else
710                     {
711                         
712                         /* get field info */
713                         RecordsetField f = null;
714                         if (!fakeField)
715                             f = (RecordsetField)rsFlds.get(fName);
716                         else
717                             f = new RecordsetField(fName,"INTEGER", Types.INTEGER);
718                             
719                         
720                         /* format value according to data type*/
721                         if (f.getType()!=Types.DATE && f.getType()!=Types.TIMESTAMP )
722                         {
723                             /* format defined? */
724                             if (fFormat==null)
725                             {
726                                 strValue = String.valueOf(value);
727                             }
728                             else
729                             {
730                                 //is a string data type?
731
if (f.getType()==Types.VARCHAR || f.getType()==Types.CHAR || f.getType()==Types.CLOB || f.getType()==Types.LONGVARCHAR)
732                                 {
733                                     if (fFormat.equals("xml"))
734                                     {
735                                         //encode special characters for xml/html output
736
strValue = encodeXML((String JavaDoc)value);
737                                     }
738                                     else if (fFormat.equals("html"))
739                                     {
740                                         //encode special characters for xml/html output
741
strValue = encodeHTML((String JavaDoc)value);
742                                     }
743                                     else if (fFormat.equals("url"))
744                                     {
745                                         //encode special characters for xml/html output
746
strValue = URLEncoder.encode((String JavaDoc)value, "UTF-8");
747                                     }
748                                     else
749                                     {
750                                         throw new Throwable JavaDoc("Invalid format mask for the field:" + fName);
751                                     }
752                                     
753                                 }
754                                 // it is a numeric data type
755
else
756                                 {
757                                         
758                                     if (_locale==null)
759                                         strValue = StringUtil.formatNumber(value, fFormat);
760                                     else
761                                         strValue = StringUtil.formatNumber(value, fFormat, _locale);
762     
763                                 }
764                             }
765                         }
766                         else
767                         {
768                             /* apply default or custom date format? */
769                             if (fFormat==null)
770                                 fFormat = defDateFmt;
771                             if (_locale==null)
772                                 strValue = StringUtil.formatDate((java.util.Date JavaDoc)value, fFormat);
773                             else
774                                 strValue = StringUtil.formatDate((java.util.Date JavaDoc)value, fFormat, _locale);
775                         }
776                         
777                     }
778
779                 }
780                     
781                 /* replace marker with value */
782                 _template = StringUtil.replace(_template,toReplace,strValue);
783                         
784             }
785             
786         }
787
788     }
789
790
791     /**
792      * Replace dynamic labels ${lbl:Name} using the
793      * session locale, which must be indicated using the method
794      * setLocale, otherwise the language code
795      * specified in the context-attribute <b>def-language</b> in WEB.XML will be used
796      * to select the default locale. If none has been properly configured
797      * or the label does not exist for the selected Locale, then
798      * an exception will be triggered. This mechanism uses the label
799      * configuration file stored in /WEB-INF/labels.xml. Please check
800      * the documentation to learn the structure of this file.
801      * Place the appropiate markers and make sure the labels.xml file is properly configured.
802      * In order to use this method, the TemplateEngine must have access to
803      * the ServletContext, so use the appropiate constructor. If there is no
804      * valid reference to the ServletContext, then this method will trigger
805      * an error
806      * @throws Throwable
807      */

808     public void replaceLabels() throws Throwable JavaDoc
809     {
810
811         if (_ctx==null)
812             throw new Throwable JavaDoc("Servlet Context is null - this method can't work without a ServletContext.");
813
814         //patch june-22-2004 don't waste time
815
if (_template.indexOf("${lbl:")< 0 )
816             return;
817
818         /* parse the template and create list of label markers */
819         ArrayList JavaDoc flds = getMarkers("lbl");
820         
821         /* load labels.xml file */
822         String JavaDoc xmlData = StringUtil.getResource(_ctx, "/WEB-INF/labels.xml");
823         
824         /* parse document */
825         Document doc = new Document(xmlData);
826         Element root = doc.getRoot();
827         
828         /* identify locale to be used */
829         String JavaDoc language = null;
830         if (_locale==null)
831             language = _ctx.getInitParameter("def-language");
832         else
833             language = _locale.getLanguage();
834          
835         if (language==null || language.equals(""))
836             throw new Throwable JavaDoc("Language not defined (Locale or default language may be null)");
837         
838         for (int i=0; i<flds.size();i++)
839         {
840             Marker m = (Marker) flds.get(i);
841             String JavaDoc name = m.getName();
842             String JavaDoc label = "${" + "lbl:" + name + "}";
843             _template = StringUtil.replace(_template, label, getLabel(name, root, language));
844         }
845         
846     }
847
848     /**
849      * Lookup a dynamic label value given the language code and the label ID
850      * @param labelName Label ID
851      * @param root The root element of the labels.xml tree
852      * @param language The ISO language code (es, en, it, etc.)
853      * @return The label translation
854      * @throws Throwable if the label ID or the language code are not valid
855      */

856     String JavaDoc getLabel(String JavaDoc labelName, Element root, String JavaDoc language) throws Throwable JavaDoc
857     {
858         
859         /* find label */
860         Element label = root.getElement( new XPath("label[@id='" + labelName + "']"));
861         if (label==null)
862             throw new Throwable JavaDoc ("Label not found: " + labelName);
863         
864         
865         /* find translation for language code */
866         Element translation = label.getElement( new XPath("value[@language='" + language + "']") );
867         if (translation==null)
868             throw new Throwable JavaDoc ("Label translation not found for this language code: " + language);
869         
870         return translation.getString();
871         
872     }
873
874     /**
875      * Split template into segments stored into an array.
876      * A segment may be a printable text or an INCLUDE directive
877      * to include the content of another resource from the same context
878      * @return ArrayList containing TemplateSegment objects
879      * @throws Throwable
880      */

881     ArrayList JavaDoc getSegments() throws Throwable JavaDoc
882     {
883         
884         ArrayList JavaDoc s = new ArrayList JavaDoc();
885         
886         /* get include markers */
887         ArrayList JavaDoc l = getMarkers("inc");
888
889         if (l.size()>0)
890         {
891             int lastPos = 0;
892             for (int i=0; i<l.size();i++)
893             {
894                 /* create segment */
895                 Marker m = (Marker) l.get(i);
896                 TemplateSegment seg1 = new TemplateSegment();
897                 seg1.segmentType = "data";
898                 seg1.segmentData = _template.substring(lastPos, m.getPos1());
899                         
900                 TemplateSegment seg2 = new TemplateSegment();
901                 seg2.segmentType = "inc";
902                 seg2.segmentData = m.getName();
903
904                 lastPos = m.getPos2() + 1;
905             
906                 s.add(seg1);
907                 s.add(seg2);
908             
909             }
910             TemplateSegment seg1 = new TemplateSegment();
911             seg1.segmentType = "data";
912             seg1.segmentData = _template.substring(lastPos);
913             s.add(seg1);
914             
915         }
916         else
917         {
918             
919             TemplateSegment seg = new TemplateSegment();
920             seg.segmentType = "data";
921             seg.segmentData = _template;
922             s.add(seg);
923         }
924         
925         return s;
926     }
927     
928     /**
929      * Print template and process any INCLUDE directive
930      * present into the template; in order to do this the
931      * class required a reference to the ServletContext, Request
932      * and Response, otherwise it can't dispatch to include another servlets.
933      * No writer must be obtained from the Servlet response object
934      * prior to calling this method, because this method will call getWriter() from
935      * the passed Response object.<br>
936      * <br>
937      * <b>NOTE:</b> default values and dynamic labels will be automatically
938      * replaced by this method. This is the preferred way to print a template
939      * to make sure everything is being replaced, the caller is only responsable
940      * for setting the appropiate response headers.
941      * @param res HttpServletResponse
942      * @throws Throwable if the ServletContext reference is null
943      */

944     public void print(HttpServletResponse res) throws Throwable JavaDoc
945     {
946         
947         if (_ctx==null)
948             throw new Throwable JavaDoc("ServletContext is null - can't print template because the request dispatcher must be obtained from the ServletContext.");
949
950         replaceDefaultValues();
951         replaceLabels();
952         replaceRequestAttributes();
953         replaceSessionAttributes();
954         
955         PrintWriter JavaDoc pw = res.getWriter();
956         
957         // patch 28-june-2004 - set content length if no includes are used in this template
958
if (_template.indexOf("${inc:")>=0)
959         {
960             ArrayList JavaDoc s = getSegments();
961             for (int i=0; i<s.size();i++)
962             {
963                 TemplateSegment t = (TemplateSegment)s.get(i);
964                 if (t.segmentType.equals("inc"))
965                 {
966                     RequestDispatcher JavaDoc rd = _ctx.getRequestDispatcher(t.segmentData);
967                     rd.include(_req, res);
968                 }
969                 else
970                 {
971                     pw.print(t.segmentData);
972                 }
973             }
974         }
975         else
976         {
977             //PATCH 2005-02-23 - encoding support
978
byte body[] = null;
979             if (_encoding!=null)
980                 body = _template.getBytes(_encoding);
981             else
982                 body = _template.getBytes();
983                 
984             res.setContentLength(body.length);
985             pw.print(_template);
986         }
987         
988     }
989
990     /**
991      * HTML Control utility method.<br>
992      * Select combobox item for single select combobox. This method
993      * will insert the word "selected" in the appropiate option element
994      * from the corresponding select html control.<br>
995      * <b>NOTE:</b> All html keywords related to the control must be
996      * in lower case, including attributes and tag names. Name and Value lookup
997      * is case sensitive!
998      * @param controlName HTML control name attribute
999      * @param value Option value to search for
1000     * @throws Throwable if can't find control or its closing tag
1001     */

1002    public void setComboValue(String JavaDoc controlName, String JavaDoc value) throws Throwable JavaDoc
1003    {
1004        int pos1 = 0;
1005        int pos2 = 0;
1006        String JavaDoc combo = "";
1007
1008        /* define control to find */
1009        String JavaDoc find = "<select name=\"" + controlName + "\"";
1010        
1011        /* find it */
1012        pos1 = _template.indexOf(find);
1013        
1014        /* found? */
1015        if (pos1>=0)
1016        {
1017            /* extract segment from template */
1018            pos2 = _template.indexOf("</select>", pos1);
1019            if (pos2>0)
1020            {
1021
1022                /* extract */
1023                int newpos2 = pos2 + "</select>".length();
1024                combo = _template.substring(pos1, newpos2);
1025                
1026                /* set item=selected if found */
1027                find = "<option value=\"" + value + "\"";
1028                String JavaDoc newItem = find + " selected ";
1029                String JavaDoc temp = StringUtil.replace(combo, find, newItem);
1030
1031                /* replace into template */
1032                _template = StringUtil.replace(_template, combo, temp);
1033                
1034            }
1035            else
1036            {
1037                throw new Throwable JavaDoc("Can't find closing tag for this HTML control: " + controlName);
1038            }
1039        }
1040        else
1041        {
1042            throw new Throwable JavaDoc("HTML control not found: " + controlName);
1043        }
1044        
1045    }
1046    
1047    /**
1048     * HTML Control utility method.<br>
1049     * Set combobox values for multiple items using a recordset
1050     * to lookup the values from a field and set the corresponding option items
1051     * in the select control. All records from the recordset are used.
1052     * @param controlName Name of the html select control which is also the name
1053     * of the field name to use from the Recordset
1054     * @param rs
1055     * @throws Throwable
1056     */

1057    public void setComboValue(String JavaDoc controlName, Recordset rs) throws Throwable JavaDoc
1058    {
1059        if (rs.getRecordCount()==0)
1060            return;
1061        
1062        rs.top();
1063        while (rs.next())
1064        {
1065            /* reuse setComboValue method */
1066            String JavaDoc value = String.valueOf(rs.getValue(controlName));
1067            setComboValue(controlName, value);
1068        }
1069    }
1070
1071
1072    /**
1073     * HTML Control utility method.<br>
1074     * Select RadioButton control from a group of controls
1075     * using a value to match the appropiate control
1076     * <b>NOTE:</b> All html keywords related to the control must be
1077     * in lower case, including attributes and tag names. Name and Value lookup
1078     * is case sensitive!
1079     * @param controlName HTML control name attribute
1080     * @param value Value to search for
1081     * @throws Throwable if can't find control
1082     */

1083    public void setRadioButton(String JavaDoc controlName, String JavaDoc value) throws Throwable JavaDoc
1084    {
1085
1086        int pos1 = 0;
1087        int pos2 = 0;
1088        String JavaDoc ctrl = "";
1089        int flag = 0;
1090        int pos = 0;
1091    
1092        while (flag >= 0)
1093        {
1094
1095            /* define control to find */
1096            String JavaDoc find = "<input";
1097        
1098            /* find it */
1099            pos1 = _template.indexOf(find,pos);
1100        
1101            /* found? */
1102            if (pos1>=0)
1103            {
1104                flag = 1;
1105                
1106                /* extract segment from template */
1107                pos2 = _template.indexOf(">", pos1);
1108                if (pos2>0)
1109                {
1110
1111                    /* extract */
1112                    int newpos2 = pos2 + ">".length();
1113                    ctrl = _template.substring(pos1, newpos2);
1114                
1115                    /* check to see if this is the requested control */
1116                    find = "name=\"" + controlName + "\"";
1117                    int newpos1 = ctrl.indexOf(find);
1118                
1119                    /* found? this is one of the requested controls! */
1120                    if (newpos1>=0)
1121                    {
1122                        
1123                        /* mark this control as "selected" if its value match */
1124                        find = "value=\"" + value + "\"";
1125                        String JavaDoc newItem = find + " checked ";
1126                        String JavaDoc temp = StringUtil.replace(ctrl, find, newItem);
1127
1128                        /* replace into template */
1129                        if (!temp.equals(ctrl))
1130                        {
1131                            _template = StringUtil.replace(_template, ctrl, temp);
1132                            return;
1133                        }
1134                        else
1135                        {
1136                            ctrl = temp;
1137                        }
1138
1139                    }
1140                    pos = pos1 + ctrl.length();
1141                }
1142                else
1143                {
1144                    throw new Throwable JavaDoc("'input' Tag is not properly closed for this HTML control: " + controlName);
1145                }
1146            }
1147            else
1148            {
1149                flag = -1;
1150            }
1151
1152        }
1153
1154    }
1155
1156    /**
1157     * HTML Control utility method.<br>
1158     * Set checkbox values for multiple items using a recordset
1159     * to lookup the values from a field and set the corresponding checkbox items
1160     * in the checkbox control group. All records from the recordset are used.
1161     * @param controlName Name of the html select control which is also the name
1162     * of the field name to use from the Recordset
1163     * @param rs
1164     * @throws Throwable
1165     */

1166    public void setCheckbox(String JavaDoc controlName, Recordset rs) throws Throwable JavaDoc
1167    {
1168        if (rs.getRecordCount()==0)
1169            return;
1170        
1171        rs.top();
1172        while (rs.next())
1173        {
1174            /* reuse setRadioButton method */
1175            String JavaDoc value = String.valueOf(rs.getValue(controlName));
1176            setRadioButton(controlName, value);
1177        }
1178    }
1179
1180
1181    /**
1182     * Change template body - if necessary, should be called before replacing any data
1183     * because all previous changes will be lost
1184     * @param string New template body
1185     */

1186    public void setTemplate(String JavaDoc string)
1187    {
1188        _template = string;
1189    }
1190
1191    /**
1192     * Returns a Tag body, including the tag markers.
1193     * This is a utility method that may be used by special
1194     * Output modules, like Master/Detail reports that need
1195     * to extract and later replace subsections of a template.
1196     * @param tagName
1197     * @return
1198     * @throws Throwable if tagName is not present in the template
1199     */

1200    public String JavaDoc getTagBody(String JavaDoc tagName) throws Throwable JavaDoc
1201    {
1202
1203        int pos1 = 0;
1204        int pos2 = 0;
1205        
1206        String JavaDoc tagStart = "<" + tagName + ">";
1207        String JavaDoc tagEnd = "</" + tagName + ">";
1208        
1209        /* find start of repeat section */
1210        pos1 = _template.indexOf(tagStart);
1211        if (pos1>=0)
1212        {
1213                
1214            /* find end of repeat section */
1215            int newPos = pos1 + tagStart.length();
1216            pos2 = _template.indexOf(tagEnd, newPos);
1217                
1218            if (pos2>0)
1219            {
1220                /* extract tag body */
1221                return _template.substring(pos1, pos2 + tagEnd.length());
1222            }
1223            else
1224            {
1225                String JavaDoc args[] = {tagName};
1226                String JavaDoc msg = Errors.REPEAT_TAG_NOT_CLOSED;
1227                msg = MessageFormat.format(msg, args);
1228                throw new Throwable JavaDoc(msg);
1229            }
1230
1231        }
1232        else
1233        {
1234            String JavaDoc args[] = {tagName};
1235            String JavaDoc msg = Errors.REPEAT_TAG_NOT_FOUND;
1236            msg = MessageFormat.format(msg, args);
1237            throw new Throwable JavaDoc(msg);
1238        }
1239
1240
1241    }
1242
1243    /**
1244     * Replace field markers representing request attribute values
1245     * like ${req:attributeID}
1246     * @throws Throwable
1247     */

1248    public void replaceRequestAttributes() throws Throwable JavaDoc
1249    {
1250        if (_ctx==null)
1251            throw new Throwable JavaDoc("Servlet Context is null - this method can't work without a ServletContext.");
1252
1253        //patch june-22-2004 don't waste time
1254
if (_template.indexOf("${req:")< 0 )
1255            return;
1256
1257        /* parse the template and create list of label markers */
1258        ArrayList JavaDoc flds = getMarkers("req");
1259        
1260        for (int i=0; i<flds.size();i++)
1261        {
1262            Marker m = (Marker) flds.get(i);
1263            
1264            String JavaDoc name = m.getName();
1265            
1266            //PATCH 2005-04-15 - support for XML/URL encoding
1267
String JavaDoc fmt = m.getExtraInfo();
1268            if (fmt==null)
1269                fmt = "";
1270            else
1271                fmt = "@" + fmt;
1272            String JavaDoc label = "${" + "req:" + name + fmt + "}";
1273            
1274            /* PATCH 2004-12-06 - request markers were
1275             * being eliminated if request attribute was null, creating
1276             * problems for custom output modules that set request attributes
1277             */

1278            String JavaDoc value = (String JavaDoc)_req.getAttribute(name);
1279            if (value!=null)
1280            {
1281                if (!fmt.equals(""))
1282                {
1283                    if (fmt.equals("@xml"))
1284                        value = encodeXML(value);
1285                    else if (fmt.equals("@html"))
1286                        value = encodeHTML(value);
1287                    else if (fmt.equals("@url"))
1288                        value = URLEncoder.encode(value, "UTF-8");
1289                    else
1290                        throw new Throwable JavaDoc("Invalid encoding directive for request attribute: " + name);
1291                }
1292                _template = StringUtil.replace(_template, label, value);
1293            }
1294        }
1295    }
1296
1297    /**
1298     * Replace field markers representing session attribute values
1299     * like ${ses:attributeID}
1300     * @throws Throwable
1301     */

1302    public void replaceSessionAttributes() throws Throwable JavaDoc
1303    {
1304
1305        if (_req==null)
1306            throw new Throwable JavaDoc("Request is null - this method can't work without a Request object.");
1307
1308        //patch june-22-2004 don't waste time
1309
if (_template.indexOf("${ses:")< 0 )
1310            return;
1311
1312        //get session object
1313
HttpSession session = _req.getSession(true);
1314
1315        /* parse the template and create list of label markers */
1316        ArrayList JavaDoc flds = getMarkers("ses");
1317        
1318        for (int i=0; i<flds.size();i++)
1319        {
1320            Marker m = (Marker) flds.get(i);
1321            String JavaDoc name = m.getName();
1322            
1323            // PATCH 2005-05-25 - test existence of session attribute
1324
Object JavaDoc obj = session.getAttribute(name);
1325            
1326            if (obj==null)
1327                throw new Throwable JavaDoc("Cannot find Session attribute [" + name + "]; UserID: " + _req.getRemoteUser() + "; Session isNew: " + session.isNew() + "; ");
1328
1329            //patch 2005-06-09 - avoid errors if attribute type is not String
1330
String JavaDoc value = String.valueOf(obj);
1331            String JavaDoc label = "${" + "ses:" + name + "}";
1332            _template = StringUtil.replace(_template, label, value);
1333            
1334        }
1335
1336    }
1337
1338    /**
1339     * Encode reserved xml characters (&amp;,&lt;,&gt;,',").<br>
1340     * This characters will be replaced by the pre-defined entities.
1341     * @param input String that will be processed
1342     * @return String with all reserved characters replaced
1343     */

1344    public String JavaDoc encodeXML(String JavaDoc input)
1345    {
1346        input = StringUtil.replace(input, "&", "&amp;");
1347        input = StringUtil.replace(input, "<", "&lt;");
1348        input = StringUtil.replace(input, ">", "&gt;");
1349        input = StringUtil.replace(input, "'", "&apos;");
1350        input = StringUtil.replace(input, "\"", "&quot;");
1351
1352        return input;
1353    }
1354
1355    /**
1356     * Encode reserved html characters (&amp;,&lt;,&gt;,',").<br>
1357     * This characters will be replaced by the pre-defined entities.
1358     * @param input String that will be processed
1359     * @return String with all reserved characters replaced
1360     */

1361    public String JavaDoc encodeHTML(String JavaDoc input)
1362    {
1363        input = StringUtil.replace(input, "&", "&amp;");
1364        input = StringUtil.replace(input, "<", "&lt;");
1365        input = StringUtil.replace(input, ">", "&gt;");
1366        input = StringUtil.replace(input, "\"", "&quot;");
1367
1368        return input;
1369    }
1370    
1371    /**
1372     * Replace any text into the template
1373     * @param toReplace Text to be replaced
1374     * @param newValue New value
1375     */

1376    public void replace(String JavaDoc toReplace, String JavaDoc newValue)
1377    {
1378        _template = StringUtil.replace(_template, toReplace, newValue);
1379    }
1380
1381    /**
1382     * Set corresponding column values for template markers<br>
1383     * Patch june-28-2004 - Fast parser technique
1384     * @param fte Fast template parser (new fck package)
1385     * @param rs Recordset positioned on a valid record
1386     * @param nullExpression String used to represent a null value
1387     * @throws Throwable
1388     */

1389    public void setValues(dinamica.parser.FastTemplateEngine fte, ArrayList JavaDoc markers, Recordset rs, String JavaDoc nullExpression) throws Throwable JavaDoc
1390    {
1391
1392        String JavaDoc strValue = null;
1393        Object JavaDoc value = null;
1394        
1395        /* read default date format */
1396        String JavaDoc defDateFmt = null;
1397        defDateFmt = _ctx.getInitParameter("def-format-date");
1398        if (defDateFmt==null || defDateFmt.equals(""))
1399            defDateFmt = "dd-MM-yyyy";
1400        
1401        
1402        /* get recordset fields */
1403        HashMap JavaDoc rsFlds = rs.getFields();
1404        
1405        /* parse the template and create list of field markers */
1406        ArrayList JavaDoc flds = markers;
1407        
1408        /* for each field marker set value */
1409        Iterator JavaDoc i = flds.iterator();
1410        while (i.hasNext())
1411        {
1412
1413            String JavaDoc formatPluginName = null;
1414            IFormatPlugin fmtObj = null;
1415            FormatPluginParser fpp = null;
1416
1417            /* get next marker */
1418            dinamica.parser.Marker m = (dinamica.parser.Marker)i.next();
1419            String JavaDoc fName = m.getColumnName();
1420            String JavaDoc fFormat = m.getFormat();
1421
1422            /* determine if it is an special field (rowNumber/rowIndex) otherwise if the field exists */
1423            boolean found = true;
1424            boolean fakeField = false;
1425            if (!fName.equals("_rowNumber") && !fName.equals("_rowIndex"))
1426            {
1427                if (!rsFlds.containsKey(fName))
1428                    found = false;
1429            }
1430            else
1431            {
1432                fakeField = true;
1433            }
1434                            
1435            
1436            /* recordset contains this field? */
1437            if (found)
1438            {
1439
1440                if (fFormat!=null)
1441                {
1442                    //PATCH 2005-05-23 - get plugin name if available
1443
if (fFormat.startsWith("class:"))
1444                    {
1445                        formatPluginName = fFormat.substring(6);
1446                        fpp = new FormatPluginParser(formatPluginName);
1447                        fmtObj = (IFormatPlugin)Thread.currentThread().getContextClassLoader().loadClass(fpp.getName()).newInstance();
1448                    }
1449                }
1450                
1451                /* get field value */
1452                value = rs.getValue(fName);
1453
1454                if (fmtObj!=null)
1455                {
1456                    strValue = fmtObj.format(fName, rs, _locale, fpp.getArgs());
1457                }
1458                else
1459                {
1460                    /* apply appropiate null representation */
1461                    if (value==null)
1462                    {
1463                        strValue=nullExpression;
1464                    }
1465                    else
1466                    {
1467                        
1468
1469                        /* get field info */
1470                        RecordsetField f = null;
1471                        if (!fakeField)
1472                            f = (RecordsetField)rsFlds.get(fName);
1473                        else
1474                            f = new RecordsetField(fName,"INTEGER", Types.INTEGER);
1475                            
1476                        
1477                        /* format value according to data type*/
1478                        if (f.getType()!=Types.DATE && f.getType()!=Types.TIMESTAMP )
1479                        {
1480                            /* format defined? */
1481                            if (fFormat==null)
1482                            {
1483                                strValue = String.valueOf(value);
1484                            }
1485                            else
1486                            {
1487                                //is a string data type?
1488
if (f.getType()==Types.VARCHAR || f.getType()==Types.CHAR || f.getType()==Types.CLOB )
1489                                {
1490                                    if (fFormat.equals("xml"))
1491                                    {
1492                                        //encode special characters for xml/html output
1493
strValue = encodeXML((String JavaDoc)value);
1494                                    }
1495                                    else if (fFormat.equals("url"))
1496                                    {
1497                                        //encode special characters for xml/html output
1498
strValue = URLEncoder.encode((String JavaDoc)value, "UTF-8");
1499                                    }
1500                                    else
1501                                    {
1502                                        throw new Throwable JavaDoc("Invalid format mask for the field:" + fName);
1503                                    }
1504                                    
1505                                }
1506                                // it is a numeric data type
1507
else
1508                                {
1509                                        
1510                                    if (_locale==null)
1511                                        strValue = StringUtil.formatNumber(value, fFormat);
1512                                    else
1513                                        strValue = StringUtil.formatNumber(value, fFormat, _locale);
1514    
1515                                }
1516                            }
1517                        }
1518                        else
1519                        {
1520                            /* apply default or custom date format? */
1521                            if (fFormat==null)
1522                                fFormat = defDateFmt;
1523                            if (_locale==null)
1524                                strValue = StringUtil.formatDate((java.util.Date JavaDoc)value, fFormat);
1525                            else
1526                                strValue = StringUtil.formatDate((java.util.Date JavaDoc)value, fFormat, _locale);
1527                        }
1528                        
1529                    }
1530                
1531                }
1532                    
1533                // set value
1534
fte.setValue(m.getKey(), strValue);
1535                        
1536            }
1537            
1538        }
1539        
1540    }
1541
1542    /**
1543     * Replace all markers of type ${fld:xxx} with an empty string "".<br>
1544     * Added on Aug-30-2005 to support a new print mode="clear" in config.xml.
1545     * @throws Throwable
1546     */

1547    public void clearFieldMarkers() throws Throwable JavaDoc
1548    {
1549
1550        String JavaDoc toReplace = null;
1551        
1552        /* parse the template and create list of field markers */
1553        ArrayList JavaDoc flds = getMarkers("fld");
1554        
1555        /* for each field marker set value */
1556        Iterator JavaDoc i = flds.iterator();
1557        while (i.hasNext())
1558        {
1559
1560            /* get next marker */
1561            Marker m = (Marker)i.next();
1562            String JavaDoc fName = m.getName();
1563            String JavaDoc fFormat = m.getExtraInfo();
1564
1565            if (fFormat!=null)
1566                toReplace = "${fld:" + fName + "@" + fFormat + "}";
1567            else
1568                toReplace = "${fld:" + fName + "}";
1569                
1570            /* replace marker with value */
1571            _template = StringUtil.replace(_template,toReplace,"");
1572                        
1573        }
1574        
1575    }
1576    
1577}
1578
Popular Tags