KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > template > Configuration


1 /*
2  * Copyright (c) 2003 The Visigoth Software Society. All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowledgement:
19  * "This product includes software developed by the
20  * Visigoth Software Society (http://www.visigoths.org/)."
21  * Alternately, this acknowledgement may appear in the software itself,
22  * if and wherever such third-party acknowledgements normally appear.
23  *
24  * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
25  * project contributors may be used to endorse or promote products derived
26  * from this software without prior written permission. For written
27  * permission, please contact visigoths@visigoths.org.
28  *
29  * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
30  * nor may "FreeMarker" or "Visigoth" appear in their names
31  * without prior written permission of the Visigoth Software Society.
32  *
33  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36  * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
37  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  * ====================================================================
46  *
47  * This software consists of voluntary contributions made by many
48  * individuals on behalf of the Visigoth Software Society. For more
49  * information on the Visigoth Software Society, please see
50  * http://www.visigoths.org/
51  */

52
53 package freemarker.template;
54
55 import java.io.*;
56 import java.util.*;
57
58 import freemarker.cache.*;
59 import freemarker.core.*;
60 import freemarker.template.utility.*;
61
62 /**
63  * Main entry point into the FreeMarker API, this class encapsulates the
64  * various configuration parameters with which FreeMarker is run, as well
65  * as serves as a central template loading and caching point. Note that
66  * this class uses a default strategy for loading
67  * and caching templates. You can plug in a replacement
68  * template loading mechanism by using the {@link #setTemplateLoader(TemplateLoader)}
69  * method.
70  *
71  * This object is <em>not synchronized</em>. Thus, the settings must not be changed
72  * after you have started to access the object from multiple threads. If you use multiple
73  * threads, set everything directly after you have instantiated the <code>Configuration</code>
74  * object, and don't change the settings anymore.
75  *
76  * @author <a HREF="mailto:jon@revusky.com">Jonathan Revusky</a>
77  * @author Attila Szegedi
78  * @version $Id: Configuration.java,v 1.122 2004/12/03 11:48:22 ddekany Exp $
79  */

80
81 public class Configuration extends Configurable implements Cloneable JavaDoc {
82     public static final String JavaDoc DEFAULT_ENCODING_KEY = "default_encoding";
83     public static final String JavaDoc LOCALIZED_LOOKUP_KEY = "localized_lookup";
84     public static final String JavaDoc STRICT_SYNTAX_KEY = "strict_syntax";
85     public static final String JavaDoc WHITESPACE_STRIPPING_KEY = "whitespace_stripping";
86     public static final String JavaDoc CACHE_STORAGE_KEY = "cache_storage";
87     public static final String JavaDoc TEMPLATE_UPDATE_DELAY_KEY = "template_update_delay";
88     public static final String JavaDoc AUTO_IMPORT_KEY = "auto_import";
89     public static final String JavaDoc AUTO_INCLUDE_KEY = "auto_include";
90
91     private static Configuration defaultConfig = new Configuration();
92     private static String JavaDoc cachedVersion;
93     private boolean strictSyntax = true, localizedLookup = true, whitespaceStripping = true;
94     private TemplateCache cache;
95     private HashMap variables = new HashMap();
96     private HashMap encodingMap = new HashMap();
97     private Map autoImportMap = new HashMap();
98     private ArrayList autoImports = new ArrayList(), autoIncludes = new ArrayList();
99     private String JavaDoc defaultEncoding = SecurityUtilities.getSystemProperty("file.encoding");
100      
101
102     public Configuration() {
103         cache = new TemplateCache();
104         cache.setConfiguration(this);
105         cache.setDelay(5000);
106         loadBuiltInSharedVariables();
107     }
108
109     public Object JavaDoc clone() {
110         try {
111             Configuration copy = (Configuration)super.clone();
112             copy.variables = new HashMap(variables);
113             copy.encodingMap = new HashMap(encodingMap);
114             copy.createTemplateCache(cache.getTemplateLoader(), cache.getCacheStorage());
115             return copy;
116         } catch (CloneNotSupportedException JavaDoc e) {
117             throw new RuntimeException JavaDoc("Clone is not supported, but it should be: " + e.getMessage());
118         }
119     }
120     
121     private void loadBuiltInSharedVariables() {
122         variables.put("capture_output", new CaptureOutput());
123         variables.put("compress", StandardCompress.INSTANCE);
124         variables.put("html_escape", new HtmlEscape());
125         variables.put("normalize_newlines", new NormalizeNewlines());
126         variables.put("xml_escape", new XmlEscape());
127     }
128     
129     /**
130      * Loads a preset language-to-encoding map. It assumes the usual character
131      * encodings for most languages.
132      * The previous content of the encoding map will be lost.
133      * This default map currently contains the following mappings:
134      * <table>
135      * <tr><td>ar</td><td>ISO-8859-6</td></tr>
136      * <tr><td>be</td><td>ISO-8859-5</td></tr>
137      * <tr><td>bg</td><td>ISO-8859-5</td></tr>
138      * <tr><td>ca</td><td>ISO-8859-1</td></tr>
139      * <tr><td>cs</td><td>ISO-8859-2</td></tr>
140      * <tr><td>da</td><td>ISO-8859-1</td></tr>
141      * <tr><td>de</td><td>ISO-8859-1</td></tr>
142      * <tr><td>el</td><td>ISO-8859-7</td></tr>
143      * <tr><td>en</td><td>ISO-8859-1</td></tr>
144      * <tr><td>es</td><td>ISO-8859-1</td></tr>
145      * <tr><td>et</td><td>ISO-8859-1</td></tr>
146      * <tr><td>fi</td><td>ISO-8859-1</td></tr>
147      * <tr><td>fr</td><td>ISO-8859-1</td></tr>
148      * <tr><td>hr</td><td>ISO-8859-2</td></tr>
149      * <tr><td>hu</td><td>ISO-8859-2</td></tr>
150      * <tr><td>is</td><td>ISO-8859-1</td></tr>
151      * <tr><td>it</td><td>ISO-8859-1</td></tr>
152      * <tr><td>iw</td><td>ISO-8859-8</td></tr>
153      * <tr><td>ja</td><td>Shift_JIS</td></tr>
154      * <tr><td>ko</td><td>EUC-KR</td></tr>
155      * <tr><td>lt</td><td>ISO-8859-2</td></tr>
156      * <tr><td>lv</td><td>ISO-8859-2</td></tr>
157      * <tr><td>mk</td><td>ISO-8859-5</td></tr>
158      * <tr><td>nl</td><td>ISO-8859-1</td></tr>
159      * <tr><td>no</td><td>ISO-8859-1</td></tr>
160      * <tr><td>pl</td><td>ISO-8859-2</td></tr>
161      * <tr><td>pt</td><td>ISO-8859-1</td></tr>
162      * <tr><td>ro</td><td>ISO-8859-2</td></tr>
163      * <tr><td>ru</td><td>ISO-8859-5</td></tr>
164      * <tr><td>sh</td><td>ISO-8859-5</td></tr>
165      * <tr><td>sk</td><td>ISO-8859-2</td></tr>
166      * <tr><td>sl</td><td>ISO-8859-2</td></tr>
167      * <tr><td>sq</td><td>ISO-8859-2</td></tr>
168      * <tr><td>sr</td><td>ISO-8859-5</td></tr>
169      * <tr><td>sv</td><td>ISO-8859-1</td></tr>
170      * <tr><td>tr</td><td>ISO-8859-9</td></tr>
171      * <tr><td>uk</td><td>ISO-8859-5</td></tr>
172      * <tr><td>zh</td><td>GB2312</td></tr>
173      * <tr><td>zh_TW</td><td>Big5</td></tr>
174      * </table>
175      * @see #clearEncodingMap
176      * @see #setEncoding
177      */

178     public void loadBuiltInEncodingMap() {
179         encodingMap.clear();
180         encodingMap.put("ar", "ISO-8859-6");
181         encodingMap.put("be", "ISO-8859-5");
182         encodingMap.put("bg", "ISO-8859-5");
183         encodingMap.put("ca", "ISO-8859-1");
184         encodingMap.put("cs", "ISO-8859-2");
185         encodingMap.put("da", "ISO-8859-1");
186         encodingMap.put("de", "ISO-8859-1");
187         encodingMap.put("el", "ISO-8859-7");
188         encodingMap.put("en", "ISO-8859-1");
189         encodingMap.put("es", "ISO-8859-1");
190         encodingMap.put("et", "ISO-8859-1");
191         encodingMap.put("fi", "ISO-8859-1");
192         encodingMap.put("fr", "ISO-8859-1");
193         encodingMap.put("hr", "ISO-8859-2");
194         encodingMap.put("hu", "ISO-8859-2");
195         encodingMap.put("is", "ISO-8859-1");
196         encodingMap.put("it", "ISO-8859-1");
197         encodingMap.put("iw", "ISO-8859-8");
198         encodingMap.put("ja", "Shift_JIS");
199         encodingMap.put("ko", "EUC-KR");
200         encodingMap.put("lt", "ISO-8859-2");
201         encodingMap.put("lv", "ISO-8859-2");
202         encodingMap.put("mk", "ISO-8859-5");
203         encodingMap.put("nl", "ISO-8859-1");
204         encodingMap.put("no", "ISO-8859-1");
205         encodingMap.put("pl", "ISO-8859-2");
206         encodingMap.put("pt", "ISO-8859-1");
207         encodingMap.put("ro", "ISO-8859-2");
208         encodingMap.put("ru", "ISO-8859-5");
209         encodingMap.put("sh", "ISO-8859-5");
210         encodingMap.put("sk", "ISO-8859-2");
211         encodingMap.put("sl", "ISO-8859-2");
212         encodingMap.put("sq", "ISO-8859-2");
213         encodingMap.put("sr", "ISO-8859-5");
214         encodingMap.put("sv", "ISO-8859-1");
215         encodingMap.put("tr", "ISO-8859-9");
216         encodingMap.put("uk", "ISO-8859-5");
217         encodingMap.put("zh", "GB2312");
218         encodingMap.put("zh_TW", "Big5");
219     }
220
221     /**
222      * Clears language-to-encoding map.
223      * @see #loadBuiltInEncodingMap
224      * @see #setEncoding
225      */

226     public void clearEncodingMap() {
227         encodingMap.clear();
228     }
229
230     /**
231      * Returns the default (singleton) Configuration object. Note that you can
232      * create as many separate configurations as you wish; this global instance
233      * is provided for convenience, or when you have no reason to use a separate
234      * instance.
235      *
236      * @deprecated The usage of the static singleton (the "default")
237      * {@link Configuration} instance can easily cause erroneous, unpredictable
238      * behavior. This is because multiple independent software components may use
239      * FreeMarker internally inside the same application, so they will interfere
240      * because of the common {@link Configuration} instance. Each such component
241      * should use its own private {@link Configuration} object instead, that it
242      * typically creates with <code>new Configuration()</code> when the component
243      * is initialized.
244      */

245     static public Configuration getDefaultConfiguration() {
246         return defaultConfig;
247     }
248
249     /**
250      * Sets the Configuration object that will be retrieved from future calls
251      * to {@link #getDefaultConfiguration()}.
252      *
253      * @deprecated Using the "default" {@link Configuration} instance can
254      * easily lead to erroneous, unpredictable behaviour.
255      * See more {@link Configuration#getDefaultConfiguration() here...}.
256      */

257     static public void setDefaultConfiguration(Configuration config) {
258         defaultConfig = config;
259     }
260     
261     /**
262      * Sets a template loader that is used to look up and load templates.
263      * By providing your own template loader, you can customize the way
264      * templates are loaded. Several convenience methods in this class already
265      * allow you to install commonly used loaders:
266      * {@link #setClassForTemplateLoading(Class, String)},
267      * {@link #setDirectoryForTemplateLoading(File)}, and
268      * {@link #setServletContextForTemplateLoading(Object, String)}. By default,
269      * a multi-loader is used that first tries to load a template from the file
270      * in the current directory, then from a resource on the classpath.
271      */

272     public synchronized void setTemplateLoader(TemplateLoader loader) {
273         createTemplateCache(loader, cache.getCacheStorage());
274     }
275
276     private void createTemplateCache(TemplateLoader loader, CacheStorage storage)
277     {
278         TemplateCache oldCache = cache;
279         cache = new TemplateCache(loader, storage);
280         cache.setDelay(oldCache.getDelay());
281         cache.setConfiguration(this);
282         cache.setLocalizedLookup(localizedLookup);
283     }
284     /**
285      * @return the template loader that is used to look up and load templates.
286      * @see #setTemplateLoader
287      */

288     public TemplateLoader getTemplateLoader()
289     {
290         return cache.getTemplateLoader();
291     }
292
293     public synchronized void setCacheStorage(CacheStorage storage) {
294         createTemplateCache(cache.getTemplateLoader(), storage);
295     }
296     
297     /**
298      * Set the explicit directory from which to load templates.
299      */

300     public void setDirectoryForTemplateLoading(File dir) throws IOException {
301         TemplateLoader tl = getTemplateLoader();
302         if (tl instanceof FileTemplateLoader) {
303             String JavaDoc path = ((FileTemplateLoader) tl).baseDir.getCanonicalPath();
304             if (path.equals(dir.getCanonicalPath()))
305                 return;
306         }
307         setTemplateLoader(new FileTemplateLoader(dir));
308     }
309
310     /**
311      * Sets the servlet context from which to load templates
312      * @param sctxt the ServletContext object. Note that the type is <code>Object</code>
313      * to prevent class loading errors when user who uses FreeMarker not for
314      * servlets has no javax.servlet in the CLASSPATH.
315      * @param path the path relative to the ServletContext.
316      * If this path is absolute, it is taken to be relative
317      * to the server's URL, i.e. http://myserver.com/
318      * and if the path is relative, it is taken to be
319      * relative to the web app context, i.e.
320      * http://myserver.context.com/mywebappcontext/
321      */

322     public void setServletContextForTemplateLoading(Object JavaDoc sctxt, String JavaDoc path) {
323         try {
324             if (path == null) {
325                 setTemplateLoader( (TemplateLoader)
326                         ClassUtil.forName("freemarker.cache.WebappTemplateLoader")
327                             .getConstructor(new Class JavaDoc[]{ClassUtil.forName("javax.servlet.ServletContext")})
328                                     .newInstance(new Object JavaDoc[]{sctxt}) );
329             }
330             else {
331                 setTemplateLoader( (TemplateLoader)
332                         ClassUtil.forName("freemarker.cache.WebappTemplateLoader")
333                             .getConstructor(new Class JavaDoc[]{ClassUtil.forName("javax.servlet.ServletContext"), String JavaDoc.class})
334                                     .newInstance(new Object JavaDoc[]{sctxt, path}) );
335             }
336         } catch (Exception JavaDoc exc) {
337             throw new RuntimeException JavaDoc("Internal FreeMarker error: " + exc);
338         }
339     }
340
341     /**
342      * Sets a class relative to which we do the
343      * Class.getResource() call to load templates.
344      */

345     public void setClassForTemplateLoading(Class JavaDoc clazz, String JavaDoc pathPrefix) {
346         setTemplateLoader(new ClassTemplateLoader(clazz, pathPrefix));
347     }
348
349     /**
350      * Set the time in seconds that must elapse before checking whether there is a newer
351      * version of a template file.
352      * This method is thread-safe and can be called while the engine works.
353      */

354     public void setTemplateUpdateDelay(int delay) {
355         cache.setDelay(1000L * delay);
356     }
357
358     /**
359      * Sets whether directives such as if, else, etcetera
360      * must be written as #if, #else, etcetera.
361      * Any tag not starting with &lt;# or &lt;/# is considered as plain text
362      * and will go to the output as is. Tag starting with &lt# or &lt/# must
363      * be valid FTL tag, or else the template is invalid (i.e. &lt;#noSuchDirective>
364      * is an error).
365      */

366
367     public void setStrictSyntaxMode(boolean b) {
368         strictSyntax = b;
369     }
370
371     /**
372      * Tells whether directives such as if, else, etcetera
373      * must be written as #if, #else, etcetera.
374      *
375      * @see #setStrictSyntaxMode
376      */

377     public boolean getStrictSyntaxMode() {
378         return strictSyntax;
379     }
380
381     /**
382      * Sets whether the FTL parser will try to remove
383      * superfluous white-space around certain FTL tags.
384      */

385     public void setWhitespaceStripping(boolean b) {
386         whitespaceStripping = b;
387     }
388
389     /**
390      * Gets whether the FTL parser will try to remove
391      * superfluous white-space around certain FTL tags.
392      *
393      * @see #setWhitespaceStripping
394      */

395     public boolean getWhitespaceStripping() {
396         return whitespaceStripping;
397     }
398
399     /**
400      * Equivalent to <tt>getTemplate(name, thisCfg.getLocale(), thisCfg.getEncoding(thisCfg.getLocale()), true)</tt>.
401      */

402     public Template getTemplate(String JavaDoc name) throws IOException {
403         Locale loc = getLocale();
404         return getTemplate(name, loc, getEncoding(loc), true);
405     }
406
407     /**
408      * Equivalent to <tt>getTemplate(name, locale, thisCfg.getEncoding(locale), true)</tt>.
409      */

410     public Template getTemplate(String JavaDoc name, Locale locale) throws IOException {
411         return getTemplate(name, locale, getEncoding(locale), true);
412     }
413
414     /**
415      * Equivalent to <tt>getTemplate(name, thisCfg.getLocale(), encoding, true)</tt>.
416      */

417     public Template getTemplate(String JavaDoc name, String JavaDoc encoding) throws IOException {
418         return getTemplate(name, getLocale(), encoding, true);
419     }
420
421     /**
422      * Equivalent to <tt>getTemplate(name, locale, encoding, true)</tt>.
423      */

424     public Template getTemplate(String JavaDoc name, Locale locale, String JavaDoc encoding) throws IOException {
425         return getTemplate(name, locale, encoding, true);
426     }
427
428     /**
429      * Retrieves a template specified by a name and locale, interpreted using
430      * the specified character encoding, either parsed or unparsed. For the
431      * exact semantics of parameters, see
432      * {@link TemplateCache#getTemplate(String, Locale, String, boolean)}.
433      * @return the requested template.
434      * @throws FileNotFoundException if the template could not be found.
435      * @throws IOException if there was a problem loading the template.
436      * @throws ParseException (extends <code>IOException</code>) if the template is syntactically bad.
437      */

438     public Template getTemplate(String JavaDoc name, Locale locale, String JavaDoc encoding, boolean parse) throws IOException {
439         Template result = cache.getTemplate(name, locale, encoding, parse);
440         if (result == null) {
441             throw new FileNotFoundException("Template " + name + " not found.");
442         }
443         return result;
444     }
445
446     /**
447      * Sets the default encoding for converting bytes to characters when
448      * reading template files in a locale for which no explicit encoding
449      * was specified. Defaults to default system encoding.
450      */

451     public void setDefaultEncoding(String JavaDoc encoding) {
452         defaultEncoding = encoding;
453     }
454
455     /**
456      * Gets the default encoding for converting bytes to characters when
457      * reading template files in a locale for which no explicit encoding
458      * was specified. Defaults to default system encoding.
459      */

460     public String JavaDoc getDefaultEncoding() {
461         return defaultEncoding;
462     }
463
464     /**
465      * Gets the preferred character encoding for the given locale, or the
466      * default encoding if no encoding is set explicitly for the specified
467      * locale. You can associate encodings with locales using
468      * {@link #setEncoding(Locale, String)} or {@link #loadBuiltInEncodingMap()}.
469      * @param loc the locale
470      * @return the preferred character encoding for the locale.
471      */

472     public String JavaDoc getEncoding(Locale loc) {
473         // Try for a full name match (may include country and variant)
474
String JavaDoc charset = (String JavaDoc) encodingMap.get(loc.toString());
475         if (charset == null) {
476             if (loc.getVariant().length() > 0) {
477                 Locale l = new Locale(loc.getLanguage(), loc.getCountry());
478                 charset = (String JavaDoc) encodingMap.get(l.toString());
479                 if (charset != null) {
480                     encodingMap.put(loc.toString(), charset);
481                 }
482             }
483             charset = (String JavaDoc) encodingMap.get(loc.getLanguage());
484             if (charset != null) {
485                 encodingMap.put(loc.toString(), charset);
486             }
487         }
488         return charset != null ? charset : defaultEncoding;
489     }
490
491     /**
492      * Sets the character set encoding to use for templates of
493      * a given locale. If there is no explicit encoding set for some
494      * locale, then the default encoding will be used, what you can
495      * set with {@link #setDefaultEncoding}.
496      *
497      * @see #clearEncodingMap
498      * @see #loadBuiltInEncodingMap
499      */

500     public void setEncoding(Locale locale, String JavaDoc encoding) {
501         encodingMap.put(locale.toString(), encoding);
502     }
503
504     /**
505      * Adds a shared variable to the configuration.
506      * Shared variables are variables that are visible
507      * as top-level variables for all templates which use this
508      * configuration, if the data model does not contain a
509      * variable with the same name.
510      *
511      * <p>Never use <tt>TemplateModel</tt> implementation that is not thread-safe for shared variables,
512      * if the configuration is used by multiple threads! It is the typical situation for Servlet based Web sites.
513      *
514      * @param name the name used to access the data object from your template.
515      * If a shared variable with this name already exists, it will replace
516      * that.
517      * @see #setSharedVariable(String,Object)
518      * @see #setAllSharedVariables
519      */

520     public void setSharedVariable(String JavaDoc name, TemplateModel tm) {
521         variables.put(name, tm);
522     }
523
524     /**
525      * Returns the set containing the names of all defined shared variables.
526      * The method returns a new Set object on each call that is completely
527      * disconnected from the Configuration. That is, modifying the set will have
528      * no effect on the Configuration object.
529      */

530     public Set getSharedVariableNames() {
531         return new HashSet(variables.keySet());
532     }
533     
534     /**
535      * Adds shared variable to the configuration.
536      * It uses {@link Configurable#getObjectWrapper()} to wrap the
537      * <code>obj</code>.
538      * @see #setSharedVariable(String,TemplateModel)
539      * @see #setAllSharedVariables
540      */

541     public void setSharedVariable(String JavaDoc name, Object JavaDoc obj) throws TemplateModelException {
542         setSharedVariable(name, getObjectWrapper().wrap(obj));
543     }
544
545     /**
546      * Adds all object in the hash as shared variable to the configuration.
547      *
548      * <p>Never use <tt>TemplateModel</tt> implementation that is not thread-safe for shared variables,
549      * if the configuration is used by multiple threads! It is the typical situation for Servlet based Web sites.
550      *
551      * @param hash a hash model whose objects will be copied to the
552      * configuration with same names as they are given in the hash.
553      * If a shared variable with these names already exist, it will be replaced
554      * with those from the map.
555      *
556      * @see #setSharedVariable(String,Object)
557      * @see #setSharedVariable(String,TemplateModel)
558      */

559     public void setAllSharedVariables(TemplateHashModelEx hash) throws TemplateModelException {
560         TemplateModelIterator keys = hash.keys().iterator();
561         TemplateModelIterator values = hash.values().iterator();
562         while(keys.hasNext())
563         {
564             setSharedVariable(((TemplateScalarModel)keys.next()).getAsString(), values.next());
565         }
566     }
567     
568     /**
569      * Gets a shared variable. Shared variables are variables that are
570      * available to all templates. When a template is processed, and an identifier
571      * is undefined in the data model, a shared variable object with the same identifier
572      * is then looked up in the configuration. There are several predefined variables
573      * that are always available through this method, see the FreeMarker manual
574      * for a comprehensive list of them.
575      *
576      * @see #setSharedVariable(String,Object)
577      * @see #setSharedVariable(String,TemplateModel)
578      * @see #setAllSharedVariables
579      */

580     public TemplateModel getSharedVariable(String JavaDoc name) {
581         return (TemplateModel) variables.get(name);
582     }
583     
584     /**
585      * Removes all shared variables, except the predefined ones (compress, html_escape, etc.).
586      */

587     public void clearSharedVariables() {
588         variables.clear();
589         loadBuiltInSharedVariables();
590     }
591     
592     /**
593      * Removes all entries from the template cache, thus forcing reloading of templates
594      * on subsequent <code>getTemplate</code> calls.
595      * This method is thread-safe and can be called while the engine works.
596      */

597     public void clearTemplateCache() {
598         cache.clear();
599     }
600     
601     /**
602      * Returns if localized template lookup is enabled or not.
603      * This method is thread-safe and can be called while the engine works.
604      */

605     public boolean getLocalizedLookup() {
606         return cache.getLocalizedLookup();
607     }
608     
609     /**
610      * Enables/disables localized template lookup. Enabled by default.
611      * This method is thread-safe and can be called while the engine works.
612      */

613     public void setLocalizedLookup(boolean localizedLookup) {
614         this.localizedLookup = localizedLookup;
615         cache.setLocalizedLookup(localizedLookup);
616     }
617     
618     /**
619      * Sets a setting by name and string value.
620      *
621      * In additional to the settings understood by
622      * {@link Configurable#setSetting the super method}, it understands these:
623      * <ul>
624      * <li><code>"auto_import"</code>: Sets the list of auto-imports. Example of valid value:
625      * <br><code>/lib/form.ftl as f, /lib/widget as w, "/lib/evil name.ftl" as odd</code>
626      * See: {@link #setAutoImports}
627      * <li><code>"auto_include"</code>: Sets the list of auto-includes. Example of valid value:
628      * <br><code>/include/common.ftl, "/include/evil name.ftl"</code>
629      * See: {@link #setAutoIncludes}
630      * <li><code>"default_encoding"</code>: The name of the charset, such as <code>"UTF-8"</code>.
631      * See: {@link #setDefaultEncoding}
632      * <li><code>"localized_lookup"</code>:
633      * <code>"true"</code>, <code>"false"</code>, <code>"yes"</code>, <code>"no"</code>,
634      * <code>"t"</code>, <code>"f"</code>, <code>"y"</code>, <code>"n"</code>.
635      * Case insensitive.
636      * See: {@link #setLocalizedLookup}
637      * <li><code>"strict_syntax"</code>: <code>"true"</code>, <code>"false"</code>, etc.
638      * See: {@link #setStrictSyntaxMode}
639      * <li><code>"whitespace_stripping"</code>: <code>"true"</code>, <code>"false"</code>, etc.
640      * See: {@link #setWhitespaceStripping}
641      * <li><code>"cache_storage"</code>: If the value contains dot, then it is
642      * interpreted as class name, and the object will be created with
643      * its parameterless constructor. If the value does not contain dot,
644      * then a {@link freemarker.cache.MruCacheStorage} will be used with the
645      * maximum strong and soft sizes specified with the setting value. Examples
646      * of valid setting values:
647      * <table border=1 cellpadding=4>
648      * <tr><th>Setting value<th>max. strong size<th>max. soft size
649      * <tr><td><code>"strong:50, soft:500"</code><td>50<td>500
650      * <tr><td><code>"strong:100, soft"</code><td>100<td><code>Integer.MAX_VALUE</code>
651      * <tr><td><code>"strong:100"</code><td>100<td>0
652      * <tr><td><code>"soft:100"</code><td>0<td>100
653      * <tr><td><code>"strong"</code><td><code>Integer.MAX_VALUE</code><td>0
654      * <tr><td><code>"soft"</code><td>0<td><code>Integer.MAX_VALUE</code>
655      * </table>
656      * The value is not case sensitive. The order of <tt>soft</tt> and <tt>strong</tt>
657      * entries is not significant.
658      * See also: {@link #setCacheStorage}
659      * <li><code>"template_update_delay"</code>: Valid positive integer, the
660      * update delay measured in seconds.
661      * See: {@link #setTemplateUpdateDelay}
662      * </ul>
663      *
664      * @param key the name of the setting.
665      * @param value the string that describes the new value of the setting.
666      *
667      * @throws UnknownSettingException if the key is wrong.
668      * @throws TemplateException if the new value of the setting can't be set
669      * for any other reasons.
670      */

671     public void setSetting(String JavaDoc key, String JavaDoc value) throws TemplateException {
672         if ("TemplateUpdateInterval".equalsIgnoreCase(key)) {
673             key = TEMPLATE_UPDATE_DELAY_KEY;
674         } else if ("DefaultEncoding".equalsIgnoreCase(key)) {
675             key = DEFAULT_ENCODING_KEY;
676         }
677         try {
678             if (DEFAULT_ENCODING_KEY.equals(key)) {
679                 setDefaultEncoding(value);
680             } else if (LOCALIZED_LOOKUP_KEY.equals(key)) {
681                 setLocalizedLookup(StringUtil.getYesNo(value));
682             } else if (STRICT_SYNTAX_KEY.equals(key)) {
683                 setStrictSyntaxMode(StringUtil.getYesNo(value));
684             } else if (WHITESPACE_STRIPPING_KEY.equals(key)) {
685                 setWhitespaceStripping(StringUtil.getYesNo(value));
686             } else if (CACHE_STORAGE_KEY.equals(key)) {
687                 if (value.indexOf('.') == -1) {
688                     int strongSize = 0;
689                     int softSize = 0;
690                     Map map = StringUtil.parseNameValuePairList(
691                             value, String.valueOf(Integer.MAX_VALUE));
692                     Iterator it = map.entrySet().iterator();
693                     while (it.hasNext()) {
694                         Map.Entry ent = (Map.Entry) it.next();
695                         String JavaDoc pname = (String JavaDoc) ent.getKey();
696                         int pvalue;
697                         try {
698                             pvalue = Integer.parseInt((String JavaDoc) ent.getValue());
699                         } catch (NumberFormatException JavaDoc e) {
700                             throw invalidSettingValueException(key, value);
701                         }
702                         if ("soft".equalsIgnoreCase(pname)) {
703                             softSize = pvalue;
704                         } else if ("strong".equalsIgnoreCase(pname)) {
705                             strongSize = pvalue;
706                         } else {
707                             throw invalidSettingValueException(key, value);
708                         }
709                     }
710                     if (softSize == 0 && strongSize == 0) {
711                         throw invalidSettingValueException(key, value);
712                     }
713                     setCacheStorage(new MruCacheStorage(strongSize, softSize));
714                 } else {
715                     setCacheStorage((CacheStorage) ClassUtil.forName(value)
716                             .newInstance());
717                 }
718             } else if (TEMPLATE_UPDATE_DELAY_KEY.equals(key)) {
719                 setTemplateUpdateDelay(Integer.parseInt(value));
720             } else if (AUTO_INCLUDE_KEY.equals(key)) {
721                 setAutoIncludes(new SettingStringParser(value).parseAsList());
722             } else if (AUTO_IMPORT_KEY.equals(key)) {
723                 setAutoImports(new SettingStringParser(value).parseAsImportList());
724             } else {
725                 super.setSetting(key, value);
726             }
727         } catch(TemplateException e) {
728             throw e;
729         } catch(Exception JavaDoc e) {
730             throw new TemplateException(
731                     "Failed to set setting " + key + " to value " + value,
732                     e, getEnvironment());
733         }
734     }
735     
736     
737     /**
738      * Add an auto-imported template.
739      * The importing will happen at the top of any template that
740      * is vended by this Configuration object.
741      * @param namespace the name of the namespace into which the template is imported
742      * @param template the name of the template
743      */

744     public synchronized void addAutoImport(String JavaDoc namespace, String JavaDoc template) {
745         autoImports.remove(namespace);
746         autoImports.add(namespace);
747         autoImportMap.put(namespace, template);
748     }
749     
750     /**
751      * Remove an auto-imported template
752      * @param namespace the name of the namespace into which the template was imported
753      */

754     
755     public synchronized void removeAutoImport(String JavaDoc namespace) {
756         autoImports.remove(namespace);
757         autoImportMap.remove(namespace);
758     }
759     
760     /**
761      * set a map of namespace names to templates for auto-importing
762      * a set of templates. Note that all previous auto-imports are removed.
763      */

764     
765     public synchronized void setAutoImports(Map map) {
766         autoImports = new ArrayList(map.keySet());
767         if (map instanceof HashMap) {
768             autoImportMap = (Map) ((HashMap) map).clone();
769         }
770         else if (map instanceof SortedMap) {
771             autoImportMap = new TreeMap(map);
772         }
773         else {
774             autoImportMap = new HashMap(map);
775         }
776     }
777     
778     void doAutoImports(Environment env) throws TemplateException, IOException {
779         for (int i=0; i<autoImports.size(); i++) {
780             String JavaDoc namespace = (String JavaDoc) autoImports.get(i);
781             String JavaDoc templateName = (String JavaDoc) autoImportMap.get(namespace);
782             env.importLib(templateName, namespace);
783         }
784     }
785     
786     /**
787      * add a template to be automatically included at the top of any template that
788      * is vended by this Configuration object.
789      * @param templateName the lookup name of the template.
790      */

791      
792     public synchronized void addAutoInclude(String JavaDoc templateName) {
793         autoIncludes.remove(templateName);
794         autoIncludes.add(templateName);
795     }
796
797     /**
798      * set the list of automatically included templates.
799      * Note that all previous auto-includes are removed.
800      */

801     public synchronized void setAutoIncludes(List templateNames) {
802         autoIncludes.clear();
803         Iterator it = templateNames.iterator();
804         while (it.hasNext()) {
805             Object JavaDoc o = it.next();
806             if (!(o instanceof String JavaDoc)) {
807                 throw new IllegalArgumentException JavaDoc("List items must be String-s.");
808             }
809             autoIncludes.add(o);
810         }
811     }
812     
813     /**
814      * remove a template from the auto-include list.
815      * @param templateName the lookup name of the template in question.
816      */

817      
818     public synchronized void removeAutoInclude(String JavaDoc templateName) {
819         autoIncludes.remove(templateName);
820     }
821
822     /**
823      * Returns FreeMarker version number string.
824      * Examples of possible return values:
825      * <code>"2.2.5"</code>, <code>"2.3pre13"</code>,
826      * <code>"2.3pre13mod"</code>, <code>"2.3rc1"</code>, <code>"2.3"</code>,
827      * <code>"3.0"</code>.
828      *
829      * <p>Notes on FreeMarker version numbering rules:
830      * <ul>
831      * <li>"pre" and "rc" (lowercase!) means "preview" and "release
832      * candidate" respectively. It is must be followed with a
833      * number (as "1" for the first release candidate).
834      * <li>The "mod" after the version number indicates that it's an
835      * unreleased modified version of the released version.
836      * After releases, the nighly builds are such releases. E.g.
837      * the nightly build after releasing "2.2.1" but before releasing
838      * "2.2.2" is "2.2.1mod".
839      * <li>The 2nd version number must be present, and maybe 0,
840      * as in "3.0".
841      * <li>The 3rd version number is never 0. E.g. the version
842      * number string for the first release of the 2.2 series
843      * is "2.2", and NOT "2.2.0".
844      * <li>When only the 3rd version number increases
845      * (2.2 -> 2.2.1, 2.2.1 -> 2.2.2 etc.), 100% backward compatiblity
846      * with the previous version MUST be kept.
847      * This means that <tt>freemarker.jar</tt> can be replaced in an
848      * application without risk (as far as the application doesn't depend
849      * on the presence of a FreeMarker bug).
850      * Note that backward compatibility restrictions do not apply for
851      * preview releases.
852      * </ul>
853      */

854     public static String JavaDoc getVersionNumber() {
855         if (cachedVersion != null) {
856             return cachedVersion;
857         }
858         try {
859             Properties vp = new Properties();
860             InputStream ins = Configuration.class.getClassLoader()
861                     .getResourceAsStream("freemarker/version.properties");
862             if (ins == null) {
863                 throw new RuntimeException JavaDoc("Version file is missing.");
864             } else {
865                 try {
866                     vp.load(ins);
867                 } finally {
868                     ins.close();
869                 }
870                 String JavaDoc v = vp.getProperty("version");
871                 if (v == null) {
872                     throw new RuntimeException JavaDoc("Version file is corrupt: version key is missing.");
873                 }
874                 cachedVersion = v;
875             }
876             return cachedVersion;
877         } catch (IOException e) {
878             throw new RuntimeException JavaDoc("Failed to load version file: " + e);
879         }
880     }
881     
882     void doAutoIncludes(Environment env) throws TemplateException, IOException {
883         for (int i = 0; i < autoIncludes.size(); i++) {
884             String JavaDoc templateName = (String JavaDoc) autoIncludes.get(i);
885             Template template = getTemplate(templateName, env.getLocale());
886             env.include(template);
887         }
888     }
889     
890 }
891
Popular Tags