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

hazendaz / displaytag / 1525

05 Dec 2025 01:30AM UTC coverage: 76.996% (-0.04%) from 77.034%
1525

push

github

hazendaz
Cleanup deprecations and various code issues

1377 of 1935 branches covered (71.16%)

Branch coverage included in aggregate %.

22 of 27 new or added lines in 13 files covered. (81.48%)

1 existing line in 1 file now uncovered.

3898 of 4916 relevant lines covered (79.29%)

0.79 hits per line

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

70.09
/displaytag/src/main/java/org/displaytag/properties/TableProperties.java
1
/*
2
 * Copyright (C) 2002-2025 Fabrizio Giustina, the Displaytag team
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining a copy
5
 * of this software and associated documentation files (the "Software"), to deal
6
 * in the Software without restriction, including without limitation the rights
7
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
 * copies of the Software, and to permit persons to whom the Software is
9
 * furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in
12
 * all copies or substantial portions of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
 * THE SOFTWARE.
21
 */
22
package org.displaytag.properties;
23

24
import jakarta.servlet.jsp.PageContext;
25

26
import java.io.IOException;
27
import java.io.InputStream;
28
import java.lang.reflect.InvocationTargetException;
29
import java.text.Collator;
30
import java.util.Comparator;
31
import java.util.Enumeration;
32
import java.util.HashMap;
33
import java.util.Locale;
34
import java.util.Map;
35
import java.util.MissingResourceException;
36
import java.util.Properties;
37
import java.util.ResourceBundle;
38

39
import org.apache.commons.lang3.ClassUtils;
40
import org.apache.commons.lang3.StringUtils;
41
import org.apache.commons.lang3.Strings;
42
import org.displaytag.Messages;
43
import org.displaytag.decorator.DecoratorFactory;
44
import org.displaytag.decorator.DefaultDecoratorFactory;
45
import org.displaytag.exception.FactoryInstantiationException;
46
import org.displaytag.exception.TablePropertiesLoadException;
47
import org.displaytag.localization.I18nResourceProvider;
48
import org.displaytag.localization.LocaleResolver;
49
import org.displaytag.model.DefaultComparator;
50
import org.displaytag.util.DefaultRequestHelperFactory;
51
import org.displaytag.util.ReflectHelper;
52
import org.displaytag.util.RequestHelperFactory;
53
import org.slf4j.Logger;
54
import org.slf4j.LoggerFactory;
55

56
/**
57
 * The properties used by the Table tags. The properties are loaded in the following order, in increasing order of
58
 * priority. The locale of getInstance() is used to determine the locale of the property file to use; if the key
59
 * required does not exist in the specified file, the key will be loaded from a more general property file.
60
 * <ol>
61
 * <li>First, from the TableTag.properties included with the DisplayTag distribution.</li>
62
 * <li>Then, from the file displaytag.properties, if it is present; these properties are intended to be set by the user
63
 * for sitewide application. Messages are gathered according to the Locale of the property file.</li>
64
 * <li>Finally, if this class has a userProperties defined, all of the properties from that Properties object are copied
65
 * in as well.</li>
66
 * </ol>
67
 */
68
public final class TableProperties implements Cloneable {
69

70
    /**
71
     * name of the default properties file name ("displaytag.properties").
72
     */
73
    public static final String DEFAULT_FILENAME = "displaytag.properties"; //$NON-NLS-1$
74

75
    /**
76
     * The name of the local properties file that is searched for on the classpath. Settings in this file will override
77
     * the defaults loaded from TableTag.properties.
78
     */
79
    public static final String LOCAL_PROPERTIES = "displaytag"; //$NON-NLS-1$
80

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

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

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

96
    /**
97
     * property <code>export.banner.sepchar</code>.
98
     */
99
    public static final String PROPERTY_STRING_EXPORTBANNER_SEPARATOR = "export.banner.sepchar"; //$NON-NLS-1$
100

101
    /**
102
     * property <code>export.decorated</code>.
103
     */
104
    public static final String PROPERTY_BOOLEAN_EXPORTDECORATED = "export.decorated"; //$NON-NLS-1$
105

106
    /**
107
     * property <code>export.amount</code>.
108
     */
109
    public static final String PROPERTY_STRING_EXPORTAMOUNT = "export.amount"; //$NON-NLS-1$
110

111
    /**
112
     * property <code>sort.amount</code>.
113
     */
114
    public static final String PROPERTY_STRING_SORTAMOUNT = "sort.amount"; //$NON-NLS-1$
115

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

121
    /**
122
     * property <code>basic.msg.empty_list</code>.
123
     */
124
    public static final String PROPERTY_STRING_EMPTYLIST_MESSAGE = "basic.msg.empty_list"; //$NON-NLS-1$
125

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

131
    /**
132
     * property <code>basic.empty.showtable</code>.
133
     */
134
    public static final String PROPERTY_BOOLEAN_EMPTYLIST_SHOWTABLE = "basic.empty.showtable"; //$NON-NLS-1$
135

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

141
    /**
142
     * property <code>error.msg.invalid_page</code>.
143
     */
144
    public static final String PROPERTY_STRING_PAGING_INVALIDPAGE = "error.msg.invalid_page"; //$NON-NLS-1$
145

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

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

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

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

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

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

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

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

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

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

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

201
    /**
202
     * property <code>paging.banner.page.link</code>.
203
     */
204
    public static final String PROPERTY_STRING_PAGING_PAGE_LINK = "paging.banner.page.link"; //$NON-NLS-1$
205

206
    /**
207
     * property <code>paging.banner.page.selected</code>.
208
     */
209
    public static final String PROPERTY_STRING_PAGING_PAGE_SELECTED = "paging.banner.page.selected"; //$NON-NLS-1$
210

211
    /**
212
     * property <code>paging.banner.page.separator</code>.
213
     */
214
    public static final String PROPERTY_STRING_PAGING_PAGE_SPARATOR = "paging.banner.page.separator"; //$NON-NLS-1$
215

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

221
    /**
222
     * property <code>factory.decorators</code>.
223
     */
224
    public static final String PROPERTY_CLASS_DECORATORFACTORY = "factory.decorator"; //$NON-NLS-1$
225

226
    /**
227
     * property <code>locale.provider</code>.
228
     */
229
    public static final String PROPERTY_CLASS_LOCALEPROVIDER = "locale.provider"; //$NON-NLS-1$
230

231
    /**
232
     * property <code>locale.resolver</code>.
233
     */
234
    public static final String PROPERTY_CLASS_LOCALERESOLVER = "locale.resolver"; //$NON-NLS-1$
235

236
    /**
237
     * property <code>css.tr.even</code>: holds the name of the css class for even rows. Defaults to <code>even</code>.
238
     */
239
    public static final String PROPERTY_CSS_TR_EVEN = "css.tr.even"; //$NON-NLS-1$
240

241
    /**
242
     * property <code>css.tr.odd</code>: holds the name of the css class for odd rows. Defaults to <code>odd</code>.
243
     */
244
    public static final String PROPERTY_CSS_TR_ODD = "css.tr.odd"; //$NON-NLS-1$
245

246
    /**
247
     * property <code>css.table</code>: holds the name of the css class added to the main table tag. By default no css
248
     * class is added.
249
     */
250
    public static final String PROPERTY_CSS_TABLE = "css.table"; //$NON-NLS-1$
251

252
    /**
253
     * property <code>css.th.sortable</code>: holds the name of the css class added to the the header of a sortable
254
     * column. By default no css class is added.
255
     */
256
    public static final String PROPERTY_CSS_TH_SORTABLE = "css.th.sortable"; //$NON-NLS-1$
257

258
    /**
259
     * property <code>css.th.sorted</code>: holds the name of the css class added to the the header of a sorted column.
260
     * Defaults to <code>sorted</code>.
261
     */
262
    public static final String PROPERTY_CSS_TH_SORTED = "css.th.sorted"; //$NON-NLS-1$
263

264
    /**
265
     * property <code>css.th.ascending</code>: holds the name of the css class added to the the header of a column
266
     * sorted in ascending order. Defaults to <code>order1</code>.
267
     */
268
    public static final String PROPERTY_CSS_TH_SORTED_ASCENDING = "css.th.ascending"; //$NON-NLS-1$
269

270
    /**
271
     * property <code>css.th.descending</code>: holds the name of the css class added to the the header of a column
272
     * sorted in descending order. Defaults to <code>order2</code>.
273
     */
274
    public static final String PROPERTY_CSS_TH_SORTED_DESCENDING = "css.th.descending"; //$NON-NLS-1$
275

276
    /**
277
     * prefix used for all the properties related to export ("export"). The full property name is <code>export.</code>
278
     * <em>[export type]</em><code>.</code><em>[property name]</em>
279
     */
280
    public static final String PROPERTY_EXPORT_PREFIX = "export"; //$NON-NLS-1$
281

282
    /**
283
     * prefix used to set the media decorator property name. The full property name is <code>decorator.media.</code>
284
     * <em>[export type]</em>.
285
     */
286
    public static final String PROPERTY_DECORATOR_SUFFIX = "decorator"; //$NON-NLS-1$
287

288
    /**
289
     * used to set the media decorator property name. The full property name is <code>decorator.media.</code>
290
     * <em>[export type]</em>
291
     */
292
    public static final String PROPERTY_DECORATOR_MEDIA = "media"; //$NON-NLS-1$
293

294
    /**
295
     * used to set the totaler property name. The property name is <code>totaler</code>
296
     */
297
    public static final String TOTALER_NAME = "totaler"; //$NON-NLS-1$
298

299
    /**
300
     * property <code>export.types</code>: holds the list of export available export types.
301
     */
302
    public static final String PROPERTY_EXPORTTYPES = "export.types"; //$NON-NLS-1$
303

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

309
    /**
310
     * export property <code>class</code>.
311
     */
312
    public static final String EXPORTPROPERTY_STRING_CLASS = "class"; //$NON-NLS-1$
313

314
    /**
315
     * export property <code>include_header</code>.
316
     */
317
    public static final String EXPORTPROPERTY_BOOLEAN_EXPORTHEADER = "include_header"; //$NON-NLS-1$
318

319
    /**
320
     * export property <code>filename</code>.
321
     */
322
    public static final String EXPORTPROPERTY_STRING_FILENAME = "filename"; //$NON-NLS-1$
323

324
    /**
325
     * Property <code>pagination.sort.param</code>. If external pagination and sorting is used, it holds the name of the
326
     * parameter used to hold the sort criterion in generated links
327
     */
328
    public static final String PROPERTY_STRING_PAGINATION_SORT_PARAM = "pagination.sort.param"; //$NON-NLS-1$
329

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

336
    /**
337
     * Property <code>pagination.pagenumber.param</code>. If external pagination and sorting is used, it holds the name
338
     * of the parameter used to hold the page number in generated links
339
     */
340
    public static final String PROPERTY_STRING_PAGINATION_PAGE_NUMBER_PARAM = "pagination.pagenumber.param"; //$NON-NLS-1$
341

342
    /**
343
     * Property <code>pagination.searchid.param</code>. If external pagination and sorting is used, it holds the name of
344
     * the parameter used to hold the search ID in generated links
345
     */
346
    public static final String PROPERTY_STRING_PAGINATION_SEARCH_ID_PARAM = "pagination.searchid.param"; //$NON-NLS-1$
347

348
    /**
349
     * Property <code>pagination.sort.asc.value</code>. If external pagination and sorting is used, it holds the value
350
     * of the parameter of the sort direction parameter for "ascending"
351
     */
352
    public static final String PROPERTY_STRING_PAGINATION_ASC_VALUE = "pagination.sort.asc.value"; //$NON-NLS-1$
353

354
    /**
355
     * Property <code>pagination.sort.desc.value</code>. If external pagination and sorting is used, it holds the value
356
     * of the parameter of the sort direction parameter for "descending"
357
     */
358
    public static final String PROPERTY_STRING_PAGINATION_DESC_VALUE = "pagination.sort.desc.value"; //$NON-NLS-1$
359

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

368
    /**
369
     * Property <code>comparator.default</code>. If present, will use use as the classname of the default comparator.
370
     * Will be overriden by column level comparators.
371
     */
372
    public static final String PROPERTY_DEFAULT_COMPARATOR = "comparator.default"; //$NON-NLS-1$
373

374
    /**
375
     * Property <code>escapeXml.default</code>. Specifies the default value for column <code>escapeXml</code> attribute.
376
     */
377
    public static final String PROPERTY_BOOLEAN_ESCAPEXML_DEFAULT = "escapeXml.default"; //$NON-NLS-1$
378

379
    // </JBN>
380

381
    /**
382
     * Separator char used in property names.
383
     */
384
    private static final char SEP = '.';
385

386
    /**
387
     * logger.
388
     */
389
    private static Logger log = LoggerFactory.getLogger(TableProperties.class);
1✔
390

391
    /**
392
     * The userProperties are local, non-default properties; these settings override the defaults from
393
     * displaytag.properties and TableTag.properties.
394
     */
395
    private static Properties userProperties = new Properties();
1✔
396

397
    /**
398
     * Configured resource provider. If no ResourceProvider is configured, an no-op one is used. This instance is
399
     * initialized at first use and shared.
400
     */
401
    private static I18nResourceProvider resourceProvider;
402

403
    /**
404
     * Configured locale resolver.
405
     */
406
    private static LocaleResolver localeResolver;
407

408
    /**
409
     * TableProperties for each locale are loaded as needed, and cloned for public usage.
410
     */
411
    private static Map<Locale, TableProperties> prototypes = new HashMap<>();
1✔
412

413
    /**
414
     * Loaded properties (defaults from defaultProperties + custom from bundle).
415
     */
416
    private Properties properties;
417

418
    /**
419
     * The locale for these properties.
420
     */
421
    private final Locale locale;
422

423
    /**
424
     * Cache for dynamically instantiated object (request factory, decorator factory).
425
     */
426
    private final Map<String, Object> objectCache = new HashMap<>();
1✔
427

428
    /**
429
     * Setter for I18nResourceProvider. A resource provider is usually set using displaytag properties, this accessor is
430
     * needed for tests.
431
     *
432
     * @param provider
433
     *            I18nResourceProvider instance
434
     */
435
    protected static void setResourceProvider(final I18nResourceProvider provider) {
436
        TableProperties.resourceProvider = provider;
1✔
437
    }
1✔
438

439
    /**
440
     * Setter for LocaleResolver. A locale resolver is usually set using displaytag properties, this accessor is needed
441
     * for tests.
442
     *
443
     * @param resolver
444
     *            LocaleResolver instance
445
     */
446
    protected static void setLocaleResolver(final LocaleResolver resolver) {
447
        TableProperties.localeResolver = resolver;
1✔
448
    }
1✔
449

450
    /**
451
     * Loads default properties (TableTag.properties).
452
     *
453
     * @return loaded properties
454
     */
455
    private static Properties loadBuiltInProperties() {
456
        final Properties defaultProperties = new Properties();
1✔
457

458
        try {
459
            final InputStream is = TableProperties.class.getResourceAsStream(TableProperties.DEFAULT_FILENAME);
1✔
460
            if (is == null) {
1!
461
                throw new TablePropertiesLoadException(TableProperties.class, TableProperties.DEFAULT_FILENAME, null);
×
462
            }
463
            defaultProperties.load(is);
1✔
464
        } catch (final IOException e) {
×
465
            throw new TablePropertiesLoadException(TableProperties.class, TableProperties.DEFAULT_FILENAME, e);
×
466
        }
1✔
467

468
        return defaultProperties;
1✔
469
    }
470

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

497
        return bundle;
1✔
498
    }
499

500
    /**
501
     * Returns the configured Locale Resolver. This method is called before the loading of localized properties.
502
     *
503
     * @return LocaleResolver instance.
504
     */
505
    public static LocaleResolver getLocaleResolverInstance() {
506

507
        if (TableProperties.localeResolver == null) {
1✔
508

509
            // special handling, table properties is not yet instantiated
510
            String className = null;
1✔
511

512
            final ResourceBundle defaultUserProperties = TableProperties.loadUserProperties(Locale.getDefault());
1✔
513

514
            // if available, user properties have higher precedence
515
            if (defaultUserProperties != null) {
1!
516
                try {
517
                    className = defaultUserProperties.getString(TableProperties.PROPERTY_CLASS_LOCALERESOLVER);
×
518
                } catch (final MissingResourceException e) {
1✔
519
                    // no problem
520
                }
×
521
            }
522

523
            // still null? load defaults
524
            if (className == null) {
1!
525
                final Properties defaults = TableProperties.loadBuiltInProperties();
1✔
526
                className = defaults.getProperty(TableProperties.PROPERTY_CLASS_LOCALERESOLVER);
1✔
527
            }
528

529
            if (className != null) {
1!
530
                try {
531
                    final Class<LocaleResolver> classProperty = (Class<LocaleResolver>) ReflectHelper
×
532
                            .classForName(className);
×
533
                    TableProperties.localeResolver = classProperty.getDeclaredConstructor().newInstance();
×
534

535
                    TableProperties.log.info(Messages.getString("TableProperties.classinitializedto", //$NON-NLS-1$
×
536
                            new Object[] { ClassUtils.getShortClassName(LocaleResolver.class), className }));
×
537
                } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException
×
538
                        | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
539
                        | SecurityException e) {
540
                    TableProperties.log.warn(Messages.getString("TableProperties.errorloading", //$NON-NLS-1$
×
541
                            new Object[] { ClassUtils.getShortClassName(LocaleResolver.class), e.getClass().getName(),
×
542
                                    e.getMessage() }));
×
543
                }
×
544
            } else {
545
                TableProperties.log.info(Messages.getString("TableProperties.noconfigured", //$NON-NLS-1$
1✔
546
                        new Object[] { ClassUtils.getShortClassName(LocaleResolver.class) }));
1✔
547
            }
548

549
            // still null?
550
            if (TableProperties.localeResolver == null) {
1!
551
                // fallback locale resolver
552
                TableProperties.localeResolver = pageContext -> pageContext.getRequest().getLocale();
1✔
553
            }
554
        }
555

556
        return TableProperties.localeResolver;
1✔
557
    }
558

559
    /**
560
     * Initialize a new TableProperties loading the default properties file and the user defined one. There is no
561
     * caching used here, caching is assumed to occur in the getInstance factory method.
562
     *
563
     * @param myLocale
564
     *            the locale we are in
565
     */
566
    private TableProperties(final Locale myLocale) {
1✔
567
        this.locale = myLocale;
1✔
568
        // default properties will not change unless this class is reloaded
569
        final Properties defaultProperties = TableProperties.loadBuiltInProperties();
1✔
570

571
        this.properties = new Properties(defaultProperties);
1✔
572
        this.addProperties(myLocale);
1✔
573

574
        // Now copy in the user properties (properties file set by calling setUserProperties()).
575
        // note setUserProperties() MUST BE CALLED before the first TableProperties instantation
576
        final Enumeration<Object> keys = TableProperties.userProperties.keys();
1✔
577
        while (keys.hasMoreElements()) {
1✔
578
            final String key = (String) keys.nextElement();
1✔
579
            if (key != null) {
1!
580
                this.properties.setProperty(key, (String) TableProperties.userProperties.get(key));
1✔
581
            }
582
        }
1✔
583
    }
1✔
584

585
    /**
586
     * Try to load the properties from the local properties file, displaytag.properties, and merge them into the
587
     * existing properties.
588
     *
589
     * @param userLocale
590
     *            the locale from which the properties are to be loaded
591
     */
592
    private void addProperties(final Locale userLocale) {
593
        final ResourceBundle bundle = TableProperties.loadUserProperties(userLocale);
1✔
594

595
        if (bundle != null) {
1!
596
            final Enumeration<String> keys = bundle.getKeys();
1✔
597
            while (keys.hasMoreElements()) {
1✔
598
                final String key = keys.nextElement();
1✔
599
                this.properties.setProperty(key, bundle.getString(key));
1✔
600
            }
1✔
601
        }
602
    }
1✔
603

604
    /**
605
     * Clones the properties as well.
606
     *
607
     * @return a new clone of oneself
608
     */
609
    @Override
610
    protected Object clone() {
611
        TableProperties twin;
612
        try {
613
            twin = (TableProperties) super.clone();
1✔
614
        } catch (final CloneNotSupportedException e) {
×
615
            // should never happen
616
            throw new RuntimeException(e);
×
617
        }
1✔
618
        twin.properties = (Properties) this.properties.clone();
1✔
619
        return twin;
1✔
620
    }
621

622
    /**
623
     * Returns a new TableProperties instance for the given locale.
624
     *
625
     * @param pageContext
626
     *            PageContext needed to extract the locale to use. If null the default locale will be used.
627
     *
628
     * @return TableProperties instance
629
     */
630
    public static TableProperties getInstance(final PageContext pageContext) {
631
        Locale locale;
632
        if (pageContext != null) {
1✔
633
            locale = TableProperties.getLocaleResolverInstance().resolveLocale(pageContext);
1✔
634
        } else {
635
            // for some configuration parameters locale doesn't matter
636
            locale = Locale.getDefault();
1✔
637
        }
638

639
        TableProperties props = TableProperties.prototypes.get(locale);
1✔
640
        if (props == null) {
1✔
641
            final TableProperties lprops = new TableProperties(locale);
1✔
642
            TableProperties.prototypes.put(locale, lprops);
1✔
643
            props = lprops;
1✔
644
        }
645
        return (TableProperties) props.clone();
1✔
646
    }
647

648
    /**
649
     * Unload all cached properties. This will not clear properties set by by setUserProperties; you must clear those
650
     * manually.
651
     */
652
    public static void clearProperties() {
653
        TableProperties.prototypes.clear();
1✔
654
    }
1✔
655

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

677
    /**
678
     * The locale for which these properties are intended.
679
     *
680
     * @return the locale
681
     */
682
    public Locale getLocale() {
683
        return this.locale;
1✔
684
    }
685

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

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

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

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

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

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

740
    /**
741
     * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_SOMEITEMS</code> property.
742
     *
743
     * @return String
744
     */
745
    public String getPagingFoundSomeItems() {
746
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_FOUND_SOMEITEMS);
1✔
747
    }
748

749
    /**
750
     * Getter for the <code>PROPERTY_INT_PAGING_GROUPSIZE</code> property.
751
     *
752
     * @return int
753
     */
754
    public int getPagingGroupSize() {
755
        // default size is 8
756
        return this.getIntProperty(TableProperties.PROPERTY_INT_PAGING_GROUPSIZE, 8);
1✔
757
    }
758

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

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

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

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

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

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

813
    /**
814
     * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_SPARATOR</code> property.
815
     *
816
     * @return String
817
     */
818
    public String getPagingPageSeparator() {
819
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_PAGE_SPARATOR);
1✔
820
    }
821

822
    /**
823
     * Is the given export option enabled?.
824
     *
825
     * @param exportType
826
     *            instance of MediaTypeEnum
827
     *
828
     * @return boolean true if export is enabled
829
     */
830
    public boolean getAddExport(final MediaTypeEnum exportType) {
831
        return this.getBooleanProperty(
1✔
832
                TableProperties.PROPERTY_EXPORT_PREFIX + TableProperties.SEP + exportType.getName());
1✔
833
    }
834

835
    /**
836
     * Should headers be included in given export type?.
837
     *
838
     * @param exportType
839
     *            instance of MediaTypeEnum
840
     *
841
     * @return boolean true if export should include headers
842
     */
843
    public boolean getExportHeader(final MediaTypeEnum exportType) {
844
        return this.getBooleanProperty(TableProperties.PROPERTY_EXPORT_PREFIX + TableProperties.SEP
1✔
845
                + exportType.getName() + TableProperties.SEP + TableProperties.EXPORTPROPERTY_BOOLEAN_EXPORTHEADER);
1✔
846
    }
847

848
    /**
849
     * Returns the label for the given export option.
850
     *
851
     * @param exportType
852
     *            instance of MediaTypeEnum
853
     *
854
     * @return String label
855
     */
856
    public String getExportLabel(final MediaTypeEnum exportType) {
857
        return this.getProperty(TableProperties.PROPERTY_EXPORT_PREFIX + TableProperties.SEP + exportType.getName()
1✔
858
                + TableProperties.SEP + TableProperties.EXPORTPROPERTY_STRING_LABEL);
859
    }
860

861
    /**
862
     * Returns the file name for the given media. Can be null
863
     *
864
     * @param exportType
865
     *            instance of MediaTypeEnum
866
     *
867
     * @return String filename
868
     */
869
    public String getExportFileName(final MediaTypeEnum exportType) {
870
        return this.getProperty(TableProperties.PROPERTY_EXPORT_PREFIX + TableProperties.SEP + exportType.getName()
1✔
871
                + TableProperties.SEP + TableProperties.EXPORTPROPERTY_STRING_FILENAME);
872
    }
873

874
    /**
875
     * Getter for the <code>PROPERTY_BOOLEAN_EXPORTDECORATED</code> property.
876
     *
877
     * @return boolean <code>true</code> if decorators should be used in exporting
878
     */
879
    public boolean getExportDecorated() {
880
        return this.getBooleanProperty(TableProperties.PROPERTY_BOOLEAN_EXPORTDECORATED);
1✔
881
    }
882

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

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

901
    /**
902
     * Getter for the <code>PROPERTY_STRING_EXPORTBANNER_SEPARATOR</code> property.
903
     *
904
     * @return String
905
     */
906
    public String getExportBannerSeparator() {
907
        return this.getProperty(TableProperties.PROPERTY_STRING_EXPORTBANNER_SEPARATOR);
1✔
908
    }
909

910
    /**
911
     * Getter for the <code>PROPERTY_BOOLEAN_SHOWHEADER</code> property.
912
     *
913
     * @return boolean
914
     */
915
    public boolean getShowHeader() {
916
        return this.getBooleanProperty(TableProperties.PROPERTY_BOOLEAN_SHOWHEADER);
1✔
917
    }
918

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

928
    /**
929
     * Getter for the <code>PROPERTY_STRING_EMPTYLISTROW_MESSAGE</code> property.
930
     *
931
     * @return String
932
     */
933
    public String getEmptyListRowMessage() {
934
        return this.getProperty(TableProperties.PROPERTY_STRING_EMPTYLISTROW_MESSAGE);
1✔
935
    }
936

937
    /**
938
     * Getter for the <code>PROPERTY_BOOLEAN_EMPTYLIST_SHOWTABLE</code> property.
939
     *
940
     * @return boolean <code>true</code> if table should be displayed also if no items are found
941
     */
942
    public boolean getEmptyListShowTable() {
943
        return this.getBooleanProperty(TableProperties.PROPERTY_BOOLEAN_EMPTYLIST_SHOWTABLE);
1✔
944
    }
945

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

955
    /**
956
     * Getter for the <code>PROPERTY_STRING_SORTAMOUNT</code> property.
957
     *
958
     * @return boolean <code>true</code> if <code>sort.amount</code> is <code>list</code>
959
     */
960
    public boolean getSortFullList() {
961
        return "list".equals(this.getProperty(TableProperties.PROPERTY_STRING_SORTAMOUNT)); //$NON-NLS-1$
1✔
962
    }
963

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

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

984
    /**
985
     * Should paging banner be added before the table?.
986
     *
987
     * @return boolean
988
     */
989
    public boolean getAddExportBannerTop() {
990
        final String placement = this.getProperty(TableProperties.PROPERTY_STRING_EXPORTBANNER_PLACEMENT);
1✔
991
        return Strings.CS.equals("top", placement) || Strings.CS.equals("both", placement); //$NON-NLS-1$ //$NON-NLS-2$
1!
992
    }
993

994
    /**
995
     * Should paging banner be added after the table?.
996
     *
997
     * @return boolean
998
     */
999
    public boolean getAddExportBannerBottom() {
1000
        final String placement = this.getProperty(TableProperties.PROPERTY_STRING_EXPORTBANNER_PLACEMENT);
1✔
1001
        // no value specified puts it on th bottom too to ensure proper backward compatibility
1002
        return !Strings.CS.equals("top", placement); //$NON-NLS-1$
1!
1003
    }
1004

1005
    /**
1006
     * Returns the appropriate css class for a table row.
1007
     *
1008
     * @param rowNumber
1009
     *            row number
1010
     *
1011
     * @return the value of <code>PROPERTY_CSS_TR_EVEN</code> if rowNumber is even or <code>PROPERTY_CSS_TR_ODD</code>
1012
     *         if rowNumber is odd.
1013
     */
1014
    public String getCssRow(final int rowNumber) {
1015
        return this.getProperty(
1✔
1016
                rowNumber % 2 == 0 ? TableProperties.PROPERTY_CSS_TR_ODD : TableProperties.PROPERTY_CSS_TR_EVEN);
1✔
1017
    }
1018

1019
    /**
1020
     * Returns the appropriate css class for a sorted column header.
1021
     *
1022
     * @param ascending
1023
     *            <code>true</code> if column is sorded in ascending order.
1024
     *
1025
     * @return the value of <code>PROPERTY_CSS_TH_SORTED_ASCENDING</code> if column is sorded in ascending order or
1026
     *         <code>PROPERTY_CSS_TH_SORTED_DESCENDING</code> if column is sorded in descending order.
1027
     */
1028
    public String getCssOrder(final boolean ascending) {
1029
        return this.getProperty(ascending ? TableProperties.PROPERTY_CSS_TH_SORTED_ASCENDING
1✔
1030
                : TableProperties.PROPERTY_CSS_TH_SORTED_DESCENDING);
1✔
1031
    }
1032

1033
    /**
1034
     * Returns the configured css class for a sorted column header.
1035
     *
1036
     * @return the value of <code>PROPERTY_CSS_TH_SORTED</code>
1037
     */
1038
    public String getCssSorted() {
1039
        return this.getProperty(TableProperties.PROPERTY_CSS_TH_SORTED);
1✔
1040
    }
1041

1042
    /**
1043
     * Returns the configured css class for the main table tag.
1044
     *
1045
     * @return the value of <code>PROPERTY_CSS_TABLE</code>
1046
     */
1047
    public String getCssTable() {
1048
        return this.getProperty(TableProperties.PROPERTY_CSS_TABLE);
1✔
1049
    }
1050

1051
    /**
1052
     * Returns the configured css class for a sortable column header.
1053
     *
1054
     * @return the value of <code>PROPERTY_CSS_TH_SORTABLE</code>
1055
     */
1056
    public String getCssSortable() {
1057
        return this.getProperty(TableProperties.PROPERTY_CSS_TH_SORTABLE);
1✔
1058
    }
1059

1060
    /**
1061
     * Returns the configured list of media.
1062
     *
1063
     * @return the value of <code>PROPERTY_EXPORTTYPES</code>
1064
     */
1065
    public String[] getExportTypes() {
1066
        final String list = this.getProperty(TableProperties.PROPERTY_EXPORTTYPES);
1✔
1067
        if (list == null) {
1!
1068
            return new String[0];
×
1069
        }
1070

1071
        return StringUtils.split(list);
1✔
1072
    }
1073

1074
    /**
1075
     * Returns the class responsible for the given export.
1076
     *
1077
     * @param exportName
1078
     *            export name
1079
     *
1080
     * @return String classname
1081
     */
1082
    public String getExportClass(final String exportName) {
1083
        return this.getProperty(TableProperties.PROPERTY_EXPORT_PREFIX + TableProperties.SEP + exportName
1✔
1084
                + TableProperties.SEP + TableProperties.EXPORTPROPERTY_STRING_CLASS);
1085
    }
1086

1087
    /**
1088
     * Returns an instance of configured requestHelperFactory.
1089
     *
1090
     * @return RequestHelperFactory instance.
1091
     */
1092
    public RequestHelperFactory getRequestHelperFactoryInstance() {
1093
        final Object loadedObject = this.getClassPropertyInstance(TableProperties.PROPERTY_CLASS_REQUESTHELPERFACTORY);
1✔
1094

1095
        // should not be null, but avoid errors just in case... see DISPL-148
1096
        if (loadedObject == null) {
1!
1097
            return new DefaultRequestHelperFactory();
×
1098
        }
1099

1100
        try {
1101
            return (RequestHelperFactory) loadedObject;
1✔
1102
        } catch (final ClassCastException e) {
×
1103
            throw new FactoryInstantiationException(this.getClass(),
×
1104
                    TableProperties.PROPERTY_CLASS_REQUESTHELPERFACTORY, loadedObject.getClass().getName(), e);
×
1105
        }
1106
    }
1107

1108
    /**
1109
     * Returns an instance of configured DecoratorFactory.
1110
     *
1111
     * @return DecoratorFactory instance.
1112
     */
1113
    public DecoratorFactory getDecoratorFactoryInstance() {
1114
        final Object loadedObject = this.getClassPropertyInstance(TableProperties.PROPERTY_CLASS_DECORATORFACTORY);
1✔
1115

1116
        if (loadedObject == null) {
1!
1117
            return new DefaultDecoratorFactory();
×
1118
        }
1119

1120
        try {
1121
            return (DecoratorFactory) loadedObject;
1✔
1122
        } catch (final ClassCastException e) {
×
1123
            throw new FactoryInstantiationException(this.getClass(), TableProperties.PROPERTY_CLASS_DECORATORFACTORY,
×
1124
                    loadedObject.getClass().getName(), e);
×
1125
        }
1126
    }
1127

1128
    /**
1129
     * Gets the pagination sort param.
1130
     *
1131
     * @return the pagination sort param
1132
     */
1133
    public String getPaginationSortParam() {
1134
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_SORT_PARAM);
1✔
1135
        if (result == null) {
1!
1136
            result = "sort";
×
1137
        }
1138
        return result;
1✔
1139
    }
1140

1141
    /**
1142
     * Gets the pagination page number param.
1143
     *
1144
     * @return the pagination page number param
1145
     */
1146
    public String getPaginationPageNumberParam() {
1147
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_PAGE_NUMBER_PARAM);
1✔
1148
        if (result == null) {
1!
1149
            result = "page";
×
1150
        }
1151
        return result;
1✔
1152
    }
1153

1154
    /**
1155
     * Gets the pagination sort direction param.
1156
     *
1157
     * @return the pagination sort direction param
1158
     */
1159
    public String getPaginationSortDirectionParam() {
1160
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_SORT_DIRECTION_PARAM);
1✔
1161
        if (result == null) {
1!
1162
            result = "dir";
×
1163
        }
1164
        return result;
1✔
1165
    }
1166

1167
    /**
1168
     * Gets the pagination search id param.
1169
     *
1170
     * @return the pagination search id param
1171
     */
1172
    public String getPaginationSearchIdParam() {
1173
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_SEARCH_ID_PARAM);
1✔
1174
        if (result == null) {
1!
1175
            result = "searchId";
×
1176
        }
1177
        return result;
1✔
1178
    }
1179

1180
    /**
1181
     * Gets the pagination asc value.
1182
     *
1183
     * @return the pagination asc value
1184
     */
1185
    public String getPaginationAscValue() {
1186
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_ASC_VALUE);
1✔
1187
        if (result == null) {
1!
1188
            result = "asc";
×
1189
        }
1190
        return result;
1✔
1191
    }
1192

1193
    /**
1194
     * Gets the pagination desc value.
1195
     *
1196
     * @return the pagination desc value
1197
     */
1198
    public String getPaginationDescValue() {
1199
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_DESC_VALUE);
×
1200
        if (result == null) {
×
1201
            result = "desc";
×
1202
        }
1203
        return result;
×
1204
    }
1205

1206
    /**
1207
     * Gets the pagination skip page number in sort.
1208
     *
1209
     * @return the pagination skip page number in sort
1210
     */
1211
    public boolean getPaginationSkipPageNumberInSort() {
1212
        final String s = this.getProperty(TableProperties.PROPERTY_BOOLEAN_PAGINATION_SKIP_PAGE_NUMBER_IN_SORT);
1✔
1213
        if (s == null) {
1!
1214
            return true;
×
1215
        }
1216
        return this.getBooleanProperty(TableProperties.PROPERTY_BOOLEAN_PAGINATION_SKIP_PAGE_NUMBER_IN_SORT);
1✔
1217
    }
1218

1219
    // </JBN>
1220

1221
    /**
1222
     * Returns the configured resource provider instance. If necessary instantiate the resource provider from config and
1223
     * then keep a cached instance.
1224
     *
1225
     * @return I18nResourceProvider instance.
1226
     *
1227
     * @see I18nResourceProvider
1228
     */
1229
    public I18nResourceProvider geResourceProvider() {
1230
        final String className = this.getProperty(TableProperties.PROPERTY_CLASS_LOCALEPROVIDER);
1✔
1231

1232
        if (TableProperties.resourceProvider == null) {
1✔
1233
            if (className != null) {
1!
1234
                try {
1235
                    final Class<I18nResourceProvider> classProperty = (Class<I18nResourceProvider>) ReflectHelper
1✔
1236
                            .classForName(className);
1✔
1237
                    TableProperties.resourceProvider = classProperty.getDeclaredConstructor().newInstance();
1✔
1238

1239
                    if (log.isInfoEnabled()) {
1!
1240
                        TableProperties.log.info(Messages.getString("TableProperties.classinitializedto", //$NON-NLS-1$
1✔
1241
                                new Object[] { ClassUtils.getShortClassName(I18nResourceProvider.class), className }));
1✔
1242
                    }
UNCOV
1243
                } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException
×
1244
                        | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
1245
                        | SecurityException e) {
1246
                    TableProperties.log.warn(Messages.getString("TableProperties.errorloading", //$NON-NLS-1$
×
1247
                            new Object[] { ClassUtils.getShortClassName(I18nResourceProvider.class),
×
1248
                                    e.getClass().getName(), e.getMessage() }));
×
1249
                }
1✔
1250
            } else {
NEW
1251
                if (log.isInfoEnabled()) {
×
NEW
1252
                    TableProperties.log.info(Messages.getString("TableProperties.noconfigured", //$NON-NLS-1$
×
NEW
1253
                            new Object[] { ClassUtils.getShortClassName(I18nResourceProvider.class) }));
×
1254
                }
1255
            }
1256

1257
            // still null?
1258
            if (TableProperties.resourceProvider == null) {
1!
1259
                // fallback provider, no i18n
1260
                TableProperties.resourceProvider = (titleKey, property, tag, context) -> null;
×
1261
            }
1262
        }
1263

1264
        return TableProperties.resourceProvider;
1✔
1265
    }
1266

1267
    /**
1268
     * Reads a String property.
1269
     *
1270
     * @param key
1271
     *            property name
1272
     *
1273
     * @return property value or <code>null</code> if property is not found
1274
     */
1275
    public String getProperty(final String key) {
1276
        return this.properties.getProperty(key);
1✔
1277
    }
1278

1279
    /**
1280
     * Sets a property.
1281
     *
1282
     * @param key
1283
     *            property name
1284
     * @param value
1285
     *            property value
1286
     */
1287
    public void setProperty(final String key, final String value) {
1288
        this.properties.setProperty(key, value);
1✔
1289
    }
1✔
1290

1291
    /**
1292
     * Reads a boolean property.
1293
     *
1294
     * @param key
1295
     *            property name
1296
     *
1297
     * @return boolean <code>true</code> if the property value is "true", <code>false</code> for any other value.
1298
     */
1299
    private boolean getBooleanProperty(final String key) {
1300
        return Boolean.TRUE.toString().equals(this.getProperty(key));
1✔
1301
    }
1302

1303
    /**
1304
     * Returns an instance of a configured Class. Returns a configured Class instantiated
1305
     * callingClass.forName([configuration value]).
1306
     *
1307
     * @param key
1308
     *            configuration key
1309
     *
1310
     * @return instance of configured class
1311
     */
1312
    private Object getClassPropertyInstance(final String key) {
1313

1314
        final String className = this.getProperty(key);
1✔
1315

1316
        // shouldn't be null, but better check it
1317
        if (className == null) {
1!
1318
            return null;
×
1319
        }
1320

1321
        Object instance = this.objectCache.get(className);
1✔
1322
        if (instance != null) {
1✔
1323
            return instance;
1✔
1324
        }
1325

1326
        try {
1327
            final Class<?> classProperty = ReflectHelper.classForName(className);
1✔
1328
            instance = classProperty.getDeclaredConstructor().newInstance();
1✔
1329
            this.objectCache.put(className, instance);
1✔
1330
            return instance;
1✔
1331
        } catch (final Exception e) {
×
1332
            throw new FactoryInstantiationException(this.getClass(), key, className, e);
×
1333
        }
1334
    }
1335

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

1355
        return defaultValue;
×
1356
    }
1357

1358
    /**
1359
     * Obtain the name of the decorator configured for a given media type.
1360
     *
1361
     * @param thatEnum
1362
     *            A media type
1363
     *
1364
     * @return The name of the decorator configured for a given media type.
1365
     */
1366
    public String getMediaTypeDecoratorName(final MediaTypeEnum thatEnum) {
1367
        return this.getProperty(TableProperties.PROPERTY_DECORATOR_SUFFIX + TableProperties.SEP
1✔
1368
                + TableProperties.PROPERTY_DECORATOR_MEDIA + TableProperties.SEP + thatEnum);
1369
    }
1370

1371
    /**
1372
     * the classname of the totaler.
1373
     *
1374
     * @return the classname of the totaler
1375
     */
1376
    public String getTotalerName() {
1377
        return this.getProperty(TableProperties.TOTALER_NAME);
1✔
1378
    }
1379

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

1403
    /**
1404
     * Returns the default value for column <code>escapeXml</code> attribute.
1405
     *
1406
     * @return The default value for column <code>escapeXml</code> attribute
1407
     */
1408
    public boolean getEscapeXmlDefault() {
1409
        return getBooleanProperty(PROPERTY_BOOLEAN_ESCAPEXML_DEFAULT);
1✔
1410
    }
1411
}
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