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

hazendaz / displaytag / 1654

20 Jan 2026 04:13PM UTC coverage: 76.983% (-0.01%) from 76.996%
1654

Pull #1066

github

web-flow
Merge 6873e8d51 into 716ac10c6
Pull Request #1066: Make js form submit method configurable

1379 of 1939 branches covered (71.12%)

Branch coverage included in aggregate %.

4 of 5 new or added lines in 2 files covered. (80.0%)

38 existing lines in 1 file now uncovered.

3902 of 4921 relevant lines covered (79.29%)

0.79 hits per line

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

70.03
/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
    /**
380
     * Property <code>legacy.form.submit</code>. Specifies the default value for <code>legacy.form.submit</code> attribute.
381
     */
382
    public static final String PROPERTY_BOOLEAN_LEGACY_FORM_SUBMIT = "legacy.form.submit"; //$NON-NLS-1$
383

384
    // </JBN>
385

386
    /**
387
     * Separator char used in property names.
388
     */
389
    private static final char SEP = '.';
390

391
    /**
392
     * logger.
393
     */
394
    private static Logger log = LoggerFactory.getLogger(TableProperties.class);
395

1✔
396
    /**
397
     * The userProperties are local, non-default properties; these settings override the defaults from
398
     * displaytag.properties and TableTag.properties.
399
     */
400
    private static Properties userProperties = new Properties();
401

1✔
402
    /**
403
     * Configured resource provider. If no ResourceProvider is configured, an no-op one is used. This instance is
404
     * initialized at first use and shared.
405
     */
406
    private static I18nResourceProvider resourceProvider;
407

408
    /**
409
     * Configured locale resolver.
410
     */
411
    private static LocaleResolver localeResolver;
412

413
    /**
414
     * TableProperties for each locale are loaded as needed, and cloned for public usage.
415
     */
416
    private static Map<Locale, TableProperties> prototypes = new HashMap<>();
417

1✔
418
    /**
419
     * Loaded properties (defaults from defaultProperties + custom from bundle).
420
     */
421
    private Properties properties;
422

423
    /**
424
     * The locale for these properties.
425
     */
426
    private final Locale locale;
427

428
    /**
429
     * Cache for dynamically instantiated object (request factory, decorator factory).
430
     */
431
    private final Map<String, Object> objectCache = new HashMap<>();
432

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

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

1✔
455
    /**
456
     * Loads default properties (TableTag.properties).
457
     *
458
     * @return loaded properties
459
     */
460
    private static Properties loadBuiltInProperties() {
461
        final Properties defaultProperties = new Properties();
462

1✔
463
        try {
464
            final InputStream is = TableProperties.class.getResourceAsStream(TableProperties.DEFAULT_FILENAME);
465
            if (is == null) {
1✔
466
                throw new TablePropertiesLoadException(TableProperties.class, TableProperties.DEFAULT_FILENAME, null);
1!
UNCOV
467
            }
×
468
            defaultProperties.load(is);
469
        } catch (final IOException e) {
1✔
470
            throw new TablePropertiesLoadException(TableProperties.class, TableProperties.DEFAULT_FILENAME, e);
×
UNCOV
471
        }
×
472

1✔
473
        return defaultProperties;
474
    }
1✔
475

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

1✔
502
        return bundle;
503
    }
1✔
504

505
    /**
506
     * Returns the configured Locale Resolver. This method is called before the loading of localized properties.
507
     *
508
     * @return LocaleResolver instance.
509
     */
510
    public static LocaleResolver getLocaleResolverInstance() {
511

512
        if (TableProperties.localeResolver == null) {
513

1✔
514
            // special handling, table properties is not yet instantiated
515
            String className = null;
516

1✔
517
            final ResourceBundle defaultUserProperties = TableProperties.loadUserProperties(Locale.getDefault());
518

1✔
519
            // if available, user properties have higher precedence
520
            if (defaultUserProperties != null) {
521
                try {
1!
522
                    className = defaultUserProperties.getString(TableProperties.PROPERTY_CLASS_LOCALERESOLVER);
UNCOV
523
                } catch (final MissingResourceException e) {
×
524
                    // no problem
1✔
525
                }
UNCOV
526
            }
×
527

528
            // still null? load defaults
529
            if (className == null) {
530
                final Properties defaults = TableProperties.loadBuiltInProperties();
1!
531
                className = defaults.getProperty(TableProperties.PROPERTY_CLASS_LOCALERESOLVER);
1✔
532
            }
1✔
533

534
            if (className != null) {
535
                try {
1!
536
                    final Class<LocaleResolver> classProperty = (Class<LocaleResolver>) ReflectHelper
537
                            .classForName(className);
×
538
                    TableProperties.localeResolver = classProperty.getDeclaredConstructor().newInstance();
×
UNCOV
539

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

554
            // still null?
555
            if (TableProperties.localeResolver == null) {
556
                // fallback locale resolver
1!
557
                TableProperties.localeResolver = pageContext -> pageContext.getRequest().getLocale();
558
            }
1✔
559
        }
560

561
        return TableProperties.localeResolver;
562
    }
1✔
563

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

1✔
576
        this.properties = new Properties(defaultProperties);
577
        this.addProperties(myLocale);
1✔
578

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

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

1✔
600
        if (bundle != null) {
601
            final Enumeration<String> keys = bundle.getKeys();
1!
602
            while (keys.hasMoreElements()) {
1✔
603
                final String key = keys.nextElement();
1✔
604
                this.properties.setProperty(key, bundle.getString(key));
1✔
605
            }
1✔
606
        }
1✔
607
    }
608

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

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

644
        TableProperties props = TableProperties.prototypes.get(locale);
645
        if (props == null) {
1✔
646
            final TableProperties lprops = new TableProperties(locale);
1✔
647
            TableProperties.prototypes.put(locale, lprops);
1✔
648
            props = lprops;
1✔
649
        }
1✔
650
        return (TableProperties) props.clone();
651
    }
1✔
652

653
    /**
654
     * Unload all cached properties. This will not clear properties set by by setUserProperties; you must clear those
655
     * manually.
656
     */
657
    public static void clearProperties() {
658
        TableProperties.prototypes.clear();
659
    }
1✔
660

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

1✔
682
    /**
683
     * The locale for which these properties are intended.
684
     *
685
     * @return the locale
686
     */
687
    public Locale getLocale() {
688
        return this.locale;
689
    }
1✔
690

691
    /**
692
     * Getter for the <code>PROPERTY_STRING_PAGING_INVALIDPAGE</code> property.
693
     *
694
     * @return String
695
     */
696
    public String getPagingInvalidPage() {
697
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_INVALIDPAGE);
UNCOV
698
    }
×
699

700
    /**
701
     * Getter for the <code>PROPERTY_STRING_PAGING_ITEM_NAME</code> property.
702
     *
703
     * @return String
704
     */
705
    public String getPagingItemName() {
706
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_ITEM_NAME);
707
    }
1✔
708

709
    /**
710
     * Getter for the <code>PROPERTY_STRING_PAGING_ITEMS_NAME</code> property.
711
     *
712
     * @return String
713
     */
714
    public String getPagingItemsName() {
715
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_ITEMS_NAME);
716
    }
1✔
717

718
    /**
719
     * Getter for the <code>PROPERTY_STRING_PAGING_NOITEMS</code> property.
720
     *
721
     * @return String
722
     */
723
    public String getPagingFoundNoItems() {
724
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_NOITEMS);
UNCOV
725
    }
×
726

727
    /**
728
     * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_ONEITEM</code> property.
729
     *
730
     * @return String
731
     */
732
    public String getPagingFoundOneItem() {
733
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_FOUND_ONEITEM);
734
    }
1✔
735

736
    /**
737
     * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_ALLITEMS</code> property.
738
     *
739
     * @return String
740
     */
741
    public String getPagingFoundAllItems() {
742
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_FOUND_ALLITEMS);
743
    }
1✔
744

745
    /**
746
     * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_SOMEITEMS</code> property.
747
     *
748
     * @return String
749
     */
750
    public String getPagingFoundSomeItems() {
751
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_FOUND_SOMEITEMS);
752
    }
1✔
753

754
    /**
755
     * Getter for the <code>PROPERTY_INT_PAGING_GROUPSIZE</code> property.
756
     *
757
     * @return int
758
     */
759
    public int getPagingGroupSize() {
760
        // default size is 8
761
        return this.getIntProperty(TableProperties.PROPERTY_INT_PAGING_GROUPSIZE, 8);
762
    }
1✔
763

764
    /**
765
     * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_ONEPAGE</code> property.
766
     *
767
     * @return String
768
     */
769
    public String getPagingBannerOnePage() {
770
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_BANNER_ONEPAGE);
771
    }
1✔
772

773
    /**
774
     * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_FIRST</code> property.
775
     *
776
     * @return String
777
     */
778
    public String getPagingBannerFirst() {
779
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_BANNER_FIRST);
780
    }
1✔
781

782
    /**
783
     * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_LAST</code> property.
784
     *
785
     * @return String
786
     */
787
    public String getPagingBannerLast() {
788
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_BANNER_LAST);
789
    }
1✔
790

791
    /**
792
     * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_FULL</code> property.
793
     *
794
     * @return String
795
     */
796
    public String getPagingBannerFull() {
797
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_BANNER_FULL);
798
    }
1✔
799

800
    /**
801
     * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_LINK</code> property.
802
     *
803
     * @return String
804
     */
805
    public String getPagingPageLink() {
806
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_PAGE_LINK);
807
    }
1✔
808

809
    /**
810
     * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_SELECTED</code> property.
811
     *
812
     * @return String
813
     */
814
    public String getPagingPageSelected() {
815
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_PAGE_SELECTED);
816
    }
1✔
817

818
    /**
819
     * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_SPARATOR</code> property.
820
     *
821
     * @return String
822
     */
823
    public String getPagingPageSeparator() {
824
        return this.getProperty(TableProperties.PROPERTY_STRING_PAGING_PAGE_SPARATOR);
825
    }
1✔
826

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

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

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

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

879
    /**
880
     * Getter for the <code>PROPERTY_BOOLEAN_EXPORTDECORATED</code> property.
881
     *
882
     * @return boolean <code>true</code> if decorators should be used in exporting
883
     */
884
    public boolean getExportDecorated() {
885
        return this.getBooleanProperty(TableProperties.PROPERTY_BOOLEAN_EXPORTDECORATED);
886
    }
1✔
887

888
    /**
889
     * Getter for the <code>PROPERTY_STRING_EXPORTBANNER</code> property.
890
     *
891
     * @return String
892
     */
893
    public String getExportBanner() {
894
        return this.getProperty(TableProperties.PROPERTY_STRING_EXPORTBANNER);
895
    }
1✔
896

897
    /**
898
     * Getter for the <code>PROPERTY_STRING_EXPORTBANNER_ITEM</code> property.
899
     *
900
     * @return String
901
     */
902
    public String getExportBannerItem() {
903
        return this.getProperty(TableProperties.PROPERTY_STRING_EXPORTBANNER_ITEM);
904
    }
1✔
905

906
    /**
907
     * Getter for the <code>PROPERTY_STRING_EXPORTBANNER_SEPARATOR</code> property.
908
     *
909
     * @return String
910
     */
911
    public String getExportBannerSeparator() {
912
        return this.getProperty(TableProperties.PROPERTY_STRING_EXPORTBANNER_SEPARATOR);
913
    }
1✔
914

915
    /**
916
     * Getter for the <code>PROPERTY_BOOLEAN_SHOWHEADER</code> property.
917
     *
918
     * @return boolean
919
     */
920
    public boolean getShowHeader() {
921
        return this.getBooleanProperty(TableProperties.PROPERTY_BOOLEAN_SHOWHEADER);
922
    }
1✔
923

924
    /**
925
     * Getter for the <code>PROPERTY_STRING_EMPTYLIST_MESSAGE</code> property.
926
     *
927
     * @return String
928
     */
929
    public String getEmptyListMessage() {
930
        return this.getProperty(TableProperties.PROPERTY_STRING_EMPTYLIST_MESSAGE);
931
    }
1✔
932

933
    /**
934
     * Getter for the <code>PROPERTY_STRING_EMPTYLISTROW_MESSAGE</code> property.
935
     *
936
     * @return String
937
     */
938
    public String getEmptyListRowMessage() {
939
        return this.getProperty(TableProperties.PROPERTY_STRING_EMPTYLISTROW_MESSAGE);
940
    }
1✔
941

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

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

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

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

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

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

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

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

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

1038
    /**
1039
     * Returns the configured css class for a sorted column header.
1040
     *
1041
     * @return the value of <code>PROPERTY_CSS_TH_SORTED</code>
1042
     */
1043
    public String getCssSorted() {
1044
        return this.getProperty(TableProperties.PROPERTY_CSS_TH_SORTED);
1045
    }
1✔
1046

1047
    /**
1048
     * Returns the configured css class for the main table tag.
1049
     *
1050
     * @return the value of <code>PROPERTY_CSS_TABLE</code>
1051
     */
1052
    public String getCssTable() {
1053
        return this.getProperty(TableProperties.PROPERTY_CSS_TABLE);
1054
    }
1✔
1055

1056
    /**
1057
     * Returns the configured css class for a sortable column header.
1058
     *
1059
     * @return the value of <code>PROPERTY_CSS_TH_SORTABLE</code>
1060
     */
1061
    public String getCssSortable() {
1062
        return this.getProperty(TableProperties.PROPERTY_CSS_TH_SORTABLE);
1063
    }
1✔
1064

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

1076
        return StringUtils.split(list);
1077
    }
1✔
1078

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

1092
    /**
1093
     * Returns an instance of configured requestHelperFactory.
1094
     *
1095
     * @return RequestHelperFactory instance.
1096
     */
1097
    public RequestHelperFactory getRequestHelperFactoryInstance() {
1098
        final Object loadedObject = this.getClassPropertyInstance(TableProperties.PROPERTY_CLASS_REQUESTHELPERFACTORY);
1099

1✔
1100
        // should not be null, but avoid errors just in case... see DISPL-148
1101
        if (loadedObject == null) {
1102
            return new DefaultRequestHelperFactory();
1!
UNCOV
1103
        }
×
1104

1105
        try {
1106
            return (RequestHelperFactory) loadedObject;
1107
        } catch (final ClassCastException e) {
1✔
1108
            throw new FactoryInstantiationException(this.getClass(),
×
1109
                    TableProperties.PROPERTY_CLASS_REQUESTHELPERFACTORY, loadedObject.getClass().getName(), e);
×
UNCOV
1110
        }
×
1111
    }
1112

1113
    /**
1114
     * Returns an instance of configured DecoratorFactory.
1115
     *
1116
     * @return DecoratorFactory instance.
1117
     */
1118
    public DecoratorFactory getDecoratorFactoryInstance() {
1119
        final Object loadedObject = this.getClassPropertyInstance(TableProperties.PROPERTY_CLASS_DECORATORFACTORY);
1120

1✔
1121
        if (loadedObject == null) {
1122
            return new DefaultDecoratorFactory();
1!
UNCOV
1123
        }
×
1124

1125
        try {
1126
            return (DecoratorFactory) loadedObject;
1127
        } catch (final ClassCastException e) {
1✔
1128
            throw new FactoryInstantiationException(this.getClass(), TableProperties.PROPERTY_CLASS_DECORATORFACTORY,
×
1129
                    loadedObject.getClass().getName(), e);
×
UNCOV
1130
        }
×
1131
    }
1132

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

1146
    /**
1147
     * Gets the pagination page number param.
1148
     *
1149
     * @return the pagination page number param
1150
     */
1151
    public String getPaginationPageNumberParam() {
1152
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_PAGE_NUMBER_PARAM);
1153
        if (result == null) {
1✔
1154
            result = "page";
1!
UNCOV
1155
        }
×
1156
        return result;
1157
    }
1✔
1158

1159
    /**
1160
     * Gets the pagination sort direction param.
1161
     *
1162
     * @return the pagination sort direction param
1163
     */
1164
    public String getPaginationSortDirectionParam() {
1165
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_SORT_DIRECTION_PARAM);
1166
        if (result == null) {
1✔
1167
            result = "dir";
1!
UNCOV
1168
        }
×
1169
        return result;
1170
    }
1✔
1171

1172
    /**
1173
     * Gets the pagination search id param.
1174
     *
1175
     * @return the pagination search id param
1176
     */
1177
    public String getPaginationSearchIdParam() {
1178
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_SEARCH_ID_PARAM);
1179
        if (result == null) {
1✔
1180
            result = "searchId";
1!
UNCOV
1181
        }
×
1182
        return result;
1183
    }
1✔
1184

1185
    /**
1186
     * Gets the pagination asc value.
1187
     *
1188
     * @return the pagination asc value
1189
     */
1190
    public String getPaginationAscValue() {
1191
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_ASC_VALUE);
1192
        if (result == null) {
1✔
1193
            result = "asc";
1!
UNCOV
1194
        }
×
1195
        return result;
1196
    }
1✔
1197

1198
    /**
1199
     * Gets the pagination desc value.
1200
     *
1201
     * @return the pagination desc value
1202
     */
1203
    public String getPaginationDescValue() {
1204
        String result = this.getProperty(TableProperties.PROPERTY_STRING_PAGINATION_DESC_VALUE);
1205
        if (result == null) {
×
1206
            result = "desc";
×
UNCOV
1207
        }
×
1208
        return result;
UNCOV
1209
    }
×
1210

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

1224
    // </JBN>
1225

1226
    /**
1227
     * Returns the configured resource provider instance. If necessary instantiate the resource provider from config and
1228
     * then keep a cached instance.
1229
     *
1230
     * @return I18nResourceProvider instance.
1231
     *
1232
     * @see I18nResourceProvider
1233
     */
1234
    public I18nResourceProvider geResourceProvider() {
1235
        final String className = this.getProperty(TableProperties.PROPERTY_CLASS_LOCALEPROVIDER);
1236

1✔
1237
        if (TableProperties.resourceProvider == null) {
1238
            if (className != null) {
1✔
1239
                try {
1!
1240
                    final Class<I18nResourceProvider> classProperty = (Class<I18nResourceProvider>) ReflectHelper
1241
                            .classForName(className);
1✔
1242
                    TableProperties.resourceProvider = classProperty.getDeclaredConstructor().newInstance();
1✔
1243

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

1262
            // still null?
1263
            if (TableProperties.resourceProvider == null) {
1264
                // fallback provider, no i18n
1!
1265
                TableProperties.resourceProvider = (titleKey, property, tag, context) -> null;
UNCOV
1266
            }
×
1267
        }
1268

1269
        return TableProperties.resourceProvider;
1270
    }
1✔
1271

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

1284
    /**
1285
     * Sets a property.
1286
     *
1287
     * @param key
1288
     *            property name
1289
     * @param value
1290
     *            property value
1291
     */
1292
    public void setProperty(final String key, final String value) {
1293
        this.properties.setProperty(key, value);
1294
    }
1✔
1295

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

1308
    /**
1309
     * Returns an instance of a configured Class. Returns a configured Class instantiated
1310
     * callingClass.forName([configuration value]).
1311
     *
1312
     * @param key
1313
     *            configuration key
1314
     *
1315
     * @return instance of configured class
1316
     */
1317
    private Object getClassPropertyInstance(final String key) {
1318

1319
        final String className = this.getProperty(key);
1320

1✔
1321
        // shouldn't be null, but better check it
1322
        if (className == null) {
1323
            return null;
1!
UNCOV
1324
        }
×
1325

1326
        Object instance = this.objectCache.get(className);
1327
        if (instance != null) {
1✔
1328
            return instance;
1✔
1329
        }
1✔
1330

1331
        try {
1332
            final Class<?> classProperty = ReflectHelper.classForName(className);
1333
            instance = classProperty.getDeclaredConstructor().newInstance();
1✔
1334
            this.objectCache.put(className, instance);
1✔
1335
            return instance;
1✔
1336
        } catch (final Exception e) {
1✔
1337
            throw new FactoryInstantiationException(this.getClass(), key, className, e);
×
UNCOV
1338
        }
×
1339
    }
1340

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

1360
        return defaultValue;
UNCOV
1361
    }
×
1362

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

1376
    /**
1377
     * the classname of the totaler.
1378
     *
1379
     * @return the classname of the totaler
1380
     */
1381
    public String getTotalerName() {
1382
        return this.getProperty(TableProperties.TOTALER_NAME);
1383
    }
1✔
1384

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

1408
    /**
1409
     * Returns the default value for column <code>escapeXml</code> attribute.
1410
     *
1411
     * @return The default value for column <code>escapeXml</code> attribute
1412
     */
1413
    public boolean getEscapeXmlDefault() {
1414
        return getBooleanProperty(PROPERTY_BOOLEAN_ESCAPEXML_DEFAULT);
1415
    }
1✔
1416

1417
    /**
1418
     * Returns the default value for <code>legacy.form.submit</code> attribute.
1419
     *
1420
     * @return the default value for <code>legacy.form.submit</code> attribute
1421
     */
1422
    public boolean getUseLegacyFormSubmit() {
1423
        final String s = this.getProperty(TableProperties.PROPERTY_BOOLEAN_LEGACY_FORM_SUBMIT);
1424
        if (s == null) {
1✔
1425
            return false;
1!
1426
        }
1✔
1427
        return this.getBooleanProperty(TableProperties.PROPERTY_BOOLEAN_LEGACY_FORM_SUBMIT);
NEW
1428
    }
×
1429
}
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