d6ef7463a8fc815862a11e26d6af9db7dd22f9df
[ccsdk/sli.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                      reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.ccsdk.sli.plugins.restapicall;
23
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import org.apache.commons.text.StringEscapeUtils;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 public final class XmlJsonUtil {
34
35     @SuppressWarnings("unused")
36     private static final Logger log = LoggerFactory.getLogger(XmlJsonUtil.class);
37
38     private XmlJsonUtil() {
39         // Preventing instantiation of the same.
40     }
41
42     public static String getXml(Map<String, String> varmap, String var) {
43         boolean escape = true;
44         if (var.startsWith("'")) {
45             var = var.substring(1);
46             escape = false;
47         }
48
49         Object o = createStructure(varmap, var);
50         return generateXml(o, 0, escape);
51     }
52
53     public static String getJson(Map<String, String> varmap, String var) {
54         boolean keepEmpty = false;
55         if (var.startsWith("~")) {
56             var = var.substring(1);
57             keepEmpty = true;
58         }
59
60         boolean escape = true;
61         if (var.startsWith("'")) {
62             var = var.substring(1);
63             escape = false;
64         }
65
66         boolean quotes = true;
67         if (var.startsWith("\"")) {
68             var = var.substring(1);
69             quotes = false;
70         }
71
72         Object o = createStructure(varmap, var);
73         return generateJson(o, escape, quotes, keepEmpty);
74     }
75
76     private static Object createStructure(Map<String, String> flatmap, String var) {
77         if (flatmap.containsKey(var)) {
78             return flatmap.get(var);
79         }
80
81         Map<String, Object> mm = new HashMap<>();
82         List<Object> ll = new ArrayList<>();
83
84         for (Map.Entry<String, String> e : flatmap.entrySet()) {
85             String key = e.getKey();
86             String value = e.getValue();
87
88             if (key.endsWith("_length") || key.endsWith("].key")) {
89                 continue;
90             }
91
92             if (value == null || value.trim().isEmpty()) {
93                 continue;
94             }
95
96             if (key.startsWith(var + "[")) {
97                 String newKey = key.substring(var.length());
98                 set(ll, newKey, value);
99             } else if (var == null || var.isEmpty()) {
100                 set(mm, key, value);
101             } else if (key.startsWith(var + ".")) {
102                 String newKey = key.substring(var.length() + 1);
103                 set(mm, newKey, value);
104             }
105         }
106
107         if (!mm.isEmpty()) {
108             return mm;
109         }
110         if (!ll.isEmpty()) {
111             return ll;
112         }
113         return null;
114     }
115
116     @SuppressWarnings("unchecked")
117     public static void set(Object struct, String compositeKey, Object value) {
118         if (struct == null) {
119             throw new IllegalArgumentException("Null argument: struct");
120         }
121
122         if (compositeKey == null || compositeKey.length() == 0) {
123             throw new IllegalArgumentException("Null or empty argument: compositeKey");
124         }
125
126         if (value == null) {
127             return;
128         }
129
130         List<Object> keys = splitCompositeKey(compositeKey);
131         Object currentValue = struct;
132         String currentKey = "";
133
134         for (int i = 0; i < keys.size() - 1; i++) {
135             Object key = keys.get(i);
136
137             if (key instanceof Integer) {
138                 if (!(currentValue instanceof List)) {
139                     throw new IllegalArgumentException("Cannot resolve: " + compositeKey + ": References list '" + currentKey + "', but '" + currentKey + "' is not a list");
140                 }
141
142                 Integer keyi = (Integer) key;
143                 List<Object> currentValueL = (List<Object>) currentValue;
144                 int size = currentValueL.size();
145
146                 if (keyi >= size) {
147                     for (int k = 0; k < keyi - size + 1; k++) {
148                         currentValueL.add(null);
149                     }
150                 }
151
152                 Object newValue = currentValueL.get(keyi);
153                 if (newValue == null) {
154                     Object nextKey = keys.get(i + 1);
155                     if (nextKey instanceof Integer) {
156                         newValue = new ArrayList<>();
157                     } else {
158                         newValue = new HashMap<>();
159                     }
160                     currentValueL.set(keyi, newValue);
161                 }
162
163                 currentValue = newValue;
164                 currentKey += "[" + key + "]";
165
166             } else {
167                 if (!(currentValue instanceof Map)) {
168                     throw new IllegalArgumentException("Cannot resolve: " + compositeKey + ": References map '" + currentKey + "', but '" + currentKey + "' is not a map");
169                 }
170
171                 Object newValue = ((Map<String, Object>) currentValue).get(key);
172                 if (newValue == null) {
173                     Object nextKey = keys.get(i + 1);
174                     if (nextKey instanceof Integer) {
175                         newValue = new ArrayList<>();
176                     } else {
177                         newValue = new HashMap<>();
178                     }
179                     ((Map<String, Object>) currentValue).put((String) key, newValue);
180                 }
181
182                 currentValue = newValue;
183                 currentKey += "." + key;
184             }
185         }
186
187         Object key = keys.get(keys.size() - 1);
188         if (key instanceof Integer) {
189             if (!(currentValue instanceof List)) {
190                 throw new IllegalArgumentException("Cannot resolve: " + compositeKey + ": References list '" + currentKey + "', but '" + currentKey + "' is not a list");
191             }
192
193             Integer keyi = (Integer) key;
194             List<Object> currentValueL = (List<Object>) currentValue;
195             int size = currentValueL.size();
196
197             if (keyi >= size) {
198                 for (int k = 0; k < keyi - size + 1; k++) {
199                     currentValueL.add(null);
200                 }
201             }
202
203             currentValueL.set(keyi, value);
204
205         } else {
206             if (!(currentValue instanceof Map)) {
207                 throw new IllegalArgumentException("Cannot resolve: " + compositeKey + ": References map '" + currentKey + "', but '" + currentKey + "' is not a map");
208             }
209
210             ((Map<String, Object>) currentValue).put((String) key, value);
211         }
212     }
213
214     private static List<Object> splitCompositeKey(String compositeKey) {
215         if (compositeKey == null) {
216             return Collections.emptyList();
217         }
218
219         String[] ss = compositeKey.split("\\.");
220         List<Object> ll = new ArrayList<>();
221         for (String s : ss) {
222             if (s.length() == 0) {
223                 continue;
224             }
225
226             int i1 = s.indexOf('[');
227             if (i1 < 0) {
228                 ll.add(s);
229             } else {
230                 if (!s.endsWith("]")) {
231                     throw new IllegalArgumentException("Invalid composite key: " + compositeKey + ": No matching ] found");
232                 }
233
234                 String s1 = s.substring(0, i1);
235                 if (s1.length() > 0) {
236                     ll.add(s1);
237                 }
238
239                 String s2 = s.substring(i1 + 1, s.length() - 1);
240                 try {
241                     int n = Integer.parseInt(s2);
242                     if (n < 0) {
243                         throw new IllegalArgumentException("Invalid composite key: " + compositeKey + ": Index must be >= 0: " + n);
244                     }
245
246                     ll.add(n);
247                 } catch (NumberFormatException e) {
248                     throw new IllegalArgumentException("Invalid composite key: " + compositeKey + ": Index not a number: " + s2);
249                 }
250             }
251         }
252
253         return ll;
254     }
255
256     @SuppressWarnings("unchecked")
257     private static String generateXml(Object o, int indent, boolean escape) {
258         if (o == null) {
259             return null;
260         }
261
262         if (o instanceof String) {
263             return escape ? StringEscapeUtils.escapeXml10((String) o) : (String) o;
264         };
265
266         if (o instanceof Map) {
267             StringBuilder ss = new StringBuilder();
268             Map<String, Object> mm = (Map<String, Object>) o;
269             for (Map.Entry<String, Object> entry : mm.entrySet()) {
270                 Object v = entry.getValue();
271                 String key = entry.getKey();
272                 if (v instanceof String) {
273                     String s = escape ? StringEscapeUtils.escapeXml10((String) v) : (String) v;
274                     ss.append(pad(indent)).append('<').append(key).append('>');
275                     ss.append(s);
276                     ss.append("</").append(key).append('>').append('\n');
277                 } else if (v instanceof Map) {
278                     ss.append(pad(indent)).append('<').append(key).append('>').append('\n');
279                     ss.append(generateXml(v, indent + 1, escape));
280                     ss.append(pad(indent)).append("</").append(key).append('>').append('\n');
281                 } else if (v instanceof List) {
282                     List<Object> ll = (List<Object>) v;
283                     for (Object o1 : ll) {
284                         ss.append(pad(indent)).append('<').append(key).append('>').append('\n');
285                         ss.append(generateXml(o1, indent + 1, escape));
286                         ss.append(pad(indent)).append("</").append(key).append('>').append('\n');
287                     }
288                 }
289             }
290             return ss.toString();
291         }
292
293         return null;
294     }
295     private static String generateJson(Object o, boolean escape, boolean quotes, boolean keepEmpty) {
296         if (o == null) {
297             return null;
298         }
299         if (o instanceof String && ((String) o).length() == 0 && !keepEmpty) {
300             return null;
301         }
302
303         StringBuilder ss = new StringBuilder();
304         generateJson(ss, o, 0, false, escape, quotes);
305         return ss.toString();
306     }
307
308     @SuppressWarnings("unchecked")
309     private static void generateJson(StringBuilder ss, Object o, int indent, boolean padFirst, boolean escape, boolean quotes) {
310         if (o instanceof String) {
311             String s = escape ? StringEscapeUtils.escapeJson((String) o) : (String) o;
312             if (padFirst) {
313                 ss.append(pad(indent));
314             }
315             if (quotes) {
316                 ss.append('"').append(s).append('"');
317             } else {
318                 ss.append(s);
319             }
320             return;
321         }
322
323         if (o instanceof Map) {
324             Map<String, Object> mm = (Map<String, Object>) o;
325
326             if (padFirst) {
327                 ss.append(pad(indent));
328             }
329             ss.append("{\n");
330
331             boolean first = true;
332             for (Map.Entry<String, Object> entry : mm.entrySet()) {
333                 if (!first) {
334                     ss.append(",\n");
335                 }
336                 first = false;
337                 Object v = entry.getValue();
338                 String key = entry.getKey();
339                 ss.append(pad(indent + 1)).append('"').append(key).append("\": ");
340                 generateJson(ss, v, indent + 1, false, escape, true);
341             }
342
343             ss.append("\n");
344             ss.append(pad(indent)).append('}');
345
346             return;
347         }
348
349         if (o instanceof List) {
350             List<Object> ll = (List<Object>) o;
351
352             if (padFirst) {
353                 ss.append(pad(indent));
354             }
355             ss.append("[\n");
356
357             boolean first = true;
358             for (Object o1 : ll) {
359                 if (!first) {
360                     ss.append(",\n");
361                 }
362                 first = false;
363
364                 generateJson(ss, o1, indent + 1, true, escape, quotes);
365             }
366
367             ss.append("\n");
368             ss.append(pad(indent)).append(']');
369         }
370     }
371
372     public static String removeLastCommaJson(String s) {
373         StringBuilder sb = new StringBuilder();
374         int k = 0;
375         int start = 0;
376         while (k < s.length()) {
377             int i11 = s.indexOf('}', k);
378             int i12 = s.indexOf(']', k);
379             int i1 = -1;
380             if (i11 < 0) {
381                 i1 = i12;
382             } else if (i12 < 0) {
383                 i1 = i11;
384             } else {
385                 i1 = i11 < i12 ? i11 : i12;
386             }
387             if (i1 < 0) {
388                 break;
389             }
390
391             int i2 = s.lastIndexOf(',', i1);
392             if (i2 < 0) {
393                 k = i1 + 1;
394                 continue;
395             }
396
397             String between = s.substring(i2 + 1, i1);
398             if (between.trim().length() > 0) {
399                 k = i1 + 1;
400                 continue;
401             }
402
403             sb.append(s.substring(start, i2));
404             start = i2 + 1;
405             k = i1 + 1;
406         }
407
408         sb.append(s.substring(start, s.length()));
409
410         return sb.toString();
411     }
412
413     public static String removeEmptyStructJson(String template, String s) {
414         int k = 0;
415         while (k < s.length()) {
416             boolean curly = true;
417             int i11 = s.indexOf('{', k);
418             int i12 = s.indexOf('[', k);
419             int i1 = -1;
420             if (i11 < 0) {
421                 i1 = i12;
422                 curly = false;
423             } else if (i12 < 0) {
424                 i1 = i11;
425             } else if (i11 < i12) {
426                 i1 = i11;
427             } else {
428                 i1 = i12;
429                 curly = false;
430             }
431
432             if (i1 >= 0) {
433                 int i2 = curly ? s.indexOf('}', i1) : s.indexOf(']', i1);
434                 if (i2 > 0) {
435                     String value = s.substring(i1 + 1, i2);
436                     if (value.trim().length() == 0) {
437                         int i4 = s.lastIndexOf('\n', i1);
438                         if (i4 < 0) {
439                             i4 = 0;
440                         }
441                         int i5 = s.indexOf('\n', i2);
442                         if (i5 < 0) {
443                             i5 = s.length();
444                         }
445
446
447                         /*If template mandates empty construct to be present, those should not be removed.*/
448                         if (template != null && template.contains(s.substring(i4))) {
449                             k = i1 + 1;
450                         } else {
451                             s = s.substring(0, i4) + s.substring(i5);
452                             k = 0;
453                         }
454                     } else {
455                         k = i1 + 1;
456                     }
457                 } else {
458                     break;
459                 }
460             } else {
461                 break;
462             }
463         }
464
465         return s;
466     }
467
468     public static String removeEmptyStructXml(String s) {
469         int k = 0;
470         while (k < s.length()) {
471             int i1 = s.indexOf('<', k);
472             if (i1 < 0 || i1 == s.length() - 1) {
473                 break;
474             }
475
476             char c1 = s.charAt(i1 + 1);
477             if (c1 == '?' || c1 == '!') {
478                 k = i1 + 2;
479                 continue;
480             }
481
482             int i2 = s.indexOf('>', i1);
483             if (i2 < 0) {
484                 k = i1 + 1;
485                 continue;
486             }
487
488             String closingTag = "</" + s.substring(i1 + 1, i2 + 1);
489             int i3 = s.indexOf(closingTag, i2 + 1);
490             if (i3 < 0) {
491                 k = i2 + 1;
492                 continue;
493             }
494
495             String value = s.substring(i2 + 1, i3);
496             if (value.trim().length() > 0) {
497                 k = i2 + 1;
498                 continue;
499             }
500
501             int i4 = s.lastIndexOf('\n', i1);
502             if (i4 < 0) {
503                 i4 = 0;
504             }
505             int i5 = s.indexOf('\n', i3);
506             if (i5 < 0) {
507                 i5 = s.length();
508             }
509
510             s = s.substring(0, i4) + s.substring(i5);
511             k = 0;
512         }
513
514         return s;
515     }
516
517     private static String pad(int n) {
518         StringBuilder s = new StringBuilder();
519         for (int i = 0; i < n; i++) {
520             s.append(Character.toString('\t'));
521         }
522         return s.toString();
523     }
524 }