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.StringReader;
28  import java.io.UnsupportedEncodingException;
29  import java.io.Writer;
30  import java.util.Properties;
31  
32  import org.apache.commons.collections.ExtendedProperties;
33  import org.apache.velocity.Template;
34  import org.apache.velocity.context.Context;
35  import org.apache.velocity.context.InternalContextAdapterImpl;
36  import org.apache.velocity.exception.MethodInvocationException;
37  import org.apache.velocity.exception.ParseErrorException;
38  import org.apache.velocity.exception.ResourceNotFoundException;
39  import org.apache.velocity.exception.TemplateInitException;
40  import org.apache.velocity.runtime.RuntimeConstants;
41  import org.apache.velocity.runtime.RuntimeSingleton;
42  import org.apache.velocity.runtime.log.Log;
43  import org.apache.velocity.runtime.parser.ParseException;
44  import org.apache.velocity.runtime.parser.node.SimpleNode;
45  
46  /**
47   * This class provides  services to the application
48   * developer, such as :
49   * <ul>
50   * <li> Simple Velocity Runtime engine initialization methods.
51   * <li> Functions to apply the template engine to streams and strings
52   *      to allow embedding and dynamic template generation.
53   * <li> Methods to access Velocimacros directly.
54   * </ul>
55   *
56   * <br><br>
57   * While the most common way to use Velocity is via templates, as
58   * Velocity is a general-purpose template engine, there are other
59   * uses that Velocity is well suited for, such as processing dynamically
60   * created templates, or processing content streams.
61   *
62   * <br><br>
63   * The methods herein were developed to allow easy access to the Velocity
64   * facilities without direct spelunking of the internals.  If there is
65   * something you feel is necessary to add here, please, send a patch.
66   *
67   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
68   * @author <a href="mailto:Christoph.Reck@dlr.de">Christoph Reck</a>
69   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
70   * @version $Id: Velocity.java 471381 2006-11-05 08:56:58Z wglass $
71   */
72  public class Velocity implements RuntimeConstants
73  {
74      /**
75       *  initialize the Velocity runtime engine, using the default
76       *  properties of the Velocity distribution
77       *
78       * @throws Exception When an error during initialization occurs.
79       */
80      public static void init()
81          throws Exception
82      {
83          RuntimeSingleton.init();
84      }
85  
86      /**
87       *  initialize the Velocity runtime engine, using default properties
88       *  plus the properties in the properties file passed in as the arg
89       *
90       *  @param propsFilename file containing properties to use to initialize
91       *         the Velocity runtime
92       * @throws Exception When an error during initialization occurs.
93       */
94      public static void init( String propsFilename )
95          throws Exception
96      {
97          RuntimeSingleton.init(propsFilename);
98      }
99  
100     /**
101      *  initialize the Velocity runtime engine, using default properties
102      *  plus the properties in the passed in java.util.Properties object
103      *
104      *  @param p  Properties object containing initialization properties
105      * @throws Exception When an error during initialization occurs.
106      *
107      */
108     public static void init( Properties p )
109         throws Exception
110     {
111         RuntimeSingleton.init( p );
112     }
113 
114     /**
115      * Set a Velocity Runtime property.
116      *
117      * @param key The property key.
118      * @param value The property value.
119      */
120     public static void setProperty(String key, Object value)
121     {
122         RuntimeSingleton.setProperty(key,value);
123     }
124 
125     /**
126      * Add a Velocity Runtime property.
127      *
128      * @param key The property key.
129      * @param value The property value.
130      */
131     public static void addProperty(String key, Object value)
132     {
133         RuntimeSingleton.addProperty(key,value);
134     }
135 
136     /**
137      * Clear a Velocity Runtime property.
138      *
139      * @param key of property to clear
140      */
141     public static void clearProperty(String key)
142     {
143         RuntimeSingleton.clearProperty(key);
144     }
145 
146     /**
147      * Set an entire configuration at once. This is
148      * useful in cases where the parent application uses
149      * the ExtendedProperties class and the velocity configuration
150      * is a subset of the parent application's configuration.
151      *
152      * @param configuration A configuration object.
153      *
154      */
155     public static void setExtendedProperties( ExtendedProperties configuration)
156     {
157         RuntimeSingleton.setConfiguration( configuration );
158     }
159 
160     /**
161      *  Get a Velocity Runtime property.
162      *
163      *  @param key property to retrieve
164      *  @return property value or null if the property
165      *        not currently set
166      */
167     public static Object getProperty( String key )
168     {
169         return RuntimeSingleton.getProperty( key );
170     }
171 
172     /**
173      *  renders the input string using the context into the output writer.
174      *  To be used when a template is dynamically constructed, or want to use
175      *  Velocity as a token replacer.
176      *
177      *  @param context context to use in rendering input string
178      *  @param out  Writer in which to render the output
179      *  @param logTag  string to be used as the template name for log
180      *                 messages in case of error
181      *  @param instring input string containing the VTL to be rendered
182      *
183      *  @return true if successful, false otherwise.  If false, see
184      *             Velocity runtime log
185      * @throws ParseErrorException The template could not be parsed.
186      * @throws MethodInvocationException A method on a context object could not be invoked.
187      * @throws ResourceNotFoundException A referenced resource could not be loaded.
188      * @throws IOException While loading a reference, an I/O problem occured.
189      */
190     public static  boolean evaluate( Context context,  Writer out,
191                                      String logTag, String instring )
192         throws ParseErrorException, MethodInvocationException,
193             ResourceNotFoundException, IOException
194     {
195         return evaluate( context, out, logTag, new BufferedReader( new StringReader( instring )) );
196     }
197 
198     /**
199      *  Renders the input stream using the context into the output writer.
200      *  To be used when a template is dynamically constructed, or want to
201      *  use Velocity as a token replacer.
202      *
203      *  @param context context to use in rendering input string
204      *  @param writer  Writer in which to render the output
205      *  @param logTag  string to be used as the template name for log messages
206      *                 in case of error
207      *  @param instream input stream containing the VTL to be rendered
208      *
209      *  @return true if successful, false otherwise.  If false, see
210      *               Velocity runtime log
211      *  @deprecated Use
212      *  {@link #evaluate( Context context, Writer writer,
213      *      String logTag, Reader reader ) }
214      * @throws ParseErrorException The template could not be parsed.
215      * @throws MethodInvocationException A method on a context object could not be invoked.
216      * @throws ResourceNotFoundException A referenced resource could not be loaded.
217      * @throws IOException While loading a reference, an I/O problem occured.
218      */
219     public static boolean evaluate( Context context, Writer writer,
220                                     String logTag, InputStream instream )
221         throws ParseErrorException, MethodInvocationException,
222             ResourceNotFoundException, IOException
223     {
224         /*
225          *  first, parse - convert ParseException if thrown
226          */
227         BufferedReader br  = null;
228         String encoding = null;
229 
230         try
231         {
232             encoding = RuntimeSingleton.getString(INPUT_ENCODING,ENCODING_DEFAULT);
233             br = new BufferedReader(  new InputStreamReader( instream, encoding));
234         }
235         catch( UnsupportedEncodingException  uce )
236         {
237             String msg = "Unsupported input encoding : " + encoding
238                 + " for template " + logTag;
239             throw new ParseErrorException( msg );
240         }
241 
242         return evaluate( context, writer, logTag, br );
243     }
244 
245     /**
246      *  Renders the input reader using the context into the output writer.
247      *  To be used when a template is dynamically constructed, or want to
248      *  use Velocity as a token replacer.
249      *
250      *  @param context context to use in rendering input string
251      *  @param writer  Writer in which to render the output
252      *  @param logTag  string to be used as the template name for log messages
253      *                 in case of error
254      *  @param reader Reader containing the VTL to be rendered
255      *
256      *  @return true if successful, false otherwise.  If false, see
257      *               Velocity runtime log
258      * @throws ParseErrorException The template could not be parsed.
259      * @throws MethodInvocationException A method on a context object could not be invoked.
260      * @throws ResourceNotFoundException A referenced resource could not be loaded.
261      * @throws IOException While loading a reference, an I/O problem occured.
262      *
263      *  @since Velocity v1.1
264      */
265     public static boolean evaluate( Context context, Writer writer,
266                                     String logTag, Reader reader )
267         throws ParseErrorException, MethodInvocationException,
268             ResourceNotFoundException,IOException
269     {
270         SimpleNode nodeTree = null;
271 
272         try
273         {
274             nodeTree = RuntimeSingleton.parse( reader, logTag );
275         }
276         catch ( ParseException pex )
277         {
278             throw  new ParseErrorException( pex );
279         }
280         catch (TemplateInitException pex)
281         {
282             throw  new ParseErrorException( pex );
283         }
284 
285         /*
286          * now we want to init and render
287          */
288 
289         if (nodeTree != null)
290         {
291             InternalContextAdapterImpl ica =
292                 new InternalContextAdapterImpl( context );
293 
294             ica.pushCurrentTemplateName( logTag );
295 
296             try
297             {
298                 try
299                 {
300                     nodeTree.init( ica, RuntimeSingleton.getRuntimeServices() );
301                 }
302                 catch (TemplateInitException pex)
303                 {
304                     throw  new ParseErrorException( pex );
305                 }
306                 /**
307                  * pass through application level runtime exceptions
308                  */
309                 catch( RuntimeException e )
310                 {
311                     throw e;
312                 }
313                 catch( Exception e )
314                 {
315                     getLog().error("Velocity.evaluate() : init exception for tag = "+logTag, e);
316                 }
317 
318                 /*
319                  *  now render, and let any exceptions fly
320                  */
321 
322                 nodeTree.render( ica, writer );
323             }
324             finally
325             {
326                 ica.popCurrentTemplateName();
327             }
328 
329             return true;
330         }
331 
332         return false;
333     }
334 
335     /**
336      *  Invokes a currently registered Velocimacro with the parms provided
337      *  and places the rendered stream into the writer.
338      *
339      *  Note : currently only accepts args to the VM if they are in the context.
340      *
341      *  @param vmName name of Velocimacro to call
342      *  @param logTag string to be used for template name in case of error
343      *  @param params args used to invoke Velocimacro. In context key format :
344      *                  eg  "foo","bar" (rather than "$foo","$bar")
345      *  @param context Context object containing data/objects used for rendering.
346      *  @param writer  Writer for output stream
347      *  @return true if Velocimacro exists and successfully invoked, false otherwise.
348      */
349     public static  boolean invokeVelocimacro( String vmName, String logTag,
350                                               String params[], Context context,
351                                               Writer writer )
352     {
353         /*
354          *  check parms
355          */
356 
357         if ( vmName == null ||  params == null ||  context == null
358              || writer == null || logTag == null)
359         {
360             getLog().error("Velocity.invokeVelocimacro() : invalid parameter");
361             return false;
362         }
363 
364         /*
365          * does the VM exist?
366          */
367 
368         if (!RuntimeSingleton.isVelocimacro( vmName, logTag ))
369         {
370             getLog().error("Velocity.invokeVelocimacro() : VM '"+ vmName
371                            + "' not registered.");
372             return false;
373         }
374 
375         /*
376          *  now just create the VM call, and use evaluate
377          */
378 
379         StringBuffer construct = new StringBuffer("#");
380 
381         construct.append( vmName );
382         construct.append( "(" );
383 
384         for( int i = 0; i < params.length; i++)
385         {
386             construct.append( " $" );
387             construct.append( params[i] );
388         }
389 
390         construct.append(" )");
391 
392         try
393         {
394             return evaluate(  context,  writer,
395                                          logTag, construct.toString() );
396         }
397 
398         catch(ParseErrorException pee)
399         {
400             throw pee;
401         }
402         catch(MethodInvocationException mie)
403         {
404             throw mie;
405         }
406         catch(ResourceNotFoundException rnfe)
407         {
408             throw rnfe;
409         }
410         catch(IOException ioe)
411         {
412             getLog().error("Velocity.invokeVelocimacro() failed", ioe);
413         }
414         /**
415          * pass through application level runtime exceptions
416          */
417         catch(RuntimeException re)
418         {
419             throw re;
420         }
421         return false;
422     }
423 
424     /**
425      *  Merges a template and puts the rendered stream into the writer.
426      *  The default encoding that Velocity uses to read template files is defined in
427      *  the property input.encoding and defaults to ISO-8859-1.
428      *
429      *  @param templateName name of template to be used in merge
430      *  @param context  filled context to be used in merge
431      *  @param  writer  writer to write template into
432      *
433      *  @return true if successful, false otherwise.  Errors
434      *           logged to velocity log.
435      *  @deprecated Use
436      *  {@link #mergeTemplate( String templateName, String encoding,
437      *                Context context, Writer writer )}
438      * @throws ParseErrorException The template could not be parsed.
439      * @throws MethodInvocationException A method on a context object could not be invoked.
440      * @throws ResourceNotFoundException A referenced resource could not be loaded.
441      * @throws Exception Any other exception.
442      */
443     public static boolean mergeTemplate( String templateName,
444                                          Context context, Writer writer )
445         throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception
446     {
447         return mergeTemplate( templateName, RuntimeSingleton.getString(INPUT_ENCODING,ENCODING_DEFAULT),
448                                context, writer );
449     }
450 
451     /**
452      *  merges a template and puts the rendered stream into the writer
453      *
454      *  @param templateName name of template to be used in merge
455      *  @param encoding encoding used in template
456      *  @param context  filled context to be used in merge
457      *  @param  writer  writer to write template into
458      *
459      *  @return true if successful, false otherwise.  Errors
460      *           logged to velocity log
461      *
462      * @throws ParseErrorException The template could not be parsed.
463      * @throws MethodInvocationException A method on a context object could not be invoked.
464      * @throws ResourceNotFoundException A referenced resource could not be loaded.
465      * @throws Exception Any other exception.
466      *
467      * @since Velocity v1.1
468      */
469     public static boolean mergeTemplate( String templateName, String encoding,
470                                       Context context, Writer writer )
471         throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception
472     {
473         Template template = RuntimeSingleton.getTemplate(templateName, encoding);
474 
475         if ( template == null )
476         {
477             getLog().error("Velocity.mergeTemplate() was unable to load template '"
478                            + templateName + "'");
479             return false;
480         }
481         else
482         {
483             template.merge(context, writer);
484             return true;
485         }
486     }
487 
488     /**
489      *  Returns a <code>Template</code> from the Velocity
490      *  resource management system.
491      *
492      * @param name The file name of the desired template.
493      * @return     The template.
494      * @throws ResourceNotFoundException if template not found
495      *          from any available source.
496      * @throws ParseErrorException if template cannot be parsed due
497      *          to syntax (or other) error.
498      * @throws Exception if an error occurs in template initialization
499      */
500     public static Template getTemplate(String name)
501         throws ResourceNotFoundException, ParseErrorException, Exception
502     {
503         return RuntimeSingleton.getTemplate( name );
504     }
505 
506     /**
507      *  Returns a <code>Template</code> from the Velocity
508      *  resource management system.
509      *
510      * @param name The file name of the desired template.
511      * @param encoding The character encoding to use for the template.
512      * @return     The template.
513      * @throws ResourceNotFoundException if template not found
514      *          from any available source.
515      * @throws ParseErrorException if template cannot be parsed due
516      *          to syntax (or other) error.
517      * @throws Exception if an error occurs in template initialization
518      *
519      *  @since Velocity v1.1
520      */
521     public static Template getTemplate(String name, String encoding)
522         throws ResourceNotFoundException, ParseErrorException, Exception
523     {
524         return RuntimeSingleton.getTemplate( name, encoding );
525     }
526 
527     /**
528      * <p>Determines whether a resource is accessable via the
529      * currently configured resource loaders.  {@link
530      * org.apache.velocity.runtime.resource.Resource} is the generic
531      * description of templates, static content, etc.</p>
532      *
533      * <p>Note that the current implementation will <b>not</b> change
534      * the state of the system in any real way - so this cannot be
535      * used to pre-load the resource cache, as the previous
536      * implementation did as a side-effect.</p>
537      *
538      * @param resourceName The name of the resource to search for.
539      * @return Whether the resource was located.
540      */
541     public static boolean resourceExists(String resourceName)
542     {
543         return (RuntimeSingleton.getLoaderNameForResource(resourceName) != null);
544     }
545 
546     /**
547      * Returns a convenient Log instance that wraps the current LogChute.
548      * Use this to log error messages. It has the usual methods.
549      *
550      * @return A convenience Log instance that wraps the current LogChute.
551      */
552     public static Log getLog()
553     {
554         return RuntimeSingleton.getLog();
555     }
556 
557     /**
558      * @deprecated Use getLog() and call warn() on it.
559      * @see Log#warn(Object)
560      * @param message The message to log.
561      */
562     public static void warn(Object message)
563     {
564         getLog().warn( message );
565     }
566 
567     /**
568      * @deprecated Use getLog() and call info() on it.
569      * @see Log#info(Object)
570      * @param message The message to log.
571      */
572     public static void info(Object message)
573     {
574         getLog().info( message );
575     }
576 
577     /**
578      * @deprecated Use getLog() and call error() on it.
579      * @see Log#error(Object)
580      * @param message The message to log.
581      */
582     public static void error(Object message)
583     {
584         getLog().error( message );
585     }
586 
587     /**
588      * @deprecated Use getLog() and call debug() on it.
589      * @see Log#debug(Object)
590      * @param message The message to log.
591      */
592     public static void debug(Object message)
593     {
594         getLog().debug( message );
595     }
596 
597     /**
598      *  <p>
599      *  Set the an ApplicationAttribue, which is an Object
600      *  set by the application which is accessable from
601      *  any component of the system that gets a RuntimeServices.
602      *  This allows communication between the application
603      *  environment and custom pluggable components of the
604      *  Velocity engine, such as loaders and loggers.
605      *  </p>
606      *
607      *  <p>
608      *  Note that there is no enfocement or rules for the key
609      *  used - it is up to the application developer.  However, to
610      *  help make the intermixing of components possible, using
611      *  the target Class name (e.g.  com.foo.bar ) as the key
612      *   might help avoid collision.
613      *  </p>
614      *
615      *  @param key object 'name' under which the object is stored
616      *  @param value object to store under this key
617      */
618      public static void setApplicationAttribute( Object key, Object value )
619      {
620         RuntimeSingleton.getRuntimeInstance().setApplicationAttribute( key, value);
621      }
622 
623     /**
624      * @param resourceName Name of the Template to check.
625      * @return True if the template exists.
626      * @see #resourceExists(String)
627      * @deprecated Use resourceExists(String) instead.
628      */
629     public static boolean templateExists(String resourceName)
630     {
631         return resourceExists(resourceName);
632     }
633 }