• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / displaytag / 1791

14 Feb 2026 05:47PM UTC coverage: 77.264% (-0.06%) from 77.321%
1791

push

github

web-flow
Merge pull request #1111 from hazendaz/renovate/javax-support-logback-monorepo

Update dependency ch.qos.logback:logback-classic to v1.5.30 (javax-support)

1438 of 2003 branches covered (71.79%)

Branch coverage included in aggregate %.

4030 of 5074 relevant lines covered (79.42%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.44
/displaytag/src/main/java/org/displaytag/properties/TableProperties.java
1
/*
2
 * SPDX-License-Identifier: MIT
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2002-2026 Fabrizio Giustina, the Displaytag team
6
 */
7
package org.displaytag.properties;
8

9
import java.io.IOException;
10
import java.io.InputStream;
11
import java.lang.reflect.InvocationTargetException;
12
import java.text.Collator;
13
import java.util.Comparator;
14
import java.util.Enumeration;
15
import java.util.HashMap;
16
import java.util.Locale;
17
import java.util.Map;
18
import java.util.MissingResourceException;
19
import java.util.Properties;
20
import java.util.ResourceBundle;
21

22
import javax.servlet.jsp.PageContext;
23

24
import org.apache.commons.lang3.ClassUtils;
25
import org.apache.commons.lang3.StringUtils;
26
import org.apache.commons.lang3.Strings;
27
import org.displaytag.Messages;
28
import org.displaytag.decorator.DecoratorFactory;
29
import org.displaytag.decorator.DefaultDecoratorFactory;
30
import org.displaytag.exception.FactoryInstantiationException;
31
import org.displaytag.exception.TablePropertiesLoadException;
32
import org.displaytag.localization.I18nResourceProvider;
33
import org.displaytag.localization.LocaleResolver;
34
import org.displaytag.model.DefaultComparator;
35
import org.displaytag.util.DefaultRequestHelperFactory;
36
import org.displaytag.util.ReflectHelper;
37
import org.displaytag.util.RequestHelperFactory;
38
import org.slf4j.Logger;
39
import org.slf4j.LoggerFactory;
40

41
/**
42
 * The properties used by the Table tags. The properties are loaded in the following order, in increasing order of
43
 * priority. The locale of getInstance() is used to determine the locale of the property file to use; if the key
44
 * required does not exist in the specified file, the key will be loaded from a more general property file.
45
 * <ol>
46
 * <li>First, from the TableTag.properties included with the DisplayTag distribution.</li>
47
 * <li>Then, from the file displaytag.properties, if it is present; these properties are intended to be set by the user
48
 * for sitewide application. Messages are gathered according to the Locale of the property file.</li>
49
 * <li>Finally, if this class has a userProperties defined, all of the properties from that Properties object are copied
50
 * in as well.</li>
51
 * </ol>
52
 */
53
public final class TableProperties implements Cloneable {
54

55
    /**
56
     * name of the default properties file name ("displaytag.properties").
57
     */
58
    public static final String DEFAULT_FILENAME = "displaytag.properties"; //$NON-NLS-1$
59

60
    /**
61
     * The name of the local properties file that is searched for on the classpath. Settings in this file will override
62
     * the defaults loaded from TableTag.properties.
63
     */
64
    public static final String LOCAL_PROPERTIES = "displaytag"; //$NON-NLS-1$
65

66
    /**
67
     * property <code>export.banner</code>.
68
     */
69
    public static final String PROPERTY_STRING_EXPORTBANNER = "export.banner"; //$NON-NLS-1$
70

71
    /**
72
     * property <code>export.banner.item</code>.
73
     */
74
    public static final String PROPERTY_STRING_EXPORTBANNER_ITEM = "export.banner.item"; //$NON-NLS-1$
75

76
    /**
77
     * property <code>export.banner</code>.
78
     */
79
    public static final String PROPERTY_STRING_EXPORTBANNER_PLACEMENT = "export.banner.placement"; //$NON-NLS-1$
80

81
    /**
82
     * property <code>export.banner.sepchar</code>.
83
     */
84
    public static final String PROPERTY_STRING_EXPORTBANNER_SEPARATOR = "export.banner.sepchar"; //$NON-NLS-1$
85

86
    /**
87
     * property <code>export.decorated</code>.
88
     */
89
    public static final String PROPERTY_BOOLEAN_EXPORTDECORATED = "export.decorated"; //$NON-NLS-1$
90

91
    /**
92
     * property <code>export.amount</code>.
93
     */
94
    public static final String PROPERTY_STRING_EXPORTAMOUNT = "export.amount"; //$NON-NLS-1$
95

96
    /**
97
     * property <code>sort.amount</code>.
98
     */
99
    public static final String PROPERTY_STRING_SORTAMOUNT = "sort.amount"; //$NON-NLS-1$
100

101
    /**
102
     * property <code>basic.show.header</code>.
103
     */
104
    public static final String PROPERTY_BOOLEAN_SHOWHEADER = "basic.show.header"; //$NON-NLS-1$
105

106
    /**
107
     * property <code>basic.msg.empty_list</code>.
108
     */
109
    public static final String PROPERTY_STRING_EMPTYLIST_MESSAGE = "basic.msg.empty_list"; //$NON-NLS-1$
110

111
    /**
112
     * property <code>basic.msg.empty_list_row</code>.
113
     */
114
    public static final String PROPERTY_STRING_EMPTYLISTROW_MESSAGE = "basic.msg.empty_list_row"; //$NON-NLS-1$
115

116
    /**
117
     * property <code>basic.empty.showtable</code>.
118
     */
119
    public static final String PROPERTY_BOOLEAN_EMPTYLIST_SHOWTABLE = "basic.empty.showtable"; //$NON-NLS-1$
120

121
    /**
122
     * property <code>paging.banner.placement</code>.
123
     */
124
    public static final String PROPERTY_STRING_BANNER_PLACEMENT = "paging.banner.placement"; //$NON-NLS-1$
125

126
    /**
127
     * property <code>error.msg.invalid_page</code>.
128
     */
129
    public static final String PROPERTY_STRING_PAGING_INVALIDPAGE = "error.msg.invalid_page"; //$NON-NLS-1$
130

131
    /**
132
     * property <code>paging.banner.item_name</code>.
133
     */
134
    public static final String PROPERTY_STRING_PAGING_ITEM_NAME = "paging.banner.item_name"; //$NON-NLS-1$
135

136
    /**
137
     * property <code>paging.banner.items_name</code>.
138
     */
139
    public static final String PROPERTY_STRING_PAGING_ITEMS_NAME = "paging.banner.items_name"; //$NON-NLS-1$
140

141
    /**
142
     * property <code>paging.banner.no_items_found</code>.
143
     */
144
    public static final String PROPERTY_STRING_PAGING_NOITEMS = "paging.banner.no_items_found"; //$NON-NLS-1$
145

146
    /**
147
     * property <code>paging.banner.one_item_found</code>.
148
     */
149
    public static final String PROPERTY_STRING_PAGING_FOUND_ONEITEM = "paging.banner.one_item_found"; //$NON-NLS-1$
150

151
    /**
152
     * property <code>paging.banner.all_items_found</code>.
153
     */
154
    public static final String PROPERTY_STRING_PAGING_FOUND_ALLITEMS = "paging.banner.all_items_found"; //$NON-NLS-1$
155

156
    /**
157
     * property <code>paging.banner.some_items_found</code>.
158
     */
159
    public static final String PROPERTY_STRING_PAGING_FOUND_SOMEITEMS = "paging.banner.some_items_found"; //$NON-NLS-1$
160

161
    /**
162
     * property <code>paging.banner.group_size</code>.
163
     */
164
    public static final String PROPERTY_INT_PAGING_GROUPSIZE = "paging.banner.group_size"; //$NON-NLS-1$
165

166
    /**
167
     * property <code>paging.banner.onepage</code>.
168
     */
169
    public static final String PROPERTY_STRING_PAGING_BANNER_ONEPAGE = "paging.banner.onepage"; //$NON-NLS-1$
170

171
    /**
172
     * property <code>paging.banner.first</code>.
173
     */
174
    public static final String PROPERTY_STRING_PAGING_BANNER_FIRST = "paging.banner.first"; //$NON-NLS-1$
175

176
    /**
177
     * property <code>paging.banner.last</code>.
178
     */
179
    public static final String PROPERTY_STRING_PAGING_BANNER_LAST = "paging.banner.last"; //$NON-NLS-1$
180

181
    /**
182
     * property <code>paging.banner.full</code>.
183
     */
184
    public static final String PROPERTY_STRING_PAGING_BANNER_FULL = "paging.banner.full"; //$NON-NLS-1$
185

186
    /**
187
     * property <code>paging.banner.page.link</code>.
188
     */
189
    public static final String PROPERTY_STRING_PAGING_PAGE_LINK = "paging.banner.page.link"; //$NON-NLS-1$
190

191
    /**
192
     * property <code>paging.banner.page.selected</code>.
193
     */
194
    public static final String PROPERTY_STRING_PAGING_PAGE_SELECTED = "paging.banner.page.selected"; //$NON-NLS-1$
195

196
    /**
197
     * property <code>paging.banner.page.separator</code>.
198
     */
199
    public static final String PROPERTY_STRING_PAGING_PAGE_SPARATOR = "paging.banner.page.separator"; //$NON-NLS-1$
200

201
    /**
202
     * property <code>factory.requestHelper</code>.
203
     */
204
    public static final String PROPERTY_CLASS_REQUESTHELPERFACTORY = "factory.requestHelper"; //$NON-NLS-1$
205

206
    /**
207
     * property <code>factory.decorators</code>.
208
     */
209
    public static final String PROPERTY_CLASS_DECORATORFACTORY = "factory.decorator"; //$NON-NLS-1$
210

211
    /**
212
     * property <code>locale.provider</code>.
213
     */
214
    public static final String PROPERTY_CLASS_LOCALEPROVIDER = "locale.provider"; //$NON-NLS-1$
215

216
    /**
217
     * property <code>locale.resolver</code>.
218
     */
219
    public static final String PROPERTY_CLASS_LOCALERESOLVER = "locale.resolver"; //$NON-NLS-1$
220

221
    /**
222
     * property <code>css.tr.even</code>: holds the name of the css class for even rows. Defaults to <code>even</code>.
223
     */
224
    public static final String PROPERTY_CSS_TR_EVEN = "css.tr.even"; //$NON-NLS-1$
225

226
    /**
227
     * property <code>css.tr.odd</code>: holds the name of the css class for odd rows. Defaults to <code>odd</code>.
228
     */
229
    public static final String PROPERTY_CSS_TR_ODD = "css.tr.odd"; //$NON-NLS-1$
230

231
    /**
232
     * property <code>css.table</code>: holds the name of the css class added to the main table tag. By default no css
233
     * class is added.
234
     */
235
    public static final String PROPERTY_CSS_TABLE = "css.table"; //$NON-NLS-1$
236

237
    /**
238
     * property <code>css.th.sortable</code>: holds the name of the css class added to the the header of a sortable
239
     * column. By default no css class is added.
240
     */
241
    public static final String PROPERTY_CSS_TH_SORTABLE = "css.th.sortable"; //$NON-NLS-1$
242

243
    /**
244
     * property <code>css.th.sorted</code>: holds the name of the css class added to the the header of a sorted column.
245
     * Defaults to <code>sorted</code>.
246
     */
247
    public static final String PROPERTY_CSS_TH_SORTED = "css.th.sorted"; //$NON-NLS-1$
248

249
    /**
250
     * property <code>css.th.ascending</code>: holds the name of the css class added to the the header of a column
251
     * sorted in ascending order. Defaults to <code>order1</code>.
252
     */
253
    public static final String PROPERTY_CSS_TH_SORTED_ASCENDING = "css.th.ascending"; //$NON-NLS-1$
254

255
    /**
256
     * property <code>css.th.descending</code>: holds the name of the css class added to the the header of a column
257
     * sorted in descending order. Defaults to <code>order2</code>.
258
     */
259
    public static final String PROPERTY_CSS_TH_SORTED_DESCENDING = "css.th.descending"; //$NON-NLS-1$
260

261
    /**
262
     * prefix used for all the properties related to export ("export"). The full property name is <code>export.</code>
263
     * <em>[export type]</em><code>.</code><em>[property name]</em>
264
     */
265
    public static final String PROPERTY_EXPORT_PREFIX = "export"; //$NON-NLS-1$
266

267
    /**
268
     * prefix used to set the media decorator property name. The full property name is <code>decorator.media.</code>
269
     * <em>[export type]</em>.
270
     */
271
    public static final String PROPERTY_DECORATOR_SUFFIX = "decorator"; //$NON-NLS-1$
272

273
    /**
274
     * used to set the media decorator property name. The full property name is <code>decorator.media.</code>
275
     * <em>[export type]</em>
276
     */
277
    public static final String PROPERTY_DECORATOR_MEDIA = "media"; //$NON-NLS-1$
278

279
    /**
280
     * used to set the totaler property name. The property name is <code>totaler</code>
281
     */
282
    public static final String TOTALER_NAME = "totaler"; //$NON-NLS-1$
283

284
    /**
285
     * property <code>export.types</code>: holds the list of export available export types.
286
     */
287
    public static final String PROPERTY_EXPORTTYPES = "export.types"; //$NON-NLS-1$
288

289
    /**
290
     * export property <code>label</code>.
291
     */
292
    public static final String EXPORTPROPERTY_STRING_LABEL = "label"; //$NON-NLS-1$
293

294
    /**
295
     * export property <code>class</code>.
296
     */
297
    public static final String EXPORTPROPERTY_STRING_CLASS = "class"; //$NON-NLS-1$
298

299
    /**
300
     * export property <code>include_header</code>.
301
     */
302
    public static final String EXPORTPROPERTY_BOOLEAN_EXPORTHEADER = "include_header"; //$NON-NLS-1$
303

304
    /**
305
     * export property <code>filename</code>.
306
     */
307
    public static final String EXPORTPROPERTY_STRING_FILENAME = "filename"; //$NON-NLS-1$
308

309
    /**
310
     * Property <code>pagination.sort.param</code>. If external pagination and sorting is used, it holds the name of the
311
     * parameter used to hold the sort criterion in generated links
312
     */
313
    public static final String PROPERTY_STRING_PAGINATION_SORT_PARAM = "pagination.sort.param"; //$NON-NLS-1$
314

315
    /**
316
     * Property <code>pagination.sortdirection.param</code>. If external pagination and sorting is used, it holds the
317
     * name of the parameter used to hold the sort direction in generated links (asc or desc)
318
     */
319
    public static final String PROPERTY_STRING_PAGINATION_SORT_DIRECTION_PARAM = "pagination.sortdirection.param"; //$NON-NLS-1$
320

321
    /**
322
     * Property <code>pagination.pagenumber.param</code>. If external pagination and sorting is used, it holds the name
323
     * of the parameter used to hold the page number in generated links
324
     */
325
    public static final String PROPERTY_STRING_PAGINATION_PAGE_NUMBER_PARAM = "pagination.pagenumber.param"; //$NON-NLS-1$
326

327
    /**
328
     * Property <code>pagination.searchid.param</code>. If external pagination and sorting is used, it holds the name of
329
     * the parameter used to hold the search ID in generated links
330
     */
331
    public static final String PROPERTY_STRING_PAGINATION_SEARCH_ID_PARAM = "pagination.searchid.param"; //$NON-NLS-1$
332

333
    /**
334
     * Property <code>pagination.sort.asc.value</code>. If external pagination and sorting is used, it holds the value
335
     * of the parameter of the sort direction parameter for "ascending"
336
     */
337
    public static final String PROPERTY_STRING_PAGINATION_ASC_VALUE = "pagination.sort.asc.value"; //$NON-NLS-1$
338

339
    /**
340
     * Property <code>pagination.sort.desc.value</code>. If external pagination and sorting is used, it holds the value
341
     * of the parameter of the sort direction parameter for "descending"
342
     */
343
    public static final String PROPERTY_STRING_PAGINATION_DESC_VALUE = "pagination.sort.desc.value"; //$NON-NLS-1$
344

345
    /**
346
     * Property <code>pagination.sort.skippagenumber</code>. If external pagination and sorting is used, it determines
347
     * if the current page number must be added in sort links or not. If this property is true, it means that each click
348
     * on a generated sort link will re-sort the list, and go back to the default page number. If it is false, each
349
     * click on a generated sort link will re-sort the list, and ask the current page number.
350
     */
351
    public static final String PROPERTY_BOOLEAN_PAGINATION_SKIP_PAGE_NUMBER_IN_SORT = "pagination.sort.skippagenumber"; //$NON-NLS-1$
352

353
    /**
354
     * Property <code>comparator.default</code>. If present, will use use as the classname of the default comparator.
355
     * Will be overriden by column level comparators.
356
     */
357
    public static final String PROPERTY_DEFAULT_COMPARATOR = "comparator.default"; //$NON-NLS-1$
358

359
    /**
360
     * Property <code>escapeXml.default</code>. Specifies the default value for column <code>escapeXml</code> attribute.
361
     */
362
    public static final String PROPERTY_BOOLEAN_ESCAPEXML_DEFAULT = "escapeXml.default"; //$NON-NLS-1$
363

364
    /**
365
     * Property <code>legacy.form.submit</code>. Specifies the default value for <code>legacy.form.submit</code>
366
     * attribute.
367
     */
368
    public static final String PROPERTY_BOOLEAN_LEGACY_FORM_SUBMIT = "legacy.form.submit"; //$NON-NLS-1$
369

370
    // </JBN>
371

372
    /**
373
     * Separator char used in property names.
374
     */
375
    private static final char SEP = '.';
376

377
    /**
378
     * logger.
379
     */
380
    private static Logger log = LoggerFactory.getLogger(TableProperties.class);
1✔
381

382
    /**
383
     * The userProperties are local, non-default properties; these settings override the defaults from
384
     * displaytag.properties and TableTag.properties.
385
     */
386
    private static Properties userProperties = new Properties();
1✔
387

388
    /**
389
     * Configured resource provider. If no ResourceProvider is configured, an no-op one is used. This instance is
390
     * initialized at first use and shared.
391
     */
392
    private static I18nResourceProvider resourceProvider;
393

394
    /**
395
     * Configured locale resolver.
396
     */
397
    private static LocaleResolver localeResolver;
398

399
    /**
400
     * TableProperties for each locale are loaded as needed, and cloned for public usage.
401
     */
402
    private static Map<Locale, TableProperties> prototypes = new HashMap<>();
1✔
403

404
    /**
405
     * Loaded properties (defaults from defaultProperties + custom from bundle).
406
     */
407
    private Properties properties;
408

409
    /**
410
     * The locale for these properties.
411
     */
412
    private final Locale locale;
413

414
    /**
415
     * Cache for dynamically instantiated object (request factory, decorator factory).
416
     */
417
    private final Map<String, Object> objectCache = new HashMap<>();
1✔
418

419
    /**
420
     * Setter for I18nResourceProvider. A resource provider is usually set using displaytag properties, this accessor is
421
     * needed for tests.
422
     *
423
     * @param provider
424
     *            I18nResourceProvider instance
425
     */
426
    protected static void setResourceProvider(final I18nResourceProvider provider) {
427
        TableProperties.resourceProvider = provider;
1✔
428
    }
1✔
429

430
    /**
431
     * Setter for LocaleResolver. A locale resolver is usually set using displaytag properties, this accessor is needed
432
     * for tests.
433
     *
434
     * @param resolver
435
     *            LocaleResolver instance
436
     */
437
    protected static void setLocaleResolver(final LocaleResolver resolver) {
438
        TableProperties.localeResolver = resolver;
1✔
439
    }
1✔
440

441
    /**
442
     * Loads default properties (TableTag.properties).
443
     *
444
     * @return loaded properties
445
     */
446
    private static Properties loadBuiltInProperties() {
447
        final Properties defaultProperties = new Properties();
1✔
448

449
        try {
450
            final InputStream is = TableProperties.class.getResourceAsStream(TableProperties.DEFAULT_FILENAME);
1✔
451
            if (is == null) {
1!
452
                throw new TablePropertiesLoadException(TableProperties.class, TableProperties.DEFAULT_FILENAME, null);
×
453
            }
454
            defaultProperties.load(is);
1✔
455
        } catch (final IOException e) {
×
456
            throw new TablePropertiesLoadException(TableProperties.class, TableProperties.DEFAULT_FILENAME, e);
×
457
        }
1✔
458

459
        return defaultProperties;
1✔
460
    }
461

462
    /**
463
     * Loads user properties (displaytag.properties) according to the given locale. User properties are not guarantee to
464
     * exist, so the method can return <code>null</code> (no exception will be thrown).
465
     *
466
     * @param locale
467
     *            requested Locale
468
     *
469
     * @return loaded properties
470
     */
471
    private static ResourceBundle loadUserProperties(final Locale locale) {
472
        ResourceBundle bundle = null;
1✔
473
        try {
474
            bundle = ResourceBundle.getBundle(TableProperties.LOCAL_PROPERTIES, locale);
1✔
475
        } catch (final MissingResourceException e) {
×
476
            // if no resource bundle is found, try using the context classloader
477
            try {
478
                bundle = ResourceBundle.getBundle(TableProperties.LOCAL_PROPERTIES, locale,
×
479
                        Thread.currentThread().getContextClassLoader());
×
480
            } catch (final MissingResourceException mre) {
×
481
                if (TableProperties.log.isDebugEnabled()) {
×
482
                    TableProperties.log.debug(Messages.getString("TableProperties.propertiesnotfound", //$NON-NLS-1$
×
483
                            new Object[] { mre.getMessage() }));
×
484
                }
485
            }
×
486
        }
1✔
487

488
        return bundle;
1✔
489
    }
490

491
    /**
492
     * Returns the configured Locale Resolver. This method is called before the loading of localized properties.
493
     *
494
     * @return LocaleResolver instance.
495
     */
496
    public static LocaleResolver getLocaleResolverInstance() {
497

498
        if (TableProperties.localeResolver == null) {
1✔
499

500
            // special handling, table properties is not yet instantiated
501
            String className = null;
1✔
502

503
            final ResourceBundle defaultUserProperties = TableProperties.loadUserProperties(Locale.getDefault());
1✔
504

505
            // if available, user properties have higher precedence
506
            if (defaultUserProperties != null) {
1!
507
                try {
508
                    className = defaultUserProperties.getString(TableProperties.PROPERTY_CLASS_LOCALERESOLVER);
×
509
                } catch (final MissingResourceException e) {
1✔
510
                    // no problem
511
                }
×
512
            }
513

514
            // still null? load defaults
515
            if (className == null) {
1!
516
                final Properties defaults = TableProperties.loadBuiltInProperties();
1✔
517
                className = defaults.getProperty(TableProperties.PROPERTY_CLASS_LOCALERESOLVER);
1✔
518
            }
519

520
            if (className != null) {
1!
521
                try {
522
                    final Class<LocaleResolver> classProperty = (Class<LocaleResolver>) ReflectHelper
×
523
                            .classForName(className);
×
524
                    TableProperties.localeResolver = classProperty.getDeclaredConstructor().newInstance();
×
525

526
                    TableProperties.log.info(Messages.getString("TableProperties.classinitializedto", //$NON-NLS-1$
×
527
                            new Object[] { ClassUtils.getShortClassName(LocaleResolver.class), className }));
×
528
                } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException
×
529
                        | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
530
                        | SecurityException e) {
531
                    TableProperties.log.warn(Messages.getString("TableProperties.errorloading", //$NON-NLS-1$
×
532
                            new Object[] { ClassUtils.getShortClassName(LocaleResolver.class), e.getClass().getName(),
×
533
                                    e.getMessage() }));
×
534
                }
×
535
            } else {
536
                TableProperties.log.info(Messages.getString("TableProperties.noconfigured", //$NON-NLS-1$
1✔
537
                        new Object[] { ClassUtils.getShortClassName(LocaleResolver.class) }));
1✔
538
            }
539

540
            // still null?
541
            if (TableProperties.localeResolver == null) {
1!
542
                // fallback locale resolver
543
                TableProperties.localeResolver = pageContext -> pageContext.getRequest().getLocale();
1✔
544
            }
545
        }
546

547
        return TableProperties.localeResolver;
1✔
548
    }
549

550
    /**
551
     * Initialize a new TableProperties loading the default properties file and the user defined one. There is no
552
     * caching used here, caching is assumed to occur in the getInstance factory method.
553
     *
554
     * @param myLocale
555
     *            the locale we are in
556
     */
557
    private TableProperties(final Locale myLocale) {
1✔
558
        this.locale = myLocale;
1✔
559
        // default properties will not change unless this class is reloaded
560
        final Properties defaultProperties = TableProperties.loadBuiltInProperties();
1✔
561

562
        this.properties = new Properties(defaultProperties);
1✔
563
        this.addProperties(myLocale);
1✔
564

565
        // Now copy in the user properties (properties file set by calling setUserProperties()).
566
        // note setUserProperties() MUST BE CALLED before the first TableProperties instantation
567
        final Enumeration<Object> keys = TableProperties.userProperties.keys();
1✔
568
        while (keys.hasMoreElements()) {
1✔
569
            final String key = (String) keys.nextElement();
1✔
570
            if (key != null) {
1!
571
                this.properties.setProperty(key, (String) TableProperties.userProperties.get(key));
1✔
572
            }
573
        }
1✔
574
    }
1✔
575

576
    /**
577
     * Try to load the properties from the local properties file, displaytag.properties, and merge them into the
578
     * existing properties.
579
     *
580
     * @param userLocale
581
     *            the locale from which the properties are to be loaded
582
     */
583
    private void addProperties(final Locale userLocale) {
584
        final ResourceBundle bundle = TableProperties.loadUserProperties(userLocale);
1✔
585

586
        if (bundle != null) {
1!
587
            final Enumeration<String> keys = bundle.getKeys();
1✔
588
            while (keys.hasMoreElements()) {
1✔
589
                final String key = keys.nextElement();
1✔
590
                this.properties.setProperty(key, bundle.getString(key));
1✔
591
            }
1✔
592
        }
593
    }
1✔
594

595
    /**
596
     * Clones the properties as well.
597
     *
598
     * @return a new clone of oneself
599
     */
600
    @Override
601
    protected Object clone() {
602
        TableProperties twin;
603
        try {
604
            twin = (TableProperties) super.clone();
1✔
605
        } catch (final CloneNotSupportedException e) {
×
606
            // should never happen
607
            throw new RuntimeException(e);
×
608
        }
1✔
609
        twin.properties = (Properties) this.properties.clone();
1✔
610
        return twin;
1✔
611
    }
612

613
    /**
614
     * Returns a new TableProperties instance for the given locale.
615
     *
616
     * @param pageContext
617
     *            PageContext needed to extract the locale to use. If null the default locale will be used.
618
     *
619
     * @return TableProperties instance
620
     */
621
    public static TableProperties getInstance(final PageContext pageContext) {
622
        Locale locale;
623
        if (pageContext != null) {
1✔
624
            locale = TableProperties.getLocaleResolverInstance().resolveLocale(pageContext);
1✔
625
        } else {
626
            // for some configuration parameters locale doesn't matter
627
            locale = Locale.getDefault();
1✔
628
        }
629

630
        TableProperties props = TableProperties.prototypes.get(locale);
1✔
631
        if (props == null) {
1✔
632
            final TableProperties lprops = new TableProperties(locale);
1✔
633
            TableProperties.prototypes.put(locale, lprops);
1✔
634
            props = lprops;
1✔
635
        }
636
        return (TableProperties) props.clone();
1✔
637
    }
638

639
    /**
640
     * Unload all cached properties. This will not clear properties set by by setUserProperties; you must clear those
641
     * manually.
642
     */
643
    public static void clearProperties() {
644
        TableProperties.prototypes.clear();
1✔
645
    }
1✔
646

647
    /**
648
     * Local, non-default properties; these settings override the defaults from displaytag.properties and
649
     * TableTag.properties. Please note that the values are copied in, so that multiple calls with non-overlapping
650
     * properties will be merged, not overwritten. Note: setUserProperties() MUST BE CALLED before the first
651
     * TableProperties instantiation.
652
     *
653
     * @param overrideProperties
654
     *            - The local, non-default properties
655
     */
656
    public static void setUserProperties(final Properties overrideProperties) {
657
        // copy keys here, so that this can be invoked more than once from different sources.
658
        // if default properties are not yet loaded they will be copied in constructor
659
        final Enumeration<Object> keys = overrideProperties.keys();
1✔
660
        while (keys.hasMoreElements()) {
1✔
661
            final String key = (String) keys.nextElement();
1✔
662
            if (key != null) {
1!
663
                TableProperties.userProperties.setProperty(key, (String) overrideProperties.get(key));
1✔
664
            }
665
        }
1✔
666
    }
1✔
667

668
    /**
669
     * The locale for which these properties are intended.
670
     *
671
     * @return the locale
672
     */
673
    public Locale getLocale() {
674
        return this.locale;
1✔
675
    }
676

677
    /**
678
     * Getter for the <code>PROPERTY_STRING_PAGING_INVALIDPAGE</code> property.
679
     *
680
     * @return String
681
     */
682
    public String getPagingInvalidPage() {
683
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_INVALIDPAGE);
×
684
    }
685

686
    /**
687
     * Getter for the <code>PROPERTY_STRING_PAGING_ITEM_NAME</code> property.
688
     *
689
     * @return String
690
     */
691
    public String getPagingItemName() {
692
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_ITEM_NAME);
1✔
693
    }
694

695
    /**
696
     * Getter for the <code>PROPERTY_STRING_PAGING_ITEMS_NAME</code> property.
697
     *
698
     * @return String
699
     */
700
    public String getPagingItemsName() {
701
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_ITEMS_NAME);
1✔
702
    }
703

704
    /**
705
     * Getter for the <code>PROPERTY_STRING_PAGING_NOITEMS</code> property.
706
     *
707
     * @return String
708
     */
709
    public String getPagingFoundNoItems() {
710
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_NOITEMS);
×
711
    }
712

713
    /**
714
     * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_ONEITEM</code> property.
715
     *
716
     * @return String
717
     */
718
    public String getPagingFoundOneItem() {
719
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_FOUND_ONEITEM);
1✔
720
    }
721

722
    /**
723
     * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_ALLITEMS</code> property.
724
     *
725
     * @return String
726
     */
727
    public String getPagingFoundAllItems() {
728
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_FOUND_ALLITEMS);
1✔
729
    }
730

731
    /**
732
     * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_SOMEITEMS</code> property.
733
     *
734
     * @return String
735
     */
736
    public String getPagingFoundSomeItems() {
737
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_FOUND_SOMEITEMS);
1✔
738
    }
739

740
    /**
741
     * Getter for the <code>PROPERTY_INT_PAGING_GROUPSIZE</code> property.
742
     *
743
     * @return int
744
     */
745
    public int getPagingGroupSize() {
746
        // default size is 8
747
        return this.getIntProperty(TableProperties.PROPERTY_INT_PAGING_GROUPSIZE, 8);
1✔
748
    }
749

750
    /**
751
     * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_ONEPAGE</code> property.
752
     *
753
     * @return String
754
     */
755
    public String getPagingBannerOnePage() {
756
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_BANNER_ONEPAGE);
1✔
757
    }
758

759
    /**
760
     * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_FIRST</code> property.
761
     *
762
     * @return String
763
     */
764
    public String getPagingBannerFirst() {
765
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_BANNER_FIRST);
1✔
766
    }
767

768
    /**
769
     * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_LAST</code> property.
770
     *
771
     * @return String
772
     */
773
    public String getPagingBannerLast() {
774
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_BANNER_LAST);
1✔
775
    }
776

777
    /**
778
     * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_FULL</code> property.
779
     *
780
     * @return String
781
     */
782
    public String getPagingBannerFull() {
783
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_BANNER_FULL);
1✔
784
    }
785

786
    /**
787
     * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_LINK</code> property.
788
     *
789
     * @return String
790
     */
791
    public String getPagingPageLink() {
792
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_PAGE_LINK);
1✔
793
    }
794

795
    /**
796
     * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_SELECTED</code> property.
797
     *
798
     * @return String
799
     */
800
    public String getPagingPageSelected() {
801
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_PAGE_SELECTED);
1✔
802
    }
803

804
    /**
805
     * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_SPARATOR</code> property.
806
     *
807
     * @return String
808
     */
809
    public String getPagingPageSeparator() {
810
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_PAGE_SPARATOR);
1✔
811
    }
812

813
    /**
814
     * Is the given export option enabled?.
815
     *
816
     * @param exportType
817
     *            instance of MediaTypeEnum
818
     *
819
     * @return boolean true if export is enabled
820
     */
821
    public boolean getAddExport(final MediaTypeEnum exportType) {
822
        return this.getBooleanProperty(
1✔
823
                TableProperties.PROPERTY_EXPORT_PREFIX + TableProperties.SEP + exportType.getName());
1✔
824
    }
825

826
    /**
827
     * Should headers be included in given export type?.
828
     *
829
     * @param exportType
830
     *            instance of MediaTypeEnum
831
     *
832
     * @return boolean true if export should include headers
833
     */
834
    public boolean getExportHeader(final MediaTypeEnum exportType) {
835
        return this.getBooleanProperty(TableProperties.PROPERTY_EXPORT_PREFIX + TableProperties.SEP
1✔
836
                + exportType.getName() + TableProperties.SEP + TableProperties.EXPORTPROPERTY_BOOLEAN_EXPORTHEADER);
1✔
837
    }
838

839
    /**
840
     * Returns the label for the given export option.
841
     *
842
     * @param exportType
843
     *            instance of MediaTypeEnum
844
     *
845
     * @return String label
846
     */
847
    public String getExportLabel(final MediaTypeEnum exportType) {
848
        return this.getProperty(TableProperties.PROPERTY_EXPORT_PREFIX + TableProperties.SEP + exportType.getName()
1✔
849
                + TableProperties.SEP + TableProperties.EXPORTPROPERTY_STRING_LABEL);
850
    }
851

852
    /**
853
     * Returns the file name for the given media. Can be null
854
     *
855
     * @param exportType
856
     *            instance of MediaTypeEnum
857
     *
858
     * @return String filename
859
     */
860
    public String getExportFileName(final MediaTypeEnum exportType) {
861
        return this.getProperty(TableProperties.PROPERTY_EXPORT_PREFIX + TableProperties.SEP + exportType.getName()
1✔
862
                + TableProperties.SEP + TableProperties.EXPORTPROPERTY_STRING_FILENAME);
863
    }
864

865
    /**
866
     * Getter for the <code>PROPERTY_BOOLEAN_EXPORTDECORATED</code> property.
867
     *
868
     * @return boolean <code>true</code> if decorators should be used in exporting
869
     */
870
    public boolean getExportDecorated() {
871
        return this.getBooleanProperty(TableProperties.PROPERTY_BOOLEAN_EXPORTDECORATED);
1✔
872
    }
873

874
    /**
875
     * Getter for the <code>PROPERTY_STRING_EXPORTBANNER</code> property.
876
     *
877
     * @return String
878
     */
879
    public String getExportBanner() {
880
        return this.getProperty(TableProperties.PROPERTY_STRING_EXPORTBANNER);
1✔
881
    }
882

883
    /**
884
     * Getter for the <code>PROPERTY_STRING_EXPORTBANNER_ITEM</code> property.
885
     *
886
     * @return String
887
     */
888
    public String getExportBannerItem() {
889
        return this.getProperty(TableProperties.PROPERTY_STRING_EXPORTBANNER_ITEM);
1✔
890
    }
891

892
    /**
893
     * Getter for the <code>PROPERTY_STRING_EXPORTBANNER_SEPARATOR</code> property.
894
     *
895
     * @return String
896
     */
897
    public String getExportBannerSeparator() {
898
        return this.getProperty(TableProperties.PROPERTY_STRING_EXPORTBANNER_SEPARATOR);
1✔
899
    }
900

901
    /**
902
     * Getter for the <code>PROPERTY_BOOLEAN_SHOWHEADER</code> property.
903
     *
904
     * @return boolean
905
     */
906
    public boolean getShowHeader() {
907
        return this.getBooleanProperty(TableProperties.PROPERTY_BOOLEAN_SHOWHEADER);
1✔
908
    }
909

910
    /**
911
     * Getter for the <code>PROPERTY_STRING_EMPTYLIST_MESSAGE</code> property.
912
     *
913
     * @return String
914
     */
915
    public String getEmptyListMessage() {
916
        return this.getProperty(TableProperties.PROPERTY_STRING_EMPTYLIST_MESSAGE);
1✔
917
    }
918

919
    /**
920
     * Getter for the <code>PROPERTY_STRING_EMPTYLISTROW_MESSAGE</code> property.
921
     *
922
     * @return String
923
     */
924
    public String getEmptyListRowMessage() {
925
        return this.getProperty(TableProperties.PROPERTY_STRING_EMPTYLISTROW_MESSAGE);
1✔
926
    }
927

928
    /**
929
     * Getter for the <code>PROPERTY_BOOLEAN_EMPTYLIST_SHOWTABLE</code> property.
930
     *
931
     * @return boolean <code>true</code> if table should be displayed also if no items are found
932
     */
933
    public boolean getEmptyListShowTable() {
934
        return this.getBooleanProperty(TableProperties.PROPERTY_BOOLEAN_EMPTYLIST_SHOWTABLE);
1✔
935
    }
936

937
    /**
938
     * Getter for the <code>PROPERTY_STRING_EXPORTAMOUNT</code> property.
939
     *
940
     * @return boolean <code>true</code> if <code>export.amount</code> is <code>list</code>
941
     */
942
    public boolean getExportFullList() {
943
        return "list".equals(this.getProperty(TableProperties.PROPERTY_STRING_EXPORTAMOUNT)); //$NON-NLS-1$
1✔
944
    }
945

946
    /**
947
     * Getter for the <code>PROPERTY_STRING_SORTAMOUNT</code> property.
948
     *
949
     * @return boolean <code>true</code> if <code>sort.amount</code> is <code>list</code>
950
     */
951
    public boolean getSortFullList() {
952
        return "list".equals(this.getProperty(TableProperties.PROPERTY_STRING_SORTAMOUNT)); //$NON-NLS-1$
1✔
953
    }
954

955
    /**
956
     * Should paging banner be added before the table?.
957
     *
958
     * @return boolean
959
     */
960
    public boolean getAddPagingBannerTop() {
961
        final String placement = this.getProperty(TableProperties.PROPERTY_STRING_BANNER_PLACEMENT);
1✔
962
        return Strings.CS.equals("top", placement) || Strings.CS.equals("both", placement); //$NON-NLS-1$ //$NON-NLS-2$
1✔
963
    }
964

965
    /**
966
     * Should paging banner be added after the table?.
967
     *
968
     * @return boolean
969
     */
970
    public boolean getAddPagingBannerBottom() {
971
        final String placement = this.getProperty(TableProperties.PROPERTY_STRING_BANNER_PLACEMENT);
1✔
972
        return Strings.CS.equals("bottom", placement) || Strings.CS.equals("both", placement); //$NON-NLS-1$ //$NON-NLS-2$
1✔
973
    }
974

975
    /**
976
     * Should paging banner be added before the table?.
977
     *
978
     * @return boolean
979
     */
980
    public boolean getAddExportBannerTop() {
981
        final String placement = this.getProperty(TableProperties.PROPERTY_STRING_EXPORTBANNER_PLACEMENT);
1✔
982
        return Strings.CS.equals("top", placement) || Strings.CS.equals("both", placement); //$NON-NLS-1$ //$NON-NLS-2$
1!
983
    }
984

985
    /**
986
     * Should paging banner be added after the table?.
987
     *
988
     * @return boolean
989
     */
990
    public boolean getAddExportBannerBottom() {
991
        final String placement = this.getProperty(TableProperties.PROPERTY_STRING_EXPORTBANNER_PLACEMENT);
1✔
992
        // no value specified puts it on th bottom too to ensure proper backward compatibility
993
        return !Strings.CS.equals("top", placement); //$NON-NLS-1$
1!
994
    }
995

996
    /**
997
     * Returns the appropriate css class for a table row.
998
     *
999
     * @param rowNumber
1000
     *            row number
1001
     *
1002
     * @return the value of <code>PROPERTY_CSS_TR_EVEN</code> if rowNumber is even or <code>PROPERTY_CSS_TR_ODD</code>
1003
     *         if rowNumber is odd.
1004
     */
1005
    public String getCssRow(final int rowNumber) {
1006
        return this.getProperty(
1✔
1007
                rowNumber % 2 == 0 ? TableProperties.PROPERTY_CSS_TR_ODD : TableProperties.PROPERTY_CSS_TR_EVEN);
1✔
1008
    }
1009

1010
    /**
1011
     * Returns the appropriate css class for a sorted column header.
1012
     *
1013
     * @param ascending
1014
     *            <code>true</code> if column is sorded in ascending order.
1015
     *
1016
     * @return the value of <code>PROPERTY_CSS_TH_SORTED_ASCENDING</code> if column is sorded in ascending order or
1017
     *         <code>PROPERTY_CSS_TH_SORTED_DESCENDING</code> if column is sorded in descending order.
1018
     */
1019
    public String getCssOrder(final boolean ascending) {
1020
        return this.getProperty(ascending ? TableProperties.PROPERTY_CSS_TH_SORTED_ASCENDING
1✔
1021
                : TableProperties.PROPERTY_CSS_TH_SORTED_DESCENDING);
1✔
1022
    }
1023

1024
    /**
1025
     * Returns the configured css class for a sorted column header.
1026
     *
1027
     * @return the value of <code>PROPERTY_CSS_TH_SORTED</code>
1028
     */
1029
    public String getCssSorted() {
1030
        return this.getProperty(TableProperties.PROPERTY_CSS_TH_SORTED);
1✔
1031
    }
1032

1033
    /**
1034
     * Returns the configured css class for the main table tag.
1035
     *
1036
     * @return the value of <code>PROPERTY_CSS_TABLE</code>
1037
     */
1038
    public String getCssTable() {
1039
        return this.getProperty(TableProperties.PROPERTY_CSS_TABLE);
1✔
1040
    }
1041

1042
    /**
1043
     * Returns the configured css class for a sortable column header.
1044
     *
1045
     * @return the value of <code>PROPERTY_CSS_TH_SORTABLE</code>
1046
     */
1047
    public String getCssSortable() {
1048
        return this.getProperty(TableProperties.PROPERTY_CSS_TH_SORTABLE);
1✔
1049
    }
1050

1051
    /**
1052
     * Returns the configured list of media.
1053
     *
1054
     * @return the value of <code>PROPERTY_EXPORTTYPES</code>
1055
     */
1056
    public String[] getExportTypes() {
1057
        final String list = this.getProperty(TableProperties.PROPERTY_EXPORTTYPES);
1✔
1058
        if (list == null) {
1!
1059
            return new String[0];
×
1060
        }
1061

1062
        return StringUtils.split(list);
1✔
1063
    }
1064

1065
    /**
1066
     * Returns the class responsible for the given export.
1067
     *
1068
     * @param exportName
1069
     *            export name
1070
     *
1071
     * @return String classname
1072
     */
1073
    public String getExportClass(final String exportName) {
1074
        return this.getProperty(TableProperties.PROPERTY_EXPORT_PREFIX + TableProperties.SEP + exportName
1✔
1075
                + TableProperties.SEP + TableProperties.EXPORTPROPERTY_STRING_CLASS);
1076
    }
1077

1078
    /**
1079
     * Returns an instance of configured requestHelperFactory.
1080
     *
1081
     * @return RequestHelperFactory instance.
1082
     */
1083
    public RequestHelperFactory getRequestHelperFactoryInstance() {
1084
        final Object loadedObject = this.getClassPropertyInstance(TableProperties.PROPERTY_CLASS_REQUESTHELPERFACTORY);
1✔
1085

1086
        // should not be null, but avoid errors just in case... see DISPL-148
1087
        if (loadedObject == null) {
1!
1088
            return new DefaultRequestHelperFactory();
×
1089
        }
1090

1091
        try {
1092
            return (RequestHelperFactory) loadedObject;
1✔
1093
        } catch (final ClassCastException e) {
×
1094
            throw new FactoryInstantiationException(this.getClass(),
×
1095
                    TableProperties.PROPERTY_CLASS_REQUESTHELPERFACTORY, loadedObject.getClass().getName(), e);
×
1096
        }
1097
    }
1098

1099
    /**
1100
     * Returns an instance of configured DecoratorFactory.
1101
     *
1102
     * @return DecoratorFactory instance.
1103
     */
1104
    public DecoratorFactory getDecoratorFactoryInstance() {
1105
        final Object loadedObject = this.getClassPropertyInstance(TableProperties.PROPERTY_CLASS_DECORATORFACTORY);
1✔
1106

1107
        if (loadedObject == null) {
1!
1108
            return new DefaultDecoratorFactory();
×
1109
        }
1110

1111
        try {
1112
            return (DecoratorFactory) loadedObject;
1✔
1113
        } catch (final ClassCastException e) {
×
1114
            throw new FactoryInstantiationException(this.getClass(), TableProperties.PROPERTY_CLASS_DECORATORFACTORY,
×
1115
                    loadedObject.getClass().getName(), e);
×
1116
        }
1117
    }
1118

1119
    /**
1120
     * Gets the pagination sort param.
1121
     *
1122
     * @return the pagination sort param
1123
     */
1124
    public String getPaginationSortParam() {
1125
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_SORT_PARAM);
1✔
1126
        if (result == null) {
1!
1127
            result = "sort";
×
1128
        }
1129
        return result;
1✔
1130
    }
1131

1132
    /**
1133
     * Gets the pagination page number param.
1134
     *
1135
     * @return the pagination page number param
1136
     */
1137
    public String getPaginationPageNumberParam() {
1138
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_PAGE_NUMBER_PARAM);
1✔
1139
        if (result == null) {
1!
1140
            result = "page";
×
1141
        }
1142
        return result;
1✔
1143
    }
1144

1145
    /**
1146
     * Gets the pagination sort direction param.
1147
     *
1148
     * @return the pagination sort direction param
1149
     */
1150
    public String getPaginationSortDirectionParam() {
1151
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_SORT_DIRECTION_PARAM);
1✔
1152
        if (result == null) {
1!
1153
            result = "dir";
×
1154
        }
1155
        return result;
1✔
1156
    }
1157

1158
    /**
1159
     * Gets the pagination search id param.
1160
     *
1161
     * @return the pagination search id param
1162
     */
1163
    public String getPaginationSearchIdParam() {
1164
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_SEARCH_ID_PARAM);
1✔
1165
        if (result == null) {
1!
1166
            result = "searchId";
×
1167
        }
1168
        return result;
1✔
1169
    }
1170

1171
    /**
1172
     * Gets the pagination asc value.
1173
     *
1174
     * @return the pagination asc value
1175
     */
1176
    public String getPaginationAscValue() {
1177
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_ASC_VALUE);
1✔
1178
        if (result == null) {
1!
1179
            result = "asc";
×
1180
        }
1181
        return result;
1✔
1182
    }
1183

1184
    /**
1185
     * Gets the pagination desc value.
1186
     *
1187
     * @return the pagination desc value
1188
     */
1189
    public String getPaginationDescValue() {
1190
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_DESC_VALUE);
×
1191
        if (result == null) {
×
1192
            result = "desc";
×
1193
        }
1194
        return result;
×
1195
    }
1196

1197
    /**
1198
     * Gets the pagination skip page number in sort.
1199
     *
1200
     * @return the pagination skip page number in sort
1201
     */
1202
    public boolean getPaginationSkipPageNumberInSort() {
1203
        final String s = this.getProperty(TableProperties.PROPERTY_BOOLEAN_PAGINATION_SKIP_PAGE_NUMBER_IN_SORT);
1✔
1204
        if (s == null) {
1!
1205
            return true;
×
1206
        }
1207
        return this.getBooleanProperty(TableProperties.PROPERTY_BOOLEAN_PAGINATION_SKIP_PAGE_NUMBER_IN_SORT);
1✔
1208
    }
1209

1210
    // </JBN>
1211

1212
    /**
1213
     * Returns the configured resource provider instance. If necessary instantiate the resource provider from config and
1214
     * then keep a cached instance.
1215
     *
1216
     * @return I18nResourceProvider instance.
1217
     *
1218
     * @see I18nResourceProvider
1219
     */
1220
    public I18nResourceProvider geResourceProvider() {
1221
        final String className = this.getProperty(TableProperties.PROPERTY_CLASS_LOCALEPROVIDER);
1✔
1222

1223
        if (TableProperties.resourceProvider == null) {
1✔
1224
            if (className != null) {
1!
1225
                try {
1226
                    final Class<I18nResourceProvider> classProperty = (Class<I18nResourceProvider>) ReflectHelper
1✔
1227
                            .classForName(className);
1✔
1228
                    TableProperties.resourceProvider = classProperty.getDeclaredConstructor().newInstance();
1✔
1229

1230
                    if (log.isInfoEnabled()) {
1!
1231
                        TableProperties.log.info(Messages.getString("TableProperties.classinitializedto", //$NON-NLS-1$
×
1232
                                new Object[] { ClassUtils.getShortClassName(I18nResourceProvider.class), className }));
×
1233
                    }
1234
                } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException
×
1235
                        | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
1236
                        | SecurityException e) {
1237
                    TableProperties.log.warn(Messages.getString("TableProperties.errorloading", //$NON-NLS-1$
×
1238
                            new Object[] { ClassUtils.getShortClassName(I18nResourceProvider.class),
×
1239
                                    e.getClass().getName(), e.getMessage() }));
×
1240
                }
1✔
1241
            } else {
1242
                if (log.isInfoEnabled()) {
×
1243
                    TableProperties.log.info(Messages.getString("TableProperties.noconfigured", //$NON-NLS-1$
×
1244
                            new Object[] { ClassUtils.getShortClassName(I18nResourceProvider.class) }));
×
1245
                }
1246
            }
1247

1248
            // still null?
1249
            if (TableProperties.resourceProvider == null) {
1!
1250
                // fallback provider, no i18n
1251
                TableProperties.resourceProvider = (titleKey, property, tag, context) -> null;
×
1252
            }
1253
        }
1254

1255
        return TableProperties.resourceProvider;
1✔
1256
    }
1257

1258
    /**
1259
     * Reads a String property.
1260
     *
1261
     * @param key
1262
     *            property name
1263
     *
1264
     * @return property value or <code>null</code> if property is not found
1265
     */
1266
    public String getProperty(final String key) {
1267
        return this.properties.getProperty(key);
1✔
1268
    }
1269

1270
    /**
1271
     * Sets a property.
1272
     *
1273
     * @param key
1274
     *            property name
1275
     * @param value
1276
     *            property value
1277
     */
1278
    public void setProperty(final String key, final String value) {
1279
        this.properties.setProperty(key, value);
1✔
1280
    }
1✔
1281

1282
    /**
1283
     * Reads a boolean property.
1284
     *
1285
     * @param key
1286
     *            property name
1287
     *
1288
     * @return boolean <code>true</code> if the property value is "true", <code>false</code> for any other value.
1289
     */
1290
    private boolean getBooleanProperty(final String key) {
1291
        return Boolean.TRUE.toString().equals(this.getProperty(key));
1✔
1292
    }
1293

1294
    /**
1295
     * Returns an instance of a configured Class. Returns a configured Class instantiated
1296
     * callingClass.forName([configuration value]).
1297
     *
1298
     * @param key
1299
     *            configuration key
1300
     *
1301
     * @return instance of configured class
1302
     */
1303
    private Object getClassPropertyInstance(final String key) {
1304

1305
        final String className = this.getProperty(key);
1✔
1306

1307
        // shouldn't be null, but better check it
1308
        if (className == null) {
1!
1309
            return null;
×
1310
        }
1311

1312
        Object instance = this.objectCache.get(className);
1✔
1313
        if (instance != null) {
1✔
1314
            return instance;
1✔
1315
        }
1316

1317
        try {
1318
            final Class<?> classProperty = ReflectHelper.classForName(className);
1✔
1319
            instance = classProperty.getDeclaredConstructor().newInstance();
1✔
1320
            this.objectCache.put(className, instance);
1✔
1321
            return instance;
1✔
1322
        } catch (final Exception e) {
×
1323
            throw new FactoryInstantiationException(this.getClass(), key, className, e);
×
1324
        }
1325
    }
1326

1327
    /**
1328
     * Reads an int property.
1329
     *
1330
     * @param key
1331
     *            property name
1332
     * @param defaultValue
1333
     *            default value returned if property is not found or not a valid int value
1334
     *
1335
     * @return property value
1336
     */
1337
    private int getIntProperty(final String key, final int defaultValue) {
1338
        try {
1339
            return Integer.parseInt(this.getProperty(key));
1✔
1340
        } catch (final NumberFormatException e) {
×
1341
            // Don't care, use default
1342
            TableProperties.log.warn(Messages.getString("TableProperties.invalidvalue", //$NON-NLS-1$
×
1343
                    new Object[] { key, this.getProperty(key), Integer.valueOf(defaultValue) }));
×
1344
        }
1345

1346
        return defaultValue;
×
1347
    }
1348

1349
    /**
1350
     * Obtain the name of the decorator configured for a given media type.
1351
     *
1352
     * @param thatEnum
1353
     *            A media type
1354
     *
1355
     * @return The name of the decorator configured for a given media type.
1356
     */
1357
    public String getMediaTypeDecoratorName(final MediaTypeEnum thatEnum) {
1358
        return this.getProperty(TableProperties.PROPERTY_DECORATOR_SUFFIX + TableProperties.SEP
1✔
1359
                + TableProperties.PROPERTY_DECORATOR_MEDIA + TableProperties.SEP + thatEnum);
1360
    }
1361

1362
    /**
1363
     * the classname of the totaler.
1364
     *
1365
     * @return the classname of the totaler
1366
     */
1367
    public String getTotalerName() {
1368
        return this.getProperty(TableProperties.TOTALER_NAME);
1✔
1369
    }
1370

1371
    /**
1372
     * Gets the default comparator.
1373
     *
1374
     * @return the default comparator
1375
     */
1376
    public Comparator<Object> getDefaultComparator() {
1377
        final String className = this.getProperty(TableProperties.PROPERTY_DEFAULT_COMPARATOR);
1✔
1378
        if (className != null) {
1!
1379
            try {
1380
                final Class<Comparator<Object>> classProperty = (Class<Comparator<Object>>) ReflectHelper
×
1381
                        .classForName(className);
×
1382
                return classProperty.getDeclaredConstructor().newInstance();
×
1383
            } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException
×
1384
                    | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
1385
                    | SecurityException e) {
1386
                TableProperties.log.warn(Messages.getString("TableProperties.errorloading", //$NON-NLS-1$
×
1387
                        new Object[] { ClassUtils.getShortClassName(Comparator.class), e.getClass().getName(),
×
1388
                                e.getMessage() }));
×
1389
            }
1390
        }
1391
        return new DefaultComparator(Collator.getInstance(this.getLocale()));
1✔
1392
    }
1393

1394
    /**
1395
     * Returns the default value for column <code>escapeXml</code> attribute.
1396
     *
1397
     * @return The default value for column <code>escapeXml</code> attribute
1398
     */
1399
    public boolean getEscapeXmlDefault() {
1400
        return getBooleanProperty(PROPERTY_BOOLEAN_ESCAPEXML_DEFAULT);
1✔
1401
    }
1402

1403
    /**
1404
     * Returns the default value for <code>legacy.form.submit</code> attribute.
1405
     *
1406
     * @return the default value for <code>legacy.form.submit</code> attribute
1407
     */
1408
    public boolean getUseLegacyFormSubmit() {
1409
        final String s = this.getProperty(TableProperties.PROPERTY_BOOLEAN_LEGACY_FORM_SUBMIT);
1✔
1410
        if (s == null) {
1!
1411
            return false;
1✔
1412
        }
1413
        return this.getBooleanProperty(TableProperties.PROPERTY_BOOLEAN_LEGACY_FORM_SUBMIT);
×
1414
    }
1415
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc