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.internal.util;
21
22 import org.apache.myfaces.tobago.component.ClientBehaviors;
23 import org.apache.myfaces.tobago.context.Markup;
24 import org.apache.myfaces.tobago.internal.context.DateTimeI18n;
25 import org.apache.myfaces.tobago.internal.renderkit.Collapse;
26 import org.apache.myfaces.tobago.internal.renderkit.Command;
27 import org.apache.myfaces.tobago.internal.renderkit.CommandMap;
28 import org.apache.myfaces.tobago.layout.Measure;
29 import org.apache.myfaces.tobago.layout.MeasureList;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import java.lang.invoke.MethodHandles;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.StringTokenizer;
39
40 public class JsonUtils {
41
42 private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
43
44 private JsonUtils() {
45 }
46
47 private static void encode(final StringBuilder builder, final String name, final String[] value) {
48 builder.append("\"");
49 builder.append(name);
50 builder.append("\":");
51 encode(builder, value);
52 builder.append(",");
53 }
54
55 private static void encode(final StringBuilder builder, final String[] value) {
56 builder.append("[");
57 boolean colon = false;
58 for (final String item : value) {
59 if (colon) {
60 builder.append(",");
61 }
62 builder.append("\"");
63 for (int i = 0; i < item.length(); i++) {
64 final char c = item.charAt(i);
65 if (c == '\"') {
66 builder.append("\\\"");
67 } else {
68 builder.append(c);
69 }
70 }
71 builder.append("\"");
72 colon = true;
73 }
74 builder.append("]");
75 }
76
77 private static void encode(final StringBuilder builder, final Boolean[] value) {
78 builder.append("[");
79 boolean colon = false;
80 for (final boolean item : value) {
81 if (colon) {
82 builder.append(",");
83 }
84 builder.append(item);
85 colon = true;
86 }
87 builder.append("]");
88 }
89
90 private static void encode(final StringBuilder builder, final List<Integer> value) {
91 builder.append("[");
92 boolean colon = false;
93 for (final Integer item : value) {
94 if (colon) {
95 builder.append(",");
96 }
97 builder.append(item);
98 colon = true;
99 }
100 builder.append("]");
101 }
102
103 private static void encode(final StringBuilder builder, final String name, final Boolean value) {
104 builder.append("\"");
105 builder.append(name);
106 builder.append("\":");
107 builder.append(value);
108 builder.append(",");
109 }
110
111 private static void encode(final StringBuilder builder, final String name, final Integer value) {
112 builder.append("\"");
113 builder.append(name);
114 builder.append("\":");
115 builder.append(value);
116 builder.append(",");
117 }
118
119 private static void encode(final StringBuilder builder, final String name, final String value) {
120 builder.append("\"");
121 builder.append(name);
122 builder.append("\":\"");
123 int length = value.length();
124 for (int i = 0; i < length; i++) {
125 final char c = value.charAt(i);
126 if (c == '\"') {
127 builder.append("\\\"");
128 } else {
129 builder.append(c);
130 }
131 }
132 builder.append("\",");
133 }
134
135 public static String encode(final CommandMap commandMap) {
136
137 if (commandMap == null) {
138 return null;
139 }
140
141 final StringBuilder builder = new StringBuilder();
142 builder.append("{");
143 final int initialLength = builder.length();
144
145 final Command click = commandMap.getClick();
146 if (click != null) {
147 encode(builder, ClientBehaviors.click, click);
148 }
149
150 final Map<ClientBehaviors, Command> other = commandMap.getOther();
151 if (other != null) {
152 for (final Map.Entry<ClientBehaviors, Command> entry : other.entrySet()) {
153 encode(builder, entry.getKey(), entry.getValue());
154 }
155 }
156
157 if (builder.length() - initialLength > 0) {
158 assert builder.charAt(builder.length() - 1) == ',';
159 builder.deleteCharAt(builder.length() - 1);
160 }
161
162 builder.append("}");
163 return builder.toString();
164 }
165
166 private static void encode(final StringBuilder builder, final ClientBehaviors name, final Command command) {
167 builder.append("\"");
168 builder.append(name);
169 builder.append("\":{");
170 final int initialLength = builder.length();
171
172 final String action = command.getAction();
173 if (action != null) {
174 encode(builder, "action", action);
175 }
176 final Boolean transition = command.getTransition();
177 if (transition != null && !transition) {
178 encode(builder, "transition", transition);
179 }
180 final String target = command.getTarget();
181 if (target != null) {
182 encode(builder, "target", target);
183 }
184 final String execute = command.getExecute();
185 if (execute != null) {
186 encode(builder, "execute", execute);
187 }
188 final String render = command.getRender();
189 if (render != null) {
190 encode(builder, "render", render);
191 }
192 final Collapse collapse = command.getCollapse();
193 if (collapse != null) {
194 encode(builder, "collapse", collapse);
195 }
196 final String focus = command.getFocus();
197 if (focus != null) {
198 encode(builder, "focus", focus);
199 }
200 final String confirmation = command.getConfirmation();
201 if (confirmation != null) {
202 encode(builder, "confirmation", confirmation);
203 }
204 final Integer delay = command.getDelay();
205 if (delay != null) {
206 encode(builder, "delay", delay);
207 }
208 final Boolean omit = command.getOmit();
209 if (omit != null && omit) {
210 encode(builder, "omit", true);
211 }
212
213 if (builder.length() - initialLength > 0) {
214 assert builder.charAt(builder.length() - 1) == ',';
215 builder.deleteCharAt(builder.length() - 1);
216 }
217
218 builder.append("},");
219 }
220
221 private static void encode(final StringBuilder builder, final String name, final Collapse collapse) {
222 builder.append("\"");
223 builder.append(name);
224 builder.append("\":{");
225 final int initialLength = builder.length();
226
227 final Collapse.Action action = collapse.getAction();
228 if (action != null) {
229 encode(builder, "transition", action.name());
230 }
231 final String forId = collapse.getFor();
232 if (forId != null) {
233 encode(builder, "forId", forId);
234 }
235 if (builder.length() - initialLength > 0) {
236 assert builder.charAt(builder.length() - 1) == ',';
237 builder.deleteCharAt(builder.length() - 1);
238 }
239
240 builder.append("},");
241 }
242
243 public static String encode(final DateTimeI18n dateTimeI18n) {
244 final StringBuilder builder = new StringBuilder();
245 builder.append("{");
246 final int initialLength = builder.length();
247
248 encode(builder, "monthNames", dateTimeI18n.getMonthNames());
249 encode(builder, "monthNamesShort", dateTimeI18n.getMonthNamesShort());
250 encode(builder, "dayNames", dateTimeI18n.getDayNames());
251 encode(builder, "dayNamesShort", dateTimeI18n.getDayNamesShort());
252 encode(builder, "dayNamesMin", dateTimeI18n.getDayNamesMin());
253 encode(builder, "firstDay", dateTimeI18n.getFirstDay());
254 encode(builder, "minDays", dateTimeI18n.getMinDays());
255 encode(builder, "today", dateTimeI18n.getToday());
256 encode(builder, "cancel", dateTimeI18n.getCancel());
257 encode(builder, "clear", dateTimeI18n.getClear());
258 encode(builder, "week", dateTimeI18n.getWeek());
259
260 if (builder.length() - initialLength > 0) {
261 assert builder.charAt(builder.length() - 1) == ',';
262 builder.deleteCharAt(builder.length() - 1);
263 }
264 builder.append("}");
265 return builder.toString();
266 }
267
268 public static String encode(final String[] strings) {
269 if (strings == null) {
270 return null;
271 }
272 final StringBuilder builder = new StringBuilder();
273 encode(builder, strings);
274 return builder.toString();
275 }
276
277 public static String encode(final Integer[] integers) {
278 if (integers == null) {
279 return null;
280 }
281 final StringBuilder builder = new StringBuilder();
282 encode(builder, Arrays.asList(integers));
283 return builder.toString();
284 }
285
286 public static String encode(final Boolean[] booleans) {
287 if (booleans == null) {
288 return null;
289 }
290 final StringBuilder builder = new StringBuilder();
291 encode(builder, booleans);
292 return builder.toString();
293 }
294
295 public static String encode(final List<Integer> integers) {
296 if (integers == null) {
297 return null;
298 }
299 final StringBuilder builder = new StringBuilder();
300 encode(builder, integers);
301 return builder.toString();
302 }
303
304 private static void encode(final MeasureList layout, final StringBuilder builder) {
305 builder.append("[");
306 for (final Measure measure : layout) {
307 final Measure.Unit unit = measure.getUnit();
308 if (unit == Measure.Unit.FR) {
309 final float factor = measure.getValue();
310 builder.append(factor);
311 } else if (unit == Measure.Unit.AUTO) {
312 builder.append("\"auto\"");
313 } else {
314 builder.append("{\"measure\":\"");
315 builder.append(measure.serialize());
316 builder.append("\"}");
317 }
318 builder.append(',');
319 }
320 if (builder.charAt(builder.length() - 1) == ',') {
321 builder.deleteCharAt(builder.length() - 1);
322 }
323 builder.append("]");
324 }
325
326 public static List<Integer> decodeIntegerArray(final String json) {
327 if (json == null) {
328 return null;
329 }
330 String string = json.trim();
331 final List<Integer> result = new ArrayList<>();
332 if (string.length() < 2 || string.charAt(0) != '[' || string.charAt(string.length() - 1) != ']') {
333 LOG.warn("Can't parse JSON array: no surrounding square brackets []: '{}'", string);
334 } else {
335 string = string.substring(1, string.length() - 1);
336 final StringTokenizer tokenizer = new StringTokenizer(string, ",");
337 while (tokenizer.hasMoreTokens()) {
338 final String token = tokenizer.nextToken().trim();
339 try {
340 result.add(Integer.parseInt(token));
341 } catch (final NumberFormatException e) {
342 LOG.warn("Can't parse JSON array: not an integer token: '{}'", token);
343
344 }
345 }
346 }
347 return result;
348 }
349
350 public static String encode(final Markup markups) {
351 if (markups == null || markups.isEmpty()) {
352 return null;
353 }
354 final StringBuilder builder = new StringBuilder(20);
355 builder.append('[');
356 for (final String markup : markups) {
357 builder.append('"');
358 builder.append(markup);
359 builder.append('"');
360 builder.append(',');
361 }
362 if (builder.length() > 1) {
363 builder.deleteCharAt(builder.length() - 1);
364 }
365 builder.append(']');
366 return builder.toString();
367 }
368
369 public static String encode(final MeasureList measures, final String name) {
370 final StringBuilder builder = new StringBuilder();
371 builder.append("{\"");
372 builder.append(name);
373 builder.append("\":");
374 JsonUtils.encode(measures, builder);
375 builder.append("}");
376 return builder.toString();
377 }
378
379 public static String encodeEmptyArray() {
380 return "[]";
381 }
382 }