Source Code Cross Referenced for Configurable.java in  » Template-Engine » freemarker-2.3.10 » freemarker » core » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Template Engine » freemarker 2.3.10 » freemarker.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright (c) 2003 The Visigoth Software Society. All rights
003:         * reserved.
004:         *
005:         * Redistribution and use in source and binary forms, with or without
006:         * modification, are permitted provided that the following conditions
007:         * are met:
008:         *
009:         * 1. Redistributions of source code must retain the above copyright
010:         *    notice, this list of conditions and the following disclaimer.
011:         *
012:         * 2. Redistributions in binary form must reproduce the above copyright
013:         *    notice, this list of conditions and the following disclaimer in
014:         *    the documentation and/or other materials provided with the
015:         *    distribution.
016:         *
017:         * 3. The end-user documentation included with the redistribution, if
018:         *    any, must include the following acknowledgement:
019:         *       "This product includes software developed by the
020:         *        Visigoth Software Society (http://www.visigoths.org/)."
021:         *    Alternately, this acknowledgement may appear in the software itself,
022:         *    if and wherever such third-party acknowledgements normally appear.
023:         *
024:         * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the 
025:         *    project contributors may be used to endorse or promote products derived
026:         *    from this software without prior written permission. For written
027:         *    permission, please contact visigoths@visigoths.org.
028:         *
029:         * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
030:         *    nor may "FreeMarker" or "Visigoth" appear in their names
031:         *    without prior written permission of the Visigoth Software Society.
032:         *
033:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
034:         * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
035:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
036:         * DISCLAIMED.  IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
037:         * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
038:         * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
039:         * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
040:         * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
041:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
042:         * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
043:         * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
044:         * SUCH DAMAGE.
045:         * ====================================================================
046:         *
047:         * This software consists of voluntary contributions made by many
048:         * individuals on behalf of the Visigoth Software Society. For more
049:         * information on the Visigoth Software Society, please see
050:         * http://www.visigoths.org/
051:         */
052:
053:        package freemarker.core;
054:
055:        import java.io.IOException;
056:        import java.io.InputStream;
057:        import java.util.*;
058:
059:        import freemarker.template.*;
060:        import freemarker.template.utility.ClassUtil;
061:        import freemarker.template.utility.StringUtil;
062:        import freemarker.ext.beans.BeansWrapper;
063:
064:        /**
065:         * This is a common superclass of {@link freemarker.template.Configuration},
066:         * {@link freemarker.template.Template}, and {@link Environment} classes.
067:         * It provides settings that are common to each of them. FreeMarker
068:         * uses a three-level setting hierarchy - the return value of every setting
069:         * getter method on <code>Configurable</code> objects inherits its value from its parent 
070:         * <code>Configurable</code> object, unless explicitly overridden by a call to a 
071:         * corresponding setter method on the object itself. The parent of an 
072:         * <code>Environment</code> object is a <code>Template</code> object, the
073:         * parent of a <code>Template</code> object is a <code>Configuration</code>
074:         * object.
075:         *
076:         * @version $Id: Configurable.java,v 1.23.2.2 2007/04/02 13:46:43 szegedia Exp $
077:         * @author Attila Szegedi
078:         */
079:        public class Configurable {
080:            public static final String LOCALE_KEY = "locale";
081:            public static final String NUMBER_FORMAT_KEY = "number_format";
082:            public static final String TIME_FORMAT_KEY = "time_format";
083:            public static final String DATE_FORMAT_KEY = "date_format";
084:            public static final String DATETIME_FORMAT_KEY = "datetime_format";
085:            public static final String TIME_ZONE_KEY = "time_zone";
086:            public static final String CLASSIC_COMPATIBLE_KEY = "classic_compatible";
087:            public static final String TEMPLATE_EXCEPTION_HANDLER_KEY = "template_exception_handler";
088:            public static final String ARITHMETIC_ENGINE_KEY = "arithmetic_engine";
089:            public static final String OBJECT_WRAPPER_KEY = "object_wrapper";
090:            public static final String BOOLEAN_FORMAT_KEY = "boolean_format";
091:            public static final String OUTPUT_ENCODING_KEY = "output_encoding";
092:            public static final String URL_ESCAPING_CHARSET_KEY = "url_escaping_charset";
093:            public static final String STRICT_BEAN_MODELS = "strict_bean_models";
094:
095:            private static final char COMMA = ',';
096:
097:            private Configurable parent;
098:            private Properties properties;
099:            private HashMap customAttributes;
100:
101:            private Locale locale;
102:            private String numberFormat;
103:            private String timeFormat;
104:            private String dateFormat;
105:            private String dateTimeFormat;
106:            private TimeZone timeZone;
107:            private String trueFormat;
108:            private String falseFormat;
109:            private Boolean classicCompatible;
110:            private TemplateExceptionHandler templateExceptionHandler;
111:            private ArithmeticEngine arithmeticEngine;
112:            private ObjectWrapper objectWrapper;
113:            private String outputEncoding;
114:            private boolean outputEncodingSet;
115:            private String urlEscapingCharset;
116:            private boolean urlEscapingCharsetSet;
117:
118:            public Configurable() {
119:                parent = null;
120:                locale = Locale.getDefault();
121:                timeZone = TimeZone.getDefault();
122:                numberFormat = "number";
123:                timeFormat = "";
124:                dateFormat = "";
125:                dateTimeFormat = "";
126:                trueFormat = "true";
127:                falseFormat = "false";
128:                classicCompatible = Boolean.FALSE;
129:                templateExceptionHandler = TemplateExceptionHandler.DEBUG_HANDLER;
130:                arithmeticEngine = ArithmeticEngine.BIGDECIMAL_ENGINE;
131:                objectWrapper = ObjectWrapper.DEFAULT_WRAPPER;
132:                // outputEncoding and urlEscapingCharset defaults to null,
133:                // which means "not specified"
134:
135:                properties = new Properties();
136:                properties.setProperty(LOCALE_KEY, locale.toString());
137:                properties.setProperty(TIME_FORMAT_KEY, timeFormat);
138:                properties.setProperty(DATE_FORMAT_KEY, dateFormat);
139:                properties.setProperty(DATETIME_FORMAT_KEY, dateTimeFormat);
140:                properties.setProperty(TIME_ZONE_KEY, timeZone.getID());
141:                properties.setProperty(NUMBER_FORMAT_KEY, numberFormat);
142:                properties.setProperty(CLASSIC_COMPATIBLE_KEY,
143:                        classicCompatible.toString());
144:                properties.setProperty(TEMPLATE_EXCEPTION_HANDLER_KEY,
145:                        templateExceptionHandler.getClass().getName());
146:                properties.setProperty(ARITHMETIC_ENGINE_KEY, arithmeticEngine
147:                        .getClass().getName());
148:                properties.setProperty(BOOLEAN_FORMAT_KEY, "true,false");
149:                // as outputEncoding and urlEscapingCharset defaults to null, 
150:                // they are not set
151:
152:                customAttributes = new HashMap();
153:            }
154:
155:            /**
156:             * Creates a new instance. Normally you do not need to use this constructor,
157:             * as you don't use <code>Configurable</code> directly, but its subclasses.
158:             */
159:            public Configurable(Configurable parent) {
160:                this .parent = parent;
161:                locale = null;
162:                numberFormat = null;
163:                trueFormat = null;
164:                falseFormat = null;
165:                classicCompatible = null;
166:                templateExceptionHandler = null;
167:                properties = new Properties(parent.properties);
168:                customAttributes = new HashMap();
169:            }
170:
171:            protected Object clone() throws CloneNotSupportedException {
172:                Configurable copy = (Configurable) super .clone();
173:                copy.properties = new Properties(properties);
174:                copy.customAttributes = (HashMap) customAttributes.clone();
175:                return copy;
176:            }
177:
178:            /**
179:             * Returns the parent <tt>Configurable</tt> object of this object.
180:             * The parent stores the default values for this configurable. For example,
181:             * the parent of the {@link freemarker.template.Template} object is the
182:             * {@link freemarker.template.Configuration} object, so setting values not
183:             * specfied on template level are specified by the confuration object.
184:             *
185:             * @return the parent <tt>Configurable</tt> object, or null, if this is
186:             *    the root <tt>Configurable</tt> object.
187:             */
188:            public final Configurable getParent() {
189:                return parent;
190:            }
191:
192:            /**
193:             * Reparenting support. This is used by Environment when it includes a
194:             * template - the included template becomes the parent configurable during
195:             * its evaluation.
196:             */
197:            final void setParent(Configurable parent) {
198:                this .parent = parent;
199:            }
200:
201:            /**
202:             * Toggles the "Classic Compatibile" mode. For a comprehensive description
203:             * of this mode, see {@link #isClassicCompatible()}.
204:             */
205:            public void setClassicCompatible(boolean classicCompatibility) {
206:                this .classicCompatible = classicCompatibility ? Boolean.TRUE
207:                        : Boolean.FALSE;
208:                properties.setProperty(CLASSIC_COMPATIBLE_KEY,
209:                        classicCompatible.toString());
210:            }
211:
212:            /**
213:             * Returns whether the engine runs in the "Classic Compatibile" mode.
214:             * When this mode is active, the engine behavior is altered in following
215:             * way: (these resemble the behavior of the 1.7.x line of FreeMarker engine,
216:             * now named "FreeMarker Classic", hence the name).
217:             * <ul>
218:             * <li>handle undefined expressions gracefully. Namely when an expression
219:             *   "expr" evaluates to null:
220:             *   <ul>
221:             *     <li>as argument of the <tt>&lt;assign varname=expr></tt> directive, 
222:             *       <tt>${expr}</tt> directive, <tt>otherexpr == expr</tt> or 
223:             *       <tt>otherexpr != expr</tt> conditional expressions, or 
224:             *       <tt>hash[expr]</tt> expression, then it is treated as empty string.
225:             *     </li>
226:             *     <li>as argument of <tt>&lt;list expr as item></tt> or 
227:             *       <tt>&lt;foreach item in expr></tt>, the loop body is not executed
228:             *       (as if it were a 0-length list)
229:             *     </li>
230:             *     <li>as argument of <tt>&lt;if></tt> directive, or otherwise where a
231:             *       boolean expression is expected, it is treated as false
232:             *     </li>
233:             *   </ul>
234:             * </li>
235:             * <li>Non-boolean models are accepted in <tt>&lt;if></tt> directive,
236:             *   or as operands of logical operators. "Empty" models (zero-length string,
237:             * empty sequence or hash) are evaluated as false, all others are evaluated as
238:             * true.</li>
239:             * <li>When boolean value is treated as a string (i.e. output in 
240:             *   <tt>${...}</tt> directive, or concatenated with other string), true 
241:             * values are converted to string "true", false values are converted to 
242:             * empty string.
243:             * </li>
244:             * <li>Scalar models supplied to <tt>&lt;list></tt> and 
245:             *   <tt>&lt;foreach></tt> are treated as a one-element list consisting
246:             *   of the passed model.
247:             * </li>
248:             * <li>Paths parameter of <tt>&lt;include></tt> will be interpreted as
249:             * absolute path.
250:             * </li>
251:             * </ul>
252:             * In all other aspects, the engine is a 2.1 engine even in compatibility
253:             * mode - you don't lose any of the new functionality by enabling it.
254:             */
255:            public boolean isClassicCompatible() {
256:                return classicCompatible != null ? classicCompatible
257:                        .booleanValue() : parent.isClassicCompatible();
258:            }
259:
260:            /**
261:             * Sets the locale to assume when searching for template files with no 
262:             * explicit requested locale.
263:             */
264:            public void setLocale(Locale locale) {
265:                if (locale == null)
266:                    throw new IllegalArgumentException(
267:                            "Setting \"locale\" can't be null");
268:                this .locale = locale;
269:                properties.setProperty(LOCALE_KEY, locale.toString());
270:            }
271:
272:            /**
273:             * Returns the time zone to use when formatting time values. Defaults to 
274:             * system time zone.
275:             */
276:            public TimeZone getTimeZone() {
277:                return timeZone != null ? timeZone : parent.getTimeZone();
278:            }
279:
280:            /**
281:             * Sets the time zone to use when formatting time values. 
282:             */
283:            public void setTimeZone(TimeZone timeZone) {
284:                if (timeZone == null)
285:                    throw new IllegalArgumentException(
286:                            "Setting \"time_zone\" can't be null");
287:                this .timeZone = timeZone;
288:                properties.setProperty(TIME_ZONE_KEY, timeZone.getID());
289:            }
290:
291:            /**
292:             * Returns the assumed locale when searching for template files with no
293:             * explicit requested locale. Defaults to system locale.
294:             */
295:            public Locale getLocale() {
296:                return locale != null ? locale : parent.getLocale();
297:            }
298:
299:            /**
300:             * Sets the number format used to convert numbers to strings.
301:             */
302:            public void setNumberFormat(String numberFormat) {
303:                if (numberFormat == null)
304:                    throw new IllegalArgumentException(
305:                            "Setting \"number_format\" can't be null");
306:                this .numberFormat = numberFormat;
307:                properties.setProperty(NUMBER_FORMAT_KEY, numberFormat);
308:            }
309:
310:            /**
311:             * Returns the default number format used to convert numbers to strings.
312:             * Defaults to <tt>"number"</tt>
313:             */
314:            public String getNumberFormat() {
315:                return numberFormat != null ? numberFormat : parent
316:                        .getNumberFormat();
317:            }
318:
319:            public void setBooleanFormat(String booleanFormat) {
320:                if (booleanFormat == null) {
321:                    throw new IllegalArgumentException(
322:                            "Setting \"boolean_format\" can't be null");
323:                }
324:                int comma = booleanFormat.indexOf(COMMA);
325:                if (comma == -1) {
326:                    throw new IllegalArgumentException(
327:                            "Setting \"boolean_format\" must consist of two comma-separated values for true and false respectively");
328:                }
329:                trueFormat = booleanFormat.substring(0, comma);
330:                falseFormat = booleanFormat.substring(comma + 1);
331:                properties.setProperty(BOOLEAN_FORMAT_KEY, booleanFormat);
332:            }
333:
334:            public String getBooleanFormat() {
335:                if (trueFormat == null) {
336:                    return parent.getBooleanFormat();
337:                }
338:                return trueFormat + COMMA + falseFormat;
339:            }
340:
341:            String getBooleanFormat(boolean value) {
342:                return value ? getTrueFormat() : getFalseFormat();
343:            }
344:
345:            private String getTrueFormat() {
346:                return trueFormat != null ? trueFormat : parent.getTrueFormat();
347:            }
348:
349:            private String getFalseFormat() {
350:                return falseFormat != null ? falseFormat : parent
351:                        .getFalseFormat();
352:            }
353:
354:            /**
355:             * Sets the date format used to convert date models representing time-only
356:             * values to strings.
357:             */
358:            public void setTimeFormat(String timeFormat) {
359:                if (timeFormat == null)
360:                    throw new IllegalArgumentException(
361:                            "Setting \"time_format\" can't be null");
362:                this .timeFormat = timeFormat;
363:                properties.setProperty(TIME_FORMAT_KEY, timeFormat);
364:            }
365:
366:            /**
367:             * Returns the date format used to convert date models representing
368:             * time-only dates to strings.
369:             * Defaults to <tt>"time"</tt>
370:             */
371:            public String getTimeFormat() {
372:                return timeFormat != null ? timeFormat : parent.getTimeFormat();
373:            }
374:
375:            /**
376:             * Sets the date format used to convert date models representing date-only
377:             * dates to strings.
378:             */
379:            public void setDateFormat(String dateFormat) {
380:                if (dateFormat == null)
381:                    throw new IllegalArgumentException(
382:                            "Setting \"date_format\" can't be null");
383:                this .dateFormat = dateFormat;
384:                properties.setProperty(DATE_FORMAT_KEY, dateFormat);
385:            }
386:
387:            /**
388:             * Returns the date format used to convert date models representing 
389:             * date-only dates to strings.
390:             * Defaults to <tt>"date"</tt>
391:             */
392:            public String getDateFormat() {
393:                return dateFormat != null ? dateFormat : parent.getDateFormat();
394:            }
395:
396:            /**
397:             * Sets the date format used to convert date models representing datetime
398:             * dates to strings.
399:             */
400:            public void setDateTimeFormat(String dateTimeFormat) {
401:                if (dateTimeFormat == null)
402:                    throw new IllegalArgumentException(
403:                            "Setting \"datetime_format\" can't be null");
404:                this .dateTimeFormat = dateTimeFormat;
405:                properties.setProperty(DATETIME_FORMAT_KEY, dateTimeFormat);
406:            }
407:
408:            /**
409:             * Returns the date format used to convert date models representing datetime
410:             * dates to strings.
411:             * Defaults to <tt>"datetime"</tt>
412:             */
413:            public String getDateTimeFormat() {
414:                return dateTimeFormat != null ? dateTimeFormat : parent
415:                        .getDateTimeFormat();
416:            }
417:
418:            /**
419:             * Sets the exception handler used to handle template exceptions. 
420:             *
421:             * @param templateExceptionHandler the template exception handler to use for 
422:             * handling {@link TemplateException}s. By default, 
423:             * {@link TemplateExceptionHandler#HTML_DEBUG_HANDLER} is used.
424:             */
425:            public void setTemplateExceptionHandler(
426:                    TemplateExceptionHandler templateExceptionHandler) {
427:                if (templateExceptionHandler == null)
428:                    throw new IllegalArgumentException(
429:                            "Setting \"template_exception_handler\" can't be null");
430:                this .templateExceptionHandler = templateExceptionHandler;
431:                properties.setProperty(TEMPLATE_EXCEPTION_HANDLER_KEY,
432:                        templateExceptionHandler.getClass().getName());
433:            }
434:
435:            /**
436:             * Retrieves the exception handler used to handle template exceptions. 
437:             */
438:            public TemplateExceptionHandler getTemplateExceptionHandler() {
439:                return templateExceptionHandler != null ? templateExceptionHandler
440:                        : parent.getTemplateExceptionHandler();
441:            }
442:
443:            /**
444:             * Sets the arithmetic engine used to perform arithmetic operations.
445:             *
446:             * @param arithmeticEngine the arithmetic engine used to perform arithmetic
447:             * operations.By default, {@link ArithmeticEngine#BIGDECIMAL_ENGINE} is 
448:             * used.
449:             */
450:            public void setArithmeticEngine(ArithmeticEngine arithmeticEngine) {
451:                if (arithmeticEngine == null)
452:                    throw new IllegalArgumentException(
453:                            "Setting \"arithmetic_engine\" can't be null");
454:                this .arithmeticEngine = arithmeticEngine;
455:                properties.setProperty(ARITHMETIC_ENGINE_KEY, arithmeticEngine
456:                        .getClass().getName());
457:            }
458:
459:            /**
460:             * Retrieves the arithmetic engine used to perform arithmetic operations.
461:             */
462:            public ArithmeticEngine getArithmeticEngine() {
463:                return arithmeticEngine != null ? arithmeticEngine : parent
464:                        .getArithmeticEngine();
465:            }
466:
467:            /**
468:             * Sets the object wrapper used to wrap objects to template models.
469:             *
470:             * @param objectWrapper the object wrapper used to wrap objects to template
471:             * models.By default, {@link ObjectWrapper#DEFAULT_WRAPPER} is used.
472:             */
473:            public void setObjectWrapper(ObjectWrapper objectWrapper) {
474:                if (objectWrapper == null)
475:                    throw new IllegalArgumentException(
476:                            "Setting \"object_wrapper\" can't be null");
477:                this .objectWrapper = objectWrapper;
478:                properties.setProperty(OBJECT_WRAPPER_KEY, objectWrapper
479:                        .getClass().getName());
480:            }
481:
482:            /**
483:             * Retrieves the object wrapper used to wrap objects to template models.
484:             */
485:            public ObjectWrapper getObjectWrapper() {
486:                return objectWrapper != null ? objectWrapper : parent
487:                        .getObjectWrapper();
488:            }
489:
490:            /**
491:             * Sets the output encoding. Allows <code>null</code>, which means that the
492:             * output encoding is not known.
493:             */
494:            public void setOutputEncoding(String outputEncoding) {
495:                this .outputEncoding = outputEncoding;
496:                // java.util.Properties doesn't allow null value!
497:                if (outputEncoding != null) {
498:                    properties.setProperty(OUTPUT_ENCODING_KEY, outputEncoding);
499:                } else {
500:                    properties.remove(OUTPUT_ENCODING_KEY);
501:                }
502:                outputEncodingSet = true;
503:            }
504:
505:            public String getOutputEncoding() {
506:                return outputEncodingSet ? outputEncoding
507:                        : (parent != null ? parent.getOutputEncoding() : null);
508:            }
509:
510:            /**
511:             * Sets the URL escaping charset. Allows <code>null</code>, which means that the
512:             * output encoding will be used for URL escaping.
513:             */
514:            public void setURLEscapingCharset(String urlEscapingCharset) {
515:                this .urlEscapingCharset = urlEscapingCharset;
516:                // java.util.Properties doesn't allow null value!
517:                if (urlEscapingCharset != null) {
518:                    properties.setProperty(URL_ESCAPING_CHARSET_KEY,
519:                            urlEscapingCharset);
520:                } else {
521:                    properties.remove(URL_ESCAPING_CHARSET_KEY);
522:                }
523:                urlEscapingCharsetSet = true;
524:            }
525:
526:            public String getURLEscapingCharset() {
527:                return urlEscapingCharsetSet ? urlEscapingCharset
528:                        : (parent != null ? parent.getURLEscapingCharset()
529:                                : null);
530:            }
531:
532:            /**
533:             * Sets a setting by a name and string value.
534:             * 
535:             * <p>List of supported names and their valid values:
536:             * <ul>
537:             *   <li><code>"locale"</code>: local codes with the usual format, such as <code>"en_US"</code>.
538:             *   <li><code>"classic_compatible"</code>:
539:             *       <code>"true"</code>, <code>"false"</code>, <code>"yes"</code>, <code>"no"</code>,
540:             *       <code>"t"</code>, <code>"f"</code>, <code>"y"</code>, <code>"n"</code>.
541:             *       Case insensitive.
542:             *   <li><code>"template_exception_handler"</code>:  If the value contains dot, then it is
543:             *       interpreted as class name, and the object will be created with
544:             *       its parameterless constructor. If the value does not contain dot,
545:             *       then it must be one of these special values:
546:             *       <code>"rethrow"</code>, <code>"debug"</code>,
547:             *       <code>"html_debug"</code>, <code>"ignore"</code> (case insensitive).
548:             *   <li><code>"arithmetic_engine"</code>: If the value contains dot, then it is
549:             *       interpreted as class name, and the object will be created with
550:             *       its parameterless constructor. If the value does not contain dot,
551:             *       then it must be one of these special values:
552:             *       <code>"bigdecimal"</code>, <code>"conservative"</code> (case insensitive).  
553:             *   <li><code>"object_wrapper"</code>: If the value contains dot, then it is
554:             *       interpreted as class name, and the object will be created with
555:             *       its parameterless constructor. If the value does not contain dot,
556:             *       then it must be one of these special values:
557:             *       <code>"simple"</code>, <code>"beans"</code>, <code>"jython"</code> (case insensitive).
558:             *   <li><code>"number_format"</code>: pattern as <code>java.text.DecimalFormat</code> defines.
559:             *   <li><code>"boolean_format"</code>: the textual value for boolean true and false,
560:             *       separated with comma. For example <code>"yes,no"</code>.
561:             *   <li><code>"date_format", "time_format", "datetime_format"</code>: patterns as
562:             *       <code>java.text.SimpleDateFormat</code> defines.
563:             *   <li><code>"time_zone"</code>: time zone, with the format as
564:             *       <code>java.util.TimeZone.getTimeZone</code> defines. For example <code>"GMT-8:00"</code> or
565:             *       <code>"America/Los_Angeles"</code>
566:             *   <li><code>"output_encoding"</code>: Informs FreeMarker about the charset
567:             *       used for the output. As FreeMarker outputs character stream (not
568:             *       byte stream), it is not aware of the output charset unless the
569:             *       software that encloses it tells it explicitly with this setting.
570:             *       Some templates may use FreeMarker features that require this.</code>
571:             *   <li><code>"url_escaping_charset"</code>: If this setting is set, then it
572:             *       overrides the value of the <code>"output_encoding"</code> setting when
573:             *       FreeMarker does URL encoding.
574:             * </ul>
575:             * 
576:             * @param key the name of the setting.
577:             * @param value the string that describes the new value of the setting.
578:             * 
579:             * @throws UnknownSettingException if the key is wrong.
580:             * @throws TemplateException if the new value of the setting can't be set
581:             *     for any other reasons.
582:             */
583:            public void setSetting(String key, String value)
584:                    throws TemplateException {
585:                try {
586:                    if (LOCALE_KEY.equals(key)) {
587:                        setLocale(StringUtil.deduceLocale(value));
588:                    } else if (NUMBER_FORMAT_KEY.equals(key)) {
589:                        setNumberFormat(value);
590:                    } else if (TIME_FORMAT_KEY.equals(key)) {
591:                        setTimeFormat(value);
592:                    } else if (DATE_FORMAT_KEY.equals(key)) {
593:                        setDateFormat(value);
594:                    } else if (DATETIME_FORMAT_KEY.equals(key)) {
595:                        setDateTimeFormat(value);
596:                    } else if (TIME_ZONE_KEY.equals(key)) {
597:                        setTimeZone(TimeZone.getTimeZone(value));
598:                    } else if (CLASSIC_COMPATIBLE_KEY.equals(key)) {
599:                        setClassicCompatible(StringUtil.getYesNo(value));
600:                    } else if (TEMPLATE_EXCEPTION_HANDLER_KEY.equals(key)) {
601:                        if (value.indexOf('.') == -1) {
602:                            if ("debug".equalsIgnoreCase(value)) {
603:                                setTemplateExceptionHandler(TemplateExceptionHandler.DEBUG_HANDLER);
604:                            } else if ("html_debug".equalsIgnoreCase(value)) {
605:                                setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
606:                            } else if ("ignore".equalsIgnoreCase(value)) {
607:                                setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
608:                            } else if ("rethrow".equalsIgnoreCase(value)) {
609:                                setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
610:                            } else {
611:                                throw invalidSettingValueException(key, value);
612:                            }
613:                        } else {
614:                            setTemplateExceptionHandler((TemplateExceptionHandler) ClassUtil
615:                                    .forName(value).newInstance());
616:                        }
617:                    } else if (ARITHMETIC_ENGINE_KEY.equals(key)) {
618:                        if (value.indexOf('.') == -1) {
619:                            if ("bigdecimal".equalsIgnoreCase(value)) {
620:                                setArithmeticEngine(ArithmeticEngine.BIGDECIMAL_ENGINE);
621:                            } else if ("conservative".equalsIgnoreCase(value)) {
622:                                setArithmeticEngine(ArithmeticEngine.CONSERVATIVE_ENGINE);
623:                            } else {
624:                                throw invalidSettingValueException(key, value);
625:                            }
626:                        } else {
627:                            setArithmeticEngine((ArithmeticEngine) ClassUtil
628:                                    .forName(value).newInstance());
629:                        }
630:                    } else if (OBJECT_WRAPPER_KEY.equals(key)) {
631:                        if (value.indexOf('.') == -1) {
632:                            if ("default".equalsIgnoreCase(value)) {
633:                                setObjectWrapper(ObjectWrapper.DEFAULT_WRAPPER);
634:                            } else if ("simple".equalsIgnoreCase(value)) {
635:                                setObjectWrapper(ObjectWrapper.SIMPLE_WRAPPER);
636:                            } else if ("beans".equalsIgnoreCase(value)) {
637:                                setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
638:                            } else if ("jython".equalsIgnoreCase(value)) {
639:                                Class clazz = Class
640:                                        .forName("freemarker.ext.jython.JythonWrapper");
641:                                setObjectWrapper((ObjectWrapper) clazz
642:                                        .getField("INSTANCE").get(null));
643:                            } else {
644:                                throw invalidSettingValueException(key, value);
645:                            }
646:
647:                        } else {
648:                            setObjectWrapper((ObjectWrapper) ClassUtil.forName(
649:                                    value).newInstance());
650:                        }
651:                    } else if (BOOLEAN_FORMAT_KEY.equals(key)) {
652:                        setBooleanFormat(value);
653:                    } else if (OUTPUT_ENCODING_KEY.equals(key)) {
654:                        setOutputEncoding(value);
655:                    } else if (URL_ESCAPING_CHARSET_KEY.equals(key)) {
656:                        setURLEscapingCharset(value);
657:                    } else if (STRICT_BEAN_MODELS.equals(key)) {
658:                        setStrictBeanModels(StringUtil.getYesNo(value));
659:                    } else {
660:                        throw unknownSettingException(key);
661:                    }
662:                } catch (TemplateException e) {
663:                    throw e;
664:                } catch (Exception e) {
665:                    throw new TemplateException("Failed to set setting " + key
666:                            + " to value " + value, e, getEnvironment());
667:                }
668:            }
669:
670:            public void setStrictBeanModels(boolean strict) {
671:                if (!(objectWrapper instanceof  BeansWrapper)) {
672:                    throw new IllegalStateException("Not a beans wrapper");
673:                }
674:                ((BeansWrapper) objectWrapper).setStrict(strict);
675:            }
676:
677:            /**
678:             * Returns the textual representation of a setting.
679:             * @param key the setting key. Can be any of standard <tt>XXX_KEY</tt>
680:             * constants, or a custom key.
681:             *
682:             * @deprecated This method was always defective, and certainly it always
683:             *     will be. Don't use it. (Simply, it's hardly possible in general to
684:             *     convert setting values to text in a way that ensures that
685:             *     {@link #setSetting(String, String)} will work with them correctly.)
686:             */
687:            public String getSetting(String key) {
688:                return properties.getProperty(key);
689:            }
690:
691:            /**
692:             * This meant to return the String-to-String <code>Map</code> of the
693:             * settings. So it actually should return a <code>Properties</code> object,
694:             * but it doesn't by mistake. The returned <code>Map</code> is read-only,
695:             * but it will reflect the further configuration changes (aliasing effect).
696:             *
697:             * @deprecated This method was always defective, and certainly it always
698:             *     will be. Don't use it. (Simply, it's hardly possible in general to
699:             *     convert setting values to text in a way that ensures that
700:             *     {@link #setSettings(Properties)} will work with them correctly.)
701:             */
702:            public Map getSettings() {
703:                return Collections.unmodifiableMap(properties);
704:            }
705:
706:            protected Environment getEnvironment() {
707:                return this  instanceof  Environment ? (Environment) this 
708:                        : Environment.getCurrentEnvironment();
709:            }
710:
711:            protected TemplateException unknownSettingException(String name) {
712:                return new UnknownSettingException(name, getEnvironment());
713:            }
714:
715:            protected TemplateException invalidSettingValueException(
716:                    String name, String value) {
717:                return new TemplateException("Invalid value for setting "
718:                        + name + ": " + value, getEnvironment());
719:            }
720:
721:            public class UnknownSettingException extends TemplateException {
722:                private UnknownSettingException(String name, Environment env) {
723:                    super ("Unknown setting: " + name, env);
724:                }
725:            }
726:
727:            /**
728:             * Set the settings stored in a <code>Properties</code> object.
729:             * 
730:             * @throws TemplateException if the <code>Properties</code> object contains
731:             *     invalid keys, or invalid setting values, or any other error occurs
732:             *     while changing the settings.
733:             */
734:            public void setSettings(Properties props) throws TemplateException {
735:                Iterator it = props.keySet().iterator();
736:                while (it.hasNext()) {
737:                    String key = (String) it.next();
738:                    setSetting(key, props.getProperty(key).trim());
739:                }
740:            }
741:
742:            /**
743:             * Reads a setting list (key and element pairs) from the input stream.
744:             * The stream has to follow the usual <code>.properties</code> format.
745:             *
746:             * @throws TemplateException if the stream contains
747:             *     invalid keys, or invalid setting values, or any other error occurs
748:             *     while changing the settings.
749:             * @throws IOException if an error occurred when reading from the input stream.
750:             */
751:            public void setSettings(InputStream propsIn)
752:                    throws TemplateException, IOException {
753:                Properties p = new Properties();
754:                p.load(propsIn);
755:                setSettings(p);
756:            }
757:
758:            /**
759:             * Internal entry point for setting unnamed custom attributes
760:             */
761:            void setCustomAttribute(Object key, Object value) {
762:                synchronized (customAttributes) {
763:                    customAttributes.put(key, value);
764:                }
765:            }
766:
767:            /**
768:             * Internal entry point for getting unnamed custom attributes
769:             */
770:            Object getCustomAttribute(Object key, CustomAttribute attr) {
771:                synchronized (customAttributes) {
772:                    Object o = customAttributes.get(key);
773:                    if (o == null && !customAttributes.containsKey(key)) {
774:                        o = attr.create();
775:                        customAttributes.put(key, o);
776:                    }
777:                    return o;
778:                }
779:            }
780:
781:            /**
782:             * Sets a named custom attribute for this configurable.
783:             *
784:             * @param name the name of the custom attribute
785:             * @param value the value of the custom attribute. You can set the value to
786:             * null, however note that there is a semantic difference between an
787:             * attribute set to null and an attribute that is not present, see
788:             * {@link #removeCustomAttribute(String)}.
789:             */
790:            public void setCustomAttribute(String name, Object value) {
791:                synchronized (customAttributes) {
792:                    customAttributes.put(name, value);
793:                }
794:            }
795:
796:            /**
797:             * Returns an array with names of all custom attributes defined directly 
798:             * on this configurable. (That is, it doesn't contain the names of custom attributes
799:             * defined indirectly on its parent configurables.) The returned array is never null,
800:             * but can be zero-length.
801:             * The order of elements in the returned array is not defined and can change
802:             * between invocations.  
803:             */
804:            public String[] getCustomAttributeNames() {
805:                synchronized (customAttributes) {
806:                    Collection names = new LinkedList(customAttributes.keySet());
807:                    for (Iterator iter = names.iterator(); iter.hasNext();) {
808:                        if (!(iter.next() instanceof  String)) {
809:                            iter.remove();
810:                        }
811:                    }
812:                    return (String[]) names.toArray(new String[names.size()]);
813:                }
814:            }
815:
816:            /**
817:             * Removes a named custom attribute for this configurable. Note that this
818:             * is different than setting the custom attribute value to null. If you
819:             * set the value to null, {@link #getCustomAttribute(String)} will return
820:             * null, while if you remove the attribute, it will return the value of
821:             * the attribute in the parent configurable (if there is a parent 
822:             * configurable, that is). 
823:             *
824:             * @param name the name of the custom attribute
825:             */
826:            public void removeCustomAttribute(String name) {
827:                synchronized (customAttributes) {
828:                    customAttributes.remove(name);
829:                }
830:            }
831:
832:            /**
833:             * Retrieves a named custom attribute for this configurable. If the 
834:             * attribute is not present in the configurable, and the configurable has
835:             * a parent, then the parent is looked up as well.
836:             *
837:             * @param name the name of the custom attribute
838:             *
839:             * @return the value of the custom attribute. Note that if the custom attribute
840:             * was created with <tt>&lt;#ftl&nbsp;attributes={...}></tt>, then this value is already
841:             * unwrapped (i.e. it's a <code>String</code>, or a <code>List</code>, or a
842:             * <code>Map</code>, ...etc., not a FreeMarker specific class).
843:             */
844:            public Object getCustomAttribute(String name) {
845:                Object retval;
846:                synchronized (customAttributes) {
847:                    retval = customAttributes.get(name);
848:                    if (retval == null && customAttributes.containsKey(name)) {
849:                        return null;
850:                    }
851:                }
852:                if (retval == null && parent != null) {
853:                    return parent.getCustomAttribute(name);
854:                }
855:                return retval;
856:            }
857:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.