1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.context;
21
22 import org.apache.myfaces.tobago.internal.util.ArrayUtils;
23 import org.apache.myfaces.tobago.internal.util.StringUtils;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import java.io.Serializable;
28 import java.lang.invoke.MethodHandles;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collections;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Objects;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 public final class Markup implements Serializable, Iterable<String> {
60
61 private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
62
63 public static final Markup NULL = new Markup((String) null);
64
65 public static final Markup ASCENDING = valueOf("ascending");
66 public static final Markup BADGE = valueOf("badge");
67 public static final Markup BIG = valueOf("big");
68 public static final Markup BOLD = valueOf("bold");
69 public static final Markup BORDERED = valueOf("bordered");
70 public static final Markup BOTTOM = valueOf("bottom");
71 public static final Markup CENTER = valueOf("center");
72 public static final Markup CLICKABLE = valueOf("clickable");
73 public static final Markup DANGER = valueOf("danger");
74 public static final Markup DARK = valueOf("dark");
75 public static final Markup DEFAULT = valueOf("default");
76 public static final Markup DELETED = valueOf("deleted");
77 public static final Markup DESCENDING = valueOf("descending");
78 public static final Markup DISABLED = valueOf("disabled");
79 public static final Markup ERROR = valueOf("error");
80 public static final Markup EVEN = valueOf("even");
81 public static final Markup EXPANDED = valueOf("expanded");
82 public static final Markup EXTRA_LARGE = valueOf("extraLarge");
83 public static final Markup FILLER = valueOf("filler");
84 public static final Markup FATAL = valueOf("fatal");
85 public static final Markup FOLDER = valueOf("folder");
86 public static final Markup HOVER = valueOf("hover");
87 public static final Markup INFO = valueOf("info");
88 public static final Markup INLINE = valueOf("inline");
89 public static final Markup ITALIC = valueOf("italic");
90 public static final Markup JUSTIFY = valueOf("justify");
91 public static final Markup LARGE = valueOf("large");
92 public static final Markup LEFT = valueOf("left");
93 public static final Markup LIGHT = valueOf("light");
94 public static final Markup MARKED = valueOf("marked");
95 public static final Markup MEDIUM = valueOf("medium");
96 public static final Markup MIDDLE = valueOf("middle");
97 public static final Markup MODAL = valueOf("modal");
98 public static final Markup NONE = valueOf("none");
99 public static final Markup NUMBER = valueOf("number");
100 public static final Markup ODD = valueOf("odd");
101 public static final Markup OUTLINE_DANGER = valueOf("outlineDanger");
102 public static final Markup OUTLINE_DARK = valueOf("outlineDark");
103 public static final Markup OUTLINE_INFO = valueOf("outlineInfo");
104 public static final Markup OUTLINE_LIGHT = valueOf("outlineLight");
105 public static final Markup OUTLINE_PRIMARY = valueOf("outlinePrimary");
106 public static final Markup OUTLINE_SECONDARY = valueOf("outlineSecondary");
107 public static final Markup OUTLINE_SUCCESS = valueOf("outlineSuccess");
108 public static final Markup OUTLINE_WARNING = valueOf("outlineWarning");
109 public static final Markup PILL = valueOf("pill");
110 public static final Markup PORTLET = valueOf("portlet");
111 public static final Markup PRIMARY = valueOf("primary");
112 public static final Markup READONLY = valueOf("readonly");
113 public static final Markup REQUIRED = valueOf("required");
114 public static final Markup RESIZABLE = valueOf("resizable");
115 public static final Markup RIGHT = valueOf("right");
116 public static final Markup SECONDARY = valueOf("secondary");
117 public static final Markup SECONDS = valueOf("seconds");
118 public static final Markup SELECTED = valueOf("selected");
119 public static final Markup SMALL = valueOf("small");
120 public static final Markup SORTABLE = valueOf("sortable");
121 public static final Markup SPREAD = valueOf("spread");
122 public static final Markup STRIPED = valueOf("striped");
123 public static final Markup STRONG = valueOf("strong");
124 public static final Markup SUCCESS = valueOf("success");
125 public static final Markup THIN = valueOf("thin");
126 public static final Markup TOGGLER_LEFT = valueOf("togglerLeft");
127 public static final Markup TOP = valueOf("top");
128 public static final Markup VERTICALLY = valueOf("vertically");
129 public static final Markup WARN = valueOf("warn");
130 public static final Markup WARNING = valueOf("warning");
131
132 public static final String STRING_ASCENDING = "ascending";
133 public static final String STRING_BADGE = "badge";
134 public static final String STRING_BIG = "big";
135 public static final String STRING_BOLD = "bold";
136 public static final String STRING_BORDERED = "bordered";
137 public static final String STRING_BOTTOM = "bottom";
138 public static final String STRING_CENTER = "center";
139 public static final String STRING_CLICKABLE = "clickable";
140 public static final String STRING_DANGER = "danger";
141 public static final String STRING_DARK = "dark";
142 public static final String STRING_DEFAULT = "default";
143 public static final String STRING_DELETED = "deleted";
144 public static final String STRING_DESCENDING = "descending";
145 public static final String STRING_DISABLED = "disabled";
146 public static final String STRING_ERROR = "error";
147 public static final String STRING_EVEN = "even";
148 public static final String STRING_EXPANDED = "expanded";
149 public static final String STRING_EXTRA_LARGE = "extraLarge";
150 public static final String STRING_FILLER = "filler";
151 public static final String STRING_FATAL = "fatal";
152 public static final String STRING_FOLDER = "folder";
153 public static final String STRING_HOVER = "hover";
154 public static final String STRING_INFO = "info";
155 public static final String STRING_INLINE = "inline";
156 public static final String STRING_ITALIC = "italic";
157 public static final String STRING_JUSTIFY = "justify";
158 public static final String STRING_LARGE = "large";
159 public static final String STRING_LEFT = "left";
160 public static final String STRING_LIGHT = "light";
161 public static final String STRING_MARKED = "marked";
162 public static final String STRING_MEDIUM = "medium";
163 public static final String STRING_MIDDLE = "middle";
164 public static final String STRING_MODAL = "modal";
165 public static final String STRING_NONE = "none";
166 public static final String STRING_NUMBER = "number";
167 public static final String STRING_ODD = "odd";
168 public static final String STRING_OUTLINE_DANGER = "outlineDanger";
169 public static final String STRING_OUTLINE_DARK = "outlineDark";
170 public static final String STRING_OUTLINE_INFO = "outlineInfo";
171 public static final String STRING_OUTLINE_LIGHT = "outlineLight";
172 public static final String STRING_OUTLINE_PRIMARY = "outlinePrimary";
173 public static final String STRING_OUTLINE_SECONDARY = "outlineSecondary";
174 public static final String STRING_OUTLINE_SUCCESS = "outlineSuccess";
175 public static final String STRING_OUTLINE_WARNING = "outlineWarning";
176 public static final String STRING_PILL = "pill";
177 public static final String STRING_PORTLET = "portlet";
178 public static final String STRING_PRIMARY = "primary";
179 public static final String STRING_READONLY = "readonly";
180 public static final String STRING_REQUIRED = "required";
181 public static final String STRING_RESIZABLE = "resizable";
182 public static final String STRING_RIGHT = "right";
183 public static final String STRING_SECONDARY = "secondary";
184 public static final String STRING_SECONDS = "seconds";
185 public static final String STRING_SELECTED = "selected";
186 public static final String STRING_SMALL = "small";
187 public static final String STRING_SORTABLE = "sortable";
188 public static final String STRING_SPREAD = "spread";
189 public static final String STRING_STRIPED = "striped";
190 public static final String STRING_STRONG = "strong";
191 public static final String STRING_SUCCESS = "success";
192 public static final String STRING_THIN = "thin";
193 public static final String STRING_TOGGLER_LEFT = "togglerLeft";
194 public static final String STRING_TOP = "top";
195 public static final String STRING_VERTICALLY = "vertically";
196 public static final String STRING_WARN = "warn";
197 public static final String STRING_WARNING = "warning";
198
199
200
201 private final String[] values;
202 private final String value;
203
204 private Markup(final String[] values) {
205 this.values = values != null ? filterSpecialChars(values) : null;
206 this.value = null;
207 }
208
209 private Markup(final String value) {
210 this.values = null;
211 this.value = value != null ? filterSpecialChars(value) : null;
212 }
213
214 private String[] filterSpecialChars(final String[] strings) {
215 for (int i = 0; i < strings.length; i++) {
216 strings[i] = filterSpecialChars(strings[i]);
217 }
218 return strings;
219 }
220
221 private String filterSpecialChars(String string) {
222 StringBuilder stringBuilder = new StringBuilder(string.length());
223 boolean forbiddenCharFound = false;
224 for (int i = 0; i < string.length(); i++) {
225 final char c = string.charAt(i);
226 if (('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) {
227 stringBuilder.append(c);
228 } else {
229 forbiddenCharFound = true;
230 }
231 }
232 if (forbiddenCharFound) {
233 final String newString = stringBuilder.toString();
234 LOG.warn("Only numeric and alphabetic characters are allowed for markups: '{}' converted to '{}'.", string,
235 newString);
236 return newString;
237 } else {
238 return string;
239 }
240 }
241
242 public static Markup valueOf(final String[] values) {
243 if (values == null || values.length == 0) {
244 return null;
245 } else if (values.length == 1) {
246 return valueOf(values[0]);
247 } else {
248 final String[] clonedValues = values.clone();
249 for (int i = 0; i < clonedValues.length; i++) {
250 clonedValues[i] = clonedValues[i].trim();
251 }
252 return new Markup(clonedValues);
253 }
254 }
255
256 public static Markup valueOf(final String value) {
257 if (StringUtils.isEmpty(value)) {
258 return null;
259 }
260 if (value.contains(" ") || value.contains(",")) {
261 final String[] strings = StringUtils.split(value, ", \t\n");
262 return new Markup(strings);
263 } else {
264 return new Markup(value.trim());
265 }
266 }
267
268 public static Markup valueOf(final Object value) {
269 if (value == null) {
270 return null;
271 }
272 if (value instanceof Markup) {
273 return (Markup) value;
274 }
275 if (value instanceof String) {
276 return valueOf((String) value);
277 }
278 if (value instanceof String[]) {
279 return valueOf((String[]) value);
280 }
281 if (value instanceof Iterable) {
282 final List<String> list = new ArrayList<>();
283 for (final Object object : (Iterable) value) {
284 list.add(object.toString());
285 }
286 return valueOf(list.toArray(new String[0]));
287 }
288 return valueOf(value.toString());
289 }
290
291 @Override
292 public boolean equals(final Object o) {
293 if (this == o) {
294 return true;
295 }
296 if (o == null || getClass() != o.getClass()) {
297 return false;
298 }
299
300 final Markup markup = (Markup) o;
301
302 if (!Objects.equals(value, markup.value)) {
303 return false;
304 }
305 return Arrays.equals(values, markup.values);
306 }
307
308 @Override
309 public int hashCode() {
310 int result = values != null ? Arrays.hashCode(values) : 0;
311 result = 31 * result + (value != null ? value.hashCode() : 0);
312 return result;
313 }
314
315 @Override
316 public Iterator<String> iterator() {
317 if (value != null) {
318 return Collections.singleton(value).iterator();
319 }
320 if (values != null) {
321 return Arrays.asList(values).iterator();
322 }
323 return Collections.emptyIterator();
324 }
325
326
327
328
329
330 public Markup add(final Markup markup) {
331 if (markup == null) {
332 return this;
333 }
334 if (markup == NULL) {
335 return this;
336 }
337 if (markup.value != null) {
338 return add(markup.value);
339 } else {
340
341 Markup result = this;
342 if (markup.values != null) {
343 for (final String summand : markup.values) {
344 final Markup combined = result.add(summand);
345 if (combined != null) {
346 result = combined;
347 }
348 }
349 }
350 return result;
351 }
352 }
353
354 private Markup add(final String summand) {
355 if (summand == null) {
356 return this;
357 }
358 if (values == null) {
359 if (value == null) {
360 return valueOf(summand);
361 } else {
362 if (summand.equals(value)) {
363 return this;
364 } else {
365 return valueOf(new String[]{value, summand});
366 }
367 }
368 } else {
369 if (ArrayUtils.contains(values, summand)) {
370 return this;
371 } else {
372 final String[] strings = new String[values.length + 1];
373 System.arraycopy(values, 0, strings, 0, values.length);
374 strings[values.length] = summand;
375 return valueOf(strings);
376 }
377 }
378 }
379
380 public Markup remove(final Markup markup) {
381 if (markup.value != null) {
382 return remove(markup.value);
383 } else {
384
385 Markup result = this;
386 for (final String summand : markup.values) {
387 final Markup removed = result.remove(summand);
388 if (removed == null) {
389 result = NULL;
390 } else {
391 result = removed;
392 }
393 }
394 return result;
395 }
396 }
397
398 private Markup remove(final String summand) {
399 if (summand == null) {
400 return this;
401 }
402 if (values == null) {
403 if (value == null) {
404 return this;
405 } else {
406 if (summand.equals(value)) {
407 return NULL;
408 } else {
409 return this;
410 }
411 }
412 } else {
413 if (ArrayUtils.contains(values, summand)) {
414 final String[] strings = new String[values.length - 1];
415 int found = 0;
416 for (int i = 0; i < strings.length; i++) {
417 if (summand.equals(values[i])) {
418 found++;
419 }
420 strings[i] = values[i + found];
421 }
422 return valueOf(strings);
423 } else {
424 return this;
425 }
426 }
427 }
428
429 public boolean contains(final String markup) {
430 if (markup == null) {
431 return true;
432 }
433 if (this == NULL) {
434 return this == Markup.valueOf(markup);
435 }
436 if (value != null) {
437 return value.equals(markup);
438 }
439 for (final String v : values) {
440 if (v.equals(markup)) {
441 return true;
442 }
443 }
444 return false;
445 }
446
447 public boolean contains(final Markup markup) {
448 if (markup == null || markup == NULL) {
449 return true;
450 }
451 if (this == NULL) {
452 return this == markup;
453 }
454 if (markup.value != null) {
455 if (value != null) {
456 return value.equals(markup.value);
457 } else {
458 for (final String v : values) {
459 if (v.equals(markup.value)) {
460 return true;
461 }
462 }
463 return false;
464 }
465 } else {
466 if (value != null) {
467 return false;
468 } else {
469 for (final String markupString : markup.values) {
470 if (!contains(markupString)) {
471 return false;
472 }
473 }
474 return true;
475 }
476 }
477 }
478
479
480
481
482 public boolean isEmpty() {
483 return !(value != null || values != null && values.length != 0);
484 }
485
486 @Override
487 public String toString() {
488 if (value != null) {
489 return value;
490 }
491 if (values == null) {
492 return "null";
493 }
494 return Arrays.toString(values);
495 }
496
497 }