1 52 53 package freemarker.core; 54 55 import freemarker.template.*; 56 57 import java.io.UnsupportedEncodingException ; 58 import java.text.DateFormat ; 59 import java.text.NumberFormat ; 60 import java.util.Date ; 61 import java.util.HashMap ; 62 import java.util.Iterator ; 63 import java.util.List ; 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 77 abstract class BuiltIn extends Expression implements Cloneable { 78 Expression target; 79 String key; 80 81 static final HashMap builtins = new HashMap (); 82 83 static { 84 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")); 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 e) {} 170 } 171 172 private static Object instantiate(String className) throws Exception 173 { 174 return ClassUtil.forName(className).newInstance(); 175 } 176 177 static BuiltIn newBuiltIn(Expression target, String key, Token tok, String templateName) throws ParseException { 178 BuiltIn bi = (BuiltIn) builtins.get(key); 179 if (bi == null) { 180 String locationInfo = "Error on line " + tok.beginLine + ", column " + tok.beginColumn + ", in template " + templateName + "\n"; 181 StringBuffer buf = new StringBuffer ("Found " + key + ", expecting one of: "); 182 for (Iterator 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 e) { 199 throw new InternalError (); 200 } 201 bi.target = target; 202 bi.key = key; 203 return bi; 204 } 205 206 public String getCanonicalForm() { 207 return target.getCanonicalForm() + "?" + key; 208 } 209 210 boolean isLiteral() { 211 return false; } 213 214 Expression _deepClone(String name, Expression subst) { 215 try { 216 BuiltIn clone = (BuiltIn)clone(); 217 clone.target = target.deepClone(name, subst); 218 return clone; 219 } 220 catch (CloneNotSupportedException e) { 221 throw new InternalError (); 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 if(dateType == dtype) { 250 return model; 251 } 252 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 String 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 text; 273 private final Environment env; 274 private final DateFormat defaultFormat; 275 private Date cachedValue; 276 277 DateParser(String 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 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 pattern) throws TemplateModelException { 298 return new SimpleDate( 299 parse(env.getDateFormatObject(dateType, pattern)), 300 dateType); 301 } 302 303 public Object exec(List 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 ) arguments.get(0)); 310 } 311 312 public boolean isEmpty() 313 { 314 return false; 315 } 316 317 private Date parse(DateFormat df) 318 throws 319 TemplateModelException 320 { 321 try { 322 return df.parse(text); 323 } 324 catch(java.text.ParseException e) { 325 String 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 number; 365 private final Environment env; 366 private final NumberFormat defaultFormat; 367 private String cachedValue; 368 369 NumberFormatter(Number number, Environment env) 370 { 371 this.number = number; 372 this.env = env; 373 defaultFormat = env.getNumberFormatObject(env.getNumberFormat()); 374 } 375 376 public String getAsString() 377 { 378 if(cachedValue == null) { 379 cachedValue = defaultFormat.format(number); 380 } 381 return cachedValue; 382 } 383 384 public TemplateModel get(String key) 385 { 386 return new SimpleScalar(env.getNumberFormatObject(key).format(number)); 387 } 388 389 public Object exec(List 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 ) 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 date; 411 private final int dateType; 412 private final Environment env; 413 private final DateFormat defaultFormat; 414 private String cachedValue; 415 416 DateFormatter(Date 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 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 key) 440 throws 441 TemplateModelException 442 { 443 return new SimpleScalar(env.getDateFormatObject(dateType, key).format(date)); 444 } 445 446 public Object exec(List 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 ) 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 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 exec(List 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 ) arguments.get(bool.getAsBoolean() ? 0 : 1)); 491 } 492 } 493 } 494 495 static class trimBI extends StringBuiltIn { 496 TemplateModel calculateResult(String s, Environment env) { 497 return new SimpleScalar(s.trim()); 498 } 499 } 500 501 static class htmlBI extends StringBuiltIn { 502 TemplateModel calculateResult(String s, Environment env) { 503 return new SimpleScalar(StringUtil.HTMLEnc(s)); 504 } 505 } 506 507 static class xmlBI extends StringBuiltIn { 508 TemplateModel calculateResult(String s, Environment env) { 509 return new SimpleScalar(StringUtil.XMLEnc(s)); 510 } 511 } 512 513 static class rtfBI extends StringBuiltIn { 514 TemplateModel calculateResult(String s, Environment env) { 515 return new SimpleScalar(StringUtil.RTFEnc(s)); 516 } 517 } 518 519 static class urlBI extends StringBuiltIn { 520 521 TemplateModel calculateResult(String s, Environment env) { 522 return new urlBIResult(s, env); 523 } 524 525 static class urlBIResult implements 526 TemplateScalarModel, TemplateMethodModel { 527 528 private final String target; 529 private final Environment env; 530 private String cachedResult; 531 532 private urlBIResult(String target, Environment env) { 533 this.target = target; 534 this.env = env; 535 } 536 537 public String getAsString() throws TemplateModelException { 538 if (cachedResult == null) { 539 String 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 e) { 555 throw new TemplateModelException( 556 "Failed to execute URL encoding.", e); 557 } 558 } 559 return cachedResult; 560 } 561 562 public Object exec(List 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 ) args.get(0))); 570 } catch (UnsupportedEncodingException 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 exec(List args) { 852 return constant; 853 } 854 } 855 856 860 private static final TemplateMethodModelEx FIRST_NON_NULL_METHOD = 861 new TemplateMethodModelEx() { 862 public Object exec(List 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 s; 891 892 private BIMethod(String s) { 893 this.s = s; 894 } 895 896 public Object exec(List args) throws TemplateModelException { 897 Object obj; 898 String 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 s; 934 935 private BIMethod(String s) { 936 this.s = s; 937 } 938 939 public Object exec(List args) throws TemplateModelException { 940 Object obj; 941 String 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 s; 991 992 private BIMethod(String s) { 993 this.s = s; 994 } 995 996 public Object exec(List args) throws TemplateModelException { 997 Object obj; 998 String 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 s; 1046 1047 private BIMethod(String s) { 1048 this.s = s; 1049 } 1050 1051 public Object exec(List args) throws TemplateModelException { 1052 String sub; 1053 1054 if (args.size() != 1) { 1055 throw new TemplateModelException( 1056 "?starts_with(...) expects exactly 1 argument."); 1057 } 1058 1059 Object 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 s; 1084 1085 private BIMethod(String s) { 1086 this.s = s; 1087 } 1088 1089 public Object exec(List args) throws TemplateModelException { 1090 String sub; 1091 1092 if (args.size() != 1) { 1093 throw new TemplateModelException( 1094 "?ends_with(...) expects exactly 1 argument."); 1095 } 1096 1097 Object 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 s; 1122 1123 private BIMethod(String s) { 1124 this.s = s; 1125 } 1126 1127 public Object exec(List 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 first = (String ) args.get(0); 1134 String second = (String ) args.get(1); 1135 String flags = numArgs >2 ? (String ) 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 s; 1159 1160 private BIMethod(String s) { 1161 this.s = s; 1162 } 1163 1164 public Object exec(List 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 splitString = (String ) args.get(0); 1171 String flags = numArgs ==2 ? (String ) 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 s; 1194 1195 private BIMethod(String s) { 1196 this.s = s; 1197 } 1198 1199 public Object exec(List args) throws TemplateModelException { 1200 Object 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 filling = ((TemplateScalarModel) obj).getAsString(); 1228 try { 1229 return new SimpleScalar(StringUtil.leftPad(s, width, filling)); 1230 } catch (IllegalArgumentException 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 s; 1260 1261 private BIMethod(String s) { 1262 this.s = s; 1263 } 1264 1265 public Object exec(List args) throws TemplateModelException { 1266 Object 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 filling = ((TemplateScalarModel) obj).getAsString(); 1294 try { 1295 return new SimpleScalar(StringUtil.rightPad(s, width, filling)); 1296 } catch (IllegalArgumentException 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 |