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 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 }