src/content/engine/1.6.1/xref/org/apache/velocity/runtime/RuntimeInstance.html [1:1770]: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 package org.apache.velocity.runtime; 2 3 /* 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 import java.io.File; 23 import java.io.IOException; 24 import java.io.InputStream; 25 import java.io.Reader; 26 import java.io.StringReader; 27 import java.io.Writer; 28 import java.util.Enumeration; 29 import java.util.HashMap; 30 import java.util.Hashtable; 31 import java.util.Map; 32 import java.util.Properties; 33 34 import org.apache.commons.collections.ExtendedProperties; 35 import org.apache.commons.lang.text.StrBuilder; 36 import org.apache.velocity.Template; 37 import org.apache.velocity.app.event.EventCartridge; 38 import org.apache.velocity.app.event.EventHandler; 39 import org.apache.velocity.app.event.IncludeEventHandler; 40 import org.apache.velocity.app.event.InvalidReferenceEventHandler; 41 import org.apache.velocity.app.event.MethodExceptionEventHandler; 42 import org.apache.velocity.app.event.NullSetEventHandler; 43 import org.apache.velocity.app.event.ReferenceInsertionEventHandler; 44 import org.apache.velocity.context.Context; 45 import org.apache.velocity.context.InternalContextAdapterImpl; 46 import org.apache.velocity.exception.MethodInvocationException; 47 import org.apache.velocity.exception.ParseErrorException; 48 import org.apache.velocity.exception.ResourceNotFoundException; 49 import org.apache.velocity.exception.TemplateInitException; 50 import org.apache.velocity.exception.VelocityException; 51 import org.apache.velocity.runtime.directive.Directive; 52 import org.apache.velocity.runtime.log.Log; 53 import org.apache.velocity.runtime.log.LogManager; 54 import org.apache.velocity.runtime.parser.ParseException; 55 import org.apache.velocity.runtime.parser.Parser; 56 import org.apache.velocity.runtime.parser.node.Node; 57 import org.apache.velocity.runtime.parser.node.SimpleNode; 58 import org.apache.velocity.runtime.resource.ContentResource; 59 import org.apache.velocity.runtime.resource.ResourceManager; 60 import org.apache.velocity.util.ClassUtils; 61 import org.apache.velocity.util.RuntimeServicesAware; 62 import org.apache.velocity.util.StringUtils; 63 import org.apache.velocity.util.introspection.Introspector; 64 import org.apache.velocity.util.introspection.Uberspect; 65 import org.apache.velocity.util.introspection.UberspectLoggable; 66 import org.apache.velocity.util.introspection.ChainableUberspector; 67 import org.apache.velocity.util.introspection.LinkingUberspector; 68 69 /** 70 * This is the Runtime system for Velocity. It is the 71 * single access point for all functionality in Velocity. 72 * It adheres to the mediator pattern and is the only 73 * structure that developers need to be familiar with 74 * in order to get Velocity to perform. 75 * 76 * The Runtime will also cooperate with external 77 * systems like Turbine. Runtime properties can 78 * set and then the Runtime is initialized. 79 * 80 * Turbine, for example, knows where the templates 81 * are to be loaded from, and where the Velocity 82 * log file should be placed. 83 * 84 * So in the case of Velocity cooperating with Turbine 85 * the code might look something like the following: 86 * 87 * <blockquote><code><pre> 88 * ri.setProperty(Runtime.FILE_RESOURCE_LOADER_PATH, templatePath); 89 * ri.setProperty(Runtime.RUNTIME_LOG, pathToVelocityLog); 90 * ri.init(); 91 * </pre></code></blockquote> 92 * 93 * <pre> 94 * ----------------------------------------------------------------------- 95 * N O T E S O N R U N T I M E I N I T I A L I Z A T I O N 96 * ----------------------------------------------------------------------- 97 * init() 98 * 99 * If init() is called by itself the RuntimeInstance will initialize 100 * with a set of default values. 101 * ----------------------------------------------------------------------- 102 * init(String/Properties) 103 * 104 * In this case the default velocity properties are layed down 105 * first to provide a solid base, then any properties provided 106 * in the given properties object will override the corresponding 107 * default property. 108 * ----------------------------------------------------------------------- 109 * </pre> 110 * 111 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> 112 * @author <a href="mailto:jlb@houseofdistraction.com">Jeff Bowden</a> 113 * @author <a href="mailto:geirm@optonline.net">Geir Magusson Jr.</a> 114 * @version $Id: RuntimeInstance.java 703049 2008-10-09 03:18:58Z nbubna $ 115 */ 116 public class RuntimeInstance implements RuntimeConstants, RuntimeServices 117 { 118 /** 119 * VelocimacroFactory object to manage VMs 120 */ 121 private VelocimacroFactory vmFactory = null; 122 123 /** 124 * The Runtime logger. We start with an instance of 125 * a 'primordial logger', which just collects log messages 126 * then, when the log system is initialized, all the 127 * messages get dumpted out of the primordial one into the real one. 128 */ 129 private Log log = new Log(); 130 131 /** 132 * The Runtime parser pool 133 */ 134 private ParserPool parserPool; 135 136 /** 137 * Indicate whether the Runtime is in the midst of initialization. 138 */ 139 private boolean initializing = false; 140 141 /** 142 * Indicate whether the Runtime has been fully initialized. 143 */ 144 private boolean initialized = false; 145 146 /** 147 * These are the properties that are laid down over top 148 * of the default properties when requested. 149 */ 150 private ExtendedProperties overridingProperties = null; 151 152 /** 153 * This is a hashtable of initialized directives. 154 * The directives that populate this hashtable are 155 * taken from the RUNTIME_DEFAULT_DIRECTIVES 156 * property file. This hashtable is passed 157 * to each parser that is created. 158 */ 159 private Hashtable runtimeDirectives; 160 161 /** 162 * Object that houses the configuration options for 163 * the velocity runtime. The ExtendedProperties object allows 164 * the convenient retrieval of a subset of properties. 165 * For example all the properties for a resource loader 166 * can be retrieved from the main ExtendedProperties object 167 * using something like the following: 168 * 169 * ExtendedProperties loaderConfiguration = 170 * configuration.subset(loaderID); 171 * 172 * And a configuration is a lot more convenient to deal 173 * with then conventional properties objects, or Maps. 174 */ 175 private ExtendedProperties configuration = new ExtendedProperties(); 176 177 private ResourceManager resourceManager = null; 178 179 /** 180 * This stores the engine-wide set of event handlers. Event handlers for 181 * each specific merge are stored in the context. 182 */ 183 private EventCartridge eventCartridge = null; 184 185 /* 186 * Each runtime instance has it's own introspector 187 * to ensure that each instance is completely separate. 188 */ 189 private Introspector introspector = null; 190 191 192 /* 193 * Opaque reference to something specificed by the 194 * application for use in application supplied/specified 195 * pluggable components 196 */ 197 private Map applicationAttributes = null; 198 private Uberspect uberSpect; 199 private String encoding; 200 201 /** 202 * Creates a new RuntimeInstance object. 203 */ 204 public RuntimeInstance() 205 { 206 /* 207 * create a VM factory, introspector, and application attributes 208 */ 209 vmFactory = new VelocimacroFactory( this ); 210 211 /* 212 * make a new introspector and initialize it 213 */ 214 introspector = new Introspector(getLog()); 215 216 /* 217 * and a store for the application attributes 218 */ 219 applicationAttributes = new HashMap(); 220 } 221 222 /** 223 * This is the primary initialization method in the Velocity 224 * Runtime. The systems that are setup/initialized here are 225 * as follows: 226 * 227 * <ul> 228 * <li>Logging System</li> 229 * <li>ResourceManager</li> 230 * <li>EventHandler</li> 231 * <li>Parser Pool</li> 232 * <li>Global Cache</li> 233 * <li>Static Content Include System</li> 234 * <li>Velocimacro System</li> 235 * </ul> 236 * @throws Exception When an error occured during initialization. 237 */ 238 public synchronized void init() 239 throws Exception 240 { 241 if (!initialized && !initializing) 242 { 243 initializing = true; 244 245 log.trace("*******************************************************************"); 246 log.debug("Starting Apache Velocity v@build.version@ (compiled: @build.time@)"); 247 log.trace("RuntimeInstance initializing."); 248 249 initializeProperties(); 250 initializeLog(); 251 initializeResourceManager(); 252 initializeDirectives(); 253 initializeEventHandlers(); 254 initializeParserPool(); 255 256 initializeIntrospection(); 257 /* 258 * initialize the VM Factory. It will use the properties 259 * accessable from Runtime, so keep this here at the end. 260 */ 261 vmFactory.initVelocimacro(); 262 263 log.trace("RuntimeInstance successfully initialized."); 264 265 initialized = true; 266 initializing = false; 267 } 268 } 269 270 /** 271 * Returns true if the RuntimeInstance has been successfully initialized. 272 * @return True if the RuntimeInstance has been successfully initialized. 273 * @since 1.5 274 */ 275 public boolean isInitialized() 276 { 277 return initialized; 278 } 279 280 /** 281 * Init or die! (with some log help, of course) 282 */ 283 private void requireInitialization() 284 { 285 if (!initialized && !initializing) 286 { 287 log.debug("Velocity was not initialized! Calling init()..."); 288 try 289 { 290 init(); 291 } 292 catch (Exception e) 293 { 294 getLog().error("Could not auto-initialize Velocity", e); 295 throw new RuntimeException("Velocity could not be initialized!", e); 296 } 297 } 298 } 299 300 /** 301 * Gets the classname for the Uberspect introspection package and 302 * instantiates an instance. 303 */ 304 private void initializeIntrospection() 305 throws Exception 306 { 307 String[] uberspectors = configuration.getStringArray(RuntimeConstants.UBERSPECT_CLASSNAME); 308 for (int i=0; i <uberspectors.length;i++) 309 { 310 String rm = uberspectors[i]; 311 Object o = null; 312 313 try 314 { 315 o = ClassUtils.getNewInstance( rm ); 316 } 317 catch (ClassNotFoundException cnfe) 318 { 319 String err = "The specified class for Uberspect (" + rm 320 + ") does not exist or is not accessible to the current classloader."; 321 log.error(err); 322 throw new Exception(err); 323 } 324 325 if (!(o instanceof Uberspect)) 326 { 327 String err = "The specified class for Uberspect (" 328 + rm + ") does not implement " + Uberspect.class.getName() 329 + "; Velocity is not initialized correctly."; 330 331 log.error(err); 332 throw new Exception(err); 333 } 334 335 Uberspect u = (Uberspect)o; 336 337 if (u instanceof UberspectLoggable) 338 { 339 ((UberspectLoggable)u).setLog(getLog()); 340 } 341 342 if (u instanceof RuntimeServicesAware) 343 { 344 ((RuntimeServicesAware)u).setRuntimeServices(this); 345 } 346 347 if (uberSpect == null) 348 { 349 uberSpect = u; 350 } 351 else 352 { 353 if (u instanceof ChainableUberspector) 354 { 355 ((ChainableUberspector)u).wrap(uberSpect); 356 uberSpect = u; 357 } 358 else 359 { 360 uberSpect = new LinkingUberspector(uberSpect,u); 361 } 362 } 363 } 364 365 if(uberSpect != null) 366 { 367 uberSpect.init(); 368 } 369 else 370 { 371 /* 372 * someone screwed up. Lets not fool around... 373 */ 374 375 String err = "It appears that no class was specified as the" 376 + " Uberspect. Please ensure that all configuration" 377 + " information is correct."; 378 379 log.error(err); 380 throw new Exception(err); 381 } 382 } 383 384 /** 385 * Initializes the Velocity Runtime with properties file. 386 * The properties file may be in the file system proper, 387 * or the properties file may be in the classpath. 388 */ 389 private void setDefaultProperties() 390 { 391 InputStream inputStream = null; 392 try 393 { 394 inputStream = getClass() 395 .getResourceAsStream('/' + DEFAULT_RUNTIME_PROPERTIES); 396 397 configuration.load( inputStream ); 398 399 if (log.isDebugEnabled()) 400 { 401 log.debug("Default Properties File: " + 402 new File(DEFAULT_RUNTIME_PROPERTIES).getPath()); 403 } 404 405 406 } 407 catch (IOException ioe) 408 { 409 String msg = "Cannot get Velocity Runtime default properties!"; 410 log.error(msg, ioe); 411 throw new RuntimeException(msg, ioe); 412 } 413 finally 414 { 415 try 416 { 417 if (inputStream != null) 418 { 419 inputStream.close(); 420 } 421 } 422 catch (IOException ioe) 423 { 424 String msg = "Cannot close Velocity Runtime default properties!"; 425 log.error(msg, ioe); 426 throw new RuntimeException(msg, ioe); 427 } 428 } 429 } 430 431 /** 432 * Allows an external system to set a property in 433 * the Velocity Runtime. 434 * 435 * @param key property key 436 * @param value property value 437 */ 438 public void setProperty(String key, Object value) 439 { 440 if (overridingProperties == null) 441 { 442 overridingProperties = new ExtendedProperties(); 443 } 444 445 overridingProperties.setProperty(key, value); 446 } 447 448 /** 449 * Allow an external system to set an ExtendedProperties 450 * object to use. This is useful where the external 451 * system also uses the ExtendedProperties class and 452 * the velocity configuration is a subset of 453 * parent application's configuration. This is 454 * the case with Turbine. 455 * 456 * @param configuration 457 */ 458 public void setConfiguration( ExtendedProperties configuration) 459 { 460 if (overridingProperties == null) 461 { 462 overridingProperties = configuration; 463 } 464 else 465 { 466 // Avoid possible ConcurrentModificationException 467 if (overridingProperties != configuration) 468 { 469 overridingProperties.combine(configuration); 470 } 471 } 472 } 473 474 /** 475 * Add a property to the configuration. If it already 476 * exists then the value stated here will be added 477 * to the configuration entry. For example, if 478 * 479 * resource.loader = file 480 * 481 * is already present in the configuration and you 482 * 483 * addProperty("resource.loader", "classpath") 484 * 485 * Then you will end up with a Vector like the 486 * following: 487 * 488 * ["file", "classpath"] 489 * 490 * @param key 491 * @param value 492 */ 493 public void addProperty(String key, Object value) 494 { 495 if (overridingProperties == null) 496 { 497 overridingProperties = new ExtendedProperties(); 498 } 499 500 overridingProperties.addProperty(key, value); 501 } 502 503 /** 504 * Clear the values pertaining to a particular 505 * property. 506 * 507 * @param key of property to clear 508 */ 509 public void clearProperty(String key) 510 { 511 if (overridingProperties != null) 512 { 513 overridingProperties.clearProperty(key); 514 } 515 } 516 517 /** 518 * Allows an external caller to get a property. The calling 519 * routine is required to know the type, as this routine 520 * will return an Object, as that is what properties can be. 521 * 522 * @param key property to return 523 * @return Value of the property or null if it does not exist. 524 */ 525 public Object getProperty(String key) 526 { 527 Object o = null; 528 529 /** 530 * Before initialization, check the user-entered properties first. 531 */ 532 if (!initialized && !initializing && overridingProperties != null) 533 { 534 o = overridingProperties.get(key); 535 } 536 537 /** 538 * After initialization, configuration will hold all properties. 539 */ 540 if (o == null) 541 { 542 o = configuration.getProperty(key); 543 } 544 if (o instanceof String) 545 { 546 return StringUtils.nullTrim((String) o); 547 } 548 else 549 { 550 return o; 551 } 552 } 553 554 /** 555 * Initialize Velocity properties, if the default 556 * properties have not been laid down first then 557 * do so. Then proceed to process any overriding 558 * properties. Laying down the default properties 559 * gives a much greater chance of having a 560 * working system. 561 */ 562 private void initializeProperties() 563 { 564 /* 565 * Always lay down the default properties first as 566 * to provide a solid base. 567 */ 568 if (configuration.isInitialized() == false) 569 { 570 setDefaultProperties(); 571 } 572 573 if( overridingProperties != null) 574 { 575 configuration.combine(overridingProperties); 576 } 577 } 578 579 /** 580 * Initialize the Velocity Runtime with a Properties 581 * object. 582 * 583 * @param p 584 * @throws Exception When an error occurs during initialization. 585 */ 586 public void init(Properties p) throws Exception 587 { 588 setProperties(ExtendedProperties.convertProperties(p)); 589 init(); 590 } 591 592 private void setProperties(ExtendedProperties p) 593 { 594 if (overridingProperties == null) 595 { 596 overridingProperties = p; 597 } 598 else 599 { 600 overridingProperties.combine(p); 601 } 602 } 603 604 /** 605 * Initialize the Velocity Runtime with the name of 606 * ExtendedProperties object. 607 * 608 * @param configurationFile 609 * @throws Exception When an error occurs during initialization. 610 */ 611 public void init(String configurationFile) 612 throws Exception 613 { 614 setProperties(new ExtendedProperties(configurationFile)); 615 init(); 616 } 617 618 private void initializeResourceManager() 619 throws Exception 620 { 621 /* 622 * Which resource manager? 623 */ 624 625 String rm = getString(RuntimeConstants.RESOURCE_MANAGER_CLASS); 626 627 if (rm != null && rm.length() > 0) 628 { 629 /* 630 * if something was specified, then make one. 631 * if that isn't a ResourceManager, consider 632 * this a huge error and throw 633 */ 634 635 Object o = null; 636 637 try 638 { 639 o = ClassUtils.getNewInstance( rm ); 640 } 641 catch (ClassNotFoundException cnfe ) 642 { 643 String err = "The specified class for ResourceManager (" + rm 644 + ") does not exist or is not accessible to the current classloader."; 645 log.error(err); 646 throw new Exception(err); 647 } 648 649 if (!(o instanceof ResourceManager)) 650 { 651 String err = "The specified class for ResourceManager (" + rm 652 + ") does not implement " + ResourceManager.class.getName() 653 + "; Velocity is not initialized correctly."; 654 655 log.error(err); 656 throw new Exception(err); 657 } 658 659 resourceManager = (ResourceManager) o; 660 661 resourceManager.initialize(this); 662 } 663 else 664 { 665 /* 666 * someone screwed up. Lets not fool around... 667 */ 668 669 String err = "It appears that no class was specified as the" 670 + " ResourceManager. Please ensure that all configuration" 671 + " information is correct."; 672 673 log.error(err); 674 throw new Exception( err ); 675 } 676 } 677 678 private void initializeEventHandlers() 679 throws Exception 680 { 681 682 eventCartridge = new EventCartridge(); 683 684 /** 685 * For each type of event handler, get the class name, instantiate it, and store it. 686 */ 687 688 String[] referenceinsertion = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION); 689 if ( referenceinsertion != null ) 690 { 691 for ( int i=0; i < referenceinsertion.length; i++ ) 692 { 693 EventHandler ev = initializeSpecificEventHandler(referenceinsertion[i],RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION,ReferenceInsertionEventHandler.class); 694 if (ev != null) 695 eventCartridge.addReferenceInsertionEventHandler((ReferenceInsertionEventHandler) ev); 696 } 697 } 698 699 String[] nullset = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_NULLSET); 700 if ( nullset != null ) 701 { 702 for ( int i=0; i < nullset.length; i++ ) 703 { 704 EventHandler ev = initializeSpecificEventHandler(nullset[i],RuntimeConstants.EVENTHANDLER_NULLSET,NullSetEventHandler.class); 705 if (ev != null) 706 eventCartridge.addNullSetEventHandler((NullSetEventHandler) ev); 707 } 708 } 709 710 String[] methodexception = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION); 711 if ( methodexception != null ) 712 { 713 for ( int i=0; i < methodexception.length; i++ ) 714 { 715 EventHandler ev = initializeSpecificEventHandler(methodexception[i],RuntimeConstants.EVENTHANDLER_METHODEXCEPTION,MethodExceptionEventHandler.class); 716 if (ev != null) 717 eventCartridge.addMethodExceptionHandler((MethodExceptionEventHandler) ev); 718 } 719 } 720 721 String[] includeHandler = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_INCLUDE); 722 if ( includeHandler != null ) 723 { 724 for ( int i=0; i < includeHandler.length; i++ ) 725 { 726 EventHandler ev = initializeSpecificEventHandler(includeHandler[i],RuntimeConstants.EVENTHANDLER_INCLUDE,IncludeEventHandler.class); 727 if (ev != null) 728 eventCartridge.addIncludeEventHandler((IncludeEventHandler) ev); 729 } 730 } 731 732 String[] invalidReferenceSet = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES); 733 if ( invalidReferenceSet != null ) 734 { 735 for ( int i=0; i < invalidReferenceSet.length; i++ ) 736 { 737 EventHandler ev = initializeSpecificEventHandler(invalidReferenceSet[i],RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES,InvalidReferenceEventHandler.class); 738 if (ev != null) 739 { 740 eventCartridge.addInvalidReferenceEventHandler((InvalidReferenceEventHandler) ev); 741 } 742 } 743 } 744 745 746 } 747 748 private EventHandler initializeSpecificEventHandler(String classname, String paramName, Class EventHandlerInterface) 749 throws Exception 750 { 751 if ( classname != null && classname.length() > 0) 752 { 753 Object o = null; 754 try { 755 o = ClassUtils.getNewInstance(classname); 756 } 757 catch (ClassNotFoundException cnfe ) 758 { 759 String err = "The specified class for " 760 + paramName + " (" + classname 761 + ") does not exist or is not accessible to the current classloader."; 762 log.error(err); 763 throw new Exception(err); 764 } 765 766 if (!EventHandlerInterface.isAssignableFrom(EventHandlerInterface)) 767 { 768 String err = "The specified class for " + paramName + " (" 769 + classname + ") does not implement " 770 + EventHandlerInterface.getName() 771 + "; Velocity is not initialized correctly."; 772 773 log.error(err); 774 throw new Exception(err); 775 } 776 777 EventHandler ev = (EventHandler) o; 778 if ( ev instanceof RuntimeServicesAware ) 779 ((RuntimeServicesAware) ev).setRuntimeServices(this); 780 return ev; 781 782 } else 783 return null; 784 } 785 786 /** 787 * Initialize the Velocity logging system. 788 * 789 * @throws Exception 790 */ 791 private void initializeLog() throws Exception 792 { 793 // since the Log we started with was just placeholding, 794 // let's update it with the real LogChute settings. 795 LogManager.updateLog(this.log, this); 796 } 797 798 799 /** 800 * This methods initializes all the directives 801 * that are used by the Velocity Runtime. The 802 * directives to be initialized are listed in 803 * the RUNTIME_DEFAULT_DIRECTIVES properties 804 * file. 805 * 806 * @throws Exception 807 */ 808 private void initializeDirectives() 809 throws Exception 810 { 811 /* 812 * Initialize the runtime directive table. 813 * This will be used for creating parsers. 814 */ 815 runtimeDirectives = new Hashtable(); 816 817 Properties directiveProperties = new Properties(); 818 819 /* 820 * Grab the properties file with the list of directives 821 * that we should initialize. 822 */ 823 824 InputStream inputStream = null; 825 826 try 827 { 828 inputStream = getClass().getResourceAsStream('/' + DEFAULT_RUNTIME_DIRECTIVES); 829 830 if (inputStream == null) 831 { 832 throw new Exception("Error loading directive.properties! " + 833 "Something is very wrong if these properties " + 834 "aren't being located. Either your Velocity " + 835 "distribution is incomplete or your Velocity " + 836 "jar file is corrupted!"); 837 } 838 839 directiveProperties.load(inputStream); 840 841 } 842 catch (IOException ioe) 843 { 844 String msg = "Error while loading directive properties!"; 845 log.error(msg, ioe); 846 throw new RuntimeException(msg, ioe); 847 } 848 finally 849 { 850 try 851 { 852 if (inputStream != null) 853 { 854 inputStream.close(); 855 } 856 } 857 catch (IOException ioe) 858 { 859 String msg = "Cannot close directive properties!"; 860 log.error(msg, ioe); 861 throw new RuntimeException(msg, ioe); 862 } 863 } 864 865 866 /* 867 * Grab all the values of the properties. These 868 * are all class names for example: 869 * 870 * org.apache.velocity.runtime.directive.Foreach 871 */ 872 Enumeration directiveClasses = directiveProperties.elements(); 873 874 while (directiveClasses.hasMoreElements()) 875 { 876 String directiveClass = (String) directiveClasses.nextElement(); 877 loadDirective(directiveClass); 878 log.debug("Loaded System Directive: " + directiveClass); 879 } 880 881 /* 882 * now the user's directives 883 */ 884 885 String[] userdirective = configuration.getStringArray("userdirective"); 886 887 for( int i = 0; i < userdirective.length; i++) 888 { 889 loadDirective(userdirective[i]); 890 if (log.isDebugEnabled()) 891 { 892 log.debug("Loaded User Directive: " + userdirective[i]); 893 } 894 } 895 896 } 897 898 /** 899 * Programatically add a directive. 900 * @param directive 901 */ 902 public void addDirective(Directive directive) 903 { 904 runtimeDirectives.put(directive.getName(), directive); 905 } 906 907 /** 908 * Retrieve a previously instantiated directive. 909 * @param name name of the directive 910 * @return the {@link Directive} for that name 911 */ 912 public Directive getDirective(String name) 913 { 914 return (Directive) runtimeDirectives.get(name); 915 } 916 917 /** 918 * Remove a directive. 919 * @param name name of the directive. 920 */ 921 public void removeDirective(String name) 922 { 923 runtimeDirectives.remove(name); 924 } 925 926 /** 927 * instantiates and loads the directive with some basic checks 928 * 929 * @param directiveClass classname of directive to load 930 */ 931 private void loadDirective(String directiveClass) 932 { 933 try 934 { 935 Object o = ClassUtils.getNewInstance( directiveClass ); 936 937 if (o instanceof Directive) 938 { 939 Directive directive = (Directive) o; 940 addDirective(directive); 941 } 942 else 943 { 944 String msg = directiveClass + " does not implement " 945 + Directive.class.getName() + "; it cannot be loaded."; 946 log.error(msg); 947 throw new VelocityException(msg); 948 } 949 } 950 // The ugly threesome: ClassNotFoundException, 951 // IllegalAccessException, InstantiationException. 952 // Ignore Findbugs complaint for now. 953 catch (Exception e) 954 { 955 String msg = "Failed to load Directive: " + directiveClass; 956 log.error(msg, e); 957 throw new VelocityException(msg, e); 958 } 959 } 960 961 962 /** 963 * Initializes the Velocity parser pool. 964 */ 965 private void initializeParserPool() throws Exception 966 { 967 /* 968 * Which parser pool? 969 */ 970 String pp = getString(RuntimeConstants.PARSER_POOL_CLASS); 971 972 if (pp != null && pp.length() > 0) 973 { 974 /* 975 * if something was specified, then make one. 976 * if that isn't a ParserPool, consider 977 * this a huge error and throw 978 */ 979 980 Object o = null; 981 982 try 983 { 984 o = ClassUtils.getNewInstance( pp ); 985 } 986 catch (ClassNotFoundException cnfe ) 987 { 988 String err = "The specified class for ParserPool (" 989 + pp 990 + ") does not exist (or is not accessible to the current classloader."; 991 log.error(err); 992 throw new Exception(err); 993 } 994 995 if (!(o instanceof ParserPool)) 996 { 997 String err = "The specified class for ParserPool (" 998 + pp + ") does not implement " + ParserPool.class 999 + " Velocity not initialized correctly."; 1000 1001 log.error(err); 1002 throw new Exception(err); 1003 } 1004 1005 parserPool = (ParserPool) o; 1006 1007 parserPool.initialize(this); 1008 } 1009 else 1010 { 1011 /* 1012 * someone screwed up. Lets not fool around... 1013 */ 1014 1015 String err = "It appears that no class was specified as the" 1016 + " ParserPool. Please ensure that all configuration" 1017 + " information is correct."; 1018 1019 log.error(err); 1020 throw new Exception( err ); 1021 } 1022 1023 } 1024 1025 /** 1026 * Returns a JavaCC generated Parser. 1027 * 1028 * @return Parser javacc generated parser 1029 */ 1030 public Parser createNewParser() 1031 { 1032 requireInitialization(); 1033 1034 Parser parser = new Parser(this); 1035 parser.setDirectives(runtimeDirectives); 1036 return parser; 1037 } 1038 1039 /** 1040 * Parse the input and return the root of 1041 * AST node structure. 1042 * <br><br> 1043 * In the event that it runs out of parsers in the 1044 * pool, it will create and let them be GC'd 1045 * dynamically, logging that it has to do that. This 1046 * is considered an exceptional condition. It is 1047 * expected that the user will set the 1048 * PARSER_POOL_SIZE property appropriately for their 1049 * application. We will revisit this. 1050 * 1051 * @param string String to be parsed 1052 * @param templateName name of the template being parsed 1053 * @return A root node representing the template as an AST tree. 1054 * @throws ParseException When the string could not be parsed as a template. 1055 * @since 1.6 1056 */ 1057 public SimpleNode parse(String string, String templateName) 1058 throws ParseException 1059 { 1060 return parse(new StringReader(string), templateName); 1061 } 1062 1063 /** 1064 * Parse the input and return the root of 1065 * AST node structure. 1066 * <br><br> 1067 * In the event that it runs out of parsers in the 1068 * pool, it will create and let them be GC'd 1069 * dynamically, logging that it has to do that. This 1070 * is considered an exceptional condition. It is 1071 * expected that the user will set the 1072 * PARSER_POOL_SIZE property appropriately for their 1073 * application. We will revisit this. 1074 * 1075 * @param reader Reader retrieved by a resource loader 1076 * @param templateName name of the template being parsed 1077 * @return A root node representing the template as an AST tree. 1078 * @throws ParseException When the template could not be parsed. 1079 */ 1080 public SimpleNode parse(Reader reader, String templateName) 1081 throws ParseException 1082 { 1083 /* 1084 * do it and dump the VM namespace for this template 1085 */ 1086 return parse(reader, templateName, true); 1087 } 1088 1089 /** 1090 * Parse the input and return the root of the AST node structure. 1091 * 1092 * @param reader Reader retrieved by a resource loader 1093 * @param templateName name of the template being parsed 1094 * @param dumpNamespace flag to dump the Velocimacro namespace for this template 1095 * @return A root node representing the template as an AST tree. 1096 * @throws ParseException When the template could not be parsed. 1097 */ 1098 public SimpleNode parse(Reader reader, String templateName, boolean dumpNamespace) 1099 throws ParseException 1100 { 1101 requireInitialization(); 1102 1103 Parser parser = (Parser) parserPool.get(); 1104 boolean keepParser = true; 1105 if (parser == null) 1106 { 1107 /* 1108 * if we couldn't get a parser from the pool make one and log it. 1109 */ 1110 if (log.isInfoEnabled()) 1111 { 1112 log.info("Runtime : ran out of parsers. Creating a new one. " 1113 + " Please increment the parser.pool.size property." 1114 + " The current value is too small."); 1115 } 1116 parser = createNewParser(); 1117 keepParser = false; 1118 } 1119 1120 try 1121 { 1122 /* 1123 * dump namespace if we are told to. Generally, you want to 1124 * do this - you don't in special circumstances, such as 1125 * when a VM is getting init()-ed & parsed 1126 */ 1127 if (dumpNamespace) 1128 { 1129 dumpVMNamespace(templateName); 1130 } 1131 return parser.parse(reader, templateName); 1132 } 1133 finally 1134 { 1135 if (keepParser) 1136 { 1137 parserPool.put(parser); 1138 } 1139 1140 } 1141 } 1142 1143 /** 1144 * Renders the input string using the context into the output writer. 1145 * To be used when a template is dynamically constructed, or want to use 1146 * Velocity as a token replacer. 1147 * 1148 * @param context context to use in rendering input string 1149 * @param out Writer in which to render the output 1150 * @param logTag string to be used as the template name for log 1151 * messages in case of error 1152 * @param instring input string containing the VTL to be rendered 1153 * 1154 * @return true if successful, false otherwise. If false, see 1155 * Velocity runtime log 1156 * @throws ParseErrorException The template could not be parsed. 1157 * @throws MethodInvocationException A method on a context object could not be invoked. 1158 * @throws ResourceNotFoundException A referenced resource could not be loaded. 1159 * @throws IOException While rendering to the writer, an I/O problem occured. 1160 * @since Velocity 1.6 1161 */ 1162 public boolean evaluate(Context context, Writer out, 1163 String logTag, String instring) throws IOException 1164 { 1165 return evaluate(context, out, logTag, new StringReader(instring)); 1166 } 1167 1168 /** 1169 * Renders the input reader using the context into the output writer. 1170 * To be used when a template is dynamically constructed, or want to 1171 * use Velocity as a token replacer. 1172 * 1173 * @param context context to use in rendering input string 1174 * @param writer Writer in which to render the output 1175 * @param logTag string to be used as the template name for log messages 1176 * in case of error 1177 * @param reader Reader containing the VTL to be rendered 1178 * 1179 * @return true if successful, false otherwise. If false, see 1180 * Velocity runtime log 1181 * @throws ParseErrorException The template could not be parsed. 1182 * @throws MethodInvocationException A method on a context object could not be invoked. 1183 * @throws ResourceNotFoundException A referenced resource could not be loaded. 1184 * @throws IOException While reading from the reader or rendering to the writer, 1185 * an I/O problem occured. 1186 * @since Velocity 1.6 1187 */ 1188 public boolean evaluate(Context context, Writer writer, 1189 String logTag, Reader reader) throws IOException 1190 { 1191 if (logTag == null) 1192 { 1193 throw new NullPointerException("logTag (i.e. template name) cannot be null, you must provide an identifier for the content being evaluated"); 1194 } 1195 1196 SimpleNode nodeTree = null; 1197 try 1198 { 1199 nodeTree = parse(reader, logTag); 1200 } 1201 catch (ParseException pex) 1202 { 1203 throw new ParseErrorException(pex); 1204 } 1205 catch (TemplateInitException pex) 1206 { 1207 throw new ParseErrorException(pex); 1208 } 1209 1210 if (nodeTree == null) 1211 { 1212 return false; 1213 } 1214 else 1215 { 1216 return render(context, writer, logTag, nodeTree); 1217 } 1218 } 1219 1220 1221 /** 1222 * Initializes and renders the AST {@link SimpleNode} using the context 1223 * into the output writer. 1224 * 1225 * @param context context to use in rendering input string 1226 * @param writer Writer in which to render the output 1227 * @param logTag string to be used as the template name for log messages 1228 * in case of error 1229 * @param nodeTree SimpleNode which is the root of the AST to be rendered 1230 * 1231 * @return true if successful, false otherwise. If false, see 1232 * Velocity runtime log for errors 1233 * @throws ParseErrorException The template could not be parsed. 1234 * @throws MethodInvocationException A method on a context object could not be invoked. 1235 * @throws ResourceNotFoundException A referenced resource could not be loaded. 1236 * @throws IOException While rendering to the writer, an I/O problem occured. 1237 * @since Velocity 1.6 1238 */ 1239 public boolean render(Context context, Writer writer, 1240 String logTag, SimpleNode nodeTree) throws IOException 1241 { 1242 /* 1243 * we want to init then render 1244 */ 1245 InternalContextAdapterImpl ica = 1246 new InternalContextAdapterImpl(context); 1247 1248 ica.pushCurrentTemplateName(logTag); 1249 1250 try 1251 { 1252 try 1253 { 1254 nodeTree.init(ica, this); 1255 } 1256 catch (TemplateInitException pex) 1257 { 1258 throw new ParseErrorException(pex); 1259 } 1260 /** 1261 * pass through application level runtime exceptions 1262 */ 1263 catch(RuntimeException e) 1264 { 1265 throw e; 1266 } 1267 catch(Exception e) 1268 { 1269 String msg = "RuntimeInstance.render(): init exception for tag = "+logTag; 1270 getLog().error(msg, e); 1271 throw new VelocityException(msg, e); 1272 } 1273 1274 /* 1275 * now render, and let any exceptions fly 1276 */ 1277 nodeTree.render(ica, writer); 1278 } 1279 finally 1280 { 1281 ica.popCurrentTemplateName(); 1282 } 1283 1284 return true; 1285 } 1286 1287 /** 1288 * Invokes a currently registered Velocimacro with the params provided 1289 * and places the rendered stream into the writer. 1290 * <br> 1291 * Note : currently only accepts args to the VM if they are in the context. 1292 * 1293 * @param vmName name of Velocimacro to call 1294 * @param logTag string to be used for template name in case of error. if null, 1295 * the vmName will be used 1296 * @param params keys for args used to invoke Velocimacro, in java format 1297 * rather than VTL (eg "foo" or "bar" rather than "$foo" or "$bar") 1298 * @param context Context object containing data/objects used for rendering. 1299 * @param writer Writer for output stream 1300 * @return true if Velocimacro exists and successfully invoked, false otherwise. 1301 * @throws IOException While rendering to the writer, an I/O problem occured. 1302 * @since 1.6 1303 */ 1304 public boolean invokeVelocimacro(final String vmName, String logTag, 1305 String[] params, final Context context, 1306 final Writer writer) 1307 throws IOException 1308 { 1309 /* check necessary parameters */ 1310 if (vmName == null || context == null || writer == null) 1311 { 1312 String msg = "RuntimeInstance.invokeVelocimacro() : invalid call : vmName, context, and writer must not be null"; 1313 getLog().error(msg); 1314 throw new NullPointerException(msg); 1315 } 1316 1317 /* handle easily corrected parameters */ 1318 if (logTag == null) 1319 { 1320 logTag = vmName; 1321 } 1322 if (params == null) 1323 { 1324 params = new String[0]; 1325 } 1326 1327 /* does the VM exist? */ 1328 if (!isVelocimacro(vmName, logTag)) 1329 { 1330 String msg = "RuntimeInstance.invokeVelocimacro() : VM '" + vmName 1331 + "' is not registered."; 1332 getLog().error(msg); 1333 throw new VelocityException(msg); 1334 } 1335 1336 /* now just create the VM call, and use evaluate */ 1337 StrBuilder template = new StrBuilder("#"); 1338 template.append(vmName); 1339 template.append("("); 1340 for( int i = 0; i < params.length; i++) 1341 { 1342 template.append(" $"); 1343 template.append(params[i]); 1344 } 1345 template.append(" )"); 1346 1347 return evaluate(context, writer, logTag, template.toString()); 1348 } 1349 1350 /** 1351 * Retrieves and caches the configured default encoding 1352 * for better performance. (VELOCITY-606) 1353 */ 1354 private String getDefaultEncoding() 1355 { 1356 if (encoding == null) 1357 { 1358 encoding = getString(INPUT_ENCODING, ENCODING_DEFAULT); 1359 } 1360 return encoding; 1361 } 1362 1363 /** 1364 * Returns a <code>Template</code> from the resource manager. 1365 * This method assumes that the character encoding of the 1366 * template is set by the <code>input.encoding</code> 1367 * property. The default is "ISO-8859-1" 1368 * 1369 * @param name The file name of the desired template. 1370 * @return The template. 1371 * @throws ResourceNotFoundException if template not found 1372 * from any available source. 1373 * @throws ParseErrorException if template cannot be parsed due 1374 * to syntax (or other) error. 1375 * @throws Exception if an error occurs in template initialization 1376 */ 1377 public Template getTemplate(String name) 1378 throws ResourceNotFoundException, ParseErrorException, Exception 1379 { 1380 return getTemplate(name, getDefaultEncoding()); 1381 } 1382 1383 /** 1384 * Returns a <code>Template</code> from the resource manager 1385 * 1386 * @param name The name of the desired template. 1387 * @param encoding Character encoding of the template 1388 * @return The template. 1389 * @throws ResourceNotFoundException if template not found 1390 * from any available source. 1391 * @throws ParseErrorException if template cannot be parsed due 1392 * to syntax (or other) error. 1393 * @throws Exception if an error occurs in template initialization 1394 */ 1395 public Template getTemplate(String name, String encoding) 1396 throws ResourceNotFoundException, ParseErrorException, Exception 1397 { 1398 requireInitialization(); 1399 1400 return (Template) 1401 resourceManager.getResource(name, 1402 ResourceManager.RESOURCE_TEMPLATE, encoding); 1403 } 1404 1405 /** 1406 * Returns a static content resource from the 1407 * resource manager. Uses the current value 1408 * if INPUT_ENCODING as the character encoding. 1409 * 1410 * @param name Name of content resource to get 1411 * @return parsed ContentResource object ready for use 1412 * @throws ResourceNotFoundException if template not found 1413 * from any available source. 1414 * @throws ParseErrorException When the template could not be parsed. 1415 * @throws Exception Any other error. 1416 */ 1417 public ContentResource getContent(String name) 1418 throws ResourceNotFoundException, ParseErrorException, Exception 1419 { 1420 /* 1421 * the encoding is irrelvant as we don't do any converstion 1422 * the bytestream should be dumped to the output stream 1423 */ 1424 1425 return getContent(name, getDefaultEncoding()); 1426 } 1427 1428 /** 1429 * Returns a static content resource from the 1430 * resource manager. 1431 * 1432 * @param name Name of content resource to get 1433 * @param encoding Character encoding to use 1434 * @return parsed ContentResource object ready for use 1435 * @throws ResourceNotFoundException if template not found 1436 * from any available source. 1437 * @throws ParseErrorException When the template could not be parsed. 1438 * @throws Exception Any other error. 1439 */ 1440 public ContentResource getContent(String name, String encoding) 1441 throws ResourceNotFoundException, ParseErrorException, Exception 1442 { 1443 requireInitialization(); 1444 1445 return (ContentResource) 1446 resourceManager.getResource(name, 1447 ResourceManager.RESOURCE_CONTENT, encoding); 1448 } 1449 1450 1451 /** 1452 * Determines if a template exists and returns name of the loader that 1453 * provides it. This is a slightly less hokey way to support 1454 * the Velocity.resourceExists() utility method, which was broken 1455 * when per-template encoding was introduced. We can revisit this. 1456 * 1457 * @param resourceName Name of template or content resource 1458 * @return class name of loader than can provide it 1459 */ 1460 public String getLoaderNameForResource(String resourceName) 1461 { 1462 requireInitialization(); 1463 1464 return resourceManager.getLoaderNameForResource(resourceName); 1465 } 1466 1467 /** 1468 * Returns a convenient Log instance that wraps the current LogChute. 1469 * Use this to log error messages. It has the usual methods. 1470 * 1471 * @return A convenience Log instance that wraps the current LogChute. 1472 * @since 1.5 1473 */ 1474 public Log getLog() 1475 { 1476 return log; 1477 } 1478 1479 /** 1480 * @deprecated Use getLog() and call warn() on it. 1481 * @see Log#warn(Object) 1482 * @param message The message to log. 1483 */ 1484 public void warn(Object message) 1485 { 1486 getLog().warn(message); 1487 } 1488 1489 /** 1490 * @deprecated Use getLog() and call info() on it. 1491 * @see Log#info(Object) 1492 * @param message The message to log. 1493 */ 1494 public void info(Object message) 1495 { 1496 getLog().info(message); 1497 } 1498 1499 /** 1500 * @deprecated Use getLog() and call error() on it. 1501 * @see Log#error(Object) 1502 * @param message The message to log. 1503 */ 1504 public void error(Object message) 1505 { 1506 getLog().error(message); 1507 } 1508 1509 /** 1510 * @deprecated Use getLog() and call debug() on it. 1511 * @see Log#debug(Object) 1512 * @param message The message to log. 1513 */ 1514 public void debug(Object message) 1515 { 1516 getLog().debug(message); 1517 } 1518 1519 /** 1520 * String property accessor method with default to hide the 1521 * configuration implementation. 1522 * 1523 * @param key property key 1524 * @param defaultValue default value to return if key not 1525 * found in resource manager. 1526 * @return value of key or default 1527 */ 1528 public String getString( String key, String defaultValue) 1529 { 1530 return configuration.getString(key, defaultValue); 1531 } 1532 1533 /** 1534 * Returns the appropriate VelocimacroProxy object if vmName 1535 * is a valid current Velocimacro. 1536 * 1537 * @param vmName Name of velocimacro requested 1538 * @param templateName Name of the template that contains the velocimacro. 1539 * @return The requested VelocimacroProxy. 1540 * @since 1.6 1541 */ 1542 public Directive getVelocimacro(String vmName, String templateName) 1543 { 1544 return vmFactory.getVelocimacro( vmName, templateName ); 1545 } 1546 1547 /** 1548 * Returns the appropriate VelocimacroProxy object if vmName 1549 * is a valid current Velocimacro. 1550 * 1551 * @param vmName Name of velocimacro requested 1552 * @param templateName Name of the namespace. 1553 * @param renderingTemplate Name of the template we are currently rendering. This 1554 * information is needed when VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL setting is true 1555 * and template contains a macro with the same name as the global macro library. 1556 * 1557 * @since Velocity 1.6 1558 * 1559 * @return VelocimacroProxy 1560 */ 1561 public Directive getVelocimacro(String vmName, String templateName, String renderingTemplate) 1562 { 1563 return vmFactory.getVelocimacro( vmName, templateName, renderingTemplate ); 1564 } 1565 1566 1567 /** 1568 * Adds a new Velocimacro. Usually called by Macro only while parsing. 1569 * 1570 * @param name Name of velocimacro 1571 * @param macro String form of macro body 1572 * @param argArray Array of strings, containing the 1573 * #macro() arguments. the 0th is the name. 1574 * @param sourceTemplate Name of the template that contains the velocimacro. 1575 * 1576 * @deprecated Use addVelocimacro(String, Node, String[], String) instead 1577 * 1578 * @return True if added, false if rejected for some 1579 * reason (either parameters or permission settings) 1580 */ 1581 public boolean addVelocimacro( String name, 1582 String macro, 1583 String argArray[], 1584 String sourceTemplate ) 1585 { 1586 return vmFactory.addVelocimacro(name, macro, argArray, sourceTemplate); 1587 } 1588 1589 /** 1590 * Adds a new Velocimacro. Usually called by Macro only while parsing. 1591 * 1592 * Called by org.apache.velocity.runtime.directive.processAndRegister 1593 * 1594 * @param name Name of velocimacro 1595 * @param macro root AST node of the parsed macro 1596 * @param argArray Array of strings, containing the 1597 * #macro() arguments. the 0th is the name. 1598 * @param sourceTemplate 1599 * 1600 * @since Velocity 1.6 1601 * 1602 * @return boolean True if added, false if rejected for some 1603 * reason (either parameters or permission settings) 1604 */ 1605 public boolean addVelocimacro( String name, 1606 Node macro, 1607 String argArray[], 1608 String sourceTemplate ) 1609 { 1610 return vmFactory.addVelocimacro(name, macro, argArray, sourceTemplate); 1611 } 1612 1613 1614 /** 1615 * Checks to see if a VM exists 1616 * 1617 * @param vmName Name of the Velocimacro. 1618 * @param templateName Template on which to look for the Macro. 1619 * @return True if VM by that name exists, false if not 1620 */ 1621 public boolean isVelocimacro( String vmName, String templateName ) 1622 { 1623 return vmFactory.isVelocimacro(vmName, templateName); 1624 } 1625 1626 /** 1627 * tells the vmFactory to dump the specified namespace. This is to support 1628 * clearing the VM list when in inline-VM-local-scope mode 1629 * @param namespace Namespace to dump. 1630 * @return True if namespace was dumped successfully. 1631 */ 1632 public boolean dumpVMNamespace(String namespace) 1633 { 1634 return vmFactory.dumpVMNamespace( namespace ); 1635 } 1636 1637 /* -------------------------------------------------------------------- 1638 * R U N T I M E A C C E S S O R M E T H O D S 1639 * -------------------------------------------------------------------- 1640 * These are the getXXX() methods that are a simple wrapper 1641 * around the configuration object. This is an attempt 1642 * to make a the Velocity Runtime the single access point 1643 * for all things Velocity, and allow the Runtime to 1644 * adhere as closely as possible the the Mediator pattern 1645 * which is the ultimate goal. 1646 * -------------------------------------------------------------------- 1647 */ 1648 1649 /** 1650 * String property accessor method to hide the configuration implementation 1651 * @param key property key 1652 * @return value of key or null 1653 */ 1654 public String getString(String key) 1655 { 1656 return StringUtils.nullTrim(configuration.getString(key)); 1657 } 1658 1659 /** 1660 * Int property accessor method to hide the configuration implementation. 1661 * 1662 * @param key Property key 1663 * @return value 1664 */ 1665 public int getInt(String key) 1666 { 1667 return configuration.getInt(key); 1668 } 1669 1670 /** 1671 * Int property accessor method to hide the configuration implementation. 1672 * 1673 * @param key property key 1674 * @param defaultValue The default value. 1675 * @return value 1676 */ 1677 public int getInt(String key, int defaultValue) 1678 { 1679 return configuration.getInt(key, defaultValue); 1680 } 1681 1682 /** 1683 * Boolean property accessor method to hide the configuration implementation. 1684 * 1685 * @param key property key 1686 * @param def The default value if property not found. 1687 * @return value of key or default value 1688 */ 1689 public boolean getBoolean(String key, boolean def) 1690 { 1691 return configuration.getBoolean(key, def); 1692 } 1693 1694 /** 1695 * Return the velocity runtime configuration object. 1696 * 1697 * @return Configuration object which houses the Velocity runtime 1698 * properties. 1699 */ 1700 public ExtendedProperties getConfiguration() 1701 { 1702 return configuration; 1703 } 1704 1705 /** 1706 * Return the Introspector for this instance 1707 * @return The Introspector for this instance 1708 */ 1709 public Introspector getIntrospector() 1710 { 1711 return introspector; 1712 } 1713 1714 /** 1715 * Returns the event handlers for the application. 1716 * @return The event handlers for the application. 1717 * @since 1.5 1718 */ 1719 public EventCartridge getApplicationEventCartridge() 1720 { 1721 return eventCartridge; 1722 } 1723 1724 1725 /** 1726 * Gets the application attribute for the given key 1727 * 1728 * @param key 1729 * @return The application attribute for the given key. 1730 */ 1731 public Object getApplicationAttribute(Object key) 1732 { 1733 return applicationAttributes.get(key); 1734 } 1735 1736 /** 1737 * Sets the application attribute for the given key 1738 * 1739 * @param key 1740 * @param o The new application attribute. 1741 * @return The old value of this attribute or null if it hasn't been set before. 1742 */ 1743 public Object setApplicationAttribute(Object key, Object o) 1744 { 1745 return applicationAttributes.put(key, o); 1746 } 1747 1748 /** 1749 * Returns the Uberspect object for this Instance. 1750 * 1751 * @return The Uberspect object for this Instance. 1752 */ 1753 public Uberspect getUberspect() 1754 { 1755 return uberSpect; 1756 } 1757 1758 }
1 package org.apache.velocity.runtime; 2 3 /* 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 import java.io.File; 23 import java.io.IOException; 24 import java.io.InputStream; 25 import java.io.Reader; 26 import java.io.StringReader; 27 import java.io.Writer; 28 import java.util.Enumeration; 29 import java.util.HashMap; 30 import java.util.Hashtable; 31 import java.util.Map; 32 import java.util.Properties; 33 34 import org.apache.commons.collections.ExtendedProperties; 35 import org.apache.commons.lang.text.StrBuilder; 36 import org.apache.velocity.Template; 37 import org.apache.velocity.app.event.EventCartridge; 38 import org.apache.velocity.app.event.EventHandler; 39 import org.apache.velocity.app.event.IncludeEventHandler; 40 import org.apache.velocity.app.event.InvalidReferenceEventHandler; 41 import org.apache.velocity.app.event.MethodExceptionEventHandler; 42 import org.apache.velocity.app.event.NullSetEventHandler; 43 import org.apache.velocity.app.event.ReferenceInsertionEventHandler; 44 import org.apache.velocity.context.Context; 45 import org.apache.velocity.context.InternalContextAdapterImpl; 46 import org.apache.velocity.exception.MethodInvocationException; 47 import org.apache.velocity.exception.ParseErrorException; 48 import org.apache.velocity.exception.ResourceNotFoundException; 49 import org.apache.velocity.exception.TemplateInitException; 50 import org.apache.velocity.exception.VelocityException; 51 import org.apache.velocity.runtime.directive.Directive; 52 import org.apache.velocity.runtime.log.Log; 53 import org.apache.velocity.runtime.log.LogManager; 54 import org.apache.velocity.runtime.parser.ParseException; 55 import org.apache.velocity.runtime.parser.Parser; 56 import org.apache.velocity.runtime.parser.node.Node; 57 import org.apache.velocity.runtime.parser.node.SimpleNode; 58 import org.apache.velocity.runtime.resource.ContentResource; 59 import org.apache.velocity.runtime.resource.ResourceManager; 60 import org.apache.velocity.util.ClassUtils; 61 import org.apache.velocity.util.RuntimeServicesAware; 62 import org.apache.velocity.util.StringUtils; 63 import org.apache.velocity.util.introspection.Introspector; 64 import org.apache.velocity.util.introspection.Uberspect; 65 import org.apache.velocity.util.introspection.UberspectLoggable; 66 import org.apache.velocity.util.introspection.ChainableUberspector; 67 import org.apache.velocity.util.introspection.LinkingUberspector; 68 69 /** 70 * This is the Runtime system for Velocity. It is the 71 * single access point for all functionality in Velocity. 72 * It adheres to the mediator pattern and is the only 73 * structure that developers need to be familiar with 74 * in order to get Velocity to perform. 75 * 76 * The Runtime will also cooperate with external 77 * systems like Turbine. Runtime properties can 78 * set and then the Runtime is initialized. 79 * 80 * Turbine, for example, knows where the templates 81 * are to be loaded from, and where the Velocity 82 * log file should be placed. 83 * 84 * So in the case of Velocity cooperating with Turbine 85 * the code might look something like the following: 86 * 87 * <blockquote><code><pre> 88 * ri.setProperty(Runtime.FILE_RESOURCE_LOADER_PATH, templatePath); 89 * ri.setProperty(Runtime.RUNTIME_LOG, pathToVelocityLog); 90 * ri.init(); 91 * </pre></code></blockquote> 92 * 93 * <pre> 94 * ----------------------------------------------------------------------- 95 * N O T E S O N R U N T I M E I N I T I A L I Z A T I O N 96 * ----------------------------------------------------------------------- 97 * init() 98 * 99 * If init() is called by itself the RuntimeInstance will initialize 100 * with a set of default values. 101 * ----------------------------------------------------------------------- 102 * init(String/Properties) 103 * 104 * In this case the default velocity properties are layed down 105 * first to provide a solid base, then any properties provided 106 * in the given properties object will override the corresponding 107 * default property. 108 * ----------------------------------------------------------------------- 109 * </pre> 110 * 111 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> 112 * @author <a href="mailto:jlb@houseofdistraction.com">Jeff Bowden</a> 113 * @author <a href="mailto:geirm@optonline.net">Geir Magusson Jr.</a> 114 * @version $Id: RuntimeInstance.java 703049 2008-10-09 03:18:58Z nbubna $ 115 */ 116 public class RuntimeInstance implements RuntimeConstants, RuntimeServices 117 { 118 /** 119 * VelocimacroFactory object to manage VMs 120 */ 121 private VelocimacroFactory vmFactory = null; 122 123 /** 124 * The Runtime logger. We start with an instance of 125 * a 'primordial logger', which just collects log messages 126 * then, when the log system is initialized, all the 127 * messages get dumpted out of the primordial one into the real one. 128 */ 129 private Log log = new Log(); 130 131 /** 132 * The Runtime parser pool 133 */ 134 private ParserPool parserPool; 135 136 /** 137 * Indicate whether the Runtime is in the midst of initialization. 138 */ 139 private boolean initializing = false; 140 141 /** 142 * Indicate whether the Runtime has been fully initialized. 143 */ 144 private boolean initialized = false; 145 146 /** 147 * These are the properties that are laid down over top 148 * of the default properties when requested. 149 */ 150 private ExtendedProperties overridingProperties = null; 151 152 /** 153 * This is a hashtable of initialized directives. 154 * The directives that populate this hashtable are 155 * taken from the RUNTIME_DEFAULT_DIRECTIVES 156 * property file. This hashtable is passed 157 * to each parser that is created. 158 */ 159 private Hashtable runtimeDirectives; 160 161 /** 162 * Object that houses the configuration options for 163 * the velocity runtime. The ExtendedProperties object allows 164 * the convenient retrieval of a subset of properties. 165 * For example all the properties for a resource loader 166 * can be retrieved from the main ExtendedProperties object 167 * using something like the following: 168 * 169 * ExtendedProperties loaderConfiguration = 170 * configuration.subset(loaderID); 171 * 172 * And a configuration is a lot more convenient to deal 173 * with then conventional properties objects, or Maps. 174 */ 175 private ExtendedProperties configuration = new ExtendedProperties(); 176 177 private ResourceManager resourceManager = null; 178 179 /** 180 * This stores the engine-wide set of event handlers. Event handlers for 181 * each specific merge are stored in the context. 182 */ 183 private EventCartridge eventCartridge = null; 184 185 /* 186 * Each runtime instance has it's own introspector 187 * to ensure that each instance is completely separate. 188 */ 189 private Introspector introspector = null; 190 191 192 /* 193 * Opaque reference to something specificed by the 194 * application for use in application supplied/specified 195 * pluggable components 196 */ 197 private Map applicationAttributes = null; 198 private Uberspect uberSpect; 199 private String encoding; 200 201 /** 202 * Creates a new RuntimeInstance object. 203 */ 204 public RuntimeInstance() 205 { 206 /* 207 * create a VM factory, introspector, and application attributes 208 */ 209 vmFactory = new VelocimacroFactory( this ); 210 211 /* 212 * make a new introspector and initialize it 213 */ 214 introspector = new Introspector(getLog()); 215 216 /* 217 * and a store for the application attributes 218 */ 219 applicationAttributes = new HashMap(); 220 } 221 222 /** 223 * This is the primary initialization method in the Velocity 224 * Runtime. The systems that are setup/initialized here are 225 * as follows: 226 * 227 * <ul> 228 * <li>Logging System</li> 229 * <li>ResourceManager</li> 230 * <li>EventHandler</li> 231 * <li>Parser Pool</li> 232 * <li>Global Cache</li> 233 * <li>Static Content Include System</li> 234 * <li>Velocimacro System</li> 235 * </ul> 236 * @throws Exception When an error occured during initialization. 237 */ 238 public synchronized void init() 239 throws Exception 240 { 241 if (!initialized && !initializing) 242 { 243 initializing = true; 244 245 log.trace("*******************************************************************"); 246 log.debug("Starting Apache Velocity v@build.version@ (compiled: @build.time@)"); 247 log.trace("RuntimeInstance initializing."); 248 249 initializeProperties(); 250 initializeLog(); 251 initializeResourceManager(); 252 initializeDirectives(); 253 initializeEventHandlers(); 254 initializeParserPool(); 255 256 initializeIntrospection(); 257 /* 258 * initialize the VM Factory. It will use the properties 259 * accessable from Runtime, so keep this here at the end. 260 */ 261 vmFactory.initVelocimacro(); 262 263 log.trace("RuntimeInstance successfully initialized."); 264 265 initialized = true; 266 initializing = false; 267 } 268 } 269 270 /** 271 * Returns true if the RuntimeInstance has been successfully initialized. 272 * @return True if the RuntimeInstance has been successfully initialized. 273 * @since 1.5 274 */ 275 public boolean isInitialized() 276 { 277 return initialized; 278 } 279 280 /** 281 * Init or die! (with some log help, of course) 282 */ 283 private void requireInitialization() 284 { 285 if (!initialized && !initializing) 286 { 287 log.debug("Velocity was not initialized! Calling init()..."); 288 try 289 { 290 init(); 291 } 292 catch (Exception e) 293 { 294 getLog().error("Could not auto-initialize Velocity", e); 295 throw new RuntimeException("Velocity could not be initialized!", e); 296 } 297 } 298 } 299 300 /** 301 * Gets the classname for the Uberspect introspection package and 302 * instantiates an instance. 303 */ 304 private void initializeIntrospection() 305 throws Exception 306 { 307 String[] uberspectors = configuration.getStringArray(RuntimeConstants.UBERSPECT_CLASSNAME); 308 for (int i=0; i <uberspectors.length;i++) 309 { 310 String rm = uberspectors[i]; 311 Object o = null; 312 313 try 314 { 315 o = ClassUtils.getNewInstance( rm ); 316 } 317 catch (ClassNotFoundException cnfe) 318 { 319 String err = "The specified class for Uberspect (" + rm 320 + ") does not exist or is not accessible to the current classloader."; 321 log.error(err); 322 throw new Exception(err); 323 } 324 325 if (!(o instanceof Uberspect)) 326 { 327 String err = "The specified class for Uberspect (" 328 + rm + ") does not implement " + Uberspect.class.getName() 329 + "; Velocity is not initialized correctly."; 330 331 log.error(err); 332 throw new Exception(err); 333 } 334 335 Uberspect u = (Uberspect)o; 336 337 if (u instanceof UberspectLoggable) 338 { 339 ((UberspectLoggable)u).setLog(getLog()); 340 } 341 342 if (u instanceof RuntimeServicesAware) 343 { 344 ((RuntimeServicesAware)u).setRuntimeServices(this); 345 } 346 347 if (uberSpect == null) 348 { 349 uberSpect = u; 350 } 351 else 352 { 353 if (u instanceof ChainableUberspector) 354 { 355 ((ChainableUberspector)u).wrap(uberSpect); 356 uberSpect = u; 357 } 358 else 359 { 360 uberSpect = new LinkingUberspector(uberSpect,u); 361 } 362 } 363 } 364 365 if(uberSpect != null) 366 { 367 uberSpect.init(); 368 } 369 else 370 { 371 /* 372 * someone screwed up. Lets not fool around... 373 */ 374 375 String err = "It appears that no class was specified as the" 376 + " Uberspect. Please ensure that all configuration" 377 + " information is correct."; 378 379 log.error(err); 380 throw new Exception(err); 381 } 382 } 383 384 /** 385 * Initializes the Velocity Runtime with properties file. 386 * The properties file may be in the file system proper, 387 * or the properties file may be in the classpath. 388 */ 389 private void setDefaultProperties() 390 { 391 InputStream inputStream = null; 392 try 393 { 394 inputStream = getClass() 395 .getResourceAsStream('/' + DEFAULT_RUNTIME_PROPERTIES); 396 397 configuration.load( inputStream ); 398 399 if (log.isDebugEnabled()) 400 { 401 log.debug("Default Properties File: " + 402 new File(DEFAULT_RUNTIME_PROPERTIES).getPath()); 403 } 404 405 406 } 407 catch (IOException ioe) 408 { 409 String msg = "Cannot get Velocity Runtime default properties!"; 410 log.error(msg, ioe); 411 throw new RuntimeException(msg, ioe); 412 } 413 finally 414 { 415 try 416 { 417 if (inputStream != null) 418 { 419 inputStream.close(); 420 } 421 } 422 catch (IOException ioe) 423 { 424 String msg = "Cannot close Velocity Runtime default properties!"; 425 log.error(msg, ioe); 426 throw new RuntimeException(msg, ioe); 427 } 428 } 429 } 430 431 /** 432 * Allows an external system to set a property in 433 * the Velocity Runtime. 434 * 435 * @param key property key 436 * @param value property value 437 */ 438 public void setProperty(String key, Object value) 439 { 440 if (overridingProperties == null) 441 { 442 overridingProperties = new ExtendedProperties(); 443 } 444 445 overridingProperties.setProperty(key, value); 446 } 447 448 /** 449 * Allow an external system to set an ExtendedProperties 450 * object to use. This is useful where the external 451 * system also uses the ExtendedProperties class and 452 * the velocity configuration is a subset of 453 * parent application's configuration. This is 454 * the case with Turbine. 455 * 456 * @param configuration 457 */ 458 public void setConfiguration( ExtendedProperties configuration) 459 { 460 if (overridingProperties == null) 461 { 462 overridingProperties = configuration; 463 } 464 else 465 { 466 // Avoid possible ConcurrentModificationException 467 if (overridingProperties != configuration) 468 { 469 overridingProperties.combine(configuration); 470 } 471 } 472 } 473 474 /** 475 * Add a property to the configuration. If it already 476 * exists then the value stated here will be added 477 * to the configuration entry. For example, if 478 * 479 * resource.loader = file 480 * 481 * is already present in the configuration and you 482 * 483 * addProperty("resource.loader", "classpath") 484 * 485 * Then you will end up with a Vector like the 486 * following: 487 * 488 * ["file", "classpath"] 489 * 490 * @param key 491 * @param value 492 */ 493 public void addProperty(String key, Object value) 494 { 495 if (overridingProperties == null) 496 { 497 overridingProperties = new ExtendedProperties(); 498 } 499 500 overridingProperties.addProperty(key, value); 501 } 502 503 /** 504 * Clear the values pertaining to a particular 505 * property. 506 * 507 * @param key of property to clear 508 */ 509 public void clearProperty(String key) 510 { 511 if (overridingProperties != null) 512 { 513 overridingProperties.clearProperty(key); 514 } 515 } 516 517 /** 518 * Allows an external caller to get a property. The calling 519 * routine is required to know the type, as this routine 520 * will return an Object, as that is what properties can be. 521 * 522 * @param key property to return 523 * @return Value of the property or null if it does not exist. 524 */ 525 public Object getProperty(String key) 526 { 527 Object o = null; 528 529 /** 530 * Before initialization, check the user-entered properties first. 531 */ 532 if (!initialized && !initializing && overridingProperties != null) 533 { 534 o = overridingProperties.get(key); 535 } 536 537 /** 538 * After initialization, configuration will hold all properties. 539 */ 540 if (o == null) 541 { 542 o = configuration.getProperty(key); 543 } 544 if (o instanceof String) 545 { 546 return StringUtils.nullTrim((String) o); 547 } 548 else 549 { 550 return o; 551 } 552 } 553 554 /** 555 * Initialize Velocity properties, if the default 556 * properties have not been laid down first then 557 * do so. Then proceed to process any overriding 558 * properties. Laying down the default properties 559 * gives a much greater chance of having a 560 * working system. 561 */ 562 private void initializeProperties() 563 { 564 /* 565 * Always lay down the default properties first as 566 * to provide a solid base. 567 */ 568 if (configuration.isInitialized() == false) 569 { 570 setDefaultProperties(); 571 } 572 573 if( overridingProperties != null) 574 { 575 configuration.combine(overridingProperties); 576 } 577 } 578 579 /** 580 * Initialize the Velocity Runtime with a Properties 581 * object. 582 * 583 * @param p 584 * @throws Exception When an error occurs during initialization. 585 */ 586 public void init(Properties p) throws Exception 587 { 588 setProperties(ExtendedProperties.convertProperties(p)); 589 init(); 590 } 591 592 private void setProperties(ExtendedProperties p) 593 { 594 if (overridingProperties == null) 595 { 596 overridingProperties = p; 597 } 598 else 599 { 600 overridingProperties.combine(p); 601 } 602 } 603 604 /** 605 * Initialize the Velocity Runtime with the name of 606 * ExtendedProperties object. 607 * 608 * @param configurationFile 609 * @throws Exception When an error occurs during initialization. 610 */ 611 public void init(String configurationFile) 612 throws Exception 613 { 614 setProperties(new ExtendedProperties(configurationFile)); 615 init(); 616 } 617 618 private void initializeResourceManager() 619 throws Exception 620 { 621 /* 622 * Which resource manager? 623 */ 624 625 String rm = getString(RuntimeConstants.RESOURCE_MANAGER_CLASS); 626 627 if (rm != null && rm.length() > 0) 628 { 629 /* 630 * if something was specified, then make one. 631 * if that isn't a ResourceManager, consider 632 * this a huge error and throw 633 */ 634 635 Object o = null; 636 637 try 638 { 639 o = ClassUtils.getNewInstance( rm ); 640 } 641 catch (ClassNotFoundException cnfe ) 642 { 643 String err = "The specified class for ResourceManager (" + rm 644 + ") does not exist or is not accessible to the current classloader."; 645 log.error(err); 646 throw new Exception(err); 647 } 648 649 if (!(o instanceof ResourceManager)) 650 { 651 String err = "The specified class for ResourceManager (" + rm 652 + ") does not implement " + ResourceManager.class.getName() 653 + "; Velocity is not initialized correctly."; 654 655 log.error(err); 656 throw new Exception(err); 657 } 658 659 resourceManager = (ResourceManager) o; 660 661 resourceManager.initialize(this); 662 } 663 else 664 { 665 /* 666 * someone screwed up. Lets not fool around... 667 */ 668 669 String err = "It appears that no class was specified as the" 670 + " ResourceManager. Please ensure that all configuration" 671 + " information is correct."; 672 673 log.error(err); 674 throw new Exception( err ); 675 } 676 } 677 678 private void initializeEventHandlers() 679 throws Exception 680 { 681 682 eventCartridge = new EventCartridge(); 683 684 /** 685 * For each type of event handler, get the class name, instantiate it, and store it. 686 */ 687 688 String[] referenceinsertion = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION); 689 if ( referenceinsertion != null ) 690 { 691 for ( int i=0; i < referenceinsertion.length; i++ ) 692 { 693 EventHandler ev = initializeSpecificEventHandler(referenceinsertion[i],RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION,ReferenceInsertionEventHandler.class); 694 if (ev != null) 695 eventCartridge.addReferenceInsertionEventHandler((ReferenceInsertionEventHandler) ev); 696 } 697 } 698 699 String[] nullset = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_NULLSET); 700 if ( nullset != null ) 701 { 702 for ( int i=0; i < nullset.length; i++ ) 703 { 704 EventHandler ev = initializeSpecificEventHandler(nullset[i],RuntimeConstants.EVENTHANDLER_NULLSET,NullSetEventHandler.class); 705 if (ev != null) 706 eventCartridge.addNullSetEventHandler((NullSetEventHandler) ev); 707 } 708 } 709 710 String[] methodexception = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION); 711 if ( methodexception != null ) 712 { 713 for ( int i=0; i < methodexception.length; i++ ) 714 { 715 EventHandler ev = initializeSpecificEventHandler(methodexception[i],RuntimeConstants.EVENTHANDLER_METHODEXCEPTION,MethodExceptionEventHandler.class); 716 if (ev != null) 717 eventCartridge.addMethodExceptionHandler((MethodExceptionEventHandler) ev); 718 } 719 } 720 721 String[] includeHandler = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_INCLUDE); 722 if ( includeHandler != null ) 723 { 724 for ( int i=0; i < includeHandler.length; i++ ) 725 { 726 EventHandler ev = initializeSpecificEventHandler(includeHandler[i],RuntimeConstants.EVENTHANDLER_INCLUDE,IncludeEventHandler.class); 727 if (ev != null) 728 eventCartridge.addIncludeEventHandler((IncludeEventHandler) ev); 729 } 730 } 731 732 String[] invalidReferenceSet = configuration.getStringArray(RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES); 733 if ( invalidReferenceSet != null ) 734 { 735 for ( int i=0; i < invalidReferenceSet.length; i++ ) 736 { 737 EventHandler ev = initializeSpecificEventHandler(invalidReferenceSet[i],RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES,InvalidReferenceEventHandler.class); 738 if (ev != null) 739 { 740 eventCartridge.addInvalidReferenceEventHandler((InvalidReferenceEventHandler) ev); 741 } 742 } 743 } 744 745 746 } 747 748 private EventHandler initializeSpecificEventHandler(String classname, String paramName, Class EventHandlerInterface) 749 throws Exception 750 { 751 if ( classname != null && classname.length() > 0) 752 { 753 Object o = null; 754 try { 755 o = ClassUtils.getNewInstance(classname); 756 } 757 catch (ClassNotFoundException cnfe ) 758 { 759 String err = "The specified class for " 760 + paramName + " (" + classname 761 + ") does not exist or is not accessible to the current classloader."; 762 log.error(err); 763 throw new Exception(err); 764 } 765 766 if (!EventHandlerInterface.isAssignableFrom(EventHandlerInterface)) 767 { 768 String err = "The specified class for " + paramName + " (" 769 + classname + ") does not implement " 770 + EventHandlerInterface.getName() 771 + "; Velocity is not initialized correctly."; 772 773 log.error(err); 774 throw new Exception(err); 775 } 776 777 EventHandler ev = (EventHandler) o; 778 if ( ev instanceof RuntimeServicesAware ) 779 ((RuntimeServicesAware) ev).setRuntimeServices(this); 780 return ev; 781 782 } else 783 return null; 784 } 785 786 /** 787 * Initialize the Velocity logging system. 788 * 789 * @throws Exception 790 */ 791 private void initializeLog() throws Exception 792 { 793 // since the Log we started with was just placeholding, 794 // let's update it with the real LogChute settings. 795 LogManager.updateLog(this.log, this); 796 } 797 798 799 /** 800 * This methods initializes all the directives 801 * that are used by the Velocity Runtime. The 802 * directives to be initialized are listed in 803 * the RUNTIME_DEFAULT_DIRECTIVES properties 804 * file. 805 * 806 * @throws Exception 807 */ 808 private void initializeDirectives() 809 throws Exception 810 { 811 /* 812 * Initialize the runtime directive table. 813 * This will be used for creating parsers. 814 */ 815 runtimeDirectives = new Hashtable(); 816 817 Properties directiveProperties = new Properties(); 818 819 /* 820 * Grab the properties file with the list of directives 821 * that we should initialize. 822 */ 823 824 InputStream inputStream = null; 825 826 try 827 { 828 inputStream = getClass().getResourceAsStream('/' + DEFAULT_RUNTIME_DIRECTIVES); 829 830 if (inputStream == null) 831 { 832 throw new Exception("Error loading directive.properties! " + 833 "Something is very wrong if these properties " + 834 "aren't being located. Either your Velocity " + 835 "distribution is incomplete or your Velocity " + 836 "jar file is corrupted!"); 837 } 838 839 directiveProperties.load(inputStream); 840 841 } 842 catch (IOException ioe) 843 { 844 String msg = "Error while loading directive properties!"; 845 log.error(msg, ioe); 846 throw new RuntimeException(msg, ioe); 847 } 848 finally 849 { 850 try 851 { 852 if (inputStream != null) 853 { 854 inputStream.close(); 855 } 856 } 857 catch (IOException ioe) 858 { 859 String msg = "Cannot close directive properties!"; 860 log.error(msg, ioe); 861 throw new RuntimeException(msg, ioe); 862 } 863 } 864 865 866 /* 867 * Grab all the values of the properties. These 868 * are all class names for example: 869 * 870 * org.apache.velocity.runtime.directive.Foreach 871 */ 872 Enumeration directiveClasses = directiveProperties.elements(); 873 874 while (directiveClasses.hasMoreElements()) 875 { 876 String directiveClass = (String) directiveClasses.nextElement(); 877 loadDirective(directiveClass); 878 log.debug("Loaded System Directive: " + directiveClass); 879 } 880 881 /* 882 * now the user's directives 883 */ 884 885 String[] userdirective = configuration.getStringArray("userdirective"); 886 887 for( int i = 0; i < userdirective.length; i++) 888 { 889 loadDirective(userdirective[i]); 890 if (log.isDebugEnabled()) 891 { 892 log.debug("Loaded User Directive: " + userdirective[i]); 893 } 894 } 895 896 } 897 898 /** 899 * Programatically add a directive. 900 * @param directive 901 */ 902 public void addDirective(Directive directive) 903 { 904 runtimeDirectives.put(directive.getName(), directive); 905 } 906 907 /** 908 * Retrieve a previously instantiated directive. 909 * @param name name of the directive 910 * @return the {@link Directive} for that name 911 */ 912 public Directive getDirective(String name) 913 { 914 return (Directive) runtimeDirectives.get(name); 915 } 916 917 /** 918 * Remove a directive. 919 * @param name name of the directive. 920 */ 921 public void removeDirective(String name) 922 { 923 runtimeDirectives.remove(name); 924 } 925 926 /** 927 * instantiates and loads the directive with some basic checks 928 * 929 * @param directiveClass classname of directive to load 930 */ 931 private void loadDirective(String directiveClass) 932 { 933 try 934 { 935 Object o = ClassUtils.getNewInstance( directiveClass ); 936 937 if (o instanceof Directive) 938 { 939 Directive directive = (Directive) o; 940 addDirective(directive); 941 } 942 else 943 { 944 String msg = directiveClass + " does not implement " 945 + Directive.class.getName() + "; it cannot be loaded."; 946 log.error(msg); 947 throw new VelocityException(msg); 948 } 949 } 950 // The ugly threesome: ClassNotFoundException, 951 // IllegalAccessException, InstantiationException. 952 // Ignore Findbugs complaint for now. 953 catch (Exception e) 954 { 955 String msg = "Failed to load Directive: " + directiveClass; 956 log.error(msg, e); 957 throw new VelocityException(msg, e); 958 } 959 } 960 961 962 /** 963 * Initializes the Velocity parser pool. 964 */ 965 private void initializeParserPool() throws Exception 966 { 967 /* 968 * Which parser pool? 969 */ 970 String pp = getString(RuntimeConstants.PARSER_POOL_CLASS); 971 972 if (pp != null && pp.length() > 0) 973 { 974 /* 975 * if something was specified, then make one. 976 * if that isn't a ParserPool, consider 977 * this a huge error and throw 978 */ 979 980 Object o = null; 981 982 try 983 { 984 o = ClassUtils.getNewInstance( pp ); 985 } 986 catch (ClassNotFoundException cnfe ) 987 { 988 String err = "The specified class for ParserPool (" 989 + pp 990 + ") does not exist (or is not accessible to the current classloader."; 991 log.error(err); 992 throw new Exception(err); 993 } 994 995 if (!(o instanceof ParserPool)) 996 { 997 String err = "The specified class for ParserPool (" 998 + pp + ") does not implement " + ParserPool.class 999 + " Velocity not initialized correctly."; 1000 1001 log.error(err); 1002 throw new Exception(err); 1003 } 1004 1005 parserPool = (ParserPool) o; 1006 1007 parserPool.initialize(this); 1008 } 1009 else 1010 { 1011 /* 1012 * someone screwed up. Lets not fool around... 1013 */ 1014 1015 String err = "It appears that no class was specified as the" 1016 + " ParserPool. Please ensure that all configuration" 1017 + " information is correct."; 1018 1019 log.error(err); 1020 throw new Exception( err ); 1021 } 1022 1023 } 1024 1025 /** 1026 * Returns a JavaCC generated Parser. 1027 * 1028 * @return Parser javacc generated parser 1029 */ 1030 public Parser createNewParser() 1031 { 1032 requireInitialization(); 1033 1034 Parser parser = new Parser(this); 1035 parser.setDirectives(runtimeDirectives); 1036 return parser; 1037 } 1038 1039 /** 1040 * Parse the input and return the root of 1041 * AST node structure. 1042 * <br><br> 1043 * In the event that it runs out of parsers in the 1044 * pool, it will create and let them be GC'd 1045 * dynamically, logging that it has to do that. This 1046 * is considered an exceptional condition. It is 1047 * expected that the user will set the 1048 * PARSER_POOL_SIZE property appropriately for their 1049 * application. We will revisit this. 1050 * 1051 * @param string String to be parsed 1052 * @param templateName name of the template being parsed 1053 * @return A root node representing the template as an AST tree. 1054 * @throws ParseException When the string could not be parsed as a template. 1055 * @since 1.6 1056 */ 1057 public SimpleNode parse(String string, String templateName) 1058 throws ParseException 1059 { 1060 return parse(new StringReader(string), templateName); 1061 } 1062 1063 /** 1064 * Parse the input and return the root of 1065 * AST node structure. 1066 * <br><br> 1067 * In the event that it runs out of parsers in the 1068 * pool, it will create and let them be GC'd 1069 * dynamically, logging that it has to do that. This 1070 * is considered an exceptional condition. It is 1071 * expected that the user will set the 1072 * PARSER_POOL_SIZE property appropriately for their 1073 * application. We will revisit this. 1074 * 1075 * @param reader Reader retrieved by a resource loader 1076 * @param templateName name of the template being parsed 1077 * @return A root node representing the template as an AST tree. 1078 * @throws ParseException When the template could not be parsed. 1079 */ 1080 public SimpleNode parse(Reader reader, String templateName) 1081 throws ParseException 1082 { 1083 /* 1084 * do it and dump the VM namespace for this template 1085 */ 1086 return parse(reader, templateName, true); 1087 } 1088 1089 /** 1090 * Parse the input and return the root of the AST node structure. 1091 * 1092 * @param reader Reader retrieved by a resource loader 1093 * @param templateName name of the template being parsed 1094 * @param dumpNamespace flag to dump the Velocimacro namespace for this template 1095 * @return A root node representing the template as an AST tree. 1096 * @throws ParseException When the template could not be parsed. 1097 */ 1098 public SimpleNode parse(Reader reader, String templateName, boolean dumpNamespace) 1099 throws ParseException 1100 { 1101 requireInitialization(); 1102 1103 Parser parser = (Parser) parserPool.get(); 1104 boolean keepParser = true; 1105 if (parser == null) 1106 { 1107 /* 1108 * if we couldn't get a parser from the pool make one and log it. 1109 */ 1110 if (log.isInfoEnabled()) 1111 { 1112 log.info("Runtime : ran out of parsers. Creating a new one. " 1113 + " Please increment the parser.pool.size property." 1114 + " The current value is too small."); 1115 } 1116 parser = createNewParser(); 1117 keepParser = false; 1118 } 1119 1120 try 1121 { 1122 /* 1123 * dump namespace if we are told to. Generally, you want to 1124 * do this - you don't in special circumstances, such as 1125 * when a VM is getting init()-ed & parsed 1126 */ 1127 if (dumpNamespace) 1128 { 1129 dumpVMNamespace(templateName); 1130 } 1131 return parser.parse(reader, templateName); 1132 } 1133 finally 1134 { 1135 if (keepParser) 1136 { 1137 parserPool.put(parser); 1138 } 1139 1140 } 1141 } 1142 1143 /** 1144 * Renders the input string using the context into the output writer. 1145 * To be used when a template is dynamically constructed, or want to use 1146 * Velocity as a token replacer. 1147 * 1148 * @param context context to use in rendering input string 1149 * @param out Writer in which to render the output 1150 * @param logTag string to be used as the template name for log 1151 * messages in case of error 1152 * @param instring input string containing the VTL to be rendered 1153 * 1154 * @return true if successful, false otherwise. If false, see 1155 * Velocity runtime log 1156 * @throws ParseErrorException The template could not be parsed. 1157 * @throws MethodInvocationException A method on a context object could not be invoked. 1158 * @throws ResourceNotFoundException A referenced resource could not be loaded. 1159 * @throws IOException While rendering to the writer, an I/O problem occured. 1160 * @since Velocity 1.6 1161 */ 1162 public boolean evaluate(Context context, Writer out, 1163 String logTag, String instring) throws IOException 1164 { 1165 return evaluate(context, out, logTag, new StringReader(instring)); 1166 } 1167 1168 /** 1169 * Renders the input reader using the context into the output writer. 1170 * To be used when a template is dynamically constructed, or want to 1171 * use Velocity as a token replacer. 1172 * 1173 * @param context context to use in rendering input string 1174 * @param writer Writer in which to render the output 1175 * @param logTag string to be used as the template name for log messages 1176 * in case of error 1177 * @param reader Reader containing the VTL to be rendered 1178 * 1179 * @return true if successful, false otherwise. If false, see 1180 * Velocity runtime log 1181 * @throws ParseErrorException The template could not be parsed. 1182 * @throws MethodInvocationException A method on a context object could not be invoked. 1183 * @throws ResourceNotFoundException A referenced resource could not be loaded. 1184 * @throws IOException While reading from the reader or rendering to the writer, 1185 * an I/O problem occured. 1186 * @since Velocity 1.6 1187 */ 1188 public boolean evaluate(Context context, Writer writer, 1189 String logTag, Reader reader) throws IOException 1190 { 1191 if (logTag == null) 1192 { 1193 throw new NullPointerException("logTag (i.e. template name) cannot be null, you must provide an identifier for the content being evaluated"); 1194 } 1195 1196 SimpleNode nodeTree = null; 1197 try 1198 { 1199 nodeTree = parse(reader, logTag); 1200 } 1201 catch (ParseException pex) 1202 { 1203 throw new ParseErrorException(pex); 1204 } 1205 catch (TemplateInitException pex) 1206 { 1207 throw new ParseErrorException(pex); 1208 } 1209 1210 if (nodeTree == null) 1211 { 1212 return false; 1213 } 1214 else 1215 { 1216 return render(context, writer, logTag, nodeTree); 1217 } 1218 } 1219 1220 1221 /** 1222 * Initializes and renders the AST {@link SimpleNode} using the context 1223 * into the output writer. 1224 * 1225 * @param context context to use in rendering input string 1226 * @param writer Writer in which to render the output 1227 * @param logTag string to be used as the template name for log messages 1228 * in case of error 1229 * @param nodeTree SimpleNode which is the root of the AST to be rendered 1230 * 1231 * @return true if successful, false otherwise. If false, see 1232 * Velocity runtime log for errors 1233 * @throws ParseErrorException The template could not be parsed. 1234 * @throws MethodInvocationException A method on a context object could not be invoked. 1235 * @throws ResourceNotFoundException A referenced resource could not be loaded. 1236 * @throws IOException While rendering to the writer, an I/O problem occured. 1237 * @since Velocity 1.6 1238 */ 1239 public boolean render(Context context, Writer writer, 1240 String logTag, SimpleNode nodeTree) throws IOException 1241 { 1242 /* 1243 * we want to init then render 1244 */ 1245 InternalContextAdapterImpl ica = 1246 new InternalContextAdapterImpl(context); 1247 1248 ica.pushCurrentTemplateName(logTag); 1249 1250 try 1251 { 1252 try 1253 { 1254 nodeTree.init(ica, this); 1255 } 1256 catch (TemplateInitException pex) 1257 { 1258 throw new ParseErrorException(pex); 1259 } 1260 /** 1261 * pass through application level runtime exceptions 1262 */ 1263 catch(RuntimeException e) 1264 { 1265 throw e; 1266 } 1267 catch(Exception e) 1268 { 1269 String msg = "RuntimeInstance.render(): init exception for tag = "+logTag; 1270 getLog().error(msg, e); 1271 throw new VelocityException(msg, e); 1272 } 1273 1274 /* 1275 * now render, and let any exceptions fly 1276 */ 1277 nodeTree.render(ica, writer); 1278 } 1279 finally 1280 { 1281 ica.popCurrentTemplateName(); 1282 } 1283 1284 return true; 1285 } 1286 1287 /** 1288 * Invokes a currently registered Velocimacro with the params provided 1289 * and places the rendered stream into the writer. 1290 * <br> 1291 * Note : currently only accepts args to the VM if they are in the context. 1292 * 1293 * @param vmName name of Velocimacro to call 1294 * @param logTag string to be used for template name in case of error. if null, 1295 * the vmName will be used 1296 * @param params keys for args used to invoke Velocimacro, in java format 1297 * rather than VTL (eg "foo" or "bar" rather than "$foo" or "$bar") 1298 * @param context Context object containing data/objects used for rendering. 1299 * @param writer Writer for output stream 1300 * @return true if Velocimacro exists and successfully invoked, false otherwise. 1301 * @throws IOException While rendering to the writer, an I/O problem occured. 1302 * @since 1.6 1303 */ 1304 public boolean invokeVelocimacro(final String vmName, String logTag, 1305 String[] params, final Context context, 1306 final Writer writer) 1307 throws IOException 1308 { 1309 /* check necessary parameters */ 1310 if (vmName == null || context == null || writer == null) 1311 { 1312 String msg = "RuntimeInstance.invokeVelocimacro() : invalid call : vmName, context, and writer must not be null"; 1313 getLog().error(msg); 1314 throw new NullPointerException(msg); 1315 } 1316 1317 /* handle easily corrected parameters */ 1318 if (logTag == null) 1319 { 1320 logTag = vmName; 1321 } 1322 if (params == null) 1323 { 1324 params = new String[0]; 1325 } 1326 1327 /* does the VM exist? */ 1328 if (!isVelocimacro(vmName, logTag)) 1329 { 1330 String msg = "RuntimeInstance.invokeVelocimacro() : VM '" + vmName 1331 + "' is not registered."; 1332 getLog().error(msg); 1333 throw new VelocityException(msg); 1334 } 1335 1336 /* now just create the VM call, and use evaluate */ 1337 StrBuilder template = new StrBuilder("#"); 1338 template.append(vmName); 1339 template.append("("); 1340 for( int i = 0; i < params.length; i++) 1341 { 1342 template.append(" $"); 1343 template.append(params[i]); 1344 } 1345 template.append(" )"); 1346 1347 return evaluate(context, writer, logTag, template.toString()); 1348 } 1349 1350 /** 1351 * Retrieves and caches the configured default encoding 1352 * for better performance. (VELOCITY-606) 1353 */ 1354 private String getDefaultEncoding() 1355 { 1356 if (encoding == null) 1357 { 1358 encoding = getString(INPUT_ENCODING, ENCODING_DEFAULT); 1359 } 1360 return encoding; 1361 } 1362 1363 /** 1364 * Returns a <code>Template</code> from the resource manager. 1365 * This method assumes that the character encoding of the 1366 * template is set by the <code>input.encoding</code> 1367 * property. The default is "ISO-8859-1" 1368 * 1369 * @param name The file name of the desired template. 1370 * @return The template. 1371 * @throws ResourceNotFoundException if template not found 1372 * from any available source. 1373 * @throws ParseErrorException if template cannot be parsed due 1374 * to syntax (or other) error. 1375 * @throws Exception if an error occurs in template initialization 1376 */ 1377 public Template getTemplate(String name) 1378 throws ResourceNotFoundException, ParseErrorException, Exception 1379 { 1380 return getTemplate(name, getDefaultEncoding()); 1381 } 1382 1383 /** 1384 * Returns a <code>Template</code> from the resource manager 1385 * 1386 * @param name The name of the desired template. 1387 * @param encoding Character encoding of the template 1388 * @return The template. 1389 * @throws ResourceNotFoundException if template not found 1390 * from any available source. 1391 * @throws ParseErrorException if template cannot be parsed due 1392 * to syntax (or other) error. 1393 * @throws Exception if an error occurs in template initialization 1394 */ 1395 public Template getTemplate(String name, String encoding) 1396 throws ResourceNotFoundException, ParseErrorException, Exception 1397 { 1398 requireInitialization(); 1399 1400 return (Template) 1401 resourceManager.getResource(name, 1402 ResourceManager.RESOURCE_TEMPLATE, encoding); 1403 } 1404 1405 /** 1406 * Returns a static content resource from the 1407 * resource manager. Uses the current value 1408 * if INPUT_ENCODING as the character encoding. 1409 * 1410 * @param name Name of content resource to get 1411 * @return parsed ContentResource object ready for use 1412 * @throws ResourceNotFoundException if template not found 1413 * from any available source. 1414 * @throws ParseErrorException When the template could not be parsed. 1415 * @throws Exception Any other error. 1416 */ 1417 public ContentResource getContent(String name) 1418 throws ResourceNotFoundException, ParseErrorException, Exception 1419 { 1420 /* 1421 * the encoding is irrelvant as we don't do any converstion 1422 * the bytestream should be dumped to the output stream 1423 */ 1424 1425 return getContent(name, getDefaultEncoding()); 1426 } 1427 1428 /** 1429 * Returns a static content resource from the 1430 * resource manager. 1431 * 1432 * @param name Name of content resource to get 1433 * @param encoding Character encoding to use 1434 * @return parsed ContentResource object ready for use 1435 * @throws ResourceNotFoundException if template not found 1436 * from any available source. 1437 * @throws ParseErrorException When the template could not be parsed. 1438 * @throws Exception Any other error. 1439 */ 1440 public ContentResource getContent(String name, String encoding) 1441 throws ResourceNotFoundException, ParseErrorException, Exception 1442 { 1443 requireInitialization(); 1444 1445 return (ContentResource) 1446 resourceManager.getResource(name, 1447 ResourceManager.RESOURCE_CONTENT, encoding); 1448 } 1449 1450 1451 /** 1452 * Determines if a template exists and returns name of the loader that 1453 * provides it. This is a slightly less hokey way to support 1454 * the Velocity.resourceExists() utility method, which was broken 1455 * when per-template encoding was introduced. We can revisit this. 1456 * 1457 * @param resourceName Name of template or content resource 1458 * @return class name of loader than can provide it 1459 */ 1460 public String getLoaderNameForResource(String resourceName) 1461 { 1462 requireInitialization(); 1463 1464 return resourceManager.getLoaderNameForResource(resourceName); 1465 } 1466 1467 /** 1468 * Returns a convenient Log instance that wraps the current LogChute. 1469 * Use this to log error messages. It has the usual methods. 1470 * 1471 * @return A convenience Log instance that wraps the current LogChute. 1472 * @since 1.5 1473 */ 1474 public Log getLog() 1475 { 1476 return log; 1477 } 1478 1479 /** 1480 * @deprecated Use getLog() and call warn() on it. 1481 * @see Log#warn(Object) 1482 * @param message The message to log. 1483 */ 1484 public void warn(Object message) 1485 { 1486 getLog().warn(message); 1487 } 1488 1489 /** 1490 * @deprecated Use getLog() and call info() on it. 1491 * @see Log#info(Object) 1492 * @param message The message to log. 1493 */ 1494 public void info(Object message) 1495 { 1496 getLog().info(message); 1497 } 1498 1499 /** 1500 * @deprecated Use getLog() and call error() on it. 1501 * @see Log#error(Object) 1502 * @param message The message to log. 1503 */ 1504 public void error(Object message) 1505 { 1506 getLog().error(message); 1507 } 1508 1509 /** 1510 * @deprecated Use getLog() and call debug() on it. 1511 * @see Log#debug(Object) 1512 * @param message The message to log. 1513 */ 1514 public void debug(Object message) 1515 { 1516 getLog().debug(message); 1517 } 1518 1519 /** 1520 * String property accessor method with default to hide the 1521 * configuration implementation. 1522 * 1523 * @param key property key 1524 * @param defaultValue default value to return if key not 1525 * found in resource manager. 1526 * @return value of key or default 1527 */ 1528 public String getString( String key, String defaultValue) 1529 { 1530 return configuration.getString(key, defaultValue); 1531 } 1532 1533 /** 1534 * Returns the appropriate VelocimacroProxy object if vmName 1535 * is a valid current Velocimacro. 1536 * 1537 * @param vmName Name of velocimacro requested 1538 * @param templateName Name of the template that contains the velocimacro. 1539 * @return The requested VelocimacroProxy. 1540 * @since 1.6 1541 */ 1542 public Directive getVelocimacro(String vmName, String templateName) 1543 { 1544 return vmFactory.getVelocimacro( vmName, templateName ); 1545 } 1546 1547 /** 1548 * Returns the appropriate VelocimacroProxy object if vmName 1549 * is a valid current Velocimacro. 1550 * 1551 * @param vmName Name of velocimacro requested 1552 * @param templateName Name of the namespace. 1553 * @param renderingTemplate Name of the template we are currently rendering. This 1554 * information is needed when VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL setting is true 1555 * and template contains a macro with the same name as the global macro library. 1556 * 1557 * @since Velocity 1.6 1558 * 1559 * @return VelocimacroProxy 1560 */ 1561 public Directive getVelocimacro(String vmName, String templateName, String renderingTemplate) 1562 { 1563 return vmFactory.getVelocimacro( vmName, templateName, renderingTemplate ); 1564 } 1565 1566 1567 /** 1568 * Adds a new Velocimacro. Usually called by Macro only while parsing. 1569 * 1570 * @param name Name of velocimacro 1571 * @param macro String form of macro body 1572 * @param argArray Array of strings, containing the 1573 * #macro() arguments. the 0th is the name. 1574 * @param sourceTemplate Name of the template that contains the velocimacro. 1575 * 1576 * @deprecated Use addVelocimacro(String, Node, String[], String) instead 1577 * 1578 * @return True if added, false if rejected for some 1579 * reason (either parameters or permission settings) 1580 */ 1581 public boolean addVelocimacro( String name, 1582 String macro, 1583 String argArray[], 1584 String sourceTemplate ) 1585 { 1586 return vmFactory.addVelocimacro(name, macro, argArray, sourceTemplate); 1587 } 1588 1589 /** 1590 * Adds a new Velocimacro. Usually called by Macro only while parsing. 1591 * 1592 * Called by org.apache.velocity.runtime.directive.processAndRegister 1593 * 1594 * @param name Name of velocimacro 1595 * @param macro root AST node of the parsed macro 1596 * @param argArray Array of strings, containing the 1597 * #macro() arguments. the 0th is the name. 1598 * @param sourceTemplate 1599 * 1600 * @since Velocity 1.6 1601 * 1602 * @return boolean True if added, false if rejected for some 1603 * reason (either parameters or permission settings) 1604 */ 1605 public boolean addVelocimacro( String name, 1606 Node macro, 1607 String argArray[], 1608 String sourceTemplate ) 1609 { 1610 return vmFactory.addVelocimacro(name, macro, argArray, sourceTemplate); 1611 } 1612 1613 1614 /** 1615 * Checks to see if a VM exists 1616 * 1617 * @param vmName Name of the Velocimacro. 1618 * @param templateName Template on which to look for the Macro. 1619 * @return True if VM by that name exists, false if not 1620 */ 1621 public boolean isVelocimacro( String vmName, String templateName ) 1622 { 1623 return vmFactory.isVelocimacro(vmName, templateName); 1624 } 1625 1626 /** 1627 * tells the vmFactory to dump the specified namespace. This is to support 1628 * clearing the VM list when in inline-VM-local-scope mode 1629 * @param namespace Namespace to dump. 1630 * @return True if namespace was dumped successfully. 1631 */ 1632 public boolean dumpVMNamespace(String namespace) 1633 { 1634 return vmFactory.dumpVMNamespace( namespace ); 1635 } 1636 1637 /* -------------------------------------------------------------------- 1638 * R U N T I M E A C C E S S O R M E T H O D S 1639 * -------------------------------------------------------------------- 1640 * These are the getXXX() methods that are a simple wrapper 1641 * around the configuration object. This is an attempt 1642 * to make a the Velocity Runtime the single access point 1643 * for all things Velocity, and allow the Runtime to 1644 * adhere as closely as possible the the Mediator pattern 1645 * which is the ultimate goal. 1646 * -------------------------------------------------------------------- 1647 */ 1648 1649 /** 1650 * String property accessor method to hide the configuration implementation 1651 * @param key property key 1652 * @return value of key or null 1653 */ 1654 public String getString(String key) 1655 { 1656 return StringUtils.nullTrim(configuration.getString(key)); 1657 } 1658 1659 /** 1660 * Int property accessor method to hide the configuration implementation. 1661 * 1662 * @param key Property key 1663 * @return value 1664 */ 1665 public int getInt(String key) 1666 { 1667 return configuration.getInt(key); 1668 } 1669 1670 /** 1671 * Int property accessor method to hide the configuration implementation. 1672 * 1673 * @param key property key 1674 * @param defaultValue The default value. 1675 * @return value 1676 */ 1677 public int getInt(String key, int defaultValue) 1678 { 1679 return configuration.getInt(key, defaultValue); 1680 } 1681 1682 /** 1683 * Boolean property accessor method to hide the configuration implementation. 1684 * 1685 * @param key property key 1686 * @param def The default value if property not found. 1687 * @return value of key or default value 1688 */ 1689 public boolean getBoolean(String key, boolean def) 1690 { 1691 return configuration.getBoolean(key, def); 1692 } 1693 1694 /** 1695 * Return the velocity runtime configuration object. 1696 * 1697 * @return Configuration object which houses the Velocity runtime 1698 * properties. 1699 */ 1700 public ExtendedProperties getConfiguration() 1701 { 1702 return configuration; 1703 } 1704 1705 /** 1706 * Return the Introspector for this instance 1707 * @return The Introspector for this instance 1708 */ 1709 public Introspector getIntrospector() 1710 { 1711 return introspector; 1712 } 1713 1714 /** 1715 * Returns the event handlers for the application. 1716 * @return The event handlers for the application. 1717 * @since 1.5 1718 */ 1719 public EventCartridge getApplicationEventCartridge() 1720 { 1721 return eventCartridge; 1722 } 1723 1724 1725 /** 1726 * Gets the application attribute for the given key 1727 * 1728 * @param key 1729 * @return The application attribute for the given key. 1730 */ 1731 public Object getApplicationAttribute(Object key) 1732 { 1733 return applicationAttributes.get(key); 1734 } 1735 1736 /** 1737 * Sets the application attribute for the given key 1738 * 1739 * @param key 1740 * @param o The new application attribute. 1741 * @return The old value of this attribute or null if it hasn't been set before. 1742 */ 1743 public Object setApplicationAttribute(Object key, Object o) 1744 { 1745 return applicationAttributes.put(key, o); 1746 } 1747 1748 /** 1749 * Returns the Uberspect object for this Instance. 1750 * 1751 * @return The Uberspect object for this Instance. 1752 */ 1753 public Uberspect getUberspect() 1754 { 1755 return uberSpect; 1756 } 1757 1758 }