KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > core > BuiltIn


1 /*
2  * Copyright (c) 2003 The Visigoth Software Society. All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowledgement:
19  * "This product includes software developed by the
20  * Visigoth Software Society (http://www.visigoths.org/)."
21  * Alternately, this acknowledgement may appear in the software itself,
22  * if and wherever such third-party acknowledgements normally appear.
23  *
24  * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
25  * project contributors may be used to endorse or promote products derived
26  * from this software without prior written permission. For written
27  * permission, please contact visigoths@visigoths.org.
28  *
29  * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
30  * nor may "FreeMarker" or "Visigoth" appear in their names
31  * without prior written permission of the Visigoth Software Society.
32  *
33  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36  * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
37  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  * ====================================================================
46  *
47  * This software consists of voluntary contributions made by many
48  * individuals on behalf of the Visigoth Software Society. For more
49  * information on the Visigoth Software Society, please see
50  * http://www.visigoths.org/
51  */

52
53 package freemarker.core;
54
55 import freemarker.template.*;
56
57 import java.io.UnsupportedEncodingException JavaDoc;
58 import java.text.DateFormat JavaDoc;
59 import java.text.NumberFormat JavaDoc;
60 import java.util.Date JavaDoc;
61 import java.util.HashMap JavaDoc;
62 import java.util.Iterator JavaDoc;
63 import java.util.List JavaDoc;
64
65 import freemarker.template.utility.ClassUtil;
66 import freemarker.template.utility.StringUtil;
67 import freemarker.core.NodeBuiltins.*;
68 import freemarker.core.NumericalBuiltins.*;
69 import freemarker.core.SequenceBuiltins.*;
70 import freemarker.core.StringBuiltins.*;
71
72 /**
73  * The ? operator used to get the
74  * functionality of built-in unary operators
75  * @author <a HREF="mailto:jon@revusky.com">Jonathan Revusky</a>
76  */

77 abstract class BuiltIn extends Expression implements Cloneable JavaDoc {
78     Expression target;
79     String JavaDoc key;
80
81     static final HashMap JavaDoc builtins = new HashMap JavaDoc();
82
83     static {
84         // These are the only ones we have now.
85
// We throw a parse exception if it's not one of these.
86
builtins.put("ancestors", new ancestorsBI());
87         builtins.put("byte", new byteBI());
88         builtins.put("cap_first", new cap_firstBI());
89         builtins.put("capitalize", new capitalizeBI());
90         builtins.put("children", new childrenBI());
91         builtins.put("chop_linebreak", new chop_linebreakBI());
92         builtins.put("contains", new containsBI());
93         builtins.put("date", new dateBI(TemplateDateModel.DATE));
94         builtins.put("datetime", new dateBI(TemplateDateModel.DATETIME));
95         builtins.put("default", new defaultBI());
96         builtins.put("double", new doubleBI());
97         builtins.put("ends_with", new ends_withBI());
98         builtins.put("eval", new evalBI());
99         builtins.put("exists", new existsBI());
100         builtins.put("first", new firstBI());
101         builtins.put("float", new floatBI());
102         builtins.put("has_content", new has_contentBI());
103         builtins.put("html", new htmlBI());
104         builtins.put("if_exists", new if_existsBI());
105         builtins.put("index_of", new index_ofBI());
106         builtins.put("int", new intBI());
107         builtins.put("interpret", new Interpret());
108         builtins.put("is_boolean", new is_booleanBI());
109         builtins.put("is_collection", new is_collectionBI());
110         builtins.put("is_date", new is_dateBI());
111         builtins.put("is_directive", new is_directiveBI());
112         builtins.put("is_enumerable", new is_enumerableBI());
113         builtins.put("is_hash_ex", new is_hash_exBI());
114         builtins.put("is_hash", new is_hashBI());
115         builtins.put("is_indexable", new is_indexableBI());
116         builtins.put("is_macro", new is_macroBI());
117         builtins.put("is_method", new is_methodBI());
118         builtins.put("is_node", new is_nodeBI());
119         builtins.put("is_number", new is_numberBI());
120         builtins.put("is_sequence", new is_sequenceBI());
121         builtins.put("is_string", new is_stringBI());
122         builtins.put("is_transform", new is_transformBI());
123         builtins.put("j_string", new j_stringBI());
124         builtins.put("js_string", new js_stringBI());
125         builtins.put("keys", new keysBI());
126         builtins.put("last_index_of", new last_index_ofBI());
127         builtins.put("last", new lastBI());
128         builtins.put("left_pad", new left_padBI());
129         builtins.put("length", new lengthBI());
130         builtins.put("long", new longBI());
131         builtins.put("lower_case", new lower_caseBI());
132         builtins.put("namespace", new namespaceBI());
133         builtins.put("new", new NewBI());
134         builtins.put("node_name", new node_nameBI());
135         builtins.put("node_namespace", new node_namespaceBI());
136         builtins.put("node_type", new node_typeBI());
137         builtins.put("number", new numberBI());
138         builtins.put("parent", new parentBI());
139         builtins.put("replace", new replaceBI());
140         builtins.put("reverse", new reverseBI());
141         builtins.put("right_pad", new right_padBI());
142         builtins.put("root", new rootBI());
143         builtins.put("rtf", new rtfBI());
144         builtins.put("seq_contains", new seq_containsBI());
145         builtins.put("seq_index_of", new seq_index_ofBI(1));
146         builtins.put("seq_last_index_of", new seq_index_ofBI(-1));
147         builtins.put("short", new shortBI());
148         builtins.put("size", new sizeBI());
149         builtins.put("sort_by", new sort_byBI());
150         builtins.put("sort", new sortBI());
151         builtins.put("split", new splitBI());
152         builtins.put("starts_with", new starts_withBI());
153         builtins.put("string", new stringBI());
154         builtins.put("time", new dateBI(TemplateDateModel.TIME));
155         builtins.put("trim", new trimBI());
156         builtins.put("uncap_first", new uncap_firstBI());
157         builtins.put("upper_case", new upper_caseBI());
158         builtins.put("url", new urlBI());
159         builtins.put("values", new valuesBI());
160         builtins.put("web_safe", builtins.get("html")); // deprecated; use ?html instead
161
builtins.put("word_list", new word_listBI());
162         builtins.put("xml", new xmlBI());
163         try {
164             Class.forName("java.util.regex.Pattern");
165             builtins.put("matches", instantiate("freemarker.core.RegexBuiltins$matchesBI"));
166             builtins.put("groups", instantiate("freemarker.core.RegexBuiltins$groupsBI"));
167             builtins.put("replace", instantiate("freemarker.core.RegexBuiltins$replace_reBI"));
168             builtins.put("split", instantiate("freemarker.core.RegexBuiltins$split_reBI"));
169         } catch (Exception JavaDoc e) {}
170     }
171
172     private static Object JavaDoc instantiate(String JavaDoc className) throws Exception JavaDoc
173     {
174         return ClassUtil.forName(className).newInstance();
175     }
176     
177     static BuiltIn newBuiltIn(Expression target, String JavaDoc key, Token tok, String JavaDoc templateName) throws ParseException {
178         BuiltIn bi = (BuiltIn) builtins.get(key);
179         if (bi == null) {
180             String JavaDoc locationInfo = "Error on line " + tok.beginLine + ", column " + tok.beginColumn + ", in template " + templateName + "\n";
181             StringBuffer JavaDoc buf = new StringBuffer JavaDoc("Found " + key + ", expecting one of: ");
182             for (Iterator JavaDoc it= builtins.keySet().iterator(); it.hasNext();) {
183                 if (it.hasNext()) {
184                     buf.append(" ");
185                 } else {
186                     buf.append( " or ");
187                 }
188                 buf.append(it.next());
189                 if (it.hasNext()) {
190                     buf.append(", ");
191                 }
192             }
193             throw new ParseException(locationInfo + buf, target);
194         }
195         try {
196             bi = (BuiltIn) bi.clone();
197         }
198         catch (CloneNotSupportedException JavaDoc e) {
199             throw new InternalError JavaDoc();
200         }
201         bi.target = target;
202         bi.key = key;
203         return bi;
204     }
205
206     public String JavaDoc getCanonicalForm() {
207         return target.getCanonicalForm() + "?" + key;
208     }
209
210     boolean isLiteral() {
211         return false; // be on the safe side.
212
}
213
214     Expression _deepClone(String JavaDoc name, Expression subst) {
215         try {
216             BuiltIn clone = (BuiltIn)clone();
217             clone.target = target.deepClone(name, subst);
218             return clone;
219         }
220         catch (CloneNotSupportedException JavaDoc e) {
221             throw new InternalError JavaDoc();
222         }
223     }
224
225
226     static class lengthBI extends BuiltIn {
227         TemplateModel _getAsTemplateModel(Environment env)
228         throws TemplateException
229         {
230             return new SimpleNumber(target.getStringValue(env).length());
231         }
232     }
233
234     static class dateBI extends BuiltIn {
235         private final int dateType;
236         
237         dateBI(int dateType) {
238             this.dateType = dateType;
239         }
240         
241         TemplateModel _getAsTemplateModel(Environment env)
242                 throws TemplateException
243         {
244             TemplateModel model = target.getAsTemplateModel(env);
245             if (model instanceof TemplateDateModel) {
246                 TemplateDateModel dmodel = (TemplateDateModel)model;
247                 int dtype = dmodel.getDateType();
248                 // Any date model can be coerced into its own type
249
if(dateType == dtype) {
250                     return model;
251                 }
252                 // unknown and datetime can be coerced into any date type
253
if(dtype == TemplateDateModel.UNKNOWN || dtype == TemplateDateModel.DATETIME) {
254                     return new SimpleDate(dmodel.getAsDate(), dateType);
255                 }
256                 throw new TemplateException(
257                     "Cannot convert " + TemplateDateModel.TYPE_NAMES.get(dtype)
258                     + " into " + TemplateDateModel.TYPE_NAMES.get(dateType), env);
259             }
260             // Otherwise, interpret as a string and attempt
261
// to parse it into a date.
262
String JavaDoc s = target.getStringValue(env);
263             return new DateParser(s, env);
264         }
265         
266         private class DateParser
267         implements
268             TemplateDateModel,
269             TemplateMethodModel,
270             TemplateHashModel
271         {
272             private final String JavaDoc text;
273             private final Environment env;
274             private final DateFormat JavaDoc defaultFormat;
275             private Date JavaDoc cachedValue;
276             
277             DateParser(String JavaDoc text, Environment env)
278             throws
279                 TemplateModelException
280             {
281                 this.text = text;
282                 this.env = env;
283                 this.defaultFormat = env.getDateFormatObject(dateType);
284             }
285             
286             public Date JavaDoc getAsDate() throws TemplateModelException {
287                 if(cachedValue == null) {
288                     cachedValue = parse(defaultFormat);
289                 }
290                 return cachedValue;
291             }
292             
293             public int getDateType() {
294                 return dateType;
295             }
296
297             public TemplateModel get(String JavaDoc pattern) throws TemplateModelException {
298                 return new SimpleDate(
299                     parse(env.getDateFormatObject(dateType, pattern)),
300                     dateType);
301             }
302
303             public Object JavaDoc exec(List JavaDoc arguments)
304                 throws TemplateModelException {
305                 if (arguments.size() != 1) {
306                     throw new TemplateModelException(
307                             "string?" + key + "(...) requires exactly 1 argument.");
308                 }
309                 return get((String JavaDoc) arguments.get(0));
310             }
311
312             public boolean isEmpty()
313             {
314                 return false;
315             }
316
317             private Date JavaDoc parse(DateFormat JavaDoc df)
318             throws
319                 TemplateModelException
320             {
321                 try {
322                     return df.parse(text);
323                 }
324                 catch(java.text.ParseException JavaDoc e) {
325                     String JavaDoc mess = "Error: " + getStartLocation()
326                                  + "\nExpecting a date here, found: " + text;
327                     throw new TemplateModelException(mess);
328                 }
329             }
330         }
331     }
332
333     static class stringBI extends BuiltIn {
334         TemplateModel _getAsTemplateModel(Environment env)
335                 throws TemplateException
336         {
337             TemplateModel model = target.getAsTemplateModel(env);
338             if (model instanceof TemplateNumberModel) {
339                 return new NumberFormatter(EvaluationUtil.getNumber((TemplateNumberModel)model, target, env), env);
340             }
341             if (model instanceof TemplateDateModel) {
342                 TemplateDateModel dm = (TemplateDateModel)model;
343                 int dateType = dm.getDateType();
344                 return new DateFormatter(EvaluationUtil.getDate(dm, target, env), dateType, env);
345             }
346             if (model instanceof SimpleScalar) {
347                 return model;
348             }
349             if (model instanceof TemplateBooleanModel) {
350                 return new BooleanFormatter((TemplateBooleanModel) model, env);
351             }
352             if (model instanceof TemplateScalarModel) {
353                 return new SimpleScalar(((TemplateScalarModel) model).getAsString());
354             }
355             throw invalidTypeException(model, target, env, "number, date, or string");
356         }
357
358         private static class NumberFormatter
359         implements
360             TemplateScalarModel,
361             TemplateHashModel,
362             TemplateMethodModel
363         {
364             private final Number JavaDoc number;
365             private final Environment env;
366             private final NumberFormat JavaDoc defaultFormat;
367             private String JavaDoc cachedValue;
368
369             NumberFormatter(Number JavaDoc number, Environment env)
370             {
371                 this.number = number;
372                 this.env = env;
373                 defaultFormat = env.getNumberFormatObject(env.getNumberFormat());
374             }
375
376             public String JavaDoc getAsString()
377             {
378                 if(cachedValue == null) {
379                     cachedValue = defaultFormat.format(number);
380                 }
381                 return cachedValue;
382             }
383
384             public TemplateModel get(String JavaDoc key)
385             {
386                 return new SimpleScalar(env.getNumberFormatObject(key).format(number));
387             }
388             
389             public Object JavaDoc exec(List JavaDoc arguments)
390                 throws TemplateModelException {
391                 if (arguments.size() != 1) {
392                     throw new TemplateModelException(
393                             "number?string(...) requires exactly 1 argument.");
394                 }
395                 return get((String JavaDoc) arguments.get(0));
396             }
397
398             public boolean isEmpty()
399             {
400                 return false;
401             }
402         }
403         
404         private static class DateFormatter
405         implements
406             TemplateScalarModel,
407             TemplateHashModel,
408             TemplateMethodModel
409         {
410             private final Date JavaDoc date;
411             private final int dateType;
412             private final Environment env;
413             private final DateFormat JavaDoc defaultFormat;
414             private String JavaDoc cachedValue;
415
416             DateFormatter(Date JavaDoc date, int dateType, Environment env)
417             throws
418                 TemplateModelException
419             {
420                 this.date = date;
421                 this.dateType = dateType;
422                 this.env = env;
423                 defaultFormat = env.getDateFormatObject(dateType);
424             }
425
426             public String JavaDoc getAsString()
427             throws
428                 TemplateModelException
429             {
430                 if(dateType == TemplateDateModel.UNKNOWN) {
431                     throw new TemplateModelException("Can't convert the date to string, because it is not known which parts of the date variable are in use. Use ?date, ?time or ?datetime built-in, or ?string.<format> or ?string(format) built-in with this date.");
432                 }
433                 if(cachedValue == null) {
434                     cachedValue = defaultFormat.format(date);
435                 }
436                 return cachedValue;
437             }
438
439             public TemplateModel get(String JavaDoc key)
440             throws
441                 TemplateModelException
442             {
443                 return new SimpleScalar(env.getDateFormatObject(dateType, key).format(date));
444             }
445             
446             public Object JavaDoc exec(List JavaDoc arguments)
447                 throws TemplateModelException {
448                 if (arguments.size() != 1) {
449                     throw new TemplateModelException(
450                             "date?string(...) requires exactly 1 argument.");
451                 }
452                 return get((String JavaDoc) arguments.get(0));
453             }
454
455             public boolean isEmpty()
456             {
457                 return false;
458             }
459         }
460
461         private static class BooleanFormatter
462         implements
463             TemplateScalarModel,
464             TemplateMethodModel
465         {
466             private final TemplateBooleanModel bool;
467             private final Environment env;
468             
469             BooleanFormatter(TemplateBooleanModel bool, Environment env) {
470                 this.bool = bool;
471                 this.env = env;
472             }
473
474             public String JavaDoc getAsString() throws TemplateModelException {
475                 if (bool instanceof TemplateScalarModel) {
476                     return ((TemplateScalarModel) bool).getAsString();
477                 } else {
478                     return env.getBooleanFormat(bool.getAsBoolean());
479                 }
480             }
481
482             public Object JavaDoc exec(List JavaDoc arguments)
483                     throws TemplateModelException {
484                 if (arguments.size() != 2) {
485                     throw new TemplateModelException(
486                             "boolean?string(...) requires exactly "
487                             + "2 arguments.");
488                 }
489                 return new SimpleScalar(
490                     (String JavaDoc) arguments.get(bool.getAsBoolean() ? 0 : 1));
491             }
492         }
493     }
494
495     static class trimBI extends StringBuiltIn {
496         TemplateModel calculateResult(String JavaDoc s, Environment env) {
497             return new SimpleScalar(s.trim());
498         }
499     }
500
501     static class htmlBI extends StringBuiltIn {
502         TemplateModel calculateResult(String JavaDoc s, Environment env) {
503             return new SimpleScalar(StringUtil.HTMLEnc(s));
504         }
505     }
506
507     static class xmlBI extends StringBuiltIn {
508         TemplateModel calculateResult(String JavaDoc s, Environment env) {
509             return new SimpleScalar(StringUtil.XMLEnc(s));
510         }
511     }
512
513     static class rtfBI extends StringBuiltIn {
514         TemplateModel calculateResult(String JavaDoc s, Environment env) {
515             return new SimpleScalar(StringUtil.RTFEnc(s));
516         }
517     }
518
519     static class urlBI extends StringBuiltIn {
520         
521         TemplateModel calculateResult(String JavaDoc s, Environment env) {
522             return new urlBIResult(s, env);
523         }
524         
525         static class urlBIResult implements
526                 TemplateScalarModel, TemplateMethodModel {
527             
528             private final String JavaDoc target;
529             private final Environment env;
530             private String JavaDoc cachedResult;
531
532             private urlBIResult(String JavaDoc target, Environment env) {
533                 this.target = target;
534                 this.env = env;
535             }
536             
537             public String JavaDoc getAsString() throws TemplateModelException {
538                 if (cachedResult == null) {
539                     String JavaDoc cs = env.getEffectiveURLEscapingCharset();
540                     if (cs == null) {
541                         throw new TemplateModelException(
542                                 "To do URL encoding, the framework that encloses "
543                                 + "FreeMarker must specify the output encoding "
544                                 + "or the URL encoding charset, so ask the "
545                                 + "programmers to fix it. Or, as a last chance, "
546                                 + "you can set the url_encoding_charset setting in "
547                                 + "the template, e.g. "
548                                 + "<#setting url_escaping_charset='ISO-8859-1'>, or "
549                                 + "give the charset explicitly to the buit-in, e.g. "
550                                 + "foo?url('ISO-8859-1').");
551                     }
552                     try {
553                         cachedResult = StringUtil.URLEnc(target, cs);
554                     } catch (UnsupportedEncodingException JavaDoc e) {
555                         throw new TemplateModelException(
556                                 "Failed to execute URL encoding.", e);
557                     }
558                 }
559                 return cachedResult;
560             }
561
562             public Object JavaDoc exec(List JavaDoc args) throws TemplateModelException {
563                 if (args.size() != 1) {
564                     throw new TemplateModelException("The \"url\" built-in "
565                             + "needs exactly 1 parameter, the charset.");
566                 }
567                 try {
568                     return new SimpleScalar(
569                             StringUtil.URLEnc(target, (String JavaDoc) args.get(0)));
570                 } catch (UnsupportedEncodingException JavaDoc e) {
571                     throw new TemplateModelException(
572                             "Failed to execute URL encoding.", e);
573                 }
574             }
575             
576         }
577     }
578     
579     static class keysBI extends BuiltIn {
580         TemplateModel _getAsTemplateModel(Environment env)
581                 throws TemplateException
582         {
583             TemplateModel model = target.getAsTemplateModel(env);
584             if (model instanceof TemplateHashModelEx) {
585                 TemplateCollectionModel keys = ((TemplateHashModelEx) model).keys();
586                 assertNonNull(keys, this, env);
587                 if (!(keys instanceof TemplateSequenceModel))
588                     keys = new CollectionAndSequence(keys);
589                 return keys;
590             }
591             throw invalidTypeException(model, target, env, "extended hash");
592         }
593     }
594
595     static class valuesBI extends BuiltIn {
596         TemplateModel _getAsTemplateModel(Environment env)
597                 throws TemplateException
598         {
599             TemplateModel model = target.getAsTemplateModel(env);
600             if (model instanceof TemplateHashModelEx) {
601                 TemplateCollectionModel values = ((TemplateHashModelEx) model).values();
602                 assertNonNull(values, this, env);
603                 if (!(values instanceof TemplateSequenceModel))
604                     values = new CollectionAndSequence(values);
605                 return values;
606             }
607             throw invalidTypeException(model, target, env, "extended hash");
608         }
609     }
610
611     static class sizeBI extends BuiltIn {
612         TemplateModel _getAsTemplateModel(Environment env)
613                 throws TemplateException
614         {
615             TemplateModel model = target.getAsTemplateModel(env);
616             if (model instanceof TemplateSequenceModel) {
617                 int size = ((TemplateSequenceModel) model).size();
618                 return new SimpleNumber(size);
619             }
620             if (model instanceof TemplateHashModelEx) {
621                 int size = ((TemplateHashModelEx) model).size();
622                 return new SimpleNumber(size);
623             }
624             throw invalidTypeException(model, target, env, "extended hash or sequence");
625         }
626     }
627
628     static class existsBI extends BuiltIn {
629         TemplateModel _getAsTemplateModel(Environment env)
630                 throws TemplateException
631         {
632             try {
633                 TemplateModel model = target.getAsTemplateModel(env);
634                 return model==null ? TemplateBooleanModel.FALSE : TemplateBooleanModel.TRUE;
635             } catch (InvalidReferenceException ire) {
636                 if (target instanceof ParentheticalExpression) {
637                     return TemplateBooleanModel.FALSE;
638                 }
639                 throw ire;
640             }
641         }
642
643         boolean isTrue(Environment env) throws TemplateException {
644             return _getAsTemplateModel(env) == TemplateBooleanModel.TRUE;
645         }
646     }
647
648     static class has_contentBI extends BuiltIn {
649         TemplateModel _getAsTemplateModel(Environment env)
650                 throws TemplateException
651         {
652             try {
653                 TemplateModel model = target.getAsTemplateModel(env);
654                 return Expression.isEmpty(model) ?
655                     TemplateBooleanModel.FALSE : TemplateBooleanModel.TRUE;
656             } catch (InvalidReferenceException ire) {
657                 if (target instanceof ParentheticalExpression) {
658                     return TemplateBooleanModel.FALSE;
659                 }
660                 throw ire;
661             }
662         }
663
664         boolean isTrue(Environment env) throws TemplateException {
665             return _getAsTemplateModel(env) == TemplateBooleanModel.TRUE;
666         }
667     }
668
669     static class if_existsBI extends BuiltIn {
670         TemplateModel _getAsTemplateModel(Environment env)
671                 throws TemplateException
672         {
673             try {
674                 TemplateModel model = target.getAsTemplateModel(env);
675                 return model == null ? TemplateModel.NOTHING : model;
676             } catch (InvalidReferenceException ire) {
677                 if (target instanceof ParentheticalExpression) {
678                     return TemplateModel.NOTHING;
679                 }
680                 throw ire;
681             }
682         }
683     }
684
685     static class is_stringBI extends BuiltIn {
686         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
687             TemplateModel tm = target.getAsTemplateModel(env);
688             assertNonNull(tm, target, env);
689             return (tm instanceof TemplateScalarModel) ?
690                 TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
691         }
692     }
693
694     static class is_numberBI extends BuiltIn {
695         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
696             TemplateModel tm = target.getAsTemplateModel(env);
697             assertNonNull(tm, target, env);
698             return (tm instanceof TemplateNumberModel) ?
699                 TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
700         }
701     }
702
703     static class is_nodeBI extends BuiltIn {
704         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
705             TemplateModel tm = target.getAsTemplateModel(env);
706             assertNonNull(tm, target, env);
707             return (tm instanceof TemplateNodeModel) ?
708                 TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
709         }
710     }
711
712     static class is_booleanBI extends BuiltIn {
713         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
714             TemplateModel tm = target.getAsTemplateModel(env);
715             assertNonNull(tm, target, env);
716             return (tm instanceof TemplateBooleanModel) ?
717                 TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
718         }
719     }
720
721     static class is_dateBI extends BuiltIn {
722         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
723             TemplateModel tm = target.getAsTemplateModel(env);
724             assertNonNull(tm, target, env);
725             return (tm instanceof TemplateDateModel) ?
726                 TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
727         }
728     }
729
730     static class is_methodBI extends BuiltIn {
731         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
732             TemplateModel tm = target.getAsTemplateModel(env);
733             assertNonNull(tm, target, env);
734             return (tm instanceof TemplateMethodModel) ?
735                 TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
736         }
737     }
738
739     static class is_macroBI extends BuiltIn {
740         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
741             TemplateModel tm = target.getAsTemplateModel(env);
742             assertNonNull(tm, target, env);
743             return (tm instanceof Macro) ?
744                 TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
745         }
746     }
747
748     static class is_transformBI extends BuiltIn {
749         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
750             TemplateModel tm = target.getAsTemplateModel(env);
751             assertNonNull(tm, target, env);
752             return (tm instanceof TemplateTransformModel) ?
753                 TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
754         }
755     }
756
757     static class is_hashBI extends BuiltIn {
758         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
759             TemplateModel tm = target.getAsTemplateModel(env);
760             assertNonNull(tm, target, env);
761             return (tm instanceof TemplateHashModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
762         }
763     }
764
765     static class is_hash_exBI extends BuiltIn {
766         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
767             TemplateModel tm = target.getAsTemplateModel(env);
768             assertNonNull(tm, target, env);
769             return (tm instanceof TemplateHashModelEx) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
770         }
771     }
772
773     static class is_sequenceBI extends BuiltIn {
774         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
775             TemplateModel tm = target.getAsTemplateModel(env);
776             assertNonNull(tm, target, env);
777             return (tm instanceof TemplateSequenceModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
778         }
779     }
780
781     static class is_collectionBI extends BuiltIn {
782         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
783             TemplateModel tm = target.getAsTemplateModel(env);
784             assertNonNull(tm, target, env);
785             return (tm instanceof TemplateCollectionModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
786         }
787     }
788
789     static class is_indexableBI extends BuiltIn {
790         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
791             TemplateModel tm = target.getAsTemplateModel(env);
792             assertNonNull(tm, target, env);
793             return (tm instanceof TemplateSequenceModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
794         }
795     }
796
797     static class is_enumerableBI extends BuiltIn {
798         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
799             TemplateModel tm = target.getAsTemplateModel(env);
800             assertNonNull(tm, target, env);
801             return (tm instanceof TemplateSequenceModel || tm instanceof TemplateCollectionModel) ?
802                 TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
803         }
804     }
805
806     static class is_directiveBI extends BuiltIn {
807         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
808             TemplateModel tm = target.getAsTemplateModel(env);
809             assertNonNull(tm, target, env);
810             return (tm instanceof TemplateTransformModel || tm instanceof Macro) ?
811                 TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
812         }
813     }
814
815     static class namespaceBI extends BuiltIn {
816         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
817             TemplateModel tm = target.getAsTemplateModel(env);
818             if (!(tm instanceof Macro)) {
819                 invalidTypeException(tm, target, env, "macro");
820             }
821             return env.getMacroNamespace((Macro) tm);
822         }
823     }
824
825     static class defaultBI extends BuiltIn {
826         TemplateModel _getAsTemplateModel(final Environment env)
827                 throws TemplateException
828         {
829             try {
830                 TemplateModel model = target.getAsTemplateModel(env);
831                 return
832                     model == null
833                     ? FIRST_NON_NULL_METHOD
834                     : new ConstantMethod(model);
835             } catch (InvalidReferenceException ire) {
836                 if (target instanceof ParentheticalExpression) {
837                     return FIRST_NON_NULL_METHOD;
838                 }
839                 throw ire;
840             }
841         }
842
843         private static class ConstantMethod implements TemplateMethodModelEx
844         {
845             private final TemplateModel constant;
846
847             ConstantMethod(TemplateModel constant) {
848                 this.constant = constant;
849             }
850
851             public Object JavaDoc exec(List JavaDoc args) {
852                 return constant;
853             }
854         }
855
856         /**
857          * A method that goes through the arguments one by one and returns
858          * the first one that is non-null. If all args are null, returns null.
859          */

860         private static final TemplateMethodModelEx FIRST_NON_NULL_METHOD =
861             new TemplateMethodModelEx() {
862                 public Object JavaDoc exec(List JavaDoc args) throws TemplateModelException {
863                     if(args.isEmpty()) {
864                         throw new TemplateModelException(
865                             "?default(arg) expects at least one argument.");
866                     }
867                     TemplateModel result = null;
868                     for (int i = 0; i< args.size(); i++ ) {
869                         result = (TemplateModel) args.get(i);
870                         if (result != null) {
871                             break;
872                         }
873                     }
874                     return result;
875                 }
876             };
877     }
878
879     static class containsBI extends BuiltIn {
880         TemplateModel _getAsTemplateModel(Environment env)
881                 throws TemplateException {
882             TemplateModel model = target.getAsTemplateModel(env);
883             if (model instanceof TemplateScalarModel) {
884                 return new BIMethod(((TemplateScalarModel) model).getAsString());
885             }
886             throw invalidTypeException(model, target, env, "string");
887         }
888
889         private class BIMethod implements TemplateMethodModelEx {
890             private String JavaDoc s;
891
892             private BIMethod(String JavaDoc s) {
893                 this.s = s;
894             }
895
896             public Object JavaDoc exec(List JavaDoc args) throws TemplateModelException {
897                 Object JavaDoc obj;
898                 String JavaDoc sub;
899
900                 int ln = args.size();
901                 if (ln != 1) {
902                     throw new TemplateModelException(
903                             "?contains(...) expects one argument.");
904                 }
905
906                 obj = args.get(0);
907                 if (!(obj instanceof TemplateScalarModel)) {
908                     throw new TemplateModelException(
909                             "?contains(...) expects a string as "
910                             + "its first argument.");
911                 }
912                 sub = ((TemplateScalarModel) obj).getAsString();
913
914                 return
915                     (s.indexOf(sub) != -1) ?
916                     TemplateBooleanModel.TRUE :
917                     TemplateBooleanModel.FALSE;
918             }
919         }
920     }
921     
922     static class index_ofBI extends BuiltIn {
923         TemplateModel _getAsTemplateModel(Environment env)
924                 throws TemplateException {
925             TemplateModel model = target.getAsTemplateModel(env);
926             if (model instanceof TemplateScalarModel) {
927                 return new BIMethod(((TemplateScalarModel) model).getAsString());
928             }
929             throw invalidTypeException(model, target, env, "string");
930         }
931         
932         private class BIMethod implements TemplateMethodModelEx {
933             private String JavaDoc s;
934             
935             private BIMethod(String JavaDoc s) {
936                 this.s = s;
937             }
938             
939             public Object JavaDoc exec(List JavaDoc args) throws TemplateModelException {
940                 Object JavaDoc obj;
941                 String JavaDoc sub;
942                 int fidx;
943
944                 int ln = args.size();
945                 if (ln == 0) {
946                     throw new TemplateModelException(
947                             "?index_of(...) expects at least one argument.");
948                 }
949                 if (ln > 2) {
950                     throw new TemplateModelException(
951                             "?index_of(...) expects at most two arguments.");
952                 }
953
954                 obj = args.get(0);
955                 if (!(obj instanceof TemplateScalarModel)) {
956                     throw new TemplateModelException(
957                             "?index_of(...) expects a string as "
958                             + "its first argument.");
959                 }
960                 sub = ((TemplateScalarModel) obj).getAsString();
961                 
962                 if (ln > 1) {
963                     obj = args.get(1);
964                     if (!(obj instanceof TemplateNumberModel)) {
965                         throw new TemplateModelException(
966                                 "?index_of(...) expects a number as "
967                                 + "its second argument.");
968                     }
969                     fidx = ((TemplateNumberModel) obj).getAsNumber().intValue();
970                 } else {
971                     fidx = 0;
972                 }
973
974                 return new SimpleNumber(s.indexOf(sub, fidx));
975             }
976         }
977     }
978
979     static class last_index_ofBI extends BuiltIn {
980         TemplateModel _getAsTemplateModel(Environment env)
981                 throws TemplateException {
982             TemplateModel model = target.getAsTemplateModel(env);
983             if (model instanceof TemplateScalarModel) {
984                 return new BIMethod(((TemplateScalarModel) model).getAsString());
985             }
986             throw invalidTypeException(model, target, env, "string");
987         }
988
989         private class BIMethod implements TemplateMethodModelEx {
990             private String JavaDoc s;
991
992             private BIMethod(String JavaDoc s) {
993                 this.s = s;
994             }
995
996             public Object JavaDoc exec(List JavaDoc args) throws TemplateModelException {
997                 Object JavaDoc obj;
998                 String JavaDoc sub;
999
1000                int ln = args.size();
1001                if (ln == 0) {
1002                    throw new TemplateModelException(
1003                            "?last_index_of(...) expects at least one argument.");
1004                }
1005                if (ln > 2) {
1006                    throw new TemplateModelException(
1007                            "?last_index_of(...) expects at most two arguments.");
1008                }
1009
1010                obj = args.get(0);
1011                if (!(obj instanceof TemplateScalarModel)) {
1012                    throw new TemplateModelException(
1013                            "?last_index_of(...) expects a string as "
1014                            + "its first argument.");
1015                }
1016                sub = ((TemplateScalarModel) obj).getAsString();
1017
1018                if (ln > 1) {
1019                    obj = args.get(1);
1020                    if (!(obj instanceof TemplateNumberModel)) {
1021                        throw new TemplateModelException(
1022                                "?last_index_of(...) expects a number as "
1023                                + "its second argument.");
1024                    }
1025                    int fidx = ((TemplateNumberModel) obj).getAsNumber().intValue();
1026                    return new SimpleNumber(s.lastIndexOf(sub, fidx));
1027                } else {
1028                    return new SimpleNumber(s.lastIndexOf(sub));
1029                }
1030            }
1031        }
1032    }
1033    
1034    static class starts_withBI extends BuiltIn {
1035        TemplateModel _getAsTemplateModel(Environment env)
1036                throws TemplateException {
1037            TemplateModel model = target.getAsTemplateModel(env);
1038            if (model instanceof TemplateScalarModel) {
1039                return new BIMethod(((TemplateScalarModel) model).getAsString());
1040            }
1041            throw invalidTypeException(model, target, env, "string");
1042        }
1043
1044        private class BIMethod implements TemplateMethodModelEx {
1045            private String JavaDoc s;
1046
1047            private BIMethod(String JavaDoc s) {
1048                this.s = s;
1049            }
1050
1051            public Object JavaDoc exec(List JavaDoc args) throws TemplateModelException {
1052                String JavaDoc sub;
1053
1054                if (args.size() != 1) {
1055                    throw new TemplateModelException(
1056                            "?starts_with(...) expects exactly 1 argument.");
1057                }
1058
1059                Object JavaDoc obj = args.get(0);
1060                if (!(obj instanceof TemplateScalarModel)) {
1061                    throw new TemplateModelException(
1062                            "?starts_with(...) expects a string argument");
1063                }
1064                sub = ((TemplateScalarModel) obj).getAsString();
1065
1066                return s.startsWith(sub) ?
1067                        TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
1068            }
1069        }
1070    }
1071
1072    static class ends_withBI extends BuiltIn {
1073        TemplateModel _getAsTemplateModel(Environment env)
1074                throws TemplateException {
1075            TemplateModel model = target.getAsTemplateModel(env);
1076            if (model instanceof TemplateScalarModel) {
1077                return new BIMethod(((TemplateScalarModel) model).getAsString());
1078            }
1079            throw invalidTypeException(model, target, env, "string");
1080        }
1081
1082        private class BIMethod implements TemplateMethodModelEx {
1083            private String JavaDoc s;
1084
1085            private BIMethod(String JavaDoc s) {
1086                this.s = s;
1087            }
1088
1089            public Object JavaDoc exec(List JavaDoc args) throws TemplateModelException {
1090                String JavaDoc sub;
1091
1092                if (args.size() != 1) {
1093                    throw new TemplateModelException(
1094                            "?ends_with(...) expects exactly 1 argument.");
1095                }
1096
1097                Object JavaDoc obj = args.get(0);
1098                if (!(obj instanceof TemplateScalarModel)) {
1099                    throw new TemplateModelException(
1100                            "?ends_with(...) expects a string argument");
1101                }
1102                sub = ((TemplateScalarModel) obj).getAsString();
1103
1104                return s.endsWith(sub) ?
1105                        TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
1106            }
1107        }
1108    }
1109    
1110    static class replaceBI extends BuiltIn {
1111        TemplateModel _getAsTemplateModel(Environment env)
1112                throws TemplateException {
1113            TemplateModel model = target.getAsTemplateModel(env);
1114            if (model instanceof TemplateScalarModel) {
1115                return new BIMethod(((TemplateScalarModel) model).getAsString());
1116            }
1117            throw invalidTypeException(model, target, env, "string");
1118        }
1119
1120        private class BIMethod implements TemplateMethodModel {
1121            private String JavaDoc s;
1122
1123            private BIMethod(String JavaDoc s) {
1124                this.s = s;
1125            }
1126
1127            public Object JavaDoc exec(List JavaDoc args) throws TemplateModelException {
1128                int numArgs = args.size();
1129                if (numArgs < 2 || numArgs > 3) {
1130                    throw new TemplateModelException(
1131                            "?replace(...) needs 2 or 3 arguments.");
1132                }
1133                String JavaDoc first = (String JavaDoc) args.get(0);
1134                String JavaDoc second = (String JavaDoc) args.get(1);
1135                String JavaDoc flags = numArgs >2 ? (String JavaDoc) args.get(2) : "";
1136                boolean caseInsensitive = flags.indexOf('i') >=0;
1137                boolean firstOnly = flags.indexOf('f') >=0;
1138                if (flags.indexOf('r') >=0) {
1139                    throw new TemplateModelException("The regular expression classes are not available.");
1140                }
1141                return new SimpleScalar(StringUtil.replace(
1142                        s, first, second, caseInsensitive, firstOnly));
1143            }
1144        }
1145    }
1146
1147    static class splitBI extends BuiltIn {
1148        TemplateModel _getAsTemplateModel(Environment env)
1149                throws TemplateException {
1150            TemplateModel model = target.getAsTemplateModel(env);
1151            if (model instanceof TemplateScalarModel) {
1152                return new BIMethod(((TemplateScalarModel) model).getAsString());
1153            }
1154            throw invalidTypeException(model, target, env, "string");
1155        }
1156
1157        private class BIMethod implements TemplateMethodModel {
1158            private String JavaDoc s;
1159
1160            private BIMethod(String JavaDoc s) {
1161                this.s = s;
1162            }
1163
1164            public Object JavaDoc exec(List JavaDoc args) throws TemplateModelException {
1165                int numArgs = args.size();
1166                if (numArgs != 1 && numArgs !=2) {
1167                    throw new TemplateModelException(
1168                            "?split(...) expects 1 or 2 arguments.");
1169                }
1170                String JavaDoc splitString = (String JavaDoc) args.get(0);
1171                String JavaDoc flags = numArgs ==2 ? (String JavaDoc) args.get(1) : "";
1172                boolean caseInsensitive = flags.indexOf('i') >=0;
1173                if (flags.indexOf('r') >=0) {
1174                    throw new TemplateModelException("regular expression classes not available");
1175                }
1176                return new StringArraySequence(StringUtil.split(
1177                        s, splitString, caseInsensitive));
1178            }
1179        }
1180    }
1181
1182    static class left_padBI extends BuiltIn {
1183        TemplateModel _getAsTemplateModel(Environment env)
1184                throws TemplateException {
1185            TemplateModel model = target.getAsTemplateModel(env);
1186            if (model instanceof TemplateScalarModel) {
1187                return new BIMethod(((TemplateScalarModel) model).getAsString());
1188            }
1189            throw invalidTypeException(model, target, env, "string");
1190        }
1191
1192        private class BIMethod implements TemplateMethodModelEx {
1193            private String JavaDoc s;
1194
1195            private BIMethod(String JavaDoc s) {
1196                this.s = s;
1197            }
1198
1199            public Object JavaDoc exec(List JavaDoc args) throws TemplateModelException {
1200                Object JavaDoc obj;
1201
1202                int ln = args.size();
1203                if (ln == 0) {
1204                    throw new TemplateModelException(
1205                            "?left_pad(...) expects at least 1 argument.");
1206                }
1207                if (ln > 2) {
1208                    throw new TemplateModelException(
1209                            "?left_pad(...) expects at most 2 arguments.");
1210                }
1211
1212                obj = args.get(0);
1213                if (!(obj instanceof TemplateNumberModel)) {
1214                    throw new TemplateModelException(
1215                            "?left_pad(...) expects a number as "
1216                            + "its 1st argument.");
1217                }
1218                int width = ((TemplateNumberModel) obj).getAsNumber().intValue();
1219
1220                if (ln > 1) {
1221                    obj = args.get(1);
1222                    if (!(obj instanceof TemplateScalarModel)) {
1223                        throw new TemplateModelException(
1224                                "?left_pad(...) expects a string as "
1225                                + "its 2nd argument.");
1226                    }
1227                    String JavaDoc filling = ((TemplateScalarModel) obj).getAsString();
1228                    try {
1229                        return new SimpleScalar(StringUtil.leftPad(s, width, filling));
1230                    } catch (IllegalArgumentException JavaDoc e) {
1231                        if (filling.length() == 0) {
1232                            throw new TemplateModelException(
1233                                    "The 2nd argument of ?left_pad(...) "
1234                                    + "can't be a 0 length string.");
1235                        } else {
1236                            throw new TemplateModelException(
1237                                    "Error while executing the ?left_pad(...) "
1238                                    + "built-in.", e);
1239                        }
1240                    }
1241                } else {
1242                    return new SimpleScalar(StringUtil.leftPad(s, width));
1243                }
1244            }
1245        }
1246    }
1247
1248    static class right_padBI extends BuiltIn {
1249        TemplateModel _getAsTemplateModel(Environment env)
1250                throws TemplateException {
1251            TemplateModel model = target.getAsTemplateModel(env);
1252            if (model instanceof TemplateScalarModel) {
1253                return new BIMethod(((TemplateScalarModel) model).getAsString());
1254            }
1255            throw invalidTypeException(model, target, env, "string");
1256        }
1257
1258        private class BIMethod implements TemplateMethodModelEx {
1259            private String JavaDoc s;
1260
1261            private BIMethod(String JavaDoc s) {
1262                this.s = s;
1263            }
1264
1265            public Object JavaDoc exec(List JavaDoc args) throws TemplateModelException {
1266                Object JavaDoc obj;
1267
1268                int ln = args.size();
1269                if (ln == 0) {
1270                    throw new TemplateModelException(
1271                            "?right_pad(...) expects at least 1 argument.");
1272                }
1273                if (ln > 2) {
1274                    throw new TemplateModelException(
1275                            "?right_pad(...) expects at most 2 arguments.");
1276                }
1277
1278                obj = args.get(0);
1279                if (!(obj instanceof TemplateNumberModel)) {
1280                    throw new TemplateModelException(
1281                            "?right_pad(...) expects a number as "
1282                            + "its 1st argument.");
1283                }
1284                int width = ((TemplateNumberModel) obj).getAsNumber().intValue();
1285
1286                if (ln > 1) {
1287                    obj = args.get(1);
1288                    if (!(obj instanceof TemplateScalarModel)) {
1289                        throw new TemplateModelException(
1290                                "?right_pad(...) expects a string as "
1291                                + "its 2nd argument.");
1292                    }
1293                    String JavaDoc filling = ((TemplateScalarModel) obj).getAsString();
1294                    try {
1295                        return new SimpleScalar(StringUtil.rightPad(s, width, filling));
1296                    } catch (IllegalArgumentException JavaDoc e) {
1297                        if (filling.length() == 0) {
1298                            throw new TemplateModelException(
1299                                    "The 2nd argument of ?right_pad(...) "
1300                                    + "can't be a 0 length string.");
1301                        } else {
1302                            throw new TemplateModelException(
1303                                    "Error while executing the ?right_pad(...) "
1304                                    + "built-in.", e);
1305                        }
1306                    }
1307                } else {
1308                    return new SimpleScalar(StringUtil.rightPad(s, width));
1309                }
1310            }
1311        }
1312    }
1313    
1314}
1315
Popular Tags