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