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