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

hazendaz / sitemesh2 / 59

22 Mar 2026 02:30AM UTC coverage: 40.347%. Remained the same
59

push

github

hazendaz
[mvn] Update maven wrapper

698 of 1891 branches covered (36.91%)

Branch coverage included in aggregate %.

1555 of 3693 relevant lines covered (42.11%)

0.42 hits per line

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

60.42
/src/main/java/com/opensymphony/module/sitemesh/html/CustomTag.java
1
/*
2
 * SPDX-License-Identifier: Apache-2.0
3
 * Copyright 2011-2026 Hazendaz
4
 */
5
package com.opensymphony.module.sitemesh.html;
6

7
import com.opensymphony.module.sitemesh.DefaultSitemeshBuffer;
8
import com.opensymphony.module.sitemesh.SitemeshBufferFragment;
9
import com.opensymphony.module.sitemesh.html.tokenizer.Parser;
10
import com.opensymphony.module.sitemesh.html.util.StringSitemeshBuffer;
11

12
import java.io.StringWriter;
13
import java.util.Arrays;
14

15
/**
16
 * A CustomTag provides a mechanism to manipulate the contents of a Tag. The standard Tag implementations are immutable,
17
 * however CustomTag allows a copy to be taken of an immutable Tag that can then be manipulated.
18
 *
19
 * @author Joe Walnes
20
 *
21
 * @see Tag
22
 */
23
public class CustomTag implements Tag {
24

25
    /** The attributes. */
26
    private String[] attributes = new String[10]; // name1, value1, name2, value2...
1✔
27

28
    /** The attribute count. */
29
    private int attributeCount = 0;
1✔
30

31
    /** The name. */
32
    private String name;
33

34
    /** The type. */
35
    private int type;
36

37
    /**
38
     * Type of tag: <br/>
39
     * &lt;blah&gt; - Tag.OPEN<br/>
40
     * &lt;/blah&gt; - Tag.CLOSE<br/>
41
     * &lt;blah/&gt; - Tag.EMPTY<br/>
42
     *
43
     * @param name
44
     *            the name
45
     * @param type
46
     *            the type
47
     */
48
    public CustomTag(String name, int type) {
1✔
49
        setName(name);
1✔
50
        setType(type);
1✔
51
    }
1✔
52

53
    /**
54
     * Create a CustomTag based on an existing Tag - this takes a copy of the Tag.
55
     *
56
     * @param tag
57
     *            the tag
58
     */
59
    public CustomTag(Tag tag) {
1✔
60
        setName(tag.getName());
1✔
61
        setType(tag.getType());
1✔
62
        if (tag instanceof Parser.ReusableToken) {
1!
63
            Parser.ReusableToken orig = (Parser.ReusableToken) tag;
1✔
64
            attributeCount = orig.attributeCount;
1✔
65
            attributes = new String[attributeCount];
1✔
66
            System.arraycopy(orig.attributes, 0, attributes, 0, attributeCount);
1✔
67
        } else if (tag instanceof CustomTag) {
1!
68
            CustomTag orig = (CustomTag) tag;
×
69
            attributeCount = orig.attributeCount;
×
70
            attributes = new String[attributeCount];
×
71
            System.arraycopy(orig.attributes, 0, attributes, 0, attributeCount);
×
72
        } else {
×
73
            int c = tag.getAttributeCount();
×
74
            attributes = new String[c * 2];
×
75
            for (int i = 0; i < c; i++) {
×
76
                attributes[attributeCount++] = tag.getAttributeName(i);
×
77
                attributes[attributeCount++] = tag.getAttributeValue(i);
×
78
            }
79
        }
80
    }
1✔
81

82
    @Override
83
    public String getContents() {
84
        SitemeshBufferFragment.Builder buffer = SitemeshBufferFragment.builder()
1✔
85
                .setBuffer(new DefaultSitemeshBuffer(new char[] {}));
1✔
86
        writeTo(buffer, 0);
1✔
87
        return buffer.build().getStringContent();
1✔
88
    }
89

90
    @Override
91
    public void writeTo(SitemeshBufferFragment.Builder buffer, int position) {
92
        StringWriter out = new StringWriter();
1✔
93
        if (type == Tag.CLOSE) {
1✔
94
            out.append("</");
1✔
95
        } else {
96
            out.append('<');
1✔
97
        }
98

99
        out.append(name);
1✔
100
        final int len = attributeCount;
1✔
101

102
        for (int i = 0; i < len; i += 2) {
1✔
103
            final String name = attributes[i];
1✔
104
            final String value = attributes[i + 1];
1✔
105
            if (value == null) {
1✔
106
                out.append(' ').append(name);
1✔
107
            } else {
108
                out.append(' ').append(name).append("=\"").append(value).append("\"");
1✔
109
            }
110
        }
111

112
        if (type == Tag.EMPTY) {
1✔
113
            out.append("/>");
1✔
114
        } else {
115
            out.append('>');
1✔
116
        }
117
        buffer.insert(position, StringSitemeshBuffer.createBufferFragment(out.toString()));
1✔
118
    }
1✔
119

120
    @Override
121
    public boolean equals(Object o) {
122
        if (this == o) {
×
123
            return true;
×
124
        }
125
        if (!(o instanceof CustomTag)) {
×
126
            return false;
×
127
        }
128

129
        final CustomTag customTag = (CustomTag) o;
×
130

131
        if ((type != customTag.type)
×
132
                || (attributes != null ? !Arrays.equals(attributes, customTag.attributes)
×
133
                        : customTag.attributes != null)
134
                || (name != null ? !name.equals(customTag.name) : customTag.name != null)) {
×
135
            return false;
×
136
        }
137

138
        return true;
×
139
    }
140

141
    @Override
142
    public int hashCode() {
143
        int result = attributes != null ? attributes.hashCode() : 0;
×
144
        result = 29 * result + (name != null ? name.hashCode() : 0);
×
145
        return 29 * result + type;
×
146
    }
147

148
    @Override
149
    public String toString() {
150
        return getContents();
×
151
    }
152

153
    // ---------- Standard methods to implement Tag interface ------
154

155
    @Override
156
    public int getAttributeCount() {
157
        return attributeCount / 2;
1✔
158
    }
159

160
    @Override
161
    public int getAttributeIndex(String name, boolean caseSensitive) {
162
        if (attributes == null) {
1!
163
            return -1;
×
164
        }
165
        final int len = attributeCount;
1✔
166
        for (int i = 0; i < len; i += 2) {
1✔
167
            final String current = attributes[i];
1✔
168
            if (caseSensitive ? name.equals(current) : name.equalsIgnoreCase(current)) {
1✔
169
                return i / 2;
1✔
170
            }
171
        }
172
        return -1;
1✔
173
    }
174

175
    @Override
176
    public String getAttributeName(int index) {
177
        return attributes[index * 2];
1✔
178
    }
179

180
    @Override
181
    public String getAttributeValue(int index) {
182
        return attributes[index * 2 + 1];
1✔
183
    }
184

185
    @Override
186
    public String getAttributeValue(String name, boolean caseSensitive) {
187
        int attributeIndex = getAttributeIndex(name, caseSensitive);
1✔
188
        if (attributeIndex == -1) {
1✔
189
            return null;
1✔
190
        }
191
        return attributes[attributeIndex * 2 + 1];
1✔
192
    }
193

194
    @Override
195
    public boolean hasAttribute(String name, boolean caseSensitive) {
196
        return getAttributeIndex(name, caseSensitive) > -1;
×
197
    }
198

199
    @Override
200
    public String getName() {
201
        return name;
×
202
    }
203

204
    /**
205
     * Type of tag: <br/>
206
     * &lt;blah&gt; - Tag.OPEN<br/>
207
     * &lt;/blah&gt; - Tag.CLOSE<br/>
208
     * &lt;blah/&gt; - Tag.EMPTY<br/>
209
     */
210
    @Override
211
    public int getType() {
212
        return type;
×
213
    }
214

215
    // ----------- Additional methods for changing a tag -----------
216

217
    /**
218
     * Change the name of the attribute.
219
     *
220
     * @param name
221
     *            the new name
222
     */
223
    public void setName(String name) {
224
        if (name == null || name.length() == 0) {
1!
225
            throw new IllegalArgumentException("CustomTag requires a name");
×
226
        }
227
        this.name = name;
1✔
228
    }
1✔
229

230
    /**
231
     * Change the type of the tag. Type of tag: <br/>
232
     * &lt;blah&gt; - Tag.OPEN<br/>
233
     * &lt;/blah&gt; - Tag.CLOSE<br/>
234
     * &lt;blah/&gt; - Tag.EMPTY<br/>
235
     *
236
     * @param type
237
     *            the new type
238
     */
239
    public void setType(int type) {
240
        if ((type != Tag.OPEN) && (type != Tag.CLOSE) && (type != Tag.EMPTY)) {
1!
241
            throw new IllegalArgumentException(
×
242
                    "CustomTag must be of type Tag.OPEN, Tag.CLOSE or Tag.EMPTY - was " + type);
243
        }
244
        this.type = type;
1✔
245
    }
1✔
246

247
    /**
248
     * Grow attributes.
249
     */
250
    private void growAttributes() {
251
        int newSize = attributes.length == 0 ? 4 : attributes.length * 2;
1!
252
        String[] newAttributes = new String[newSize];
1✔
253
        System.arraycopy(attributes, 0, newAttributes, 0, attributes.length);
1✔
254
        attributes = newAttributes;
1✔
255
    }
1✔
256

257
    /**
258
     * Add a new attribute. This does not check for the existence of an attribute with the same name, thus allowing
259
     * duplicate attributes.
260
     *
261
     * @param name
262
     *            Name of attribute to change.
263
     * @param value
264
     *            New value of attribute or null for an HTML style empty attribute.
265
     *
266
     * @return Index of new attribute.
267
     */
268
    public int addAttribute(String name, String value) {
269
        if (attributeCount == attributes.length) {
1✔
270
            growAttributes();
1✔
271
        }
272
        attributes[attributeCount++] = name;
1✔
273
        attributes[attributeCount++] = value;
1✔
274
        return attributeCount / 2 - 1;
1✔
275
    }
276

277
    /**
278
     * Change the value of an attribute, or add an attribute if it does not already exist.
279
     *
280
     * @param name
281
     *            Name of attribute to change.
282
     * @param caseSensitive
283
     *            Whether the name should be treated as case sensitive when searching for an existing value.
284
     * @param value
285
     *            New value of attribute or null for an HTML style empty attribute.
286
     */
287
    public void setAttributeValue(String name, boolean caseSensitive, String value) {
288
        int attributeIndex = getAttributeIndex(name, caseSensitive);
1✔
289
        if (attributeIndex == -1) {
1!
290
            addAttribute(name, value);
×
291
        } else {
292
            attributes[attributeIndex * 2 + 1] = value;
1✔
293
        }
294
    }
1✔
295

296
    /**
297
     * Change the name of an existing attribute.
298
     *
299
     * @param attributeIndex
300
     *            the attribute index
301
     * @param name
302
     *            the name
303
     */
304
    public void setAttributeName(int attributeIndex, String name) {
305
        attributes[attributeIndex * 2] = name;
×
306
    }
×
307

308
    /**
309
     * Change the value of an existing attribute. The value may be null for an HTML style empty attribute.
310
     *
311
     * @param attributeIndex
312
     *            the attribute index
313
     * @param value
314
     *            the value
315
     */
316
    public void setAttributeValue(int attributeIndex, String value) {
317
        attributes[attributeIndex * 2 + 1] = value;
×
318
    }
×
319

320
    /**
321
     * Remove an attribute.
322
     *
323
     * @param attributeIndex
324
     *            the attribute index
325
     */
326
    public void removeAttribute(int attributeIndex) {
327
        if (attributeIndex > attributeCount / 2) {
1!
328
            throw new ArrayIndexOutOfBoundsException(
×
329
                    "Cannot remove attribute at index " + attributeIndex + ", max index is " + attributeCount / 2);
330
        }
331
        // shift everything down one and null the last two
332
        String[] newAttributes = new String[attributes.length - 2];
1✔
333
        System.arraycopy(attributes, 0, newAttributes, 0, attributeIndex * 2);
1✔
334
        int next = attributeIndex * 2 + 2;
1✔
335
        System.arraycopy(attributes, next, newAttributes, attributeIndex * 2, attributes.length - next);
1✔
336
        attributeCount = attributeCount - 2;
1✔
337
        attributes = newAttributes;
1✔
338
    }
1✔
339

340
    /**
341
     * Change the value of an attribute, or add an attribute if it does not already exist.
342
     *
343
     * @param name
344
     *            Name of attribute to remove.
345
     * @param caseSensitive
346
     *            Whether the name should be treated as case sensitive.
347
     */
348
    public void removeAttribute(String name, boolean caseSensitive) {
349
        int attributeIndex = getAttributeIndex(name, caseSensitive);
1✔
350
        if (attributeIndex == -1) {
1!
351
            throw new IllegalArgumentException("Attribute " + name + " not found");
×
352
        }
353
        removeAttribute(attributeIndex);
1✔
354
    }
1✔
355

356
    @Override
357
    public int getPosition() {
358
        return 0;
×
359
    }
360

361
    @Override
362
    public int getLength() {
363
        return 0;
×
364
    }
365
}
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