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