001: package org.apache.velocity.app;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.io.BufferedReader;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.io.InputStreamReader;
026: import java.io.Reader;
027: import java.io.StringReader;
028: import java.io.UnsupportedEncodingException;
029: import java.io.Writer;
030: import java.util.Properties;
031:
032: import org.apache.commons.collections.ExtendedProperties;
033: import org.apache.velocity.Template;
034: import org.apache.velocity.context.Context;
035: import org.apache.velocity.context.InternalContextAdapterImpl;
036: import org.apache.velocity.exception.MethodInvocationException;
037: import org.apache.velocity.exception.ParseErrorException;
038: import org.apache.velocity.exception.ResourceNotFoundException;
039: import org.apache.velocity.exception.TemplateInitException;
040: import org.apache.velocity.runtime.RuntimeConstants;
041: import org.apache.velocity.runtime.RuntimeSingleton;
042: import org.apache.velocity.runtime.log.Log;
043: import org.apache.velocity.runtime.parser.ParseException;
044: import org.apache.velocity.runtime.parser.node.SimpleNode;
045:
046: /**
047: * This class provides services to the application
048: * developer, such as :
049: * <ul>
050: * <li> Simple Velocity Runtime engine initialization methods.
051: * <li> Functions to apply the template engine to streams and strings
052: * to allow embedding and dynamic template generation.
053: * <li> Methods to access Velocimacros directly.
054: * </ul>
055: *
056: * <br><br>
057: * While the most common way to use Velocity is via templates, as
058: * Velocity is a general-purpose template engine, there are other
059: * uses that Velocity is well suited for, such as processing dynamically
060: * created templates, or processing content streams.
061: *
062: * <br><br>
063: * The methods herein were developed to allow easy access to the Velocity
064: * facilities without direct spelunking of the internals. If there is
065: * something you feel is necessary to add here, please, send a patch.
066: *
067: * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
068: * @author <a href="mailto:Christoph.Reck@dlr.de">Christoph Reck</a>
069: * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
070: * @version $Id: Velocity.java 471381 2006-11-05 08:56:58Z wglass $
071: */
072: public class Velocity implements RuntimeConstants {
073: /**
074: * initialize the Velocity runtime engine, using the default
075: * properties of the Velocity distribution
076: *
077: * @throws Exception When an error during initialization occurs.
078: */
079: public static void init() throws Exception {
080: RuntimeSingleton.init();
081: }
082:
083: /**
084: * initialize the Velocity runtime engine, using default properties
085: * plus the properties in the properties file passed in as the arg
086: *
087: * @param propsFilename file containing properties to use to initialize
088: * the Velocity runtime
089: * @throws Exception When an error during initialization occurs.
090: */
091: public static void init(String propsFilename) throws Exception {
092: RuntimeSingleton.init(propsFilename);
093: }
094:
095: /**
096: * initialize the Velocity runtime engine, using default properties
097: * plus the properties in the passed in java.util.Properties object
098: *
099: * @param p Properties object containing initialization properties
100: * @throws Exception When an error during initialization occurs.
101: *
102: */
103: public static void init(Properties p) throws Exception {
104: RuntimeSingleton.init(p);
105: }
106:
107: /**
108: * Set a Velocity Runtime property.
109: *
110: * @param key The property key.
111: * @param value The property value.
112: */
113: public static void setProperty(String key, Object value) {
114: RuntimeSingleton.setProperty(key, value);
115: }
116:
117: /**
118: * Add a Velocity Runtime property.
119: *
120: * @param key The property key.
121: * @param value The property value.
122: */
123: public static void addProperty(String key, Object value) {
124: RuntimeSingleton.addProperty(key, value);
125: }
126:
127: /**
128: * Clear a Velocity Runtime property.
129: *
130: * @param key of property to clear
131: */
132: public static void clearProperty(String key) {
133: RuntimeSingleton.clearProperty(key);
134: }
135:
136: /**
137: * Set an entire configuration at once. This is
138: * useful in cases where the parent application uses
139: * the ExtendedProperties class and the velocity configuration
140: * is a subset of the parent application's configuration.
141: *
142: * @param configuration A configuration object.
143: *
144: */
145: public static void setExtendedProperties(
146: ExtendedProperties configuration) {
147: RuntimeSingleton.setConfiguration(configuration);
148: }
149:
150: /**
151: * Get a Velocity Runtime property.
152: *
153: * @param key property to retrieve
154: * @return property value or null if the property
155: * not currently set
156: */
157: public static Object getProperty(String key) {
158: return RuntimeSingleton.getProperty(key);
159: }
160:
161: /**
162: * renders the input string using the context into the output writer.
163: * To be used when a template is dynamically constructed, or want to use
164: * Velocity as a token replacer.
165: *
166: * @param context context to use in rendering input string
167: * @param out Writer in which to render the output
168: * @param logTag string to be used as the template name for log
169: * messages in case of error
170: * @param instring input string containing the VTL to be rendered
171: *
172: * @return true if successful, false otherwise. If false, see
173: * Velocity runtime log
174: * @throws ParseErrorException The template could not be parsed.
175: * @throws MethodInvocationException A method on a context object could not be invoked.
176: * @throws ResourceNotFoundException A referenced resource could not be loaded.
177: * @throws IOException While loading a reference, an I/O problem occured.
178: */
179: public static boolean evaluate(Context context, Writer out,
180: String logTag, String instring) throws ParseErrorException,
181: MethodInvocationException, ResourceNotFoundException,
182: IOException {
183: return evaluate(context, out, logTag, new BufferedReader(
184: new StringReader(instring)));
185: }
186:
187: /**
188: * Renders the input stream using the context into the output writer.
189: * To be used when a template is dynamically constructed, or want to
190: * use Velocity as a token replacer.
191: *
192: * @param context context to use in rendering input string
193: * @param writer Writer in which to render the output
194: * @param logTag string to be used as the template name for log messages
195: * in case of error
196: * @param instream input stream containing the VTL to be rendered
197: *
198: * @return true if successful, false otherwise. If false, see
199: * Velocity runtime log
200: * @deprecated Use
201: * {@link #evaluate( Context context, Writer writer,
202: * String logTag, Reader reader ) }
203: * @throws ParseErrorException The template could not be parsed.
204: * @throws MethodInvocationException A method on a context object could not be invoked.
205: * @throws ResourceNotFoundException A referenced resource could not be loaded.
206: * @throws IOException While loading a reference, an I/O problem occured.
207: */
208: public static boolean evaluate(Context context, Writer writer,
209: String logTag, InputStream instream)
210: throws ParseErrorException, MethodInvocationException,
211: ResourceNotFoundException, IOException {
212: /*
213: * first, parse - convert ParseException if thrown
214: */
215: BufferedReader br = null;
216: String encoding = null;
217:
218: try {
219: encoding = RuntimeSingleton.getString(INPUT_ENCODING,
220: ENCODING_DEFAULT);
221: br = new BufferedReader(new InputStreamReader(instream,
222: encoding));
223: } catch (UnsupportedEncodingException uce) {
224: String msg = "Unsupported input encoding : " + encoding
225: + " for template " + logTag;
226: throw new ParseErrorException(msg);
227: }
228:
229: return evaluate(context, writer, logTag, br);
230: }
231:
232: /**
233: * Renders the input reader using the context into the output writer.
234: * To be used when a template is dynamically constructed, or want to
235: * use Velocity as a token replacer.
236: *
237: * @param context context to use in rendering input string
238: * @param writer Writer in which to render the output
239: * @param logTag string to be used as the template name for log messages
240: * in case of error
241: * @param reader Reader containing the VTL to be rendered
242: *
243: * @return true if successful, false otherwise. If false, see
244: * Velocity runtime log
245: * @throws ParseErrorException The template could not be parsed.
246: * @throws MethodInvocationException A method on a context object could not be invoked.
247: * @throws ResourceNotFoundException A referenced resource could not be loaded.
248: * @throws IOException While loading a reference, an I/O problem occured.
249: *
250: * @since Velocity v1.1
251: */
252: public static boolean evaluate(Context context, Writer writer,
253: String logTag, Reader reader) throws ParseErrorException,
254: MethodInvocationException, ResourceNotFoundException,
255: IOException {
256: SimpleNode nodeTree = null;
257:
258: try {
259: nodeTree = RuntimeSingleton.parse(reader, logTag);
260: } catch (ParseException pex) {
261: throw new ParseErrorException(pex);
262: } catch (TemplateInitException pex) {
263: throw new ParseErrorException(pex);
264: }
265:
266: /*
267: * now we want to init and render
268: */
269:
270: if (nodeTree != null) {
271: InternalContextAdapterImpl ica = new InternalContextAdapterImpl(
272: context);
273:
274: ica.pushCurrentTemplateName(logTag);
275:
276: try {
277: try {
278: nodeTree.init(ica, RuntimeSingleton
279: .getRuntimeServices());
280: } catch (TemplateInitException pex) {
281: throw new ParseErrorException(pex);
282: }
283: /**
284: * pass through application level runtime exceptions
285: */
286: catch (RuntimeException e) {
287: throw e;
288: } catch (Exception e) {
289: getLog().error(
290: "Velocity.evaluate() : init exception for tag = "
291: + logTag, e);
292: }
293:
294: /*
295: * now render, and let any exceptions fly
296: */
297:
298: nodeTree.render(ica, writer);
299: } finally {
300: ica.popCurrentTemplateName();
301: }
302:
303: return true;
304: }
305:
306: return false;
307: }
308:
309: /**
310: * Invokes a currently registered Velocimacro with the parms provided
311: * and places the rendered stream into the writer.
312: *
313: * Note : currently only accepts args to the VM if they are in the context.
314: *
315: * @param vmName name of Velocimacro to call
316: * @param logTag string to be used for template name in case of error
317: * @param params args used to invoke Velocimacro. In context key format :
318: * eg "foo","bar" (rather than "$foo","$bar")
319: * @param context Context object containing data/objects used for rendering.
320: * @param writer Writer for output stream
321: * @return true if Velocimacro exists and successfully invoked, false otherwise.
322: */
323: public static boolean invokeVelocimacro(String vmName,
324: String logTag, String params[], Context context,
325: Writer writer) {
326: /*
327: * check parms
328: */
329:
330: if (vmName == null || params == null || context == null
331: || writer == null || logTag == null) {
332: getLog().error(
333: "Velocity.invokeVelocimacro() : invalid parameter");
334: return false;
335: }
336:
337: /*
338: * does the VM exist?
339: */
340:
341: if (!RuntimeSingleton.isVelocimacro(vmName, logTag)) {
342: getLog().error(
343: "Velocity.invokeVelocimacro() : VM '" + vmName
344: + "' not registered.");
345: return false;
346: }
347:
348: /*
349: * now just create the VM call, and use evaluate
350: */
351:
352: StringBuffer construct = new StringBuffer("#");
353:
354: construct.append(vmName);
355: construct.append("(");
356:
357: for (int i = 0; i < params.length; i++) {
358: construct.append(" $");
359: construct.append(params[i]);
360: }
361:
362: construct.append(" )");
363:
364: try {
365: return evaluate(context, writer, logTag, construct
366: .toString());
367: }
368:
369: catch (ParseErrorException pee) {
370: throw pee;
371: } catch (MethodInvocationException mie) {
372: throw mie;
373: } catch (ResourceNotFoundException rnfe) {
374: throw rnfe;
375: } catch (IOException ioe) {
376: getLog().error("Velocity.invokeVelocimacro() failed", ioe);
377: }
378: /**
379: * pass through application level runtime exceptions
380: */
381: catch (RuntimeException re) {
382: throw re;
383: }
384: return false;
385: }
386:
387: /**
388: * Merges a template and puts the rendered stream into the writer.
389: * The default encoding that Velocity uses to read template files is defined in
390: * the property input.encoding and defaults to ISO-8859-1.
391: *
392: * @param templateName name of template to be used in merge
393: * @param context filled context to be used in merge
394: * @param writer writer to write template into
395: *
396: * @return true if successful, false otherwise. Errors
397: * logged to velocity log.
398: * @deprecated Use
399: * {@link #mergeTemplate( String templateName, String encoding,
400: * Context context, Writer writer )}
401: * @throws ParseErrorException The template could not be parsed.
402: * @throws MethodInvocationException A method on a context object could not be invoked.
403: * @throws ResourceNotFoundException A referenced resource could not be loaded.
404: * @throws Exception Any other exception.
405: */
406: public static boolean mergeTemplate(String templateName,
407: Context context, Writer writer)
408: throws ResourceNotFoundException, ParseErrorException,
409: MethodInvocationException, Exception {
410: return mergeTemplate(templateName, RuntimeSingleton.getString(
411: INPUT_ENCODING, ENCODING_DEFAULT), context, writer);
412: }
413:
414: /**
415: * merges a template and puts the rendered stream into the writer
416: *
417: * @param templateName name of template to be used in merge
418: * @param encoding encoding used in template
419: * @param context filled context to be used in merge
420: * @param writer writer to write template into
421: *
422: * @return true if successful, false otherwise. Errors
423: * logged to velocity log
424: *
425: * @throws ParseErrorException The template could not be parsed.
426: * @throws MethodInvocationException A method on a context object could not be invoked.
427: * @throws ResourceNotFoundException A referenced resource could not be loaded.
428: * @throws Exception Any other exception.
429: *
430: * @since Velocity v1.1
431: */
432: public static boolean mergeTemplate(String templateName,
433: String encoding, Context context, Writer writer)
434: throws ResourceNotFoundException, ParseErrorException,
435: MethodInvocationException, Exception {
436: Template template = RuntimeSingleton.getTemplate(templateName,
437: encoding);
438:
439: if (template == null) {
440: getLog().error(
441: "Velocity.mergeTemplate() was unable to load template '"
442: + templateName + "'");
443: return false;
444: } else {
445: template.merge(context, writer);
446: return true;
447: }
448: }
449:
450: /**
451: * Returns a <code>Template</code> from the Velocity
452: * resource management system.
453: *
454: * @param name The file name of the desired template.
455: * @return The template.
456: * @throws ResourceNotFoundException if template not found
457: * from any available source.
458: * @throws ParseErrorException if template cannot be parsed due
459: * to syntax (or other) error.
460: * @throws Exception if an error occurs in template initialization
461: */
462: public static Template getTemplate(String name)
463: throws ResourceNotFoundException, ParseErrorException,
464: Exception {
465: return RuntimeSingleton.getTemplate(name);
466: }
467:
468: /**
469: * Returns a <code>Template</code> from the Velocity
470: * resource management system.
471: *
472: * @param name The file name of the desired template.
473: * @param encoding The character encoding to use for the template.
474: * @return The template.
475: * @throws ResourceNotFoundException if template not found
476: * from any available source.
477: * @throws ParseErrorException if template cannot be parsed due
478: * to syntax (or other) error.
479: * @throws Exception if an error occurs in template initialization
480: *
481: * @since Velocity v1.1
482: */
483: public static Template getTemplate(String name, String encoding)
484: throws ResourceNotFoundException, ParseErrorException,
485: Exception {
486: return RuntimeSingleton.getTemplate(name, encoding);
487: }
488:
489: /**
490: * <p>Determines whether a resource is accessable via the
491: * currently configured resource loaders. {@link
492: * org.apache.velocity.runtime.resource.Resource} is the generic
493: * description of templates, static content, etc.</p>
494: *
495: * <p>Note that the current implementation will <b>not</b> change
496: * the state of the system in any real way - so this cannot be
497: * used to pre-load the resource cache, as the previous
498: * implementation did as a side-effect.</p>
499: *
500: * @param resourceName The name of the resource to search for.
501: * @return Whether the resource was located.
502: */
503: public static boolean resourceExists(String resourceName) {
504: return (RuntimeSingleton.getLoaderNameForResource(resourceName) != null);
505: }
506:
507: /**
508: * Returns a convenient Log instance that wraps the current LogChute.
509: * Use this to log error messages. It has the usual methods.
510: *
511: * @return A convenience Log instance that wraps the current LogChute.
512: */
513: public static Log getLog() {
514: return RuntimeSingleton.getLog();
515: }
516:
517: /**
518: * @deprecated Use getLog() and call warn() on it.
519: * @see Log#warn(Object)
520: * @param message The message to log.
521: */
522: public static void warn(Object message) {
523: getLog().warn(message);
524: }
525:
526: /**
527: * @deprecated Use getLog() and call info() on it.
528: * @see Log#info(Object)
529: * @param message The message to log.
530: */
531: public static void info(Object message) {
532: getLog().info(message);
533: }
534:
535: /**
536: * @deprecated Use getLog() and call error() on it.
537: * @see Log#error(Object)
538: * @param message The message to log.
539: */
540: public static void error(Object message) {
541: getLog().error(message);
542: }
543:
544: /**
545: * @deprecated Use getLog() and call debug() on it.
546: * @see Log#debug(Object)
547: * @param message The message to log.
548: */
549: public static void debug(Object message) {
550: getLog().debug(message);
551: }
552:
553: /**
554: * <p>
555: * Set the an ApplicationAttribue, which is an Object
556: * set by the application which is accessable from
557: * any component of the system that gets a RuntimeServices.
558: * This allows communication between the application
559: * environment and custom pluggable components of the
560: * Velocity engine, such as loaders and loggers.
561: * </p>
562: *
563: * <p>
564: * Note that there is no enfocement or rules for the key
565: * used - it is up to the application developer. However, to
566: * help make the intermixing of components possible, using
567: * the target Class name (e.g. com.foo.bar ) as the key
568: * might help avoid collision.
569: * </p>
570: *
571: * @param key object 'name' under which the object is stored
572: * @param value object to store under this key
573: */
574: public static void setApplicationAttribute(Object key, Object value) {
575: RuntimeSingleton.getRuntimeInstance().setApplicationAttribute(
576: key, value);
577: }
578:
579: /**
580: * @param resourceName Name of the Template to check.
581: * @return True if the template exists.
582: * @see #resourceExists(String)
583: * @deprecated Use resourceExists(String) instead.
584: */
585: public static boolean templateExists(String resourceName) {
586: return resourceExists(resourceName);
587: }
588: }
|