KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > displaytag > properties > TableProperties


1 /**
2  * Licensed under the Artistic License; you may not use this file
3  * except in compliance with the License.
4  * You may obtain a copy of the License at
5  *
6  * http://displaytag.sourceforge.net/license.html
7  *
8  * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
9  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11  */

12 package org.displaytag.properties;
13
14 import java.io.IOException JavaDoc;
15 import java.util.Enumeration JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.Locale JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.MissingResourceException JavaDoc;
20 import java.util.Properties JavaDoc;
21 import java.util.ResourceBundle JavaDoc;
22
23 import javax.servlet.http.HttpServletRequest JavaDoc;
24 import javax.servlet.jsp.PageContext JavaDoc;
25 import javax.servlet.jsp.tagext.Tag JavaDoc;
26
27 import org.apache.commons.lang.ClassUtils;
28 import org.apache.commons.lang.StringUtils;
29 import org.apache.commons.lang.UnhandledException;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.displaytag.Messages;
33 import org.displaytag.decorator.DecoratorFactory;
34 import org.displaytag.decorator.DefaultDecoratorFactory;
35 import org.displaytag.exception.FactoryInstantiationException;
36 import org.displaytag.exception.TablePropertiesLoadException;
37 import org.displaytag.localization.I18nResourceProvider;
38 import org.displaytag.localization.LocaleResolver;
39 import org.displaytag.util.DefaultRequestHelperFactory;
40 import org.displaytag.util.ReflectHelper;
41 import org.displaytag.util.RequestHelperFactory;
42
43
44 /**
45  * The properties used by the Table tags. The properties are loaded in the following order, in increasing order of
46  * priority. The locale of getInstance() is used to determine the locale of the property file to use; if the key
47  * required does not exist in the specified file, the key will be loaded from a more general property file.
48  * <ol>
49  * <li>First, from the TableTag.properties included with the DisplayTag distribution.</li>
50  * <li>Then, from the file displaytag.properties, if it is present; these properties are intended to be set by the user
51  * for sitewide application. Messages are gathered according to the Locale of the property file.</li>
52  * <li>Finally, if this class has a userProperties defined, all of the properties from that Properties object are
53  * copied in as well.</li>
54  * </ol>
55  * @author Fabrizio Giustina
56  * @author rapruitt
57  * @version $Revision: 987 $ ($Author: fgiust $)
58  */

59 public final class TableProperties implements Cloneable JavaDoc
60 {
61
62     /**
63      * name of the default properties file name ("displaytag.properties").
64      */

65     public static final String JavaDoc DEFAULT_FILENAME = "displaytag.properties"; //$NON-NLS-1$
66

67     /**
68      * The name of the local properties file that is searched for on the classpath. Settings in this file will override
69      * the defaults loaded from TableTag.properties.
70      */

71     public static final String JavaDoc LOCAL_PROPERTIES = "displaytag"; //$NON-NLS-1$
72

73     /**
74      * property <code>export.banner</code>.
75      */

76     public static final String JavaDoc PROPERTY_STRING_EXPORTBANNER = "export.banner"; //$NON-NLS-1$
77

78     /**
79      * property <code>export.banner.sepchar</code>.
80      */

81     public static final String JavaDoc PROPERTY_STRING_EXPORTBANNER_SEPARATOR = "export.banner.sepchar"; //$NON-NLS-1$
82

83     /**
84      * property <code>export.decorated</code>.
85      */

86     public static final String JavaDoc PROPERTY_BOOLEAN_EXPORTDECORATED = "export.decorated"; //$NON-NLS-1$
87

88     /**
89      * property <code>export.amount</code>.
90      */

91     public static final String JavaDoc PROPERTY_STRING_EXPORTAMOUNT = "export.amount"; //$NON-NLS-1$
92

93     /**
94      * property <code>sort.amount</code>.
95      */

96     public static final String JavaDoc PROPERTY_STRING_SORTAMOUNT = "sort.amount"; //$NON-NLS-1$
97

98     /**
99      * property <code>basic.show.header</code>.
100      */

101     public static final String JavaDoc PROPERTY_BOOLEAN_SHOWHEADER = "basic.show.header"; //$NON-NLS-1$
102

103     /**
104      * property <code>basic.msg.empty_list</code>.
105      */

106     public static final String JavaDoc PROPERTY_STRING_EMPTYLIST_MESSAGE = "basic.msg.empty_list"; //$NON-NLS-1$
107

108     /**
109      * property <code>basic.msg.empty_list_row</code>.
110      */

111     public static final String JavaDoc PROPERTY_STRING_EMPTYLISTROW_MESSAGE = "basic.msg.empty_list_row"; //$NON-NLS-1$
112

113     /**
114      * property <code>basic.empty.showtable</code>.
115      */

116     public static final String JavaDoc PROPERTY_BOOLEAN_EMPTYLIST_SHOWTABLE = "basic.empty.showtable"; //$NON-NLS-1$
117

118     /**
119      * property <code>paging.banner.placement</code>.
120      */

121     public static final String JavaDoc PROPERTY_STRING_BANNER_PLACEMENT = "paging.banner.placement"; //$NON-NLS-1$
122

123     /**
124      * property <code>error.msg.invalid_page</code>.
125      */

126     public static final String JavaDoc PROPERTY_STRING_PAGING_INVALIDPAGE = "error.msg.invalid_page"; //$NON-NLS-1$
127

128     /**
129      * property <code>paging.banner.item_name</code>.
130      */

131     public static final String JavaDoc PROPERTY_STRING_PAGING_ITEM_NAME = "paging.banner.item_name"; //$NON-NLS-1$
132

133     /**
134      * property <code>paging.banner.items_name</code>.
135      */

136     public static final String JavaDoc PROPERTY_STRING_PAGING_ITEMS_NAME = "paging.banner.items_name"; //$NON-NLS-1$
137

138     /**
139      * property <code>paging.banner.no_items_found</code>.
140      */

141     public static final String JavaDoc PROPERTY_STRING_PAGING_NOITEMS = "paging.banner.no_items_found"; //$NON-NLS-1$
142

143     /**
144      * property <code>paging.banner.one_item_found</code>.
145      */

146     public static final String JavaDoc PROPERTY_STRING_PAGING_FOUND_ONEITEM = "paging.banner.one_item_found"; //$NON-NLS-1$
147

148     /**
149      * property <code>paging.banner.all_items_found</code>.
150      */

151     public static final String JavaDoc PROPERTY_STRING_PAGING_FOUND_ALLITEMS = "paging.banner.all_items_found"; //$NON-NLS-1$
152

153     /**
154      * property <code>paging.banner.some_items_found</code>.
155      */

156     public static final String JavaDoc PROPERTY_STRING_PAGING_FOUND_SOMEITEMS = "paging.banner.some_items_found"; //$NON-NLS-1$
157

158     /**
159      * property <code>paging.banner.group_size</code>.
160      */

161     public static final String JavaDoc PROPERTY_INT_PAGING_GROUPSIZE = "paging.banner.group_size"; //$NON-NLS-1$
162

163     /**
164      * property <code>paging.banner.onepage</code>.
165      */

166     public static final String JavaDoc PROPERTY_STRING_PAGING_BANNER_ONEPAGE = "paging.banner.onepage"; //$NON-NLS-1$
167

168     /**
169      * property <code>paging.banner.first</code>.
170      */

171     public static final String JavaDoc PROPERTY_STRING_PAGING_BANNER_FIRST = "paging.banner.first"; //$NON-NLS-1$
172

173     /**
174      * property <code>paging.banner.last</code>.
175      */

176     public static final String JavaDoc PROPERTY_STRING_PAGING_BANNER_LAST = "paging.banner.last"; //$NON-NLS-1$
177

178     /**
179      * property <code>paging.banner.full</code>.
180      */

181     public static final String JavaDoc PROPERTY_STRING_PAGING_BANNER_FULL = "paging.banner.full"; //$NON-NLS-1$
182

183     /**
184      * property <code>paging.banner.page.link</code>.
185      */

186     public static final String JavaDoc PROPERTY_STRING_PAGING_PAGE_LINK = "paging.banner.page.link"; //$NON-NLS-1$
187

188     /**
189      * property <code>paging.banner.page.selected</code>.
190      */

191     public static final String JavaDoc PROPERTY_STRING_PAGING_PAGE_SELECTED = "paging.banner.page.selected"; //$NON-NLS-1$
192

193     /**
194      * property <code>paging.banner.page.separator</code>.
195      */

196     public static final String JavaDoc PROPERTY_STRING_PAGING_PAGE_SPARATOR = "paging.banner.page.separator"; //$NON-NLS-1$
197

198     /**
199      * property <code>factory.requestHelper</code>.
200      */

201     public static final String JavaDoc PROPERTY_CLASS_REQUESTHELPERFACTORY = "factory.requestHelper"; //$NON-NLS-1$
202

203     /**
204      * property <code>factory.decorators</code>.
205      */

206     public static final String JavaDoc PROPERTY_CLASS_DECORATORFACTORY = "factory.decorator"; //$NON-NLS-1$
207

208     /**
209      * property <code>locale.provider</code>.
210      */

211     public static final String JavaDoc PROPERTY_CLASS_LOCALEPROVIDER = "locale.provider"; //$NON-NLS-1$
212

213     /**
214      * property <code>locale.resolver</code>.
215      */

216     public static final String JavaDoc PROPERTY_CLASS_LOCALERESOLVER = "locale.resolver"; //$NON-NLS-1$
217

218     /**
219      * property <code>css.tr.even</code>: holds the name of the css class for even rows. Defaults to
220      * <code>even</code>.
221      */

222     public static final String JavaDoc PROPERTY_CSS_TR_EVEN = "css.tr.even"; //$NON-NLS-1$
223

224     /**
225      * property <code>css.tr.odd</code>: holds the name of the css class for odd rows. Defaults to <code>odd</code>.
226      */

227     public static final String JavaDoc PROPERTY_CSS_TR_ODD = "css.tr.odd"; //$NON-NLS-1$
228

229     /**
230      * property <code>css.table</code>: holds the name of the css class added to the main table tag. By default no
231      * css class is added.
232      */

233     public static final String JavaDoc PROPERTY_CSS_TABLE = "css.table"; //$NON-NLS-1$
234

235     /**
236      * property <code>css.th.sortable</code>: holds the name of the css class added to the the header of a sortable
237      * column. By default no css class is added.
238      */

239     public static final String JavaDoc PROPERTY_CSS_TH_SORTABLE = "css.th.sortable"; //$NON-NLS-1$
240

241     /**
242      * property <code>css.th.sorted</code>: holds the name of the css class added to the the header of a sorted
243      * column. Defaults to <code>sorted</code>.
244      */

245     public static final String JavaDoc PROPERTY_CSS_TH_SORTED = "css.th.sorted"; //$NON-NLS-1$
246

247     /**
248      * property <code>css.th.ascending</code>: holds the name of the css class added to the the header of a column
249      * sorted in ascending order. Defaults to <code>order1</code>.
250      */

251     public static final String JavaDoc PROPERTY_CSS_TH_SORTED_ASCENDING = "css.th.ascending"; //$NON-NLS-1$
252

253     /**
254      * property <code>css.th.descending</code>: holds the name of the css class added to the the header of a column
255      * sorted in descending order. Defaults to <code>order2</code>.
256      */

257     public static final String JavaDoc PROPERTY_CSS_TH_SORTED_DESCENDING = "css.th.descending"; //$NON-NLS-1$
258

259     /**
260      * prefix used for all the properties related to export ("export"). The full property name is <code>export.</code>
261      * <em>[export type]</em><code>.</code><em>[property name]</em>
262      */

263     public static final String JavaDoc PROPERTY_EXPORT_PREFIX = "export"; //$NON-NLS-1$
264

265     /**
266      * suffix used to set the export decorator property name. The full property name is <code>export.</code>
267      * <em>[export type]</em><code>.</code><em>decorator</em>
268      */

269     public static final String JavaDoc PROPERTY_EXPORT_DECORATOR_SUFFIX = "decorator"; //$NON-NLS-1$
270

271     /**
272      * property <code>export.types</code>: holds the list of export available export types.
273      */

274     public static final String JavaDoc PROPERTY_EXPORTTYPES = "export.types"; //$NON-NLS-1$
275

276     /**
277      * export property <code>label</code>.
278      */

279     public static final String JavaDoc EXPORTPROPERTY_STRING_LABEL = "label"; //$NON-NLS-1$
280

281     /**
282      * export property <code>class</code>.
283      */

284     public static final String JavaDoc EXPORTPROPERTY_STRING_CLASS = "class"; //$NON-NLS-1$
285

286     /**
287      * export property <code>include_header</code>.
288      */

289     public static final String JavaDoc EXPORTPROPERTY_BOOLEAN_EXPORTHEADER = "include_header"; //$NON-NLS-1$
290

291     /**
292      * export property <code>filename</code>.
293      */

294     public static final String JavaDoc EXPORTPROPERTY_STRING_FILENAME = "filename"; //$NON-NLS-1$
295

296     /**
297      * Property <code>pagination.sort.param</code>. If external pagination and sorting is used, it holds the name of
298      * the parameter used to hold the sort criterion in generated links
299      */

300     public static final String JavaDoc PROPERTY_STRING_PAGINATION_SORT_PARAM = "pagination.sort.param"; //$NON-NLS-1$
301

302     /**
303      * Property <code>pagination.sortdirection.param</code>. If external pagination and sorting is used, it holds the
304      * name of the parameter used to hold the sort direction in generated links (asc or desc)
305      */

306     public static final String JavaDoc PROPERTY_STRING_PAGINATION_SORT_DIRECTION_PARAM = "pagination.sortdirection.param"; //$NON-NLS-1$
307

308     /**
309      * Property <code>pagination.pagenumber.param</code>. If external pagination and sorting is used, it holds the
310      * name of the parameter used to hold the page number in generated links
311      */

312     public static final String JavaDoc PROPERTY_STRING_PAGINATION_PAGE_NUMBER_PARAM = "pagination.pagenumber.param"; //$NON-NLS-1$
313

314     /**
315      * Property <code>pagination.searchid.param</code>. If external pagination and sorting is used, it holds the name
316      * of the parameter used to hold the search ID in generated links
317      */

318     public static final String JavaDoc PROPERTY_STRING_PAGINATION_SEARCH_ID_PARAM = "pagination.searchid.param"; //$NON-NLS-1$
319

320     /**
321      * Property <code>pagination.sort.asc.value</code>. If external pagination and sorting is used, it holds the
322      * value of the parameter of the sort direction parameter for "ascending"
323      */

324     public static final String JavaDoc PROPERTY_STRING_PAGINATION_ASC_VALUE = "pagination.sort.asc.value"; //$NON-NLS-1$
325

326     /**
327      * Property <code>pagination.sort.desc.value</code>. If external pagination and sorting is used, it holds the
328      * value of the parameter of the sort direction parameter for "descending"
329      */

330     public static final String JavaDoc PROPERTY_STRING_PAGINATION_DESC_VALUE = "pagination.sort.desc.value"; //$NON-NLS-1$
331

332     /**
333      * Property <code>pagination.sort.skippagenumber</code>. If external pagination and sorting is used, it
334      * determines if the current page number must be added in sort links or not. If this property is true, it means that
335      * each click on a generated sort link will re-sort the list, and go back to the default page number. If it is
336      * false, each click on a generated sort link will re-sort the list, and ask the current page number.
337      */

338     public static final String JavaDoc PROPERTY_BOOLEAN_PAGINATION_SKIP_PAGE_NUMBER_IN_SORT = "pagination.sort.skippagenumber"; //$NON-NLS-1$
339

340     // </JBN>
341

342     /**
343      * Separator char used in property names.
344      */

345     private static final char SEP = '.';
346
347     /**
348      * logger.
349      */

350     private static Log log = LogFactory.getLog(TableProperties.class);
351
352     /**
353      * The userProperties are local, non-default properties; these settings override the defaults from
354      * displaytag.properties and TableTag.properties.
355      */

356     private static Properties JavaDoc userProperties = new Properties JavaDoc();
357
358     /**
359      * Configured resource provider. If no ResourceProvider is configured, an no-op one is used. This instance is
360      * initialized at first use and shared.
361      */

362     private static I18nResourceProvider resourceProvider;
363
364     /**
365      * Configured locale resolver.
366      */

367     private static LocaleResolver localeResolver;
368
369     /**
370      * TableProperties for each locale are loaded as needed, and cloned for public usage.
371      */

372     private static Map JavaDoc prototypes = new HashMap JavaDoc();
373
374     /**
375      * Loaded properties (defaults from defaultProperties + custom from bundle).
376      */

377     private Properties JavaDoc properties;
378
379     /**
380      * The locale for these properties.
381      */

382     private Locale JavaDoc locale;
383
384     /**
385      * Cache for dinamically instantiated object (request factory, decorator factory).
386      */

387     private Map JavaDoc objectCache = new HashMap JavaDoc();
388
389     /**
390      * Setter for I18nResourceProvider. A resource provider is usually set using displaytag properties, this accessor is
391      * needed for tests.
392      * @param provider I18nResourceProvider instance
393      */

394     protected static void setResourceProvider(I18nResourceProvider provider)
395     {
396         resourceProvider = provider;
397     }
398
399     /**
400      * Setter for LocaleResolver. A locale resolver is usually set using displaytag properties, this accessor is needed
401      * for tests.
402      * @param resolver LocaleResolver instance
403      */

404     protected static void setLocaleResolver(LocaleResolver resolver)
405     {
406         localeResolver = resolver;
407     }
408
409     /**
410      * Loads default properties (TableTag.properties).
411      * @return loaded properties
412      * @throws TablePropertiesLoadException if default properties file can't be found
413      */

414     private static Properties JavaDoc loadBuiltInProperties() throws TablePropertiesLoadException
415     {
416         Properties JavaDoc defaultProperties = new Properties JavaDoc();
417
418         try
419         {
420             defaultProperties.load(TableProperties.class.getResourceAsStream(DEFAULT_FILENAME));
421         }
422         catch (IOException JavaDoc e)
423         {
424             throw new TablePropertiesLoadException(TableProperties.class, DEFAULT_FILENAME, e);
425         }
426
427         return defaultProperties;
428     }
429
430     /**
431      * Loads user properties (displaytag.properties) according to the given locale. User properties are not guarantee to
432      * exist, so the method can return <code>null</code> (no exception will be thrown).
433      * @param locale requested Locale
434      * @return loaded properties
435      */

436     private static ResourceBundle JavaDoc loadUserProperties(Locale JavaDoc locale)
437     {
438         ResourceBundle JavaDoc bundle = null;
439         try
440         {
441             bundle = ResourceBundle.getBundle(LOCAL_PROPERTIES, locale);
442         }
443         catch (MissingResourceException JavaDoc e)
444         {
445             // if no resource bundle is found, try using the context classloader
446
try
447             {
448                 bundle = ResourceBundle.getBundle(LOCAL_PROPERTIES, locale, Thread
449                     .currentThread()
450                     .getContextClassLoader());
451             }
452             catch (MissingResourceException JavaDoc mre)
453             {
454                 if (log.isDebugEnabled())
455                 {
456                     log.debug(Messages.getString("TableProperties.propertiesnotfound", //$NON-NLS-1$
457
new Object JavaDoc[]{mre.getMessage()}));
458                 }
459             }
460         }
461
462         return bundle;
463     }
464
465     /**
466      * Returns the configured Locale Resolver. This method is called before the loading of localized properties.
467      * @return LocaleResolver instance.
468      * @throws TablePropertiesLoadException if the default <code>TableTag.properties</code> file is not found.
469      */

470     public static LocaleResolver getLocaleResolverInstance() throws TablePropertiesLoadException
471     {
472
473         if (localeResolver == null)
474         {
475
476             // special handling, table properties is not yet instantiated
477
String JavaDoc className = null;
478
479             ResourceBundle JavaDoc defaultUserProperties = loadUserProperties(Locale.getDefault());
480
481             // if available, user properties have higher precedence
482
if (defaultUserProperties != null)
483             {
484                 try
485                 {
486                     className = defaultUserProperties.getString(PROPERTY_CLASS_LOCALERESOLVER);
487                 }
488                 catch (MissingResourceException JavaDoc e)
489                 {
490                     // no problem
491
}
492             }
493
494             // still null? load defaults
495
if (className == null)
496             {
497                 Properties JavaDoc defaults = loadBuiltInProperties();
498                 className = defaults.getProperty(PROPERTY_CLASS_LOCALERESOLVER);
499             }
500
501             if (className != null)
502             {
503                 try
504                 {
505                     Class JavaDoc classProperty = ReflectHelper.classForName(className);
506                     localeResolver = (LocaleResolver) classProperty.newInstance();
507
508                     log.info(Messages.getString("TableProperties.classinitializedto", //$NON-NLS-1$
509
new Object JavaDoc[]{ClassUtils.getShortClassName(LocaleResolver.class), className}));
510                 }
511                 catch (Throwable JavaDoc e)
512                 {
513                     log.warn(Messages.getString("TableProperties.errorloading", //$NON-NLS-1$
514
new Object JavaDoc[]{
515                             ClassUtils.getShortClassName(LocaleResolver.class),
516                             e.getClass().getName(),
517                             e.getMessage()}));
518                 }
519             }
520             else
521             {
522                 log.info(Messages.getString("TableProperties.noconfigured", //$NON-NLS-1$
523
new Object JavaDoc[]{ClassUtils.getShortClassName(LocaleResolver.class)}));
524             }
525
526             // still null?
527
if (localeResolver == null)
528             {
529                 // fallback locale resolver
530
localeResolver = new LocaleResolver()
531                 {
532
533                     public Locale JavaDoc resolveLocale(HttpServletRequest JavaDoc request)
534                     {
535                         return request.getLocale();
536                     }
537                 };
538             }
539         }
540
541         return localeResolver;
542     }
543
544     /**
545      * Initialize a new TableProperties loading the default properties file and the user defined one. There is no
546      * caching used here, caching is assumed to occur in the getInstance factory method.
547      * @param myLocale the locale we are in
548      * @throws TablePropertiesLoadException for errors during loading of properties files
549      */

550     private TableProperties(Locale JavaDoc myLocale) throws TablePropertiesLoadException
551     {
552         this.locale = myLocale;
553         // default properties will not change unless this class is reloaded
554
Properties JavaDoc defaultProperties = loadBuiltInProperties();
555
556         properties = new Properties JavaDoc(defaultProperties);
557         addProperties(myLocale);
558
559         // Now copy in the user properties (properties file set by calling setUserProperties()).
560
// note setUserProperties() MUST BE CALLED before the first TableProperties instantation
561
Enumeration JavaDoc keys = userProperties.keys();
562         while (keys.hasMoreElements())
563         {
564             String JavaDoc key = (String JavaDoc) keys.nextElement();
565             if (key != null)
566             {
567                 properties.setProperty(key, (String JavaDoc) userProperties.get(key));
568             }
569         }
570     }
571
572     /**
573      * Try to load the properties from the local properties file, displaytag.properties, and merge them into the
574      * existing properties.
575      * @param userLocale the locale from which the properties are to be loaded
576      */

577     private void addProperties(Locale JavaDoc userLocale)
578     {
579         ResourceBundle JavaDoc bundle = loadUserProperties(userLocale);
580
581         if (bundle != null)
582         {
583             Enumeration JavaDoc keys = bundle.getKeys();
584             while (keys.hasMoreElements())
585             {
586                 String JavaDoc key = (String JavaDoc) keys.nextElement();
587                 properties.setProperty(key, bundle.getString(key));
588             }
589         }
590     }
591
592     /**
593      * Clones the properties as well.
594      * @return a new clone of oneself
595      */

596     protected Object JavaDoc clone()
597     {
598         TableProperties twin;
599         try
600         {
601             twin = (TableProperties) super.clone();
602         }
603         catch (CloneNotSupportedException JavaDoc e)
604         {
605             // should never happen
606
throw new UnhandledException(e);
607         }
608         twin.properties = (Properties JavaDoc) this.properties.clone();
609         return twin;
610     }
611
612     /**
613      * Returns a new TableProperties instance for the given locale.
614      * @param request HttpServletRequest needed to extract the locale to use. If null the default locale will be used.
615      * @return TableProperties instance
616      */

617     public static TableProperties getInstance(HttpServletRequest JavaDoc request)
618     {
619         Locale JavaDoc locale;
620         if (request != null)
621         {
622             locale = getLocaleResolverInstance().resolveLocale(request);
623         }
624         else
625         {
626             // for some configuration parameters locale doesn't matter
627
locale = Locale.getDefault();
628         }
629
630         TableProperties props = (TableProperties) prototypes.get(locale);
631         if (props == null)
632         {
633             TableProperties lprops = new TableProperties(locale);
634             prototypes.put(locale, lprops);
635             props = lprops;
636         }
637         return (TableProperties) props.clone();
638     }
639
640     /**
641      * Unload all cached properties. This will not clear properties set by by setUserProperties; you must clear those
642      * manually.
643      */

644     public static void clearProperties()
645     {
646         prototypes.clear();
647     }
648
649     /**
650      * Local, non-default properties; these settings override the defaults from displaytag.properties and
651      * TableTag.properties. Please note that the values are copied in, so that multiple calls with non-overlapping
652      * properties will be merged, not overwritten. Note: setUserProperties() MUST BE CALLED before the first
653      * TableProperties instantation.
654      * @param overrideProperties - The local, non-default properties
655      */

656     public static void setUserProperties(Properties JavaDoc overrideProperties)
657     {
658         // copy keys here, so that this can be invoked more than once from different sources.
659
// if default properties are not yet loaded they will be copied in constructor
660
Enumeration JavaDoc keys = overrideProperties.keys();
661         while (keys.hasMoreElements())
662         {
663             String JavaDoc key = (String JavaDoc) keys.nextElement();
664             if (key != null)
665             {
666                 userProperties.setProperty(key, (String JavaDoc) overrideProperties.get(key));
667             }
668         }
669     }
670
671     /**
672      * The locale for which these properties are intended.
673      * @return the locale
674      */

675     public Locale JavaDoc getLocale()
676     {
677         return locale;
678     }
679
680     /**
681      * Getter for the <code>PROPERTY_STRING_PAGING_INVALIDPAGE</code> property.
682      * @return String
683      */

684     public String JavaDoc getPagingInvalidPage()
685     {
686         return getProperty(PROPERTY_STRING_PAGING_INVALIDPAGE);
687     }
688
689     /**
690      * Getter for the <code>PROPERTY_STRING_PAGING_ITEM_NAME</code> property.
691      * @return String
692      */

693     public String JavaDoc getPagingItemName()
694     {
695         return getProperty(PROPERTY_STRING_PAGING_ITEM_NAME);
696     }
697
698     /**
699      * Getter for the <code>PROPERTY_STRING_PAGING_ITEMS_NAME</code> property.
700      * @return String
701      */

702     public String JavaDoc getPagingItemsName()
703     {
704         return getProperty(PROPERTY_STRING_PAGING_ITEMS_NAME);
705     }
706
707     /**
708      * Getter for the <code>PROPERTY_STRING_PAGING_NOITEMS</code> property.
709      * @return String
710      */

711     public String JavaDoc getPagingFoundNoItems()
712     {
713         return getProperty(PROPERTY_STRING_PAGING_NOITEMS);
714     }
715
716     /**
717      * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_ONEITEM</code> property.
718      * @return String
719      */

720     public String JavaDoc getPagingFoundOneItem()
721     {
722         return getProperty(PROPERTY_STRING_PAGING_FOUND_ONEITEM);
723     }
724
725     /**
726      * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_ALLITEMS</code> property.
727      * @return String
728      */

729     public String JavaDoc getPagingFoundAllItems()
730     {
731         return getProperty(PROPERTY_STRING_PAGING_FOUND_ALLITEMS);
732     }
733
734     /**
735      * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_SOMEITEMS</code> property.
736      * @return String
737      */

738     public String JavaDoc getPagingFoundSomeItems()
739     {
740         return getProperty(PROPERTY_STRING_PAGING_FOUND_SOMEITEMS);
741     }
742
743     /**
744      * Getter for the <code>PROPERTY_INT_PAGING_GROUPSIZE</code> property.
745      * @return int
746      */

747     public int getPagingGroupSize()
748     {
749         // default size is 8
750
return getIntProperty(PROPERTY_INT_PAGING_GROUPSIZE, 8);
751     }
752
753     /**
754      * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_ONEPAGE</code> property.
755      * @return String
756      */

757     public String JavaDoc getPagingBannerOnePage()
758     {
759         return getProperty(PROPERTY_STRING_PAGING_BANNER_ONEPAGE);
760     }
761
762     /**
763      * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_FIRST</code> property.
764      * @return String
765      */

766     public String JavaDoc getPagingBannerFirst()
767     {
768         return getProperty(PROPERTY_STRING_PAGING_BANNER_FIRST);
769     }
770
771     /**
772      * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_LAST</code> property.
773      * @return String
774      */

775     public String JavaDoc getPagingBannerLast()
776     {
777         return getProperty(PROPERTY_STRING_PAGING_BANNER_LAST);
778     }
779
780     /**
781      * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_FULL</code> property.
782      * @return String
783      */

784     public String JavaDoc getPagingBannerFull()
785     {
786         return getProperty(PROPERTY_STRING_PAGING_BANNER_FULL);
787     }
788
789     /**
790      * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_LINK</code> property.
791      * @return String
792      */

793     public String JavaDoc getPagingPageLink()
794     {
795         return getProperty(PROPERTY_STRING_PAGING_PAGE_LINK);
796     }
797
798     /**
799      * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_SELECTED</code> property.
800      * @return String
801      */

802     public String JavaDoc getPagingPageSelected()
803     {
804         return getProperty(PROPERTY_STRING_PAGING_PAGE_SELECTED);
805     }
806
807     /**
808      * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_SPARATOR</code> property.
809      * @return String
810      */

811     public String JavaDoc getPagingPageSeparator()
812     {
813         return getProperty(PROPERTY_STRING_PAGING_PAGE_SPARATOR);
814     }
815
816     /**
817      * Is the given export option enabled?
818      * @param exportType instance of MediaTypeEnum
819      * @return boolean true if export is enabled
820      */

821     public boolean getAddExport(MediaTypeEnum exportType)
822     {
823         return getBooleanProperty(PROPERTY_EXPORT_PREFIX + SEP + exportType.getName());
824     }
825
826     /**
827      * Should headers be included in given export type?
828      * @param exportType instance of MediaTypeEnum
829      * @return boolean true if export should include headers
830      */

831     public boolean getExportHeader(MediaTypeEnum exportType)
832     {
833         return getBooleanProperty(PROPERTY_EXPORT_PREFIX
834             + SEP
835             + exportType.getName()
836             + SEP
837             + EXPORTPROPERTY_BOOLEAN_EXPORTHEADER);
838     }
839
840     /**
841      * Returns the label for the given export option.
842      * @param exportType instance of MediaTypeEnum
843      * @return String label
844      */

845     public String JavaDoc getExportLabel(MediaTypeEnum exportType)
846     {
847         return getProperty(PROPERTY_EXPORT_PREFIX + SEP + exportType.getName() + SEP + EXPORTPROPERTY_STRING_LABEL);
848     }
849
850     /**
851      * Returns the file name for the given media. Can be null
852      * @param exportType instance of MediaTypeEnum
853      * @return String filename
854      */

855     public String JavaDoc getExportFileName(MediaTypeEnum exportType)
856     {
857         return getProperty(PROPERTY_EXPORT_PREFIX + SEP + exportType.getName() + SEP + EXPORTPROPERTY_STRING_FILENAME);
858     }
859
860     /**
861      * Getter for the <code>PROPERTY_BOOLEAN_EXPORTDECORATED</code> property.
862      * @return boolean <code>true</code> if decorators should be used in exporting
863      */

864     public boolean getExportDecorated()
865     {
866         return getBooleanProperty(PROPERTY_BOOLEAN_EXPORTDECORATED);
867     }
868
869     /**
870      * Getter for the <code>PROPERTY_STRING_EXPORTBANNER</code> property.
871      * @return String
872      */

873     public String JavaDoc getExportBanner()
874     {
875         return getProperty(PROPERTY_STRING_EXPORTBANNER);
876     }
877
878     /**
879      * Getter for the <code>PROPERTY_STRING_EXPORTBANNER_SEPARATOR</code> property.
880      * @return String
881      */

882     public String JavaDoc getExportBannerSeparator()
883     {
884         return getProperty(PROPERTY_STRING_EXPORTBANNER_SEPARATOR);
885     }
886
887     /**
888      * Getter for the <code>PROPERTY_BOOLEAN_SHOWHEADER</code> property.
889      * @return boolean
890      */

891     public boolean getShowHeader()
892     {
893         return getBooleanProperty(PROPERTY_BOOLEAN_SHOWHEADER);
894     }
895
896     /**
897      * Getter for the <code>PROPERTY_STRING_EMPTYLIST_MESSAGE</code> property.
898      * @return String
899      */

900     public String JavaDoc getEmptyListMessage()
901     {
902         return getProperty(PROPERTY_STRING_EMPTYLIST_MESSAGE);
903     }
904
905     /**
906      * Getter for the <code>PROPERTY_STRING_EMPTYLISTROW_MESSAGE</code> property.
907      * @return String
908      */

909     public String JavaDoc getEmptyListRowMessage()
910     {
911         return getProperty(PROPERTY_STRING_EMPTYLISTROW_MESSAGE);
912     }
913
914     /**
915      * Getter for the <code>PROPERTY_BOOLEAN_EMPTYLIST_SHOWTABLE</code> property.
916      * @return boolean <code>true</code> if table should be displayed also if no items are found
917      */

918     public boolean getEmptyListShowTable()
919     {
920         return getBooleanProperty(PROPERTY_BOOLEAN_EMPTYLIST_SHOWTABLE);
921     }
922
923     /**
924      * Getter for the <code>PROPERTY_STRING_EXPORTAMOUNT</code> property.
925      * @return boolean <code>true</code> if <code>export.amount</code> is <code>list</code>
926      */

927     public boolean getExportFullList()
928     {
929         return "list".equals(getProperty(PROPERTY_STRING_EXPORTAMOUNT)); //$NON-NLS-1$
930
}
931
932     /**
933      * Getter for the <code>PROPERTY_STRING_SORTAMOUNT</code> property.
934      * @return boolean <code>true</code> if <code>sort.amount</code> is <code>list</code>
935      */

936     public boolean getSortFullList()
937     {
938         return "list".equals(getProperty(PROPERTY_STRING_SORTAMOUNT)); //$NON-NLS-1$
939
}
940
941     /**
942      * Should paging banner be added before the table?
943      * @return boolean
944      */

945     public boolean getAddPagingBannerTop()
946     {
947         String JavaDoc placement = getProperty(PROPERTY_STRING_BANNER_PLACEMENT);
948         return "top".equals(placement) || "both".equals(placement); //$NON-NLS-1$ //$NON-NLS-2$
949
}
950
951     /**
952      * Should paging banner be added after the table?
953      * @return boolean
954      */

955     public boolean getAddPagingBannerBottom()
956     {
957         String JavaDoc placement = getProperty(PROPERTY_STRING_BANNER_PLACEMENT);
958         return "bottom".equals(placement) || "both".equals(placement); //$NON-NLS-1$ //$NON-NLS-2$
959
}
960
961     /**
962      * Returns the appropriate css class for a table row.
963      * @param rowNumber row number
964      * @return the value of <code>PROPERTY_CSS_TR_EVEN</code> if rowNumber is even or <code>PROPERTY_CSS_TR_ODD</code>
965      * if rowNumber is odd.
966      */

967     public String JavaDoc getCssRow(int rowNumber)
968     {
969         return getProperty((rowNumber % 2 == 0) ? PROPERTY_CSS_TR_ODD : PROPERTY_CSS_TR_EVEN);
970     }
971
972     /**
973      * Returns the appropriate css class for a sorted column header.
974      * @param ascending <code>true</code> if column is sorded in ascending order.
975      * @return the value of <code>PROPERTY_CSS_TH_SORTED_ASCENDING</code> if column is sorded in ascending order or
976      * <code>PROPERTY_CSS_TH_SORTED_DESCENDING</code> if column is sorded in descending order.
977      */

978     public String JavaDoc getCssOrder(boolean ascending)
979     {
980         return getProperty(ascending ? PROPERTY_CSS_TH_SORTED_ASCENDING : PROPERTY_CSS_TH_SORTED_DESCENDING);
981     }
982
983     /**
984      * Returns the configured css class for a sorted column header.
985      * @return the value of <code>PROPERTY_CSS_TH_SORTED</code>
986      */

987     public String JavaDoc getCssSorted()
988     {
989         return getProperty(PROPERTY_CSS_TH_SORTED);
990     }
991
992     /**
993      * Returns the configured css class for the main table tag.
994      * @return the value of <code>PROPERTY_CSS_TABLE</code>
995      */

996     public String JavaDoc getCssTable()
997     {
998         return getProperty(PROPERTY_CSS_TABLE);
999     }
1000
1001    /**
1002     * Returns the configured css class for a sortable column header.
1003     * @return the value of <code>PROPERTY_CSS_TH_SORTABLE</code>
1004     */

1005    public String JavaDoc getCssSortable()
1006    {
1007        return getProperty(PROPERTY_CSS_TH_SORTABLE);
1008    }
1009
1010    /**
1011     * Returns the configured list of media.
1012     * @return the value of <code>PROPERTY_EXPORTTYPES</code>
1013     */

1014    public String JavaDoc[] getExportTypes()
1015    {
1016        String JavaDoc list = getProperty(PROPERTY_EXPORTTYPES);
1017        if (list == null)
1018        {
1019            return new String JavaDoc[0];
1020        }
1021
1022        return StringUtils.split(list);
1023    }
1024
1025    /**
1026     * Returns the class responsible for the given export.
1027     * @param exportName export name
1028     * @return String classname
1029     */

1030    public String JavaDoc getExportClass(String JavaDoc exportName)
1031    {
1032        return getProperty(PROPERTY_EXPORT_PREFIX + SEP + exportName + SEP + EXPORTPROPERTY_STRING_CLASS);
1033    }
1034
1035    /**
1036     * Returns an instance of configured requestHelperFactory.
1037     * @return RequestHelperFactory instance.
1038     * @throws FactoryInstantiationException if unable to load or instantiate the configurated class.
1039     */

1040    public RequestHelperFactory getRequestHelperFactoryInstance() throws FactoryInstantiationException
1041    {
1042        Object JavaDoc loadedObject = getClassPropertyInstance(PROPERTY_CLASS_REQUESTHELPERFACTORY);
1043
1044        // should not be null, but avoid errors just in case... see DISPL-148
1045
if (loadedObject == null)
1046        {
1047            return new DefaultRequestHelperFactory();
1048        }
1049
1050        try
1051        {
1052            return (RequestHelperFactory) loadedObject;
1053        }
1054        catch (ClassCastException JavaDoc e)
1055        {
1056            throw new FactoryInstantiationException(getClass(), PROPERTY_CLASS_REQUESTHELPERFACTORY, loadedObject
1057                .getClass()
1058                .getName(), e);
1059        }
1060    }
1061
1062    /**
1063     * Returns an instance of configured DecoratorFactory.
1064     * @return DecoratorFactory instance.
1065     * @throws FactoryInstantiationException if unable to load or instantiate the configurated class.
1066     */

1067    public DecoratorFactory getDecoratorFactoryInstance() throws FactoryInstantiationException
1068    {
1069        Object JavaDoc loadedObject = getClassPropertyInstance(PROPERTY_CLASS_DECORATORFACTORY);
1070
1071        if (loadedObject == null)
1072        {
1073            return new DefaultDecoratorFactory();
1074        }
1075
1076        try
1077        {
1078            return (DecoratorFactory) loadedObject;
1079        }
1080        catch (ClassCastException JavaDoc e)
1081        {
1082            throw new FactoryInstantiationException(getClass(), PROPERTY_CLASS_DECORATORFACTORY, loadedObject
1083                .getClass()
1084                .getName(), e);
1085        }
1086    }
1087
1088    public String JavaDoc getPaginationSortParam()
1089    {
1090        String JavaDoc result = getProperty(PROPERTY_STRING_PAGINATION_SORT_PARAM);
1091        if (result == null)
1092        {
1093            result = "sort";
1094        }
1095        return result;
1096    }
1097
1098    public String JavaDoc getPaginationPageNumberParam()
1099    {
1100        String JavaDoc result = getProperty(PROPERTY_STRING_PAGINATION_PAGE_NUMBER_PARAM);
1101        if (result == null)
1102        {
1103            result = "page";
1104        }
1105        return result;
1106    }
1107
1108    public String JavaDoc getPaginationSortDirectionParam()
1109    {
1110        String JavaDoc result = getProperty(PROPERTY_STRING_PAGINATION_SORT_DIRECTION_PARAM);
1111        if (result == null)
1112        {
1113            result = "dir";
1114        }
1115        return result;
1116    }
1117
1118    public String JavaDoc getPaginationSearchIdParam()
1119    {
1120        String JavaDoc result = getProperty(PROPERTY_STRING_PAGINATION_SEARCH_ID_PARAM);
1121        if (result == null)
1122        {
1123            result = "searchId";
1124        }
1125        return result;
1126    }
1127
1128    public String JavaDoc getPaginationAscValue()
1129    {
1130        String JavaDoc result = getProperty(PROPERTY_STRING_PAGINATION_ASC_VALUE);
1131        if (result == null)
1132        {
1133            result = "asc";
1134        }
1135        return result;
1136    }
1137
1138    public String JavaDoc getPaginationDescValue()
1139    {
1140        String JavaDoc result = getProperty(PROPERTY_STRING_PAGINATION_DESC_VALUE);
1141        if (result == null)
1142        {
1143            result = "desc";
1144        }
1145        return result;
1146    }
1147
1148    public boolean getPaginationSkipPageNumberInSort()
1149    {
1150        String JavaDoc s = getProperty(PROPERTY_BOOLEAN_PAGINATION_SKIP_PAGE_NUMBER_IN_SORT);
1151        if (s == null)
1152        {
1153            return true;
1154        }
1155        else
1156        {
1157            return getBooleanProperty(PROPERTY_BOOLEAN_PAGINATION_SKIP_PAGE_NUMBER_IN_SORT);
1158        }
1159    }
1160
1161    // </JBN>
1162

1163    /**
1164     * Returns the configured resource provider instance. If necessary instantiate the resource provider from config and
1165     * then keep a cached instance.
1166     * @return I18nResourceProvider instance.
1167     * @see I18nResourceProvider
1168     */

1169    public I18nResourceProvider geResourceProvider()
1170    {
1171        String JavaDoc className = getProperty(PROPERTY_CLASS_LOCALEPROVIDER);
1172
1173        if (resourceProvider == null)
1174        {
1175            if (className != null)
1176            {
1177                try
1178                {
1179                    Class JavaDoc classProperty = ReflectHelper.classForName(className);
1180                    resourceProvider = (I18nResourceProvider) classProperty.newInstance();
1181
1182                    log.info(Messages.getString("TableProperties.classinitializedto", //$NON-NLS-1$
1183
new Object JavaDoc[]{ClassUtils.getShortClassName(I18nResourceProvider.class), className}));
1184                }
1185                catch (Throwable JavaDoc e)
1186                {
1187                    log.warn(Messages.getString("TableProperties.errorloading", //$NON-NLS-1$
1188
new Object JavaDoc[]{
1189                            ClassUtils.getShortClassName(I18nResourceProvider.class),
1190                            e.getClass().getName(),
1191                            e.getMessage()}));
1192                }
1193            }
1194            else
1195            {
1196                log.info(Messages.getString("TableProperties.noconfigured", //$NON-NLS-1$
1197
new Object JavaDoc[]{ClassUtils.getShortClassName(I18nResourceProvider.class)}));
1198            }
1199
1200            // still null?
1201
if (resourceProvider == null)
1202            {
1203                // fallback provider, no i18n
1204
resourceProvider = new I18nResourceProvider()
1205                {
1206
1207                    // Always returns null
1208
public String JavaDoc getResource(String JavaDoc titleKey, String JavaDoc property, Tag JavaDoc tag, PageContext JavaDoc context)
1209                    {
1210                        return null;
1211                    }
1212                };
1213            }
1214        }
1215
1216        return resourceProvider;
1217    }
1218
1219    /**
1220     * Reads a String property.
1221     * @param key property name
1222     * @return property value or <code>null</code> if property is not found
1223     */

1224    private String JavaDoc getProperty(String JavaDoc key)
1225    {
1226        return this.properties.getProperty(key);
1227    }
1228
1229    /**
1230     * Sets a property.
1231     * @param key property name
1232     * @param value property value
1233     */

1234    public void setProperty(String JavaDoc key, String JavaDoc value)
1235    {
1236        this.properties.setProperty(key, value);
1237    }
1238
1239    /**
1240     * Reads a boolean property.
1241     * @param key property name
1242     * @return boolean <code>true</code> if the property value is "true", <code>false</code> for any other value.
1243     */

1244    private boolean getBooleanProperty(String JavaDoc key)
1245    {
1246        return Boolean.TRUE.toString().equals(getProperty(key));
1247    }
1248
1249    /**
1250     * Returns an instance of a configured Class. Returns a configured Class instantiated
1251     * callingClass.forName([configuration value]).
1252     * @param key configuration key
1253     * @return instance of configured class
1254     * @throws FactoryInstantiationException if unable to load or instantiate the configurated class.
1255     */

1256    private Object JavaDoc getClassPropertyInstance(String JavaDoc key) throws FactoryInstantiationException
1257    {
1258        Object JavaDoc instance = objectCache.get(key);
1259        if (instance != null)
1260        {
1261            return instance;
1262        }
1263
1264        String JavaDoc className = getProperty(key);
1265
1266        // shouldn't be null, but better check it
1267
if (className == null)
1268        {
1269            return null;
1270        }
1271
1272        try
1273        {
1274            Class JavaDoc classProperty = ReflectHelper.classForName(className);
1275            instance = classProperty.newInstance();
1276            objectCache.put(key, instance);
1277            return instance;
1278        }
1279        catch (Exception JavaDoc e)
1280        {
1281            throw new FactoryInstantiationException(getClass(), key, className, e);
1282        }
1283    }
1284
1285    /**
1286     * Reads an int property.
1287     * @param key property name
1288     * @param defaultValue default value returned if property is not found or not a valid int value
1289     * @return property value
1290     */

1291    private int getIntProperty(String JavaDoc key, int defaultValue)
1292    {
1293        try
1294        {
1295            return Integer.parseInt(getProperty(key));
1296        }
1297        catch (NumberFormatException JavaDoc e)
1298        {
1299            // Don't care, use default
1300
log.warn(Messages.getString("TableProperties.invalidvalue", //$NON-NLS-1$
1301
new Object JavaDoc[]{key, getProperty(key), new Integer JavaDoc(defaultValue)}));
1302        }
1303
1304        return defaultValue;
1305    }
1306
1307    /**
1308     * Obtain the name of the decorator configured for a given media type.
1309     * @param thatEnum A media type
1310     * @return The name of the decorator configured for a given media type.
1311     */

1312    public String JavaDoc getExportDecoratorName(MediaTypeEnum thatEnum)
1313    {
1314        return getProperty(PROPERTY_EXPORT_PREFIX + SEP + thatEnum + SEP + PROPERTY_EXPORT_DECORATOR_SUFFIX);
1315    }
1316}
Popular Tags