1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737
|
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<document>
<properties>
<title>Developer's Guide</title>
<author email="dev@velocity.apache.org">Velocity Documentation Team</author>
</properties>
<body>
<section name="Developer Guide - Contents" href="developer_guide_-_contents">
<p>
<ol>
<li>
<a href="#Introduction">Introduction and Getting Started</a>
</li>
<li>
<a href="#Resources">Resources</a>
</li>
<li>
<a href="#How_Velocity_Works">How Velocity Works</a>
<ul>
<li><a href="#thefundamentalpattern">The Fundamental Pattern</a></li>
</ul>
</li>
<li>
<a href="#To_Singleton_Or_Not_To_Singleton...">To Singleton Or Not To Singleton...</a>
<ul>
<li><a href="#singleton">Singleton Model</a></li>
<li><a href="#separate">Separate Instance</a></li>
</ul>
</li>
<li>
<a href="#The_Context">The Context</a>
<ul>
<li><a href="#thebasics">The Basics</a></li>
<li><a href="#supportforiterativeobjectsforforeach">Support for Iterative Objects for #foreach()</a></li>
<li><a href="#supportforstaticclasses">Support for "Static Classes"</a></li>
<li><a href="#contextchaining">Context Chaining</a></li>
<li><a href="#objectscreatedinthetemplate">Objects Created by the Template</a></li>
<li><a href="#othercontextissues">Other Context Issues</a></li>
</ul>
</li>
<li>
<a href="#Using_Velocity">Using Velocity in General Applications</a>
<ul>
<li><a href="#thevelocityhelperclass">The Velocity Helper Class</a></li>
<li><a href="#exceptions">Exceptions</a></li>
<li><a href="#miscellaneousdetails">Miscellaneous Details</a></li>
</ul>
</li>
<li>
<a href="#Application_Attributes">Application Attributes</a>
</li>
<li>
<a href="#Configuring_Event_Handlers">Configuring Event Handlers</a>
</li>
<li>
<a href="#Velocity_Configuration_Keys_and_Values">Velocity Configuration Keys and Values</a>
</li>
<li>
<a href="#Configuring_Logging">Configuring Logging</a>
<ul>
<li>
<a href="#usinglog4jwithexistinglogger">Using Log4j With Existing Logger</a>
</li>
<li>
<a href="#simpleexampleofacustomlogger">Simple Example of a Custom Logger</a>
</li>
</ul>
</li>
<li>
<a href="#Configuring_Resource_Loaders">Configuring the Resource Loaders (template loaders)</a>
<ul>
<li>
<a href="#resourceloaders">Resource Loaders</a>
</li>
<li>
<a href="#configurationexamples">Configuration Examples</a>
</li>
<li>
<a href="#resourcemanagerandcache">Pluggable Resource Manager and Resource Cache</a>
</li>
</ul>
</li>
<li>
<a href="#Template_Encoding_for_Internationalization">Template Encoding for Internationalization</a>
</li>
<li>
<a href="#Velocity_and_XML">Velocity and XML</a>
</li>
<li>
<a href="#Summary">Summary</a>
</li>
</ol>
</p>
</section>
<section name="Introduction" href="Introduction">
<p>
Velocity is a Java-based template engine, a simple and powerful development tool
that allows you to easily create and render documents that format and present
your data. In this guide, we hope to give an overview of the basics of
development using Velocity.
<p>
<strong>Building Web Applications with Velocity</strong>
</p>
Velocity is often used for building web applications
In order to use Velocity in a web app you'll need a servlet or servlet-based
framework. The easiest way to get started is with
<a href="http://velocity.apache.org/tools/devel/view/">VelocityViewServlet</a> in the
<a href="http://velocity.apache.org/tools/devel/">Velocity Tools</a>
subproject. You can also use any of a number of
<a href="http://wiki.apache.org/velocity/PoweredByVelocity">third party frameworks</a>
or build your own servlet using the techniques described in this document.
</p>
<p>
We suggest you read this article on
<a href="../webapps.html">getting started with web applications</a> for
more detail on the various options.
</p>
<p>
<strong>Downloading Velocity</strong>
</p>
<p>
You can download the latest release version of
<a href="http://velocity.apache.org/download.cgi#engine">Velocity</a>
or <a href="http://velocity.apache.org/download.cgi#tools">Velocity Tools</a>
from the main Apache Velocity download site. For Velocity itself, source is included with the binary download.
</p>
<p>
If you want to download the latest source, you can do so via the Subversion (svn)
source control system, or download a complete
<a href="http://svn.apache.org/snapshots/velocity/">nightly snapshot.</a>
</p>
<p>
Instructions for building Velocity from source can be found in the
<a href="build.html">Build</a> document.
</p>
<strong>Dependencies</strong>
<p>
Velocity uses elements of the Java 2 API such as collections, and therefore
building requires the Java 2 Standard Edition SDK (Software Development Kit).
To run Velocity, the Java 2 Standard Edition RTE (Run Time Environment)
is required (or you can use the SDK, of course).
</p>
<p>
Velocity also is dependent upon a few packages for general functionality. They
are included in the <code>build/lib</code> directory for convenience, but
the default build target (see above) does not include them. If you use the
default build target, you must add the dependencies to your classpath.
</p>
<ul>
<li>
<a href="http://jakarta.apache.org/commons/collections">
<b>Jakarta Commons Collections</b></a> - required.
</li>
<li>
<a href="http://jakarta.apache.org/commons/lang">
<b>Jakarta Commons Lang</b></a> - required.
</li>
<li>
<a href="http://excalibur.apache.org/logger.html">
<b>Excalibur (ex-Avalon) Logkit</b></a> - optional, but very common.
Needed if using the default file-based logging in Velocity.
</li>
<li>
<a href="http://jakarta.apache.org/oro/index.html"><b>Jakarta ORO</b></a>
- optional. Needed when using the
<code>org.apache.velocity.convert.WebMacro</code> template conversion
utility.
</li>
</ul>
</section>
<section name="Resources" href="Resources">
<p>
There are quite a few resources and examples available to the programmer, and we
recommend that you look at our examples, documentation and even the source code.
Some great sources are:
</p>
<ul>
<li>
The user and developer community: join us via the
<a href="http://velocity.apache.org/contact.html">mail-lists</a>. Mail list archives are available from that page, too.
</li>
<li>
Wiki:
<a href="http://wiki.apache.org/velocity/">http://wiki.apache.org/velocity/</a>
The Velocity wiki contains articles, sample code, and other community-written content.
</li>
<li>
Frequently Asked Questions (FAQ):
<a href="http://wiki.apache.org/velocity/VelocityFAQ">http://wiki.apache.org/velocity/VelocityFAQ</a>
please visit this page to read the latest FAQ and to contribute your own answers.
</li>
<li>
source code: <code>src/java/...</code>: all the source code to the
Velocity project
</li>
<li>
application example 1: <code>examples/app_example1</code>: a simple
example showing how to use Velocity in an application program.
</li>
<li>
application example 2: <code>examples/app_example2</code>: a simple
example showing how to use Velocity in an application program using the
Velocity application utility class.
</li>
<li>
logger example: <code>examples/logger_example</code>: a simple example
showing how to create a custom logging class and register it with
Velocity to receive all log messages.
</li>
<li>
XML example: <code>examples/xmlapp_example</code>: a simple example
showing how to use JDOM to read and access XML document data from
within a Velocity template. It also includes a demonstration of
a recursive Velocimacro that walks the document tree.
</li>
<li>
event example: <code>examples/event_example</code>: An example that
demonstrates the use of the event handling API.
</li>
<li>
Anakia application: <code>examples/anakia</code>: example application
showing how to use Velocity for creating stylesheet renderings of xml data
</li>
<li>
documentation: <code>docs</code>: all the generated documentation for the
Velocity project in html
</li>
<li>
API documentation: <code>docs/api</code>: the generated Javadoc
documentation for the Velocity project
</li>
<li>
templates: <code>test/templates</code>: a large collection of template
examples in our testbed directory, these are a great source of useage
examples of VTL, the Velocity Template Language
</li>
<li>
context example: <code>examples/context_example</code>: two examples
showing how the Velocity context can be extended. For advanced users.
</li>
</ul>
<p>
All directory references above are relative to the distribution root directory.
</p>
</section>
<section name="How Velocity Works" href="How_Velocity_Works">
<p>
<a name="thefundamentalpattern"><strong>'The Fundamental Pattern'</strong></a>
</p>
<p>
When using Velocity in an application program or in a servlet
(or anywhere, actually), you will generally do the following:
</p>
<ol>
<li>Initialize Velocity. This applies to both usage patterns for Velocity,
the Singleton as well as the 'separate runtime instance' (see more on this
below), and you only do this once.</li>
<li>Create a Context object (more on what that is later).</li>
<li>Add your data objects to the Context.</li>
<li>Choose a template.</li>
<li>'Merge' the template and your data to produce the ouput.</li>
</ol>
<p>
In code, using the singleton pattern via the
<code>org.apache.velocity.app.Velocity</code> class,
this looks like
</p>
<source><![CDATA[
import java.io.StringWriter;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.Template;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.MethodInvocationException;
Velocity.init();
VelocityContext context = new VelocityContext();
context.put( "name", new String("Velocity") );
Template template = null;
try
{
template = Velocity.getTemplate("mytemplate.vm");
}
catch( ResourceNotFoundException rnfe )
{
// couldn't find the template
}
catch( ParseErrorException pee )
{
// syntax error: problem parsing the template
}
catch( MethodInvocationException mie )
{
// something invoked in the template
// threw an exception
}
catch( Exception e )
{}
StringWriter sw = new StringWriter();
template.merge( context, sw );
]]></source>
<p>
That's the basic pattern. It is very simple, isn't it? This is generally what
happens when you use Velocity to render a template. You probably won't be
writing code exactly like this - we provide a few tools to help make it even
easier. However, no matter how to use Velocity the above sequence is what is happening
either explicitly, or behind the scenes.
</p>
</section>
<section name="To Singleton Or Not To Singleton..." href="To_Singleton_Or_Not_To_Singleton...">
<p>
As of Velocity 1.2 and later, developers now have two options
for using the Velocity engine, the singleton model and the separate instance
model. The same core Velocity code is used for both approaches, which are
provided to make Velocity easier to integrate into your Java application.
</p>
<p>
<a name="singleton"><strong>Singleton Model</strong></a>
</p>
<p>
This is the legacy pattern, where there is only one instance of the Velocity
engine in the JVM (or web application, depending) that is shared by all.
This is very convenient as it
allows localized configuration and sharing of resources. For example, this
is a very appropriate model for use in a Servlet 2.2+ compliant web application
as each web application can have its own instance of Velocity, allowing
that web application's servlet to share resources like templates, a logger, etc.
The singleton is accessable via the <code>org.apache.velocity.app.Velocity</code>
class, and and example of use:
</p>
<source><![CDATA[
import org.apache.velocity.app.Velocity;
import org.apache.velocity.Template;
...
/*
* Configure the engine - as an example, we are using
* ourselves as the logger - see logging examples
*/
Velocity.setProperty(
Velocity.RUNTIME_LOG_LOGSYSTEM, this);
/*
* now initialize the engine
*/
Velocity.init();
...
Template t = Velocity.getTemplate("foo.vm");
]]></source>
<p>
<a name="separate"><strong>Separate Instance</strong></a>
</p>
<p>
New in version 1.2, the separate instance allows you to create, configure
and use as many instances of Velocity as you wish in the same JVM
(or web application.) This
is useful when you wish to support separate configurations, such as template
directories, loggers, etc in the same application. To use separate
instances, use the <code>org.apache.velocity.app.VelocityEngine</code>
class. An example, which parallels the above singleton example, looks
like:
</p>
<source><![CDATA[
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.Template;
...
/*
* create a new instance of the engine
*/
VelocityEngine ve = new VelocityEngine();
/*
* configure the engine. In this case, we are using
* ourselves as a logger (see logging examples..)
*/
ve.setProperty(
VelocityEngine.RUNTIME_LOG_LOGSYSTEM, this);
/*
* initialize the engine
*/
ve.init();
...
Template t = ve.getTemplate("foo.vm");
]]></source>
<p>
As you can see, this is very simple and straightforward. Except for some simple
syntax changes, using Velocity as a singleton or as separate instances requires
no changes to the high-level structure of your application or templates.
</p>
<p>
As a programmer, the classes you should use to interact with the Velocity
internals are the <code>org.apache.velocity.app.Velocity</code> class if
using the singleton model, or <code>org.apache.velocity.app.VelocityEngine</code>
if using the non-singleton model ('separate instance').
</p>
<p>
At no time should an application use the internal <code>Runtime, RuntimeConstants,
RuntimeSingleton or RuntimeInstance</code> classes in the
<code>org.apache.velocity.runtime</code> package, as these are intended for
internal use only and may change over time. As mentioned above,
the classes you should use
are located in the <code>org.apache.velocity.app</code> package, and are the
<code>Velocity</code> and <code>VelocityEngine</code> classes. If anything is
missing or needed from those classes, do not hesitate to suggest changes - these
classes are intended for the application developer.
</p>
</section>
<section name="The Context" href="The_Context">
<a name="thebasics"><strong>The Basics</strong></a>
<p>
The concept of the 'context' is central to Velocity, and is a common technique
for moving a container of data around between parts of a system. The idea is
that the context is a 'carrier' of data between the Java layer (or you the
programmer) and the template layer ( or the designer ). You as the programmer
will gather objects of various types, whatever your application calls for, and
place them in the context. To the designer, these objects, and their methods
and properties, will become accessable via template elements called
<a href="vtl-reference-guide.html"> references</a>. Generally, you will work
with the designer to determine the data needs for the application. In a sense,
this will become an 'API' as you produce a data set for the designer to access
in the template. Therefore, in this phase of the development process it is
worth devoting some time and careful analysis.
</p>
<p>
While Velocity allows you to create your own context classes to support special
needs and techniques (like a context that accesses an LDAP server directly, for
example), a good basic implementation class called VelocityContext is provided
for you as part of the distribution.
</p>
<p>
VelocityContext is suitable for all general purpose needs, and we strongly
recommended that you use it. Only in exceptional and advanced cases will you
need to extend or create your own context implementation.
</p>
<p>
Using VelocityContext is as simple as using a normal Java Hashtable class.
While the interface contains other useful methods, the two main methods you
will use are
</p>
<source><![CDATA[
public Object put(String key, Object value);
public Object get(String key);
]]></source>
<p>
Please note that like a Hashtable, the value must be derived from
java.lang.Object, and must not be null. Fundamental types like int or float must
be wrapped in the appropriate wrapper classes.
</p>
<p>
That's really all there is to basic context operations. For more information,
see the API documentation included in the distribution.
</p>
<p>
<a name="supportforiterativeobjectsforforeach"><strong>Support for Iterative Objects for
#foreach()</strong></a>
</p>
<p>
As a programmer, you have great freedom in the objects that you put into the
context. But as with most freedoms, this one comes with a little bit of
responsibility, so understand what Velocity supports, and any issues that may
arise. Velocity supports serveral types of collection types suitable for use
in the VTL <code>#foreach()</code> directive.
</p>
<ul>
<li> <code>Object [] </code> Regular object array, not much needs to be said
here. Velocity will internally wrap your array in a class that provides an
Iterator interface, but that shouldn't concern you as the programmer, or the
template author. Of more interest, is the fact that Velocity will now
allow template authors to treat arrays as fixed-length lists (as of Velocity 1.6).
This means they may call methods like <code>size()</code>,
<code>isEmpty()</code> and <code>get(int)</code> on both arrays and standard
java.util.List instances without concerning themselves about the difference.
</li>
<li> <code>java.util.Collection</code> Velocity will use the
<code>iterator()</code> method to get an Iterator to use in the loop,
so if you are implementing a Collection interface on your object, please
ensure that <code>iterator()</code> returns a working Iterator.
</li>
<li> <code>java.util.Map </code> Here, Velocity depends upon the
<code>values()</code> method of the interface to get a <code>Collection</code>
interface, on which <code>iterator()</code> is called to retrieve an Iterator
for the loop.
</li>
<li> <code>java.util.Iterator</code> USE WITH CAUTION: This is currently
supported only provisionally - the issue of concern is the
'non-resettablity' of the Iterator. If a 'naked' Iterator is placed into
the context, and used in more than one #foreach(), subsequent #foreach()
blocks after the first will fail, as the Iterator doesn't reset.
</li>
<li> <code>java.util.Enumeration</code> USE WITH CAUTION: Like
<code>java.util.Iterator</code>, this is currently
supported only provisionally - the issue of concern is the
'non-resettablity' of the Enumeration. If a 'naked' Enumeration
is placed into the context, and used in more than one #foreach(),
subsequent #foreach() blocks after the first will fail,
as the Enumeration doesn't reset.
</li>
<li> Any public class with a <code>public Iterator iterator()</code> method
that never returns <code>null</code>. As a last resort, Velocity will
look for an <code>iterator()</code> method. This provides great flexibility
and automatic support for Java 1.5's <code>java.util.Iterable</code> interface.
</li>
</ul>
<p>
In the case of the <code>Iterator</code> and <code>Enumeration</code>, it is
recommended that they are placed in the context only when it cannot be avoided,
and you should let Velocity find the appropriate reusable iterative interface when
that is sufficient and possible.
</p>
<p>
There are good reasons to use the <code>java.util.Iterator</code> interface
directly (large data sets via JDBC, for example), but if it can be
avoided, it might be better to use something else. By 'directly' , we meant
doing something like:
</p>
<source><![CDATA[
Vector v = new Vector();
v.addElement("Hello");
v.addElement("There");
context.put("words", v.iterator() );
]]></source>
<p>
where the Iterator itself is placed into the context. Instead, if you
simply did:
</p>
<source><![CDATA[
context.put("words", v );
]]></source>
<p>
then all would be fine: Velocity would figure out that Vector implement
Collection (via List), and therefore will find the <code>iterator()</code>
method, and use that to get a 'fresh' Iterator for its use each time
it needs to. With just a plain Iterator (the first snippet above...),
once velocity has used it in a <code>#foreach()</code>, Velocity has
no way of getting a new one to use for the next <code>#foreach()</code>
it is used in. The result is no output from any subsequent
<code>#foreach()</code> blocks using that reference.
</p>
<p>
This above isn't meant to give the impression that iterating over
collections in Velocity is something that requires great care and
thought. Rather, the opposite is true, in general. Just be
careful when you place an Iterator into the context.
</p>
<a name="supportforstaticclasses"><strong>Support for "Static Classes"</strong></a>
<p>Not all classes are instantiable. Classes like <code>java.lang.Math</code>
do not provide any public constructor, and yet may contain useful static methods.
In order to access these static methods from a template, you can simply add the
class itself to the context:
</p>
<source><![CDATA[
context.put("Math", Math.class);
]]></source>
<p>This will allow you to call any public static method in <code>java.lang.Math</code>
on the <code>$Math</code> reference in the template.
</p>
<a name="contextchaining"><strong>Context Chaining</strong></a>
<p>
An innovative feature of Velocity's context design is the concept
of <i>context chaining</i>. Also sometimes referred to as
<i>context wrapping</i>, this advanced feature allows you to connect
separate contexts together in a manner that makes it appear as one
'contiguous' context to the template.
</p>
<p>
This is best illustrated by an example:
</p>
<source><![CDATA[
VelocityContext context1 = new VelocityContext();
context1.put("name","Velocity");
context1.put("project", "Jakarta");
context1.put("duplicate", "I am in context1");
VelocityContext context2 = new VelocityContext( context1 );
context2.put("lang", "Java" );
context2.put("duplicate", "I am in context2");
template.merge( context2, writer );
]]></source>
<p>
In the code above, we have set up context2 such that it <i>chains</i>
context1. This means that in the template, you can access any of
the items that were put into either of the two VelocityContext objects,
as long as there is no duplication of the keys used to add objects.
If that is the case, as it is above for the key 'duplicate', the object
stored in the nearest context in the chain will be available. In this
example above, the object returned would
be the string "I am in context2".
</p>
<p>
Note that this duplication, or 'covering', of a context item does not in
any way harm or alter the covered object. So in the example above, the
string "I am in context1" is alive and well, still accessable via
context1.get("duplicate"). But in the example above, the value of the
reference '$duplicate' in the template would be 'I am in context2',
and the template has no access to the covered string 'I am in context1'.
</p>
<p>
Note also that you have to be careful when you are relying on the template
to add information to a context that you will examine later after the
rendering. The changes to the context via <code>#set()</code> statements
in a template will affect only the outer context. So make sure that you
don't discard the outer context, expecting the data from the template to
have been placed onto the inner one.
</p>
<p>
This feature has many uses, the most common so far is providing layered
data access and toolsets.
</p>
<p>
As mentioned before, the Velocity context mechanism is also extendable,
but beyond the current scope of this guide. If you are interested,
please see the classes in the package <code>org.apache.velocity.context</code>
to see how the provided contexts are put together. Futher, there are a few
examples in the <code>examples/context_example</code> directory in the
distribution which show alternate implementations, including [a goofy] one
that uses a database as the backing storage.
</p>
<p>
Please note that these examples are unsupported and are there for
demonstration/educational purposes only.
</p>
<a name="objectscreatedinthetemplate"><strong>Objects Created in the
Template</strong></a>
<p>
There are two common situations where the Java code must deal with objects
created at runtime in the template:
</p>
<p>
When a template author calls a method of an object placed into
the context by Java code.
</p>
<source><![CDATA[
#set($myarr = ["a","b","c"] )
$foo.bar( $myarr )
]]></source>
<p>
When a template adds objects to the context, the Java code can access
those objects after the merge process is complete.
</p>
<source><![CDATA[
#set($myarr = ["a","b","c"] )
#set( $foo = 1 )
#set( $bar = "bar")
]]></source>
<p>
Dealing with these cases if very straighforward, as there are just a few
things to know:
</p>
<ul>
<li>
The VTL RangeOperator [ 1..10 ] and ObjectArray ["a","b"] are
<code>java.util.ArrayList</code> objects when placed in the context
or passed to methods. Therefore, your methods that are designed to
accept arrays created in the template should be written with this
in mind.
</li>
<li>VTL Map references are unsurprisingly stored as <code>java.util.Map</code>.</li>
<li>
Decimal numbers will be Doubles or BigDecimals in the context, integer numbers will be
Integer, Long, or BigIntegers, and strings will be, of course, Strings.
</li>
<li>
Velocity will properly 'narrow' args to method calls, so calling
<code>setFoo( int i )</code> with an int placed into the
context via <code>#set()</code> will work fine.
</li>
</ul>
<a name="othercontextissues"><strong>Other Context Issues</strong></a>
<p>
One of the features provided by the VelocityContext
(or any Context derived from AbstractContext) is
node specific introspection caching. Generally, you as a the developer
don't need to worry about this when using the VelocityContext
as your context. However, there is currently one
known usage pattern where you must be aware of this feature.
</p>
<p>
The VelocityContext will accumulate intropection information about the
syntax nodes in a template as it visits those nodes. So, in the following
situation:
</p>
<ul>
<li>
You are iterating over the same template using the same VelocityContext
object.
</li>
<li>
Template caching is off.
</li>
<li>
You request the Template from getTemplate() on each iteration.
</li>
</ul>
<p>
It is possible that your VelocityContext will appear to 'leak' memory
(it is really just gathering more introspection information.) What
happens is that it accumulates template node introspection information
for each template it visits, and as template caching is off, it appears
to the VelocityContext that it is visiting a new template each time.
Hence it gathers more introspection information and grows. It is highly
recommended that you do one or more of the following:
</p>
<ul>
<li>Create a new VelocityContext for each excursion
down through the template render process. This will prevent the accumulation
of introspection cache data. For the case where you want to reuse the
VelocityContext because it's populated with data or objects,
you can simply wrap the populated
VelocityContext in another, and the 'outer' one will accumulate the
introspection information, which you will just discard. Ex.
<code>VelocityContext useThis = new VelocityContext( populatedVC );</code>
This works because the outer context will store the introspection
cache data, and get any requested data from the inner context (as it is empty.)
Be careful though - if your template places data into the context and it's
expected that it will be used in the subsequent iterations, you will need to do
one of the other fixes, as any template #set() statements will be stored in
the outermost context. See the discussion in
<a href="#contextchaining"><b>Context chaining</b></a> for more
information.
</li>
<li>
Turn on template caching. This will prevent the template from being re-parsed
on each iteration, resulting the the VelocityContext being able to not only
avoid adding to the introspection cache information, but be able to use it
resulting in a performance improvement.
</li>
<li>
Reuse the Template object for the duration of the loop iterations.
Then you won't be forcing Velocity, if the cache is turned off, to
reread and reparse the same template over and over, so the VelocityContext
won't gather new introspection information each time.
</li>
</ul>
</section>
<section name="Using Velocity" href="Using_Velocity">
<p>If you are using <a href="http://velocity.apache.org/tools/devel/view/">VelocityViewServlet</a>
or other web frameworks, you may never call Velocity directly. However, if you use
Velocity for non-web purposes, or create your own web framework you will need
to directly call the Velocity Engine similar to
<a href="#thefundamentalpattern">the fundamental pattern</a> shown earlier.
One important additional thing to remember is to initialize the Velocity Engine before
using it to merge templates.
</p>
<a name="thevelocityhelperclass"><strong>The Velocity Helper Class</strong></a>
<p>
Velocity contains an application utility class called Velocity
( <code>org.apache.velocity.app.Velocity</code> ). The purpose of this class
is to provide the necessary methods required to initialize Velocity, as well as
useful utility routines to make life easier in using Velocity. This class is
documented in the project's javadoc, so please look there for definitive
details. This documentation is intended to be of a tutorial nature; therefore
for compete API information, the Javadoc is the definitive source.
</p>
<p>
The Velocity runtime engine is a singleton instance that provides resource,
logging and other services to all Velocity users running in the same JVM.
Therefore, the runtime engine is initialized only once. You can attempt to
initialize Velocity more than once, but only the first initialization will
apply. The rest of the attempts will be ignored. The Velocity utility
class currently provides five methods used in configuration of the runtime engine.
</p>
<p>
The five configuration methods are:
</p>
<ul>
<li><code>setProperty( String key, Object o )</code><br/>
Sets the property <code>key</code> with the value <code>o</code>. The value
is typically a String, but in special cases can also be a comma-separated
list of values (in a single String, ex."foo, bar, woogie") as well as other
things that will arise.
</li>
<li><code>Object getProperty( String key )</code><br/>
Returns the value of the property key. Note that you must be aware of the
type of the return value, as they can be things other than Strings.
</li>
<li><code>init()</code><br/>
Initializes the runtime with the default properties provided in the
distribution.(These are listed below in the section pertaining to
properties.)
</li>
<li><code>init( Properties p )</code><br/> Initialize the runtime with the
properties contained in the <code>java.util.Properties</code> object passed
as an argument.
</li>
<li><code>init( String filename )</code><br/> initilizes the runtime
using the properties found in the properties file filename
</li>
</ul>
<p>
Note that in each case, the default properties will be used as a base
configuration, and any additional properties specified by the application
will replace individual defaults. Any default properties not overwritten
will remain in effect. This has the benefit that only the properties
you are interested in changing need to be specified, rather
than a complete set.
</p>
<p>
Another thing to note is that the <code>init()</code> calls may be called
more than once without harm in an application. However, the first call to any
of the <code>init()</code> functions will configure the engine with the
configuration properties set at that point, and any further configuration
changes or <code>init()</code> calls will be ignored.
</p>
<p>
The most common approaches to initializing Velocity will be something like:
</p>
<ol>
<li> Setup the configuration values you wish to set in a file in the same
format as org/apache/velocity/runtime/defaults/velocity.properties
(the default set), or in a <code>java.util.Properties</code>, and then
call either <code>init( filename )</code> or <code>init( Properties )</code>
</li>
<li> Set the configuration values individually using <code>setProperty()</code>
and then call <code>init()</code>. This method is generally used by more advanced
applications that already have their own configuration management system -
this allows the application so configure Velocity based upon values it generates
at runtime, for example.
</li>
</ol>
<p>
Once the runtime is initialized, you can do with it what you wish.. This mostly
revolves around rendering templates into an output stream, and the Velocity
utility class allows you to do this easily. Currently, here are the methods
and a brief description of what they do:
</p>
<ul>
<li>
<code> evaluate( Context context, Writer out, String logTag,
String instring )</code><br/>
<code>evaluate( Context context, Writer writer, String logTag,
InputStream instream )</code><br/>
These methods will render the input, in either the form of String or
InputStream to an output Writer, using a Context that you provide.
This is a very convenienient method to use for token replacement of
strings, or if you keep 'templates' of VTL-containing content in a
place like a database or other non-file storage, or simply generate such
dynamically.
</li>
<li>
<code>invokeVelocimacro( String vmName, String namespace, String params[],
Context context, Writer writer )</code><br/>
Allows direct access to Velocimacros. This can also be accomplished
via the <code>evaluate()</code> method above if you wish. Here you
simply name the vm you wish to be called, create an array of args to the VM,
a Context of data, and Writer for the output. Note that the VM args
must be the 'keys' of the data objects in the Context, rather than
literal data to be used as the arg. This will probably change.
</li>
<li>
<code>mergeTemplate( String templateName, Context context, Writer writer )
</code><br/>
Convenient access to the normal template handling and rendering services
of Velocity. This method will take care of getting and rendering the
template. It will take advantage of loading the template according
to the properties setting for the file resource loader, and therefore
provides the advantage of file and parsed template caching that Velocity
offers. This is the most efficient way to access templates,
and is recommended unless you have special needs.
</li>
<li>
<code> boolean templateExists( String name ) </code><br/>
Determines if a template <code>name</code> is able to be found by
the currently configured resource loaders.
</li>
</ul>
<p>
Once we know about these basic helpers, it is easy to write Java program
that uses Velocity. Here it is:
</p>
<source><![CDATA[
import java.io.StringWriter;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.VelocityContext;
public class Example2
{
public static void main( String args[] )
{
/* first, we init the runtime engine. Defaults are fine. */
Velocity.init();
/* lets make a Context and put data into it */
VelocityContext context = new VelocityContext();
context.put("name", "Velocity");
context.put("project", "Jakarta");
/* lets render a template */
StringWriter w = new StringWriter();
Velocity.mergeTemplate("testtemplate.vm", context, w );
System.out.println(" template : " + w );
/* lets make our own string to render */
String s = "We are using $project $name to render this.";
w = new StringWriter();
Velocity.evaluate( context, w, "mystring", s );
System.out.println(" string : " + w );
}
}
]]></source>
<p>
When we run this program, and have the template <code> testtemplate.vm</code>
in the same directory as our program (because we used the default
configuration properties, and the defaul place to load templates
from is the current directory...), our output should be:
</p>
<source><![CDATA[
template : Hi! This Velocity from the Jakarta project.
string : We are using Jakarta Velocity to render this.
]]></source>
<p>
where the template we used, testtemplate.vm, is
</p>
<source><![CDATA[
Hi! This $name from the $project project.
]]></source>
<p>
That's all there is to it! Note that we didn't have to use both
<code>mergeTemplate()</code> and <code>evaluate()</code> in our
program. They are both included there for demonstration purposes.
You will probably use only one of the methods, but depending
on you application requirements, you are free to do what you wish.
</p>
<p>
This appears to be a little different from the 'fundamental pattern'
that was mentioned at the beginning of this guide, but it really is the
same thing. First, you are making a context and filling it with
the data needed. Where this examples differs is that in the part of
the above example where <code>mergeTemplate()</code> is used,
<code>mergeTemplate()</code> is doing the work of getting the template
and merging it for you, using the lower-level calls in the Runtime class.
In the second example, you are making your template dynamically via the
String, so that is analgous to the 'choose template' part of the process,
and the <code>evaluate()</code> method does the merging for you using
lower level calls.
</p>
<p>
So the example above sticks to the same simply pattern of using the Velocity
template engine, but the utility functions do some of
the repeated drudge work, or allow you other options for your
template content other than template files.
</p>
<a name="exceptions"><strong>Exceptions</strong></a>
<p>
Velocity may throw one of several exceptions during the parse / merge cycle. These
exceptions extend RuntimeException and do not need to explicitly caught,
although each includes specific properties that may help in presenting
useful error messages to the end user. The exceptions
are found in the package <code>org.apache.velocity.exception</code> and are:
</p>
<ol>
<li>
<code>ResourceNotFoundException</code><br/>
Thrown when the resource managment system cannot find a resource (template) that
was requested.
</li>
<li>
<code>ParseErrorException</code><br/>
Thrown when a VTL syntax error is found when parsing a resource (template).
</li>
<li>
<code>TemplateInitException</code><br/>
Thrown during the first pass of template parsing; reports problems with macro and
directive initialization.
</li>
<li>
<code>MethodInvocationException</code><br/>
Thrown when a method of object in the context thrown an exception during
render time. This exception wraps the thrown exception and propogates it
to the application. This allows you to handle problems in your own objects
at runtime.
</li>
</ol>
<p>
In each case, a message is put into the runtime log. For more information,
see the Javadoc API documentation.
</p>
<a name="miscellaneousdetails"><strong>Miscellaneous Details</strong></a>
<p>
While the above example used the default properties, setting your own
properties is very simple. All you have to do is make a properties file
somewhere and pass the name of that file to the <code>init(String)</code>
method of the Velocity utility class, or make a
<code>java.util.Properties</code> object, add the desired properties and
values, and pass that to the <code>init(Properties)</code> method.
The latter method is convenient, because you can either fill it directly
from a separate properties file via the <code>load()</code> method, or even
better, you can fill it dynamically from your own application / framework's
property set at runtime. This gives you the freedom to combine all of the
properties for your app into one properties file.
</p>
<p>
If we wanted to use a different directory than the current directory to
load our template from, we could do something like this:
</p>
<source><![CDATA[
...
import java.util.Properties;
...
public static void main( String args[] )
{
/* first, we init the runtime engine. */
Properties p = new Properties();
p.setProperty("file.resource.loader.path", "/opt/templates");
Velocity.init( p );
/* lets make a Context and put data into it */
...
]]></source>
<p>
And, assuming you have a directory <code>/opt/templates</code> and the template
<code>testtemplate.vm</code> is in there, then things would work just fine.
If you try this and have a problem, be sure to look at the velocity.log for
information - the error messages are pretty good for figuring out what is wrong.
</p>
<p>
If you need to place objects into the Velocity properties then you cannot use
the Velocity.init(Properties p) method. Instead you should create a new instance
of the <code>org.apache.commons.collections.ExtendedProperties</code> class, copy
all properties from an existing Properties object into the ExtendedProperties and
then add new properties with your objects to the ExtendedProperties object.
</p>
<source><![CDATA[ ...
VelocityEngine velocityEngine = new VelocityEngine();
ExtendedProperties eprops = null;
if (props==null) {
eprops = new ExtendedProperties();
} else {
eprops = ExtendedProperties.convertProperties(props);
}
// Now set the property with your object instance
eprops.setProperty("name", object);
...
velocityEngine.setExtendedProperties(eprops);
velocityEngine.init();
...
]]>
</source>
<p>
You may want to also consider using the Application Attributes feature described
in the following section.
</p>
</section>
<section name="Application Attributes" href="Application_Attributes">
<p>
<i>Application Attributes</i> are name-value pairs that can be associated with
a RuntimeInstance (either via the <code>VelocityEngine</code> or
the <code>Velocity</code> singleton) and accessed from any part of the Velocity
engine that has access to the RuntimeInstance.
</p>
<p>
This feature was designed for applications that need to communicate between
the application layer and custom parts of the Velocity engine, such as
loggers, resource loaders, resource managers, etc.
</p>
<p>
The Application Attribute API is very simple. From the application layer, there
is a method of the <code>VelocityEngine</code> and the <code>Velocity</code>
classes:
</p>
<source>
<![CDATA[
public void setApplicationAttribute( Object key, Object value );
]]>
</source>
<p>
through which an application can store on Object under an application (or
internal component) specified key. There are no restrictions on the key
or the value. The value for a key may be set at any time - it is not required
that this be set before init() is called.
</p>
<p>
Internal components can access the key-value pairs if they have access to the
object via the <code>RuntimeServices</code> interface, using the method
</p>
<source>
<![CDATA[
public Object getApplicationAttribute( Object key );
]]>
</source>
<p>
Note that internal components cannot set the value of the key, just get it.
if the internal component must communicate information to the application layer,
it must do so via the Object passed as the value.
</p>
</section>
<section name="Configuring Event Handlers" href="Configuring_Event_Handlers">
<p>
Velocity contains a fine-grained event handling system that allows you to customize the operation of the engine. For example, you may change the text of references that are inserted into a page, modify which templates are actually included with <code>#include</code> or <code>#parse</code>, or capture all invalid references.
</p>
<p>All event handler interfaces available in Velocity are in the package <code>org.apache.velocity.app.event</code>. You may create your own implementation or use one of the sample implementations in the package <code>org.apache.velocity.app.event.implement</code>. (See the javadocs for more details on the provided implementations).
</p>
<p>
<i><code>org.apache.velocity.app.event.IncludeEventHandler</code></i>
<blockquote>
The <code>IncludeEventHandler</code> can be used to modify the template that is included
in a page with <code>#include</code> or <code>#parse</code>. For example, this may be used to make all includes relative to the current directory or to prevent access to unauthorized resources.
Multiple <code>IncludeEventHandler</code>'s may be chained, with the return value of the final
call used as the name of the template to retrieve.
<pre>
public IncludeEventHandler extends EventHandler
{
public String includeEvent( String includeResourcePath,
String currentResourcePath,
String directiveName );
}
</pre>
<br/>
Available implementations include:
<dl>
<li><code>org.apache.velocity.app.event.implement.IncludeNotFound</code></li>
<li><code>org.apache.velocity.app.event.implement.IncludeRelativePath</code></li>
</dl>
</blockquote>
<i><code>org.apache.velocity.app.event.InvalidReferenceEventHandler</code></i>
<blockquote>
Normally, when a template contains a bad reference an error message is logged and (unless it is part of a <code>#set</code> or <code>#if</code>), the reference is included verbatim in a page. With the <code>InvalidReferenceEventHandler</code> this behavior can be changed. Substitute values can be inserted, invalid references may be logged, or an exception can be thrown. Multiple <code>InvalidReferenceEventHandler</code>'s may be chained. The exact manner in which chained method
calls behave will differ per method. (See the javadoc for the details).
<pre>
public InvalidReferenceEventHandler extends EventHandler
{
public Object invalidGetMethod( Context context,
String reference,
Object object,
String property,
Info info);
public boolean invalidSetMethod( Context context,
String leftreference,
String rightreference,
Info info);
public Object invalidMethod( Context context,
String reference,
Object object,
String method,
Info info);
}
</pre>
<br/>
Available implementations include:
<dl>
<li><code>org.apache.velocity.app.event.implement.ReportInvalidReferences</code></li>
</dl>
</blockquote>
<i><code>org.apache.velocity.app.event.MethodExceptionEventHandler</code></i>
<blockquote>
When a user-supplied method throws an exception, the
<code>MethodExceptionEventHandler</code> is invoked with the Class, method name
and thrown Exception. The handler can either return a valid Object to be used
as the return value of the method call or throw the passed-in or new Exception,
which will be wrapped and propogated to the user as a
<code>MethodInvocationException</code>. While <code>MethodExceptionEventHandler</code>'s can be
chained only the first handler is actually called -- all others are ignored.
<pre>
public interface MethodExceptionEventHandler extends EventHandler
{
public Object methodException( Class claz,
String method,
Exception e )
throws Exception;
}
</pre>
<br/>
Available implementations include:
<dl>
<li><code>org.apache.velocity.app.event.implement.PrintExceptions</code></li>
</dl>
</blockquote>
<i><code>org.apache.velocity.app.event.NullSetEventHandler</code></i>
<blockquote>
When a #set() rejects an assignment due to the right hand side being an invalid
or null reference, this is normally
logged. The <code>NullSetEventHandler</code> allows you to 'veto' the
logging of this condition. Multiple <code>NullSetEventHandler</code>'s can
be chained; each event handler is called in sequence until a false is returned.
<br/>
<pre>
public interface NullSetEventHandler extends EventHandler
{
public boolean shouldLogOnNullSet( String lhs,
String rhs );
}
</pre>
<br/>
Available implementations include:
<dl>
<li><i>none provided</i></li>
</dl>
</blockquote>
<i><code>org.apache.velocity.app.event.ReferenceInsertionEventHandler</code></i>
<blockquote>
A <code>ReferenceInsertionEventHandler</code> allows the
developer to intercept each write of a reference ($foo) value to the output
stream and modify that output. Multiple <code>ReferenceInsertionEventHandler</code>'s
may be chained with each step potentially altering the inserted reference.
<pre>
public interface ReferenceInsertionEventHandler extends EventHandler
{
public Object referenceInsert( String reference,
Object value );
}
</pre>
<br/>
Available implementations include:
<dl>
<li><code>org.apache.velocity.app.event.implement.EscapeHtmlReference</code></li>
<li><code>org.apache.velocity.app.event.implement.EscapeJavascriptReference</code></li>
<li><code>org.apache.velocity.app.event.implement.EscapeSqlReference</code></li>
<li><code>org.apache.velocity.app.event.implement.EscapeXmlReference</code></li>
</dl>
</blockquote>
</p>
<p>
<strong>Registering Event Handlers</strong>
</p>
<p>You may register event handlers in either of two manners. The easiest way to register event handlers is to specify them in velocity.properties. (Event handlers configured in this manner are referred to as "global" event handlers). For example, the following property will escape HTML entities in any inserted reference.
</p>
<blockquote>
<pre>eventhandler.referenceinsertion.class = org.apache.velocity.app.event.implement.EscapeHtmlReference
</pre>
</blockquote>
<p>Most event handler interfaces will also permit event handlers to be chained together. Such a chain may be in a comma separated list or as additional lines with a property/value pair. For example, the following event handler properties install two <code>ReferenceInsertionEventHandler</code>'s. The first will apply to references starting with "msg" (for example <code>$msgText</code>) and will escape HTML entities (e.g. turning <code>&</code> into <code>&amp;</code>). The second will escape all references starting with "sql" (for example <code>$sqlText</code>) according to SQL escaping rules. (note that in these examples, the first two properties given relate to the event handler configuration while the second two properties are used by the specific event handler implementation).
</p>
<blockquote>
<pre>eventhandler.referenceinsertion.class = org.apache.velocity.app.event.implement.EscapeHtmlReference
eventhandler.referenceinsertion.class = org.apache.velocity.app.event.implement.EscapeSqlReference
eventhandler.escape.html.match = /msg.*<!-- -->/
eventhandler.escape.sql.match = /sql.*<!-- -->/
</pre>
</blockquote>
<p>Event handlers may also be attached to a context via an <code>EventCartridge</code>. This allows event handlers to be tied more closely to a specific template merge or group of merges. The event handler will automatically be injected with the current context if it implements the <code>ContextAware</code> interface. (Due to thread-safety reasons this is not possible with global event handlers).
</p>
<p>
The following code shows how to register an event handler with an EventCartridge and a context.
</p>
<source><![CDATA[
...
import org.apache.velocity.app.event.EventCartridge;
import org.apache.velocity.app.event.ReferenceInsertionEventHandler;
import org.apache.velocity.app.event.implement.EscapeHtmlReference;
import org.apache.velocity.app.event.implement.EscapeSqlReference;
...
public class Test
{
public void myTest()
{
....
/**
* Make a cartridge to hold the event handlers
*/
EventCartridge ec = new EventCartridge();
/*
* then register and chain two escape-related handlers
*/
ec.addEventHandler(new EscapeHtmlReference());
ec.addEventHandler(new EscapeSqlReference());
/*
* and then finally let it attach itself to the context
*/
ec.attachToContext( context );
/*
* now merge your template with the context as you normally
* do
*/
....
}
}
]]></source>
</section>
<section name="Velocity Configuration Keys and Values" href="Velocity_Configuration_Keys_and_Values">
<p>
Velocity's runtime configuration is controlled by a set of configuration keys
listed below. Generally, these keys will have values that consist of either a
String, or a comma-separated list of Strings, referred to as a CSV for
comma-separated values.
</p>
<p>
There is a set of default values contained in Velocity's jar, found in
/src/java/org/apache/velocity/runtime/defaults/velocity.defaults, that
Velocity uses as its configuration baseline.
This ensures that Velocity will always have a 'correct' value
for its configuration keys at startup, although it may not be what you want.
</p>
<p>
Any values specified before init() time will replace the default values.
Therefore, you only have toconfigure velocity with the values for the keys
that you need to change, and not worry about the rest. Further, as we add more
features and configuration capability, you don't have to change your
configuration files to suit - the Velocity engine will always have default
values.
</p>
<p>
Please sees the section above <a href="#Using_Velocity"><b>Using
Velocity</b></a> for discussion on the configuration API.
</p>
<p>
Below are listed the configuration keys that control Velocity's behavior.
Organized by category, each key is listed with its current default value
to the right of the '=' sign.
</p>
<p>
<strong>Runtime Log</strong>
</p>
<p>
<code>runtime.log = velocity.log</code><br/>
Full path and name of log file for error, warning,
and informational messages. The location, if not absolute, is
relative to the 'current directory'.
</p>
<p>
<code>runtime.log.logsystem</code><br/>
This property has no default value. It is used to give Velocity an
instantiated instance of a logging class that supports the interface
<code>org.apache.velocity.runtime.log.LogChute</code>, which allows
the combination of Velocity log messages with your other application
log messages. Please see the section
<a href="#Configuring_Logging"><b>Configuring Logging</b></a>
for more information.
</p>
<p>
<code>runtime.log.logsystem.class =
org.apache.velocity.runtime.log.AvalonLogChute</code><br/>
Class to be used for the Velocity-instantiated log system.
</p>
<p>
<code>runtime.log.invalid.references = true </code><br/>
Property to turn off the log output when a reference isn't valid.
Good thing to turn off in production, but very valuable
for debugging.
</p>
<p>
<code>runtime.log.logsystem.avalon.logger = <i>name</i> </code><br/>
Allows user to specify an existing logger <i>name</i>
in the Avalon hierarchy
without having to wrap with a LogChute interface. <b>Note:</b>
You must also specify
<code>runtime.log.logsystem.class =
org.apache.velocity.runtime.log.AvalonLogChute</code> as the default
logsystem may change. There is <b>no</b> guarantee that the Avalon
log system will remain the default log system.
</p>
<p>
<strong>Character Encoding</strong>
</p>
<p>
<code>input.encoding = ISO-8859-1</code><br/>
Character encoding for input (templates). Using this, you can use
alternative encoding for your templates, such as UTF-8.
</p>
<p>
<code>output.encoding = ISO-8859-1</code><br/>
Character encoding for output streams from the VelocityServlet and Anakia.
</p>
<p>
<strong>#evaluate() Directive</strong>
</p>
<p>
<code>directive.evaluate.context.class = org.apache.velocity.VelocityContext</code><br/>
Used in the #evaluate() directive, defines the class that is used for the
context local to the argument for #evaluate().
</p>
<p>
<strong>#foreach() Directive</strong>
</p>
<p>
<code>directive.foreach.counter.name = velocityCount</code><br/>
Used in the #foreach() directive, defines the string to be used as the
context key for the loop count. A template would access
the loop count as $velocityCount.
</p>
<p>
<code>directive.foreach.iterator.name = velocityHasNext</code><br/>
Used in the #foreach() directive, defines the string to be used as the
context key for the "has next" value. A template would access
this as $velocityHasNext.
</p>
<p>
<code>directive.foreach.counter.initial.value = 1</code><br/>
Default starting value for the loop counter reference in a #foreach() loop.
</p>
<p>
<code>directive.foreach.maxloops = -1</code><br/>
Maximum allowed number of loops for a #foreach() statement.
</p>
<p>
<code>directive.foreach.skip.invalid = true</code><br/>
Tells #foreach to simply skip rendering when the object it is
iterating over is not or cannot produce a valid Iterator.
</p>
<p>
<strong>#set() Directive</strong>
</p>
<p>
<code>directive.set.null.allowed = false</code><br/>
If true, having a right hand side of a #set() statement with
an invalid reference or null value will set the left hand side to null.
If false, the left hand side will stay the same.
</p>
<p>
<strong>#include() and #parse() Directive</strong>
</p>
<p>
<code>directive.include.output.errormsg.start
= <![CDATA[ <!-- include error : ]]> </code><br/>
<code>directive.include.output.errormsg.end
= <![CDATA[ see error log --> ]]></code><br/>
Defines the beginning and ending tags for an in-stream error message in the
case of a problem with the #include() directive. If both the .start and .end
tags are defined, an error message will be output to the stream, of the
form '.start msg .end' where .start and .end refer to the property values.
Output to the render stream will only occur if both the .start and .end
(next) tag are defined.
</p>
<p>
<code>directive.parse.max.depth = 10</code><br/>
Defines the allowable parse depth for a template. A template may #parse()
another template which itself may have a #parse() directive. This value
prevents runaway #parse() recursion.
</p>
<p>
<strong>Math</strong>
</p>
<p>
<code>resource.manager.logwhenfound = true</code><br/>
Switch to control logging of 'found' messages from resource manager.
When a resource is found for the first time, the resource name
and classname of the loader that found it will be noted in the
runtime log.
</p>
<p>
<strong>Resource Management</strong>
</p>
<p>
<code>resource.manager.logwhenfound = true</code><br/>
Switch to control logging of 'found' messages from resource manager.
When a resource is found for the first time, the resource name
and classname of the loader that found it will be noted in the
runtime log.
</p>
<p>
<code>resource.manager.cache.class</code>
<br/>
Declares the class to be used
for resource caching. The current default is
<code>org.apache.velocity.runtime.resource.ResourceCacheImpl</code>
which uses a LRU Map to prevent data from being held forever. You can
set the size of the LRU Map using the parameter
<code>resource.manager.defaultcache.size</code>. The dafault value
of the default cache size is currently 89.
</p>
<p>
<code>resource.manager.defaultcache.size</code>
<br/>
Sets the size of the
default implementation of the resource manager resource cache.
</p>
<p>
<code>resource.loader = <name> (default = file)</code><br/>
<i>Multi-valued key. Will accept CSV for value.</i> Public name of a
resource loader to be used. This public name will then be used
in the specification of the specific properties for that resource loader.
Note that as a multi-valued key, it's possible to pass
a value like "file, class" (sans quotes), indicating that following
will be configuration values for two loaders.
</p>
<p>
<code><name>.loader.description
= Velocity File Resource Loader</code><br/>
Description string for the given loader.
</p>
<p>
<code><name>.resource.loader.class
= org.apache.velocity.runtime.resource.loader.FileResourceLoader</code><br/>
Name of implementation class for the loader. The default loader
is the file loader.
</p>
<p>
<code><name>.resource.loader.path = .</code><br/>
<i>Multi-valued key. Will accept CSV for value.</i> Root(s) from which the
loader loads templates. Templates may live in subdirectories of this root.
ex. homesite/index.vm This configuration key applies currently to the
FileResourceLoader and JarResourceLoader.
</p>
<p>
<code><name>.resource.loader.cache = false</code><br/>
Controls caching of the templates in the loader. Default is false, to make
life easy for development and debugging. This should be set to true for
production deployment. When 'true', the <code>modificationCheckInterval</code>
property applies. This allows for the efficiency of caching, with the
convenience of controlled reloads - useful in a hosted or ISP environment
where templates can be modifed frequently and bouncing the application or
servlet engine is not desired or permitted.
</p>
<p>
<code><name>.resource.loader.modificationCheckInterval = 2</code><br/>
This is the number of seconds between modification checks when caching is
turned on. When this is an integer > 0, this represents the number of
seconds between checks to see if the template was modified. If the
template has been modified since last check, then it is reloaded and
reparsed. Otherwise nothing is done. When <= 0, no modification
checks will take place, and assuming that the property <code>cache</code>
(above) is true, once a template is loaded and parsed the first time it is used,
it will not be checked or reloaded after that until the application or
servlet engine is restarted.
</p>
<p> To illustrate, here is an example taken right from the default Velocity
properties, showing how setting up the FileResourceLoader is managed
</p>
<source><![CDATA[
resource.loader = file
file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = .
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 2
]]></source>
<p>
<strong>Velocimacro</strong>
</p>
<p>
<code>velocimacro.library = VM_global_library.vm </code><br/>
<i>Multi-valued key. Will accept CSV for value.</i>
Filename(s) of Velocimacro library to be loaded when the Velocity
Runtime engine starts. These Velocimacros are accessable to all
templates. The file is assumed to be relative to the root of the
file loader resource path.
</p>
<p>
<code>velocimacro.permissions.allow.inline = true</code><br/>
Determines of the definition of new Velocimacros via the #macro() directive
in templates is allowed. The default value is true, meaning any template
can define and use new Velocimacros. Note that depending on other properties,
those #macro() statements can replace global definitions.
</p>
<p>
<code>velocimacro.permissions.allow.inline.to.replace.global = false </code><br/>
Controls if a Velocimacro defind 'inline' in a template can replace
a Velocimacro defined in a library loaded at startup.
</p>
<p>
<code>velocimacro.permissions.allow.inline.local.scope = false</code><br/>
Controls 'private' templates namespaces for Velocimacros. When true, a #macro()
directive in a template creates a Velocimacro that is accessable only from the
defining template. This means that Velocimacros cannot be shared unless they
are in the global or local library loaded at startup. (See above.) It also means
that templates cannot interfere with each other. This property also allows a technique
where there is a 'default' Velocimacro definition in the global or local library,
and a template can 'override' the implementation for use within that template.
This occurrs because when this property is true, the template's namespace is
searched for a Velocimacro before the global namespace, therefore allowing
the override mechanism.
</p>
<p>
<code>velocimacro.context.localscope = false</code><br/>
Controls whether reference access (set/get) within a Velocimacro will change
the context, or be of local scope in that
Velocimacro.
</p>
<p>
<code>velocimacro.library.autoreload = false</code><br/>
Controls Velocimacro library autoloading. When set to <code>true</code>
the source Velocimacro library for an invoked Velocimacro will be checked
for changes, and reloaded if necessary. This allows you to change and
test Velocimacro libraries without having to restart your application or
servlet container, just like you can with regular templates.
This mode only works when caching is <i>off</i>
in the resource loaders (e.g. <code>file.resource.loader.cache = false</code> ).
This feature is intended for development, not for production.
</p>
<p>
<code>velocimacro.arguments.strict = false</code><br/>
When set to true, will throw a <code>ParseErrorException</code> when
parsing a template containing a macro with an invalid number of arguments.
Is set to false by default to maintain backwards compatibility with
templates written before this feature became available.
</p>
<p>
<strong>Strict Reference Setting</strong>
</p>
<p>
<code>runtime.references.strict = false</code><br/>
New in Velocity 1.6, when set to true Velocity will throw a
<code>MethodInvocationException</code> for references that are not
defined in the context, or have not been defined with a #set
directive. This setting will also throw an exception if an attempt is
made to call a non-existing property on an object or if the object is
null. When this property is true then property
'directive.set.null.allowed' is also set to true. Also,
'directive.foreach.skip.invalid' defaults to true when this property
is true, but explicitly setting 'directive.foreach.skip.invalid' will
override this default. For a complete discussion see <a
href="user-guide.html#strictreferences">Strict References Setting</a>.
</p>
<p>
<strong>String Interpolation</strong>
</p>
<p>
<code>runtime.interpolate.string.literals = true</code><br/>
Controls interpolation mechanism of VTL String Literals. Note that a VTL
StringLiteral is specifically a string using double quotes that is used
in a #set() statement, a method call of a reference, a parameter to a VM,
or as an argument to a VTL directive in general. See the VTL reference for
further information.
</p>
<p>
<strong>Math</strong>
</p>
<p>
<code>runtime.strict.math = false</code><br/>
Affects all math operations in VTL. If changed to true, this will cause
Velocity to throw a MathException whenever one side of a math operation
has a null value (e.g. <code>#set( $foo = $null * 5 )</code>) or when
trying to divide by zero. If this value is left <code>false</code>,
then rendering will continue and that math operation will be ignored.
</p>
<p>
<strong>Parser Configuration</strong>
</p>
<p>
<code>parser.pool.class = org.apache.velocity.runtime.ParserPoolImpl</code><br/>
This property selects the implementation for the parser pool. This class
must implement ParserPool. Generally there is no reason to change this though
if you are building a high volume web application you might consider including
an alternate implementation that automatically adjusts the size of the pool.
</p>
<p>
<code>parser.pool.size = 20</code><br/>
This property is used by the default pooling implementation to
set the number of parser instances that Velocity will
create at startup and keep in a pool. The default of 20 parsers
should be more than enough for most uses. In the event that Velocity
does run out of parsers, it will indicate so in the log, and
dynamically create overflow instances as needed. Note that these
extra parsers will not be added to the pool, and will be discarded
after use. This will result in very slow operation compared to the
normal usage of pooled parsers, but this is considered an exceptional
condition. A web application using Velocity as its view engine might
exhibit this behavior under extremely high concurrency (such as when
getting Slashdotted). If you see a corresponding message referencing
the <code>parser.pool.size</code> property in your log files, please
increment this property immediately to avoid performance degradation.
</p>
<p>
<strong>Pluggable Introspection</strong>
</p>
<p>
<code>runtime.introspector.uberspect =
org.apache.velocity.util.introspection.UberspectImpl</code>
<br/>
This property sets the 'Uberspector', the introspection package that
handles all introspection strategies for Velocity. You can specify a
comma-separated list of Uberspector classes, in which case all Uberspectors are
chained. The default chaining behaviour is to return the first non-null value
for each introspection call among all provided uberspectors. You can modify
this behaviour (for instance to restrict access to some methods) by subclassing
org.apache.velocity.util.introspection.AbstractChainableUberspector (or
implementing directly
org.apache.velocity.util.introspection.ChainableUberspector). This
allows you to create more interesting rules or patterns for Uberspection,
rather than just returning the first non-null value.
</p>
</section>
<section name="Configuring Logging" href="Configuring_Logging">
<p>
Velocity has a few nice logging features to allow both simplicity and
flexibility. Without any extra configuration, Velocity will setup a
file-based logger that will output all logging messages to a file
called <code>velocity.log</code> in the 'current directory' where
Velocity was initialized. For more advanced users, you may integrate
your current logging facilities with Velocity to have all log messages
sent to your logger.
</p>
<p>
Starting with version 1.3, Velocity will automatically use either the
<a href="http://jakarta.apache.org/avalon/logkit/index.html">
Jakarta Avalon Logkit</a> logger, or the
<a href="http://jakarta.apache.org/log4j/">Jakarta Log4j</a> logger.
It will do so by using whatever it finds in the current classpath, starting
first with Logkit. If Logkit isn't found, it tries Log4j.
</p>
<p>
To utilize this feature, simply use the 'non-dependency' Velocity jar
(because Logkit is baked into the jar with dependencies) and place
either the logkit or log4j jar in your classpath.
</p>
<p>
In general, you have the following logging options:
</p>
<ul>
<li>
<b>Default Configuration</b><br/>
By default, Velocity will create a file-based logger in the current
directory. See the note above regarding automatic detection of
Logkit or Log4j to use as the default logging system.
</li>
<li>
<b>Existing Log4j Logger</b><br/>
Starting with version 1.3, Velocity will log its output to an existing
Log4j Logger setup elsewhere in the application. To use this feature you must
<ol>
<li>
Make sure that the Log4j jar is in your classpath. (You would do this
anyway since you are using Log4j in the application using Velocity.)
</li>
<li>Configure Velocity to use the <code>Log4JLogChute</code> class by
specifying the name of the existing Logger to use via the
'runtime.log.logsystem.log4j.logger' property.
</li>
</ol>
Note that this support for Logger is in version 1.5 of Velocity. Further,
in version 1.5 we removed the now-ancient and very deprecated original
Log4JLogSystem class and replaced with the current Log4JLogChute class which
uses the Logger class. We apologize for the confusion, but we needed to move
on.
</li>
<li>
<b>Custom Standalone Logger</b><br/>
You can create a custom logging class - you just need to implement the
interface <code>org.apache.velocity.runtime.log.LogChute</code> and
then simply set the configuration property
<code>runtime.log.logsystem.class</code> with the
classname, and Velocity will create an instance of that class at init time.
You may specify the classname as you specify any other properties. See
the information on the
<a href="#thevelocityhelperclass">
Velocity helper class</a> as well as the
<a href="#Velocity_Configuration_Keys_and_Values">
configuration keys and values.</a>
Please note that the old <code>org.apache.velocity.runtime.log.LogSystem</code>
interface has been deprecated for v1.5 in favor of the new LogChute interface.
This is due to significant upgrades to our logging code that could not be
supported by the LogSystem interface. But don't worry, if you specify a
custom class that implements the LogSystem interface, it will still work.
However, it will generate deprecation warnings. You should upgrade your
custom logger to implement LogChute as soon as possible.
</li>
<li>
<b>Integrated Logging</b><br/>
You can integrate Velocity's logging capabilities with your applications
existing logging system, simply by implementing the
<code>org.apache.velocity.runtime.log.LogChute</code> interface. Then,
pass an instance of your logging class to Velocity via the
<code>runtime.log.logsystem</code> configuration key before
initializing the Velocity engine,
and Velocity will log messages to your application's logger.
See the information on the
<a href="#thevelocityhelperclass">Velocity helper class</a>
as well as the
<a href="#Velocity_Configuration_Keys_and_Values">configuration keys and values.</a>
</li>
</ul>
<a name="usinglog4jwithexistinglogger"><strong>Using Log4j With Existing Logger</strong></a>
<p>
Here is an example of how to configure Velocity to log to an existing Log4j
Logger.
</p>
<source><![CDATA[
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;
public class Log4jLoggerExample
{
public static String LOGGER_NAME = "velexample";
public static void main( String args[] )
throws Exception
{
/*
* configure log4j to log to console
*/
BasicConfigurator.configure();
Logger log = Logger.getLogger( LOGGER_NAME );
log.info("Log4jLoggerExample: ready to start velocity");
/*
* now create a new VelocityEngine instance, and
* configure it to use the category
*/
VelocityEngine ve = new VelocityEngine();
ve.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
"org.apache.velocity.runtime.log.Log4JLogChute" );
ve.setProperty("runtime.log.logsystem.log4j.logger",
LOGGER_NAME);
ve.init();
log.info("follows initialization output from velocity");
}
}
]]></source>
<p>
Note that the above example can be found in <code>examples/logger_example</code>.
</p>
<a name="simpleexampleofacustomlogger"><strong>Simple Example of a Custom Logger</strong></a>
<p>
Here is an example of how to use an instantiation of your class that implements
Velocity's logging system as the logger. Note that we are not passing the name
of the class to use, but rather a living, existing instantiation of the class
to be used. All that is required is that it support the
<code>LogChute</code> interface.
</p>
<source><![CDATA[
import org.apache.velocity.runtime.log.LogChute;
import org.apache.velocity.runtime.RuntimeServices;
...
public class MyClass implements LogChute
{
...
public MyClass()
{
...
try
{
/*
* register this class as a logger with the Velocity singleton
* (NOTE: this would not work for the non-singleton method.)
*/
Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, this );
Velocity.init();
}
catch (Exception e)
{
/*
* do something
*/
}
}
/**
* This init() will be invoked once by the LogManager
* to give you the current RuntimeServices intance
*/
public void init(RuntimeServices rsvc)
{
// do nothing
}
/**
* This is the method that you implement for Velocity to
* call with log messages.
*/
public void log(int level, String message)
{
/* do something useful */
}
/**
* This is the method that you implement for Velocity to
* call with log messages.
*/
public void log(int level, String message, Throwable t)
{
/* do something useful */
}
/**
* This is the method that you implement for Velocity to
* check whether a specified log level is enabled.
*/
public boolean isLevelEnabled(int level)
{
/* do something useful */
return someBooleanValue;
}
...
}
]]></source>
</section>
<section name="Configuring Resource Loaders" href="Configuring_Resource_Loaders">
<a name="resourceloaders"><strong>Resource Loaders</strong></a>
<p>
One of the fundamental and important parts about Velocity is the resource
management system and the resource loaders. They are referred to as 'resources'
here rather than 'templates' because the resource management system will also
handle non-template reasources, specifically things that are loaded via the
#include() directive.
</p>
<p>
The resource loader system if very flexible, allowing one or more resource
loaders to be in operation at the same time. This allows tremendous
flexibility in configuration and resource managment, and futher allows you
to write your own resource loaders for your special needs.
</p>
<p>
There are currently four kinds of resource loaders that are included with Velocity,
each described below. Note that in the example configuration properties given,
a common name for the loader is shown
(ex.'file' in <code>file.resource.loader.path</code>). This 'common name'
may not work for your configuration. Please read the section on
<a href="#Velocity_Configuration_Keys_and_Values">resource configuration properties</a>
to understand how this system works. Also, each of these loaders is
located in the package <code>org.apache.velocity.runtime.resource.loader</code>.
</p>
<ul>
<li>
<b>FileResourceLoader :</b> This loader gets resources from the filesystem. Its
configuration properties include:
<ul>
<li>
<code>file.resource.loader.path</code> = <path to root of templates>
</li>
<li>
<code>file.resource.loader.cache</code> = true/false
</li>
<li>
<code>file.resource.loader.modificationCheckInterval</code> = <seconds between checks>
</li>
</ul>
This is the default loader, and is configured, by default to get templates from the
'current directory'. In the case of using Velocity with servlets, this can be a problem
as you don't want to have to keep your templates in the directory from which you start
your servlet engine. See the documentation for your servlet or web framework (for example
<a href="http://velocity.apache.org/tools/devel/view/">VelocityViewServlet</a>) for more
info on how to configure the location of the Velocity templates.
</li>
<li>
<b>JarResourceLoader :</b> This loader gets resource from specific jar files. It is very
similar to the FileResourceLoader, except that you have the convenience of bundling
your templates into jars. The properties are identical, except for
<code>jar.resource.loader.path</code>, where you provide the full location of
the jar(s) you wish to load resources from. To specify a jar for the loader.path
you use the standard JAR URL syntax of <code>java.net.JarURLConnection</code>.
</li>
<li>
<b>ClasspathResourceLoader :</b> This loader gets resources from the classloader.
In general, this means that the ClasspathResourceLoader will load
templates placed in the classpath (in jars, for example)
While the
classpath is a source of great pain and suffering in general, it is a very useful
mechanism when working on a Servlet Spec 2.2 (or newer) compliant servlet runner.
<a href="http://jakarta.apache.org/tomcat/">Tomcat</a>
is an example of such. To use this loader effectively, all you must do is
jar your templates, and put that jar into the WEB-INF/lib directory of your
webapp. There are no configuration options to worry about, nor is the absolute vs.
relative path an issue, as it is with Jar and File resource loaders.
Again, please note that the ClasspathResourceLoader is not only for use with a
servlet container, but can be used in any application context.
</li>
<li>
<b>URLResourceLoader :</b> This loader gets resources from a URL connection. Its
configuration properties include:
<ul>
<li>
<code>url.resource.loader.root</code> = <root URL path of templates>
</li>
<li>
<code>url.resource.loader.cache</code> = true/false
</li>
<li>
<code>url.resource.loader.modificationCheckInterval</code> = <seconds between checks>
</li>
</ul>
This loader simply downloads resources from configured URLs. It works much like
the FileResourceLoader, however, it can pull templates down from any valid URL
to which the application can create a connection.
</li>
<li>
<b>DataSourceResourceLoader :</b> This loader will load resources from a DataSource
such as a database. This loader is only available under JDK 1.4 and later.
For more information on this loader, please see the javadoc for the class
<code>org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader</code>.
</li>
</ul>
<a name="configurationexamples"><strong>Configuration Examples</strong></a>
<p>
Configuring the resource loaders for Velocity is straightforward.
The properties that control the are listed in the
<a href="#Configuring_Resource_Loaders">resource configuration</a>
section, for further reference.
</p>
<p>
The first step in configuring one or more resource loaders is do
'declare' them by name to Velocity. Use the property
<code>resource.loader</code> and list one or more loader names.
You can use anything you want - these names are used to associate
configuration properties with a given loader.
</p>
<source><![CDATA[
resource.loader = file
]]></source>
<p>
That entry declares that we will have a resource loader known as 'file'.
The next thing to do is to set the important properties. The most critical
is to declare the class to use as the loader:
</p>
<source><![CDATA[
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
]]></source>
<p>
In this case, we are telling velocity that we are setting up
a resource loadercalled 'file', and are using the class
<code>
org.apache.velocity.runtime.resource.loader.FileResourceLoader
</code>
to be the class to use.
The next thing we do is set the properties important
to this loader.
</p>
<source><![CDATA[
file.resource.loader.path = /opt/templates
file.resource.loader.cache = true
file.resource.loader.modificationCheckInterval = 2
]]></source>
<p>
Here, we set a few things. First, we set the path to find
the templates to be <code>/opt/templates</code>. Second, we
turned caching on, so that after a template or static file
is read in, it is cached in memory. And finally, we set
the modification check interval to 2 seconds, allowing Velocity
to check for new templates.
</p>
<p>
Those are the basics. What follows are a few examples of different configuraitons.
</p>
<p>
<b>Do-nothing Default Configuration: </b> As the name says, there is nothing
you have to do or configure to get the default configuration. This configuration
uses the FileResourceLoader with the current directory as the default resource
path, and caching is off. As a properties set, this is expressed as:
</p>
<source><![CDATA[
resource.loader = file
file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = .
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 0
]]></source>
<p>
<b>Multiple Template Path Configuration: </b> This configuration
uses the FileResourceLoader with several directories as 'nodes' on the
template search path. We also want to use caching, and have the templates
checked for changes in 10 second intervals. As a properties set, this is expressed as:
</p>
<source><![CDATA[
resource.loader = file
file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = /opt/directory1, /opt/directory2
file.resource.loader.cache = true
file.resource.loader.modificationCheckInterval = 10
]]></source>
<p>
<b>Multiple Loader Configuration :</b> This configuration sets up
three loaders at the same time, the FileResourceLoader,
the ClasspathResourceLoader, and the JarResourceLoader.
The loaders are set-up such that the
FileResourceLoader is consulted first, then the
ClasspathResourceLoader, and finally the JarResourceLoader.
This would allow you to qickly
drop a template into the file template area to replace on of the
templates found in the classpath (usually via a jar) without
having to rebuild the jar.
</p>
<source><![CDATA[
#
# specify three resource loaders to use
#
resource.loader = file, class, jar
#
# for the loader we call 'file', set the FileResourceLoader as the
# class to use, turn off caching, and use 3 directories for templates
#
file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = templatedirectory1, anotherdirectory, foo/bar
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 0
#
# for the loader we call 'class', use the ClasspathResourceLoader
#
class.resource.loader.description = Velocity Classpath Resource Loader
class.resource.loader.class = org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
#
# and finally, for the loader we call 'jar', use the JarResourceLoader
# and specify two jars to load from
#
jar.resource.loader.description = Velocity Jar Resource Loader
jar.resource.loader.class = org.apache.velocity.runtime.resource.loader.JarResourceLoader
jar.resource.loader.path = jar:file:/myjarplace/myjar.jar, jar:file:/myjarplace/myjar2.jar
]]></source>
<p>
Node that the three names 'file', 'class', and 'jar' are merely for your convenience and
sanity. They can be anything you want - they are just used to associate a set of
properties together. However, it is recommended that you use names that give some hint
of the function.
</p>
<p>
Note that while all three require very little configuration information
for proper operation, the ClasspathResourceLoader is the simplest.
</p>
<a name="resourcemanagerandcache"></a>
<strong>Pluggable Resource Manager and Resource Cache</strong>
<p>
The Resource Manager is the main part of the resource (template and static content)
management system, and is responsible for taking application requests for
templates, finding them in the available resource loaders, and then optionally
caching the parsed template. The Resource Cache is the mechanism that the
Resource Manager uses to cache templates for quick reuse. While the default
versions of these two facilities are suitable for most
applications, for advanced users it now is possible
to replace the default resource manager
and resource cache with custom implementations.
</p>
<p>
A resource manager implementation must implement the
<code>org.apache.velocity.runtime.resource.ResourceManager</code> interface.
A description of the requirements of a resource manager is out of scope for
this document. Implementors are encouraged to review the default implementation.
To configure Velocity to load the replacement implementation, use the
configuration key:
</p>
<source><![CDATA[
resource.manager.class
]]></source>
<p>
This key is also defined as a contstant
<code>RuntimeConstants.RESOURCE_MANAGER_CLASS</code>
</p>
<p>
A resource cache implementation must implement the
<code>org.apache.velocity.runtime.resource.ResourceCache</code> interface
As with the resource manager, a description of the requirements of a
resource manager is out of scope for
this document. Implementors are encouraged to review the default implementation.
To configure Velocity to load the replacement implementation, use the
configuration key:
</p>
<source><![CDATA[
resource.manager.cache.class
]]></source>
<p>
This key is also defined as a contstant
<code>RuntimeConstants.RESOURCE_MANAGER_CACHE_CLASS</code>
</p>
<p>
A resource cache implementation may want to limit the cache size
(rather than providing an unbounded cache which could consume all
available memory). To configure Velocity to set the size for your
cache, use the configuration key:
</p>
<source><![CDATA[
resource.manager.cache.size
]]></source>
<p>
This key is also defined as a contstant
<code>RuntimeConstants.RESOURCE_MANAGER_CACHE_SIZE</code>
</p>
</section>
<section name="Template Encoding for Internationalization" href="Template_Encoding_for_Internationalization">
<p>
Velocity allows you to specify the character encoding of your
template resources on a template by template basis. The normal resource
API's have been extended to take the encoding as an argument:
</p>
<p>
<code>org.apache.velocity.app.Velocity</code>: <br/>
<blockquote>
<i><code>public static Template getTemplate(String name, String encoding)</code></i>
<br/>
<br/>
<i><code>public static boolean mergeTemplate( String templateName, String encoding, Context context, Writer writer )</code></i>
<br/>
<i><code> </code></i>
</blockquote>
</p>
<p>
The value for the <i>encoding</i> argument is the conventional encoding specification
supported by your JVM, for example "UTF-8" or "ISO-8859-1". For the official names
for character sets, see <a href="http://www.iana.org/assignments/character-sets">here</a>.
</p>
<p>
Note that this applies only to the encoding of the template itself - the output
encoding is an application specific issue.
</p>
</section>
<section name="Velocity and XML" href="Velocity_and_XML">
<p>
Velocity's flexibility and simple template language makes it an ideal environment
for working with XML data. <a href="anakia.html">Anakia</a> is an example of how
Velocity is used to replace XSL for rendering output from XML. The Velocity site,
including this documentation, is generated from XML source using Anakia.
The Jakarta site is also rendered using Anakia.
</p>
<p>
Generally, the pattern for dealing with XML in Velocity is to use something like
<a href="http://www.jdom.org/">JDOM</a> to process your XML into a data structure with
convenient Java access. Then, you produce templates that access data directly
out of the XML document - directly though the JDOM tree. For example, start
with an XML document such as:
</p>
<source><![CDATA[
<document>
<properties>
<title>Developer's Guide</title>
<author email="geirm@apache.org">Velocity Doc Team</author>
</properties>
</document>
]]></source>
<p>
Now make a little Java program that includes code similar to:
</p>
<source><![CDATA[
...
SAXBuilder builder;
Document root = null;
try
{
builder = new SAXBuilder(
"org.apache.xerces.parsers.SAXParser" );
root = builder.build("test.xml");
}
catch( Exception ee)
{}
VelocityContext vc = new VelocityContext();
vc.put("root", root.getRootElement());
...
]]></source>
<p>
(See the Anakia source for details on how to do this, or the Anakia
example in the <code>examples</code> directory in the distribution.)
Now, make a regular Velocity template:
</p>
<source><![CDATA[
<html>
<body>
The document title is
$root.getChild("document").getChild("properties")
.getChild("title").getText()
</body>
</html>
]]></source>
<p>
and render that template as you normally would, using the Context
containing the JDOM tree. Of course, this isn't the prettiest of
examples, but it shows the basics - that you can easily access XML data
directly from a Velocity template.
</p>
<p>
One real advantage of styling XML data in Velocity is that you have
access to any other object or data that the application provides. You
aren't limited to just using the data present in the XML document.
You may add anything you want to the context to provide additional
information for your output, or provide tools to help make working
with the XML data easier. Bob McWhirter's
<a href="http://sourceforge.net/projects/werken-xpath/"> Werken Xpath</a>
is one such useful tool - an example of how it is used in Anakia can be
found in <code>org.apache.velocity.anakia.XPathTool</code>.
</p>
<p>
One issue that arises with XML and Velocity is how to deal with XML
entities. One technique is to combine the use of Velocimacros
when you need to render an entity into the output stream:
</p>
<source><![CDATA[
## first, define the Velocimacro somewhere
#macro(xenc $sometext)$tools.escapeEntities($sometext)#end
## and use it as
#set( $sometext = " < " )
<text>#xenc($sometext)</text>
]]></source>
<p>
where the escapeEntities() is a method that does the escaping
for you. Another trick would be to create an encoding utility that takes the
context as a constructor parameter and only implements a method:
</p>
<source><![CDATA[
public String get(String key)
{
Object obj = context.get(key)
return (obj != null)
? Escape.getText( obj.toString() )
: "";
}
]]></source>
<p>
Put it into the context as "xenc". Then you can use it as:
</p>
<source><![CDATA[
<text>$xenc.sometext</text>
]]></source>
<p>
This takes advantage of Velocity's introspection process - it will try
to call get("sometext") on the $xenc object in the Context - then the
xenc object can then get the value from the Context, encode it, and
return it.
</p>
<p>
Alternatively, since Velocity makes it easy to implement custom Context
objects, you could implement your own context which always applies the
encoding to any string returned. Be careful to avoid rendering the
output of method calls directly, as they could return objects or strings
(which might need encoding). Place them first into the context with a
#set() directive and the use that, for example:
</p>
<source><![CDATA[
#set( $sometext = $jdomElement.getText() )
<text>$sometext</text>
]]></source>
<p>
The previous suggestions for dealing with XML entities came from
Christoph Reck, an active participant in the Velocity community.
</p>
</section>
<section name="Summary" href="Summary">
<p>
We hope this brief guide was a helpful introduction to using Velocity in
your Java projects, and thank you for you interest in Velocity. We
welcome any and all comments you may have about this documentation and
the Velocity template engine itself.
</p>
<p>
Please submit all detailed, thoughtful and constructive feedback through our
<a href="http://velocity.apache.org/contact.html">mailing lists</a>.
</p>
</section>
</body>
</document>
|