View Javadoc

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 }