1 package org.apache.velocity.app; 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.BufferedReader; 23 import java.io.IOException; 24 import java.io.InputStream; 25 import java.io.InputStreamReader; 26 import java.io.Reader; 27 import java.io.UnsupportedEncodingException; 28 import java.io.Writer; 29 import java.util.Properties; 30 31 import org.apache.commons.collections.ExtendedProperties; 32 import org.apache.velocity.Template; 33 import org.apache.velocity.context.Context; 34 import org.apache.velocity.exception.MethodInvocationException; 35 import org.apache.velocity.exception.ParseErrorException; 36 import org.apache.velocity.exception.ResourceNotFoundException; 37 import org.apache.velocity.runtime.RuntimeConstants; 38 import org.apache.velocity.runtime.RuntimeInstance; 39 import org.apache.velocity.runtime.log.Log; 40 41 /** 42 * <p> 43 * This class provides a separate new-able instance of the 44 * Velocity template engine. The alternative model for use 45 * is using the Velocity class which employs the singleton 46 * model. 47 * </p> 48 * <p>Velocity will call 49 * the parameter-less init() at the first use of this class 50 * if the init() wasn't explicitly called. While this will 51 * ensure that Velocity functions, it probably won't 52 * function in the way you intend, so it is strongly recommended that 53 * you call an init() method yourself if you use the default constructor. 54 * </p> 55 * 56 * @version $Id: VelocityEngine.java 687177 2008-08-19 22:00:32Z nbubna $ 57 */ 58 public class VelocityEngine implements RuntimeConstants 59 { 60 private RuntimeInstance ri = new RuntimeInstance(); 61 62 63 /** 64 * Init-less CTOR 65 */ 66 public VelocityEngine() 67 { 68 // do nothing 69 } 70 71 /** 72 * CTOR that invokes an init(String), initializing 73 * the engine using the properties file specified 74 * 75 * @param propsFilename name of properties file to init with 76 * @throws Exception 77 * @since 1.5 78 */ 79 public VelocityEngine(String propsFilename) 80 throws Exception 81 { 82 ri.init(propsFilename); 83 } 84 85 /** 86 * CTOR that invokes an init(String), initializing 87 * the engine using the Properties specified 88 * 89 * @param p name of properties to init with 90 * @throws Exception 91 * @since 1.5 92 */ 93 public VelocityEngine(Properties p) 94 throws Exception 95 { 96 ri.init(p); 97 } 98 99 /** 100 * initialize the Velocity runtime engine, using the default 101 * properties of the Velocity distribution 102 * @throws Exception 103 */ 104 public void init() 105 throws Exception 106 { 107 ri.init(); 108 } 109 110 /** 111 * initialize the Velocity runtime engine, using default properties 112 * plus the properties in the properties file passed in as the arg 113 * 114 * @param propsFilename file containing properties to use to initialize 115 * the Velocity runtime 116 * @throws Exception 117 */ 118 public void init(String propsFilename) 119 throws Exception 120 { 121 ri.init(propsFilename); 122 } 123 124 /** 125 * initialize the Velocity runtime engine, using default properties 126 * plus the properties in the passed in java.util.Properties object 127 * 128 * @param p Proprties object containing initialization properties 129 * @throws Exception 130 * 131 */ 132 public void init(Properties p) 133 throws Exception 134 { 135 ri.init(p); 136 } 137 138 /** 139 * Set a Velocity Runtime property. 140 * 141 * @param key 142 * @param value 143 */ 144 public void setProperty(String key, Object value) 145 { 146 ri.setProperty(key,value); 147 } 148 149 /** 150 * Add a Velocity Runtime property. 151 * 152 * @param key 153 * @param value 154 */ 155 public void addProperty(String key, Object value) 156 { 157 ri.addProperty(key,value); 158 } 159 160 /** 161 * Clear a Velocity Runtime property. 162 * 163 * @param key of property to clear 164 */ 165 public void clearProperty(String key) 166 { 167 ri.clearProperty(key); 168 } 169 170 /** 171 * Set an entire configuration at once. This is 172 * useful in cases where the parent application uses 173 * the ExtendedProperties class and the velocity configuration 174 * is a subset of the parent application's configuration. 175 * 176 * @param configuration 177 * 178 */ 179 public void setExtendedProperties( ExtendedProperties configuration) 180 { 181 ri.setConfiguration( configuration ); 182 } 183 184 /** 185 * Get a Velocity Runtime property. 186 * 187 * @param key property to retrieve 188 * @return property value or null if the property 189 * not currently set 190 */ 191 public Object getProperty( String key ) 192 { 193 return ri.getProperty( key ); 194 } 195 196 /** 197 * renders the input string using the context into the output writer. 198 * To be used when a template is dynamically constructed, or want to use 199 * Velocity as a token replacer. 200 * 201 * @param context context to use in rendering input string 202 * @param out Writer in which to render the output 203 * @param logTag string to be used as the template name for log 204 * messages in case of error 205 * @param instring input string containing the VTL to be rendered 206 * 207 * @return true if successful, false otherwise. If false, see 208 * Velocity runtime log 209 * @throws ParseErrorException The template could not be parsed. 210 * @throws MethodInvocationException A method on a context object could not be invoked. 211 * @throws ResourceNotFoundException A referenced resource could not be loaded. 212 * @throws IOException While rendering to the writer, an I/O problem occured. 213 */ 214 public boolean evaluate( Context context, Writer out, 215 String logTag, String instring ) 216 throws ParseErrorException, MethodInvocationException, 217 ResourceNotFoundException, IOException 218 { 219 return ri.evaluate(context, out, logTag, instring); 220 } 221 222 /** 223 * Renders the input stream using the context into the output writer. 224 * To be used when a template is dynamically constructed, or want to 225 * use Velocity as a token replacer. 226 * 227 * @param context context to use in rendering input string 228 * @param writer Writer in which to render the output 229 * @param logTag string to be used as the template name for log messages 230 * in case of error 231 * @param instream input stream containing the VTL to be rendered 232 * 233 * @return true if successful, false otherwise. If false, see 234 * Velocity runtime log 235 * @throws ParseErrorException 236 * @throws MethodInvocationException 237 * @throws ResourceNotFoundException 238 * @throws IOException 239 * @deprecated Use 240 * {@link #evaluate( Context context, Writer writer, 241 * String logTag, Reader reader ) } 242 */ 243 public boolean evaluate( Context context, Writer writer, 244 String logTag, InputStream instream ) 245 throws ParseErrorException, MethodInvocationException, 246 ResourceNotFoundException, IOException 247 { 248 /* 249 * first, parse - convert ParseException if thrown 250 */ 251 BufferedReader br = null; 252 String encoding = null; 253 254 try 255 { 256 encoding = ri.getString(INPUT_ENCODING,ENCODING_DEFAULT); 257 br = new BufferedReader( new InputStreamReader( instream, encoding)); 258 } 259 catch( UnsupportedEncodingException uce ) 260 { 261 String msg = "Unsupported input encoding : " + encoding 262 + " for template " + logTag; 263 throw new ParseErrorException( msg ); 264 } 265 266 return evaluate( context, writer, logTag, br ); 267 } 268 269 /** 270 * Renders the input reader using the context into the output writer. 271 * To be used when a template is dynamically constructed, or want to 272 * use Velocity as a token replacer. 273 * 274 * @param context context to use in rendering input string 275 * @param writer Writer in which to render the output 276 * @param logTag string to be used as the template name for log messages 277 * in case of error 278 * @param reader Reader containing the VTL to be rendered 279 * 280 * @return true if successful, false otherwise. If false, see 281 * Velocity runtime log 282 * @throws ParseErrorException The template could not be parsed. 283 * @throws MethodInvocationException A method on a context object could not be invoked. 284 * @throws ResourceNotFoundException A referenced resource could not be loaded. 285 * @throws IOException While reading from the reader or rendering to the writer, 286 * an I/O problem occured. 287 * @since Velocity v1.1 288 */ 289 public boolean evaluate(Context context, Writer writer, 290 String logTag, Reader reader) 291 throws ParseErrorException, MethodInvocationException, 292 ResourceNotFoundException,IOException 293 { 294 return ri.evaluate(context, writer, logTag, reader); 295 } 296 297 298 /** 299 * Invokes a currently registered Velocimacro with the params provided 300 * and places the rendered stream into the writer. 301 * <br> 302 * Note : currently only accepts args to the VM if they are in the context. 303 * 304 * @param vmName name of Velocimacro to call 305 * @param logTag string to be used for template name in case of error. if null, 306 * the vmName will be used 307 * @param params keys for args used to invoke Velocimacro, in java format 308 * rather than VTL (eg "foo" or "bar" rather than "$foo" or "$bar") 309 * @param context Context object containing data/objects used for rendering. 310 * @param writer Writer for output stream 311 * @return true if Velocimacro exists and successfully invoked, false otherwise. 312 * @throws IOException While rendering to the writer, an I/O problem occured. 313 */ 314 public boolean invokeVelocimacro( String vmName, String logTag, 315 String params[], Context context, 316 Writer writer ) 317 throws Exception 318 { 319 return ri.invokeVelocimacro(vmName, logTag, params, context, writer); 320 } 321 322 /** 323 * Merges a template and puts the rendered stream into the writer. 324 * The default encoding that Velocity uses to read template files is defined in 325 * the property input.encoding and defaults to ISO-8859-1. 326 * 327 * @param templateName name of template to be used in merge 328 * @param context filled context to be used in merge 329 * @param writer writer to write template into 330 * 331 * @return true if successful, false otherwise. Errors 332 * logged to velocity log. 333 * @throws ResourceNotFoundException 334 * @throws ParseErrorException 335 * @throws MethodInvocationException 336 * @throws Exception 337 * @deprecated Use 338 * {@link #mergeTemplate( String templateName, String encoding, 339 * Context context, Writer writer )} 340 */ 341 public boolean mergeTemplate( String templateName, 342 Context context, Writer writer ) 343 throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception 344 { 345 return mergeTemplate( templateName, ri.getString(INPUT_ENCODING,ENCODING_DEFAULT), 346 context, writer ); 347 } 348 349 /** 350 * merges a template and puts the rendered stream into the writer 351 * 352 * @param templateName name of template to be used in merge 353 * @param encoding encoding used in template 354 * @param context filled context to be used in merge 355 * @param writer writer to write template into 356 * 357 * @return true if successful, false otherwise. Errors 358 * logged to velocity log 359 * @throws ResourceNotFoundException 360 * @throws ParseErrorException 361 * @throws MethodInvocationException 362 * @throws Exception 363 * 364 * @since Velocity v1.1 365 */ 366 public boolean mergeTemplate( String templateName, String encoding, 367 Context context, Writer writer ) 368 throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception 369 { 370 Template template = ri.getTemplate(templateName, encoding); 371 372 if ( template == null ) 373 { 374 String msg = "VelocityEngine.mergeTemplate() was unable to load template '" 375 + templateName + "'"; 376 getLog().error(msg); 377 throw new ResourceNotFoundException(msg); 378 } 379 else 380 { 381 template.merge(context, writer); 382 return true; 383 } 384 } 385 386 /** 387 * Returns a <code>Template</code> from the Velocity 388 * resource management system. 389 * 390 * @param name The file name of the desired template. 391 * @return The template. 392 * @throws ResourceNotFoundException if template not found 393 * from any available source. 394 * @throws ParseErrorException if template cannot be parsed due 395 * to syntax (or other) error. 396 * @throws Exception if an error occurs in template initialization 397 */ 398 public Template getTemplate(String name) 399 throws ResourceNotFoundException, ParseErrorException, Exception 400 { 401 return ri.getTemplate( name ); 402 } 403 404 /** 405 * Returns a <code>Template</code> from the Velocity 406 * resource management system. 407 * 408 * @param name The file name of the desired template. 409 * @param encoding The character encoding to use for the template. 410 * @return The template. 411 * @throws ResourceNotFoundException if template not found 412 * from any available source. 413 * @throws ParseErrorException if template cannot be parsed due 414 * to syntax (or other) error. 415 * @throws Exception if an error occurs in template initialization 416 * 417 * @since Velocity v1.1 418 */ 419 public Template getTemplate(String name, String encoding) 420 throws ResourceNotFoundException, ParseErrorException, Exception 421 { 422 return ri.getTemplate( name, encoding ); 423 } 424 425 /** 426 * Determines if a resource is accessable via the currently 427 * configured resource loaders. 428 * <br><br> 429 * Note that the current implementation will <b>not</b> 430 * change the state of the system in any real way - so this 431 * cannot be used to pre-load the resource cache, as the 432 * previous implementation did as a side-effect. 433 * <br><br> 434 * The previous implementation exhibited extreme lazyness and 435 * sloth, and the author has been flogged. 436 * 437 * @param resourceName name of the resource to search for 438 * @return true if found, false otherwise 439 * @since 1.5 440 */ 441 public boolean resourceExists(String resourceName) 442 { 443 return (ri.getLoaderNameForResource(resourceName) != null); 444 } 445 446 /** 447 * @param resourceName 448 * @return True if the template exists. 449 * @see #resourceExists(String) 450 * @deprecated Use resourceExists(String) instead. 451 */ 452 public boolean templateExists(String resourceName) 453 { 454 return resourceExists(resourceName); 455 } 456 457 458 /** 459 * Returns a convenient Log instance that wraps the current LogChute. 460 * Use this to log error messages. It has the usual methods you'd expect. 461 * @return A log object. 462 * @since 1.5 463 */ 464 public Log getLog() 465 { 466 return ri.getLog(); 467 } 468 469 /** 470 * @param message 471 * @deprecated Use getLog() and call warn() on it. 472 */ 473 public void warn(Object message) 474 { 475 getLog().warn(message); 476 } 477 478 /** 479 * @param message 480 * @deprecated Use getLog() and call warn() on it. 481 */ 482 public void info(Object message) 483 { 484 getLog().info(message); 485 } 486 487 /** 488 * @param message 489 * @deprecated Use getLog() and call warn() on it. 490 */ 491 public void error(Object message) 492 { 493 getLog().error(message); 494 } 495 496 /** 497 * @param message 498 * @deprecated Use getLog() and call warn() on it. 499 */ 500 public void debug(Object message) 501 { 502 getLog().debug(message); 503 } 504 505 /** 506 * <p> 507 * Sets an application attribute (which can be any Object) that will be 508 * accessible from any component of the system that gets a 509 * RuntimeServices. This allows communication between the application 510 * environment and custom pluggable components of the Velocity engine, 511 * such as ResourceLoaders and LogChutes. 512 * </p> 513 * 514 * <p> 515 * Note that there is no enforcement or rules for the key 516 * used - it is up to the application developer. However, to 517 * help make the intermixing of components possible, using 518 * the target Class name (e.g. com.foo.bar ) as the key 519 * might help avoid collision. 520 * </p> 521 * 522 * @param key object 'name' under which the object is stored 523 * @param value object to store under this key 524 */ 525 public void setApplicationAttribute( Object key, Object value ) 526 { 527 ri.setApplicationAttribute(key, value); 528 } 529 530 /** 531 * <p> 532 * Return an application attribute (which can be any Object) 533 * that was set by the application in order to be accessible from 534 * any component of the system that gets a RuntimeServices. 535 * This allows communication between the application 536 * environment and custom pluggable components of the 537 * Velocity engine, such as ResourceLoaders and LogChutes. 538 * </p> 539 * 540 * @param key object 'name' under which the object is stored 541 * @return value object to store under this key 542 * @since 1.5 543 */ 544 public Object getApplicationAttribute( Object key ) 545 { 546 return ri.getApplicationAttribute(key); 547 } 548 549 }