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

hazendaz / displaytag / 1753

12 Feb 2026 03:17AM UTC coverage: 77.321% (-0.01%) from 77.334%
1753

push

github

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

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

1438 of 2003 branches covered (71.79%)

Branch coverage included in aggregate %.

4034 of 5074 relevant lines covered (79.5%)

0.8 hits per line

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

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

9
import java.io.IOException;
10
import java.text.MessageFormat;
11
import java.util.Iterator;
12
import java.util.Map;
13
import java.util.Map.Entry;
14
import java.util.Objects;
15

16
import javax.servlet.jsp.JspWriter;
17

18
import org.apache.commons.lang3.StringUtils;
19
import org.apache.commons.lang3.Strings;
20
import org.displaytag.exception.DecoratorException;
21
import org.displaytag.exception.ObjectLookupException;
22
import org.displaytag.exception.WrappedRuntimeException;
23
import org.displaytag.model.Column;
24
import org.displaytag.model.HeaderCell;
25
import org.displaytag.model.Row;
26
import org.displaytag.model.TableModel;
27
import org.displaytag.pagination.PaginatedList;
28
import org.displaytag.pagination.SmartListHelper;
29
import org.displaytag.properties.MediaTypeEnum;
30
import org.displaytag.properties.SortOrderEnum;
31
import org.displaytag.properties.TableProperties;
32
import org.displaytag.tags.CaptionTag;
33
import org.displaytag.tags.TableTagParameters;
34
import org.displaytag.util.Anchor;
35
import org.displaytag.util.Href;
36
import org.displaytag.util.HtmlAttributeMap;
37
import org.displaytag.util.ParamEncoder;
38
import org.displaytag.util.PostHref;
39
import org.displaytag.util.TagConstants;
40
import org.slf4j.Logger;
41
import org.slf4j.LoggerFactory;
42

43
/**
44
 * A table writer that formats a table in HTML and writes it to a JSP page.
45
 *
46
 * @see org.displaytag.render.TableWriterTemplate
47
 *
48
 * @since 1.1
49
 */
50
public class HtmlTableWriter extends TableWriterAdapter {
51

52
    /** Logger. */
53
    private static Logger logger = LoggerFactory.getLogger(HtmlTableWriter.class);
1✔
54

55
    /** <code>TableProperties</code>. */
56
    private final TableProperties properties;
57

58
    /**
59
     * Output destination.
60
     */
61
    private final JspWriter out;
62

63
    /**
64
     * The param encoder used to generate unique parameter names. Initialized at the first use of encodeParameter().
65
     */
66
    private ParamEncoder paramEncoder;
67

68
    /**
69
     * base href used for links.
70
     */
71
    private final Href baseHref;
72

73
    /**
74
     * add export links.
75
     */
76
    private final boolean export;
77

78
    /** The caption tag. */
79
    private final CaptionTag captionTag;
80

81
    /**
82
     * The paginated list containing the external pagination and sort parameters The presence of this paginated list is
83
     * what determines if external pagination and sorting is used or not.
84
     */
85
    private final PaginatedList<Row> paginatedList;
86

87
    /**
88
     * Used by various functions when the person wants to do paging.
89
     */
90
    private final SmartListHelper listHelper;
91

92
    /**
93
     * page size.
94
     */
95
    private final int pagesize;
96

97
    /** The attribute map. */
98
    private final HtmlAttributeMap attributeMap;
99

100
    /**
101
     * Unique table id.
102
     */
103
    private final String uid;
104

105
    /**
106
     * This table writer uses a <code>TableTag</code> and a <code>JspWriter</code> to do its work.
107
     *
108
     * @param tableProperties
109
     *            the table properties
110
     * @param baseHref
111
     *            the base href
112
     * @param export
113
     *            the export
114
     * @param out
115
     *            The output destination.
116
     * @param captionTag
117
     *            the caption tag
118
     * @param paginatedList
119
     *            the paginated list
120
     * @param listHelper
121
     *            the list helper
122
     * @param pagesize
123
     *            the pagesize
124
     * @param attributeMap
125
     *            the attribute map
126
     * @param uid
127
     *            the uid
128
     */
129
    public HtmlTableWriter(final TableProperties tableProperties, final Href baseHref, final boolean export,
130
            final JspWriter out, final CaptionTag captionTag, final PaginatedList<Row> paginatedList,
131
            final SmartListHelper listHelper, final int pagesize, final HtmlAttributeMap attributeMap,
132
            final String uid) {
1✔
133
        this.properties = tableProperties;
1✔
134
        this.baseHref = baseHref;
1✔
135
        this.export = export;
1✔
136
        this.out = out;
1✔
137
        this.captionTag = captionTag;
1✔
138
        this.paginatedList = paginatedList;
1✔
139
        this.listHelper = listHelper;
1✔
140
        this.pagesize = pagesize;
1✔
141
        this.attributeMap = attributeMap;
1✔
142
        this.uid = uid;
1✔
143
    }
1✔
144

145
    /**
146
     * Writes a banner containing search result and paging navigation above an HTML table to a JSP page.
147
     *
148
     * @param model
149
     *            the model
150
     *
151
     * @see org.displaytag.render.TableWriterTemplate#writeTopBanner(org.displaytag.model.TableModel)
152
     */
153
    @Override
154
    protected void writeTopBanner(final TableModel model) {
155
        if (model.getForm() != null) {
1✔
156
            final String submitMethod = properties.getUseLegacyFormSubmit() ? ".submit()" : ".requestSubmit()";
1!
157
            final String js = "<script type=\"text/javascript\">\n" + "function displaytagform(formname, fields){\n"
1✔
158
                    + "    var objfrm = document.forms[formname];\n"
159
                    + "    for (j=fields.length-1;j>=0;j--){var f= objfrm.elements[fields[j].f];if (f){f.value=fields[j].v};}\n"
160
                    + "    objfrm" + submitMethod + ";\n" + "}\n" + "</script>";
161
            this.writeFormFields(model);
1✔
162
            this.write(js);
1✔
163
        }
164

165
        // Put the page stuff there if it needs to be there...
166
        if (this.properties.getAddPagingBannerTop()) {
1✔
167
            this.writeSearchResultAndNavigation(model);
1✔
168
        }
169

170
        // add export links (only if the table is not empty)
171
        if (this.export && this.properties.getAddExportBannerTop() && !model.getRowListPage().isEmpty()) {
1!
172
            // generate export link
173
            this.writeExportLinks(model);
×
174
        }
175
    }
1✔
176

177
    /**
178
     * Writes an HTML table's opening tags to a JSP page.
179
     *
180
     * @param model
181
     *            the model
182
     *
183
     * @see org.displaytag.render.TableWriterTemplate#writeTableOpener(org.displaytag.model.TableModel)
184
     */
185
    @Override
186
    protected void writeTableOpener(final TableModel model) {
187
        this.write(this.getOpenTag());
1✔
188
    }
1✔
189

190
    /**
191
     * Write form fields.
192
     *
193
     * @param model
194
     *            the model
195
     */
196
    private void writeFormFields(final TableModel model) {
197
        final Map<String, String[]> parameters = this.baseHref.getParameterMap();
1✔
198

199
        final ParamEncoder pe = new ParamEncoder(model.getId());
1✔
200

201
        this.addIfMissing(parameters, pe.encodeParameterName(TableTagParameters.PARAMETER_ORDER));
1✔
202
        this.addIfMissing(parameters, pe.encodeParameterName(TableTagParameters.PARAMETER_PAGE));
1✔
203
        this.addIfMissing(parameters, pe.encodeParameterName(TableTagParameters.PARAMETER_SORT));
1✔
204

205
        for (final Entry<String, String[]> entry : parameters.entrySet()) {
1✔
206
            final Object value = entry.getValue();
1✔
207

208
            if (value != null && value.getClass().isArray()) {
1!
209
                final Object[] arr = (Object[]) value;
1✔
210
                for (final Object element : arr) {
1✔
211
                    this.writeField(entry.getKey(), element);
1✔
212
                }
213
            } else {
1✔
214
                this.writeField(entry.getKey(), value);
×
215
            }
216
        }
1✔
217
    }
1✔
218

219
    /**
220
     * Write field.
221
     *
222
     * @param key
223
     *            the key
224
     * @param value
225
     *            the value
226
     */
227
    private void writeField(final String key, final Object value) {
228
        final StringBuilder buffer = new StringBuilder();
1✔
229
        buffer.append("<input type=\"hidden\" name=\"");
1✔
230
        buffer.append(this.esc(key));
1✔
231
        buffer.append("\" value=\"");
1✔
232
        buffer.append(value);
1✔
233
        buffer.append("\"/>");
1✔
234

235
        this.write(buffer.toString());
1✔
236
    }
1✔
237

238
    /**
239
     * Esc.
240
     *
241
     * @param value
242
     *            the value
243
     *
244
     * @return the string
245
     */
246
    private String esc(final Object value) {
247
        return Strings.CS.replace(value != null ? value.toString() : StringUtils.EMPTY, "\"", "\\\"");
1!
248
    }
249

250
    /**
251
     * Adds an element to the given map if empty (use an empty string as value).
252
     *
253
     * @param parameters
254
     *            Map of parameters
255
     * @param key
256
     *            param key
257
     */
258
    private void addIfMissing(final Map<String, String[]> parameters, final String key) {
259
        parameters.computeIfAbsent(key, k -> new String[] { StringUtils.EMPTY });
1✔
260
    }
1✔
261

262
    /**
263
     * Writes an HTML table's caption to a JSP page.
264
     *
265
     * @param model
266
     *            the model
267
     *
268
     * @see org.displaytag.render.TableWriterTemplate#writeCaption(org.displaytag.model.TableModel)
269
     */
270
    @Override
271
    protected void writeCaption(final TableModel model) {
272
        this.write(this.captionTag.getOpenTag() + model.getCaption() + this.captionTag.getCloseTag());
1✔
273
    }
1✔
274

275
    /**
276
     * Writes an HTML table's footer to a JSP page; HTML requires tfoot to appear before tbody.
277
     *
278
     * @param model
279
     *            the model
280
     *
281
     * @see org.displaytag.render.TableWriterTemplate#writePreBodyFooter(org.displaytag.model.TableModel)
282
     */
283
    @Override
284
    protected void writePreBodyFooter(final TableModel model) {
285
        this.write(TagConstants.TAG_TFOOTER_OPEN);
1✔
286
        this.write(model.getFooter());
1✔
287
        this.write(TagConstants.TAG_TFOOTER_CLOSE);
1✔
288
    }
1✔
289

290
    /**
291
     * Writes the start of an HTML table's body to a JSP page.
292
     *
293
     * @param model
294
     *            the model
295
     *
296
     * @see org.displaytag.render.TableWriterTemplate#writeTableBodyOpener(org.displaytag.model.TableModel)
297
     */
298
    @Override
299
    protected void writeTableBodyOpener(final TableModel model) {
300
        this.write(TagConstants.TAG_TBODY_OPEN);
1✔
301

302
    }
1✔
303

304
    /**
305
     * Writes the end of an HTML table's body to a JSP page.
306
     *
307
     * @param model
308
     *            the model
309
     *
310
     * @see org.displaytag.render.TableWriterTemplate#writeTableBodyCloser(org.displaytag.model.TableModel)
311
     */
312
    @Override
313
    protected void writeTableBodyCloser(final TableModel model) {
314
        this.write(TagConstants.TAG_TBODY_CLOSE);
1✔
315
    }
1✔
316

317
    /**
318
     * Writes the closing structure of an HTML table to a JSP page.
319
     *
320
     * @param model
321
     *            the model
322
     *
323
     * @see org.displaytag.render.TableWriterTemplate#writeTableCloser(org.displaytag.model.TableModel)
324
     */
325
    @Override
326
    protected void writeTableCloser(final TableModel model) {
327
        this.write(TagConstants.TAG_OPENCLOSING);
1✔
328
        this.write(TagConstants.TABLE_TAG_NAME);
1✔
329
        this.write(TagConstants.TAG_CLOSE);
1✔
330
    }
1✔
331

332
    /**
333
     * Writes a banner containing search result, paging navigation, and export links below an HTML table to a JSP page.
334
     *
335
     * @param model
336
     *            the model
337
     *
338
     * @see org.displaytag.render.TableWriterTemplate#writeBottomBanner(org.displaytag.model.TableModel)
339
     */
340
    @Override
341
    protected void writeBottomBanner(final TableModel model) {
342
        this.writeNavigationAndExportLinks(model);
1✔
343
    }
1✔
344

345
    /**
346
     * Write decorated table finish.
347
     *
348
     * @param model
349
     *            the model
350
     *
351
     * @see org.displaytag.render.TableWriterTemplate#writeDecoratedTableFinish(org.displaytag.model.TableModel)
352
     */
353
    @Override
354
    protected void writeDecoratedTableFinish(final TableModel model) {
355
        model.getTableDecorator().finish();
1✔
356
    }
1✔
357

358
    /**
359
     * Write decorated row start.
360
     *
361
     * @param model
362
     *            the model
363
     *
364
     * @see org.displaytag.render.TableWriterTemplate#writeDecoratedRowStart(org.displaytag.model.TableModel)
365
     */
366
    @Override
367
    protected void writeDecoratedRowStart(final TableModel model) {
368
        this.write(model.getTableDecorator().startRow());
1✔
369
    }
1✔
370

371
    /**
372
     * Writes an HTML table's row-opening tag to a JSP page.
373
     *
374
     * @param row
375
     *            the row
376
     *
377
     * @see org.displaytag.render.TableWriterTemplate#writeRowOpener(org.displaytag.model.Row)
378
     */
379
    @Override
380
    protected void writeRowOpener(final Row row) {
381
        this.write(row.getOpenTag());
1✔
382
    }
1✔
383

384
    /**
385
     * Writes an HTML table's column-opening tag to a JSP page.
386
     *
387
     * @param column
388
     *            the column
389
     *
390
     * @throws ObjectLookupException
391
     *             the object lookup exception
392
     * @throws DecoratorException
393
     *             the decorator exception
394
     *
395
     * @see org.displaytag.render.TableWriterTemplate#writeColumnOpener(org.displaytag.model.Column)
396
     */
397
    @Override
398
    protected void writeColumnOpener(final Column column) throws ObjectLookupException, DecoratorException {
399
        this.write(column.getOpenTag());
1✔
400
    }
1✔
401

402
    /**
403
     * Writes an HTML table's column-closing tag to a JSP page.
404
     *
405
     * @param column
406
     *            the column
407
     *
408
     * @see org.displaytag.render.TableWriterTemplate#writeColumnCloser(org.displaytag.model.Column)
409
     */
410
    @Override
411
    protected void writeColumnCloser(final Column column) {
412
        this.write(column.getCloseTag());
1✔
413
    }
1✔
414

415
    /**
416
     * Writes to a JSP page an HTML table row that has no columns.
417
     *
418
     * @param rowValue
419
     *            the row value
420
     *
421
     * @see org.displaytag.render.TableWriterTemplate#writeRowWithNoColumns(java.lang.String)
422
     */
423
    @Override
424
    protected void writeRowWithNoColumns(final String rowValue) {
425
        this.write(TagConstants.TAG_TD_OPEN);
1✔
426
        this.write(rowValue);
1✔
427
        this.write(TagConstants.TAG_TD_CLOSE);
1✔
428
    }
1✔
429

430
    /**
431
     * Writes an HTML table's row-closing tag to a JSP page.
432
     *
433
     * @param row
434
     *            the row
435
     *
436
     * @see org.displaytag.render.TableWriterTemplate#writeRowCloser(org.displaytag.model.Row)
437
     */
438
    @Override
439
    protected void writeRowCloser(final Row row) {
440
        this.write(row.getCloseTag());
1✔
441
    }
1✔
442

443
    /**
444
     * Write decorated row finish.
445
     *
446
     * @param model
447
     *            the model
448
     *
449
     * @see org.displaytag.render.TableWriterTemplate#writeDecoratedRowFinish(org.displaytag.model.TableModel)
450
     */
451
    @Override
452
    protected void writeDecoratedRowFinish(final TableModel model) {
453
        this.write(model.getTableDecorator().finishRow());
1✔
454
    }
1✔
455

456
    /**
457
     * Writes an HTML message to a JSP page explaining that the table model contains no data.
458
     *
459
     * @param emptyListMessage
460
     *            the empty list message
461
     *
462
     * @see org.displaytag.render.TableWriterTemplate#writeEmptyListMessage(java.lang.String)
463
     */
464
    @Override
465
    protected void writeEmptyListMessage(final String emptyListMessage) {
466
        this.write(emptyListMessage);
1✔
467
    }
1✔
468

469
    /**
470
     * Writes a HTML table column value to a JSP page.
471
     *
472
     * @param value
473
     *            the value
474
     * @param column
475
     *            the column
476
     *
477
     * @see org.displaytag.render.TableWriterTemplate#writeColumnValue(java.lang.Object,org.displaytag.model.Column)
478
     */
479
    @Override
480
    protected void writeColumnValue(final Object value, final Column column) {
481
        this.write(value);
1✔
482
    }
1✔
483

484
    /**
485
     * Writes an HTML message to a JSP page explaining that the row contains no data.
486
     *
487
     * @param message
488
     *            the message
489
     *
490
     * @see org.displaytag.render.TableWriterTemplate#writeEmptyListRowMessage(java.lang.String)
491
     */
492
    @Override
493
    protected void writeEmptyListRowMessage(final String message) {
494
        this.write(message);
1✔
495
    }
1✔
496

497
    /**
498
     * Writes an HTML table's column header to a JSP page.
499
     *
500
     * @param model
501
     *            the model
502
     *
503
     * @see org.displaytag.render.TableWriterTemplate#writeTableHeader(org.displaytag.model.TableModel)
504
     */
505
    @Override
506
    protected void writeTableHeader(final TableModel model) {
507

508
        if (HtmlTableWriter.logger.isDebugEnabled()) {
1!
509
            HtmlTableWriter.logger.debug("[{}] getTableHeader called", model.getId());
×
510
        }
511

512
        // open thead
513
        this.write(TagConstants.TAG_THEAD_OPEN);
1✔
514

515
        // open tr
516
        this.write(TagConstants.TAG_TR_OPEN);
1✔
517

518
        // no columns?
519
        if (model.isEmpty()) {
1✔
520
            this.write(TagConstants.TAG_TH_OPEN);
1✔
521
            this.write(TagConstants.TAG_TH_CLOSE);
1✔
522
        }
523

524
        // iterator on columns for header
525
        final Iterator<HeaderCell> iterator = model.getHeaderCellList().iterator();
1✔
526

527
        while (iterator.hasNext()) {
1✔
528
            // get the header cell
529
            final HeaderCell headerCell = iterator.next();
1✔
530

531
            if (headerCell.getSortable()) {
1✔
532
                final String cssSortable = this.properties.getCssSortable();
1✔
533
                headerCell.addHeaderClass(cssSortable);
1✔
534
            }
535

536
            // if sorted add styles
537
            if (headerCell.isAlreadySorted()) {
1✔
538
                // sorted css class
539
                headerCell.addHeaderClass(this.properties.getCssSorted());
1✔
540

541
                // sort order css class
542
                headerCell.addHeaderClass(this.properties.getCssOrder(model.isSortOrderAscending()));
1✔
543
            }
544

545
            // append th with html attributes
546
            this.write(headerCell.getHeaderOpenTag());
1✔
547

548
            // title
549
            String header = headerCell.getTitle();
1✔
550

551
            // column is sortable, create link
552
            if (headerCell.getSortable()) {
1✔
553
                // creates the link for sorting
554
                final Anchor anchor = new Anchor(this.getSortingHref(headerCell, model), header);
1✔
555

556
                // append to buffer
557
                header = anchor.toString();
1✔
558
            }
559

560
            this.write(header);
1✔
561
            this.write(headerCell.getHeaderCloseTag());
1✔
562
        }
1✔
563

564
        // close tr
565
        this.write(TagConstants.TAG_TR_CLOSE);
1✔
566

567
        // close thead
568
        this.write(TagConstants.TAG_THEAD_CLOSE);
1✔
569

570
        if (HtmlTableWriter.logger.isDebugEnabled()) {
1!
571
            HtmlTableWriter.logger.debug("[{}] getTableHeader end", model.getId());
×
572
        }
573
    }
1✔
574

575
    /**
576
     * Generates the link to be added to a column header for sorting.
577
     *
578
     * @param headerCell
579
     *            header cell the link should be added to
580
     * @param model
581
     *            the model
582
     *
583
     * @return Href for sorting
584
     */
585
    private Href getSortingHref(final HeaderCell headerCell, final TableModel model) {
586
        // costruct Href from base href, preserving parameters
587
        Href href = (Href) this.baseHref.clone();
1✔
588

589
        if (model.getForm() != null) {
1!
590
            href = new PostHref(href, model.getForm());
×
591
        }
592

593
        if (this.paginatedList == null) {
1✔
594
            // add column number as link parameter
595
            if (!model.isLocalSort() && headerCell.getSortName() != null) {
1✔
596
                href.addParameter(this.encodeParameter(TableTagParameters.PARAMETER_SORT, model),
1✔
597
                        headerCell.getSortName());
1✔
598
                href.addParameter(this.encodeParameter(TableTagParameters.PARAMETER_SORTUSINGNAME, model), "1");
1✔
599
            } else {
600
                href.addParameter(this.encodeParameter(TableTagParameters.PARAMETER_SORT, model),
1✔
601
                        headerCell.getColumnNumber());
1✔
602
            }
603

604
            boolean nowOrderAscending = true;
1✔
605

606
            if (headerCell.getDefaultSortOrder() != null) {
1✔
607
                final boolean sortAscending = SortOrderEnum.ASCENDING.equals(headerCell.getDefaultSortOrder());
1✔
608
                nowOrderAscending = headerCell.isAlreadySorted() ? !model.isSortOrderAscending() : sortAscending;
1✔
609
            } else {
1✔
610
                nowOrderAscending = (!headerCell.isAlreadySorted() || !model.isSortOrderAscending());
1✔
611
            }
612

613
            final int sortOrderParam = nowOrderAscending ? SortOrderEnum.ASCENDING.getCode()
1✔
614
                    : SortOrderEnum.DESCENDING.getCode();
1✔
615
            href.addParameter(this.encodeParameter(TableTagParameters.PARAMETER_ORDER, model), sortOrderParam);
1✔
616

617
            // If user want to sort the full table I need to reset the page number.
618
            // or if we aren't sorting locally we need to reset the page as well.
619
            if (model.isSortFullTable() || !model.isLocalSort()) {
1✔
620
                href.addParameter(this.encodeParameter(TableTagParameters.PARAMETER_PAGE, model), 1);
1✔
621
            }
622
        } else {
1✔
623
            if (this.properties.getPaginationSkipPageNumberInSort()) {
1!
624
                href.removeParameter(this.properties.getPaginationPageNumberParam());
1✔
625
            }
626

627
            String sortProperty = headerCell.getSortProperty();
1✔
628
            if (sortProperty == null) {
1!
629
                sortProperty = headerCell.getBeanPropertyName();
1✔
630
            }
631

632
            href.addParameter(this.properties.getPaginationSortParam(), sortProperty);
1✔
633
            String dirParam;
634
            if (headerCell.isAlreadySorted()) {
1!
635
                dirParam = model.isSortOrderAscending() ? this.properties.getPaginationDescValue()
1!
636
                        : this.properties.getPaginationAscValue();
1✔
637
            } else {
638
                dirParam = this.properties.getPaginationAscValue();
×
639
            }
640
            href.addParameter(this.properties.getPaginationSortDirectionParam(), dirParam);
1✔
641
            if (this.paginatedList.getSearchId() != null) {
1!
642
                href.addParameter(this.properties.getPaginationSearchIdParam(), this.paginatedList.getSearchId());
1✔
643
            }
644
        }
645

646
        return href;
1✔
647
    }
648

649
    /**
650
     * encode a parameter name to be unique in the page using ParamEncoder.
651
     *
652
     * @param parameterName
653
     *            parameter name to encode
654
     * @param model
655
     *            the model
656
     *
657
     * @return String encoded parameter name
658
     */
659
    private String encodeParameter(final String parameterName, final TableModel model) {
660
        // paramEncoder has been already instantiated?
661
        if (this.paramEncoder == null) {
1✔
662
            // use the id attribute to get the unique identifier
663
            this.paramEncoder = new ParamEncoder(model.getId());
1✔
664
        }
665

666
        return this.paramEncoder.encodeParameterName(parameterName);
1✔
667
    }
668

669
    /**
670
     * Generates table footer with links for export commands.
671
     *
672
     * @param model
673
     *            the model
674
     */
675
    protected void writeNavigationAndExportLinks(final TableModel model) {
676
        // Put the page stuff there if it needs to be there...
677
        if (this.properties.getAddPagingBannerBottom()) {
1✔
678
            this.writeSearchResultAndNavigation(model);
1✔
679
        }
680

681
        // add export links (only if the table is not empty)
682
        if (this.export && this.properties.getAddExportBannerBottom() && !model.getRowListPage().isEmpty()) {
1!
683
            this.writeExportLinks(model);
1✔
684
        }
685
    }
1✔
686

687
    /**
688
     * generates the search result and navigation bar.
689
     *
690
     * @param model
691
     *            the model
692
     */
693
    protected void writeSearchResultAndNavigation(final TableModel model) {
694
        if (this.paginatedList == null && this.pagesize != 0 && this.listHelper != null || this.paginatedList != null) {
1!
695
            // create a new href
696
            Href navigationHref = (Href) this.baseHref.clone();
1✔
697

698
            if (model.getForm() != null) {
1✔
699
                navigationHref = new PostHref(navigationHref, model.getForm());
1✔
700
            }
701

702
            this.write(this.listHelper.getSearchResultsSummary());
1✔
703

704
            String pageParameter;
705
            if (this.paginatedList == null) {
1✔
706
                pageParameter = this.encodeParameter(TableTagParameters.PARAMETER_PAGE, model);
1✔
707
            } else {
708
                pageParameter = this.properties.getPaginationPageNumberParam();
1✔
709
                if (this.paginatedList.getSearchId() != null && !navigationHref.getParameterMap()
1!
710
                        .containsKey(this.properties.getPaginationSearchIdParam())) {
1!
711
                    navigationHref.addParameter(this.properties.getPaginationSearchIdParam(),
1✔
712
                            this.paginatedList.getSearchId());
1✔
713
                }
714
            }
715
            this.write(this.listHelper.getPageNavigationBar(navigationHref, pageParameter));
1✔
716
        }
717
    }
1✔
718

719
    /**
720
     * Writes the formatted export links section.
721
     *
722
     * @param model
723
     *            the model
724
     */
725
    private void writeExportLinks(final TableModel model) {
726
        // Figure out what formats they want to export, make up a little string
727
        final Href exportHref = (Href) this.baseHref.clone();
1✔
728

729
        final StringBuilder buffer = new StringBuilder(200);
1✔
730
        final Iterator<MediaTypeEnum> iterator = MediaTypeEnum.iterator();
1✔
731

732
        while (iterator.hasNext()) {
1✔
733
            final MediaTypeEnum currentExportType = iterator.next();
1✔
734

735
            if (this.properties.getAddExport(currentExportType)) {
1✔
736

737
                if (buffer.length() > 0) {
1✔
738
                    buffer.append(this.properties.getExportBannerSeparator());
1✔
739
                }
740

741
                exportHref.addParameter(this.encodeParameter(TableTagParameters.PARAMETER_EXPORTTYPE, model),
1✔
742
                        currentExportType.getCode());
1✔
743

744
                // export marker
745
                exportHref.addParameter(TableTagParameters.PARAMETER_EXPORTING, "1");
1✔
746

747
                final String exportBannerItem = Objects.toString(this.properties.getExportBannerItem(),
1✔
748
                        "<a href=\"{0}\">{1}</a>");
749

750
                buffer.append(MessageFormat.format(exportBannerItem, exportHref,
1✔
751
                        this.properties.getExportLabel(currentExportType)));
1✔
752
            }
753
        }
1✔
754

755
        final Object[] exportOptions = { buffer.toString() };
1✔
756
        this.write(new MessageFormat(this.properties.getExportBanner(), this.properties.getLocale())
1✔
757
                .format(exportOptions));
1✔
758
    }
1✔
759

760
    /**
761
     * create the open tag containing all the attributes.
762
     *
763
     * @return open tag string: <code>%lt;table attribute="value" ... &gt;</code>
764
     */
765
    public String getOpenTag() {
766

767
        if (this.uid != null && this.attributeMap.get(TagConstants.ATTRIBUTE_ID) == null) {
1✔
768
            // we need to clone the attribute map in order to "fix" the html id when using only the "uid" attribute
769
            final Map<String, String> localAttributeMap = (Map<String, String>) this.attributeMap.clone();
1✔
770
            localAttributeMap.put(TagConstants.ATTRIBUTE_ID, this.uid);
1✔
771

772
            final StringBuilder buffer = new StringBuilder();
1✔
773
            buffer.append(TagConstants.TAG_OPEN).append(TagConstants.TABLE_TAG_NAME);
1✔
774
            buffer.append(localAttributeMap);
1✔
775
            buffer.append(TagConstants.TAG_CLOSE);
1✔
776

777
            return buffer.toString();
1✔
778

779
        }
780

781
        // fast, no clone
782
        final StringBuilder buffer = new StringBuilder();
1✔
783

784
        buffer.append(TagConstants.TAG_OPEN).append(TagConstants.TABLE_TAG_NAME);
1✔
785
        buffer.append(this.attributeMap);
1✔
786
        buffer.append(TagConstants.TAG_CLOSE);
1✔
787

788
        return buffer.toString();
1✔
789
    }
790

791
    /**
792
     * Utility method.
793
     *
794
     * @param string
795
     *            String
796
     */
797
    public void write(final String string) {
798
        if (string != null) {
1✔
799
            try {
800
                this.out.write(string);
1✔
801
            } catch (final IOException e) {
×
802
                throw new WrappedRuntimeException(this.getClass(), e);
×
803
            }
1✔
804
        }
805

806
    }
1✔
807

808
    /**
809
     * Utility method.
810
     *
811
     * @param string
812
     *            String
813
     */
814
    public void write(final Object string) {
815
        if (string != null) {
1!
816
            try {
817
                this.out.write(string.toString());
1✔
818
            } catch (final IOException e) {
×
819
                throw new WrappedRuntimeException(this.getClass(), e);
×
820
            }
1✔
821
        }
822

823
    }
1✔
824

825
}
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