Initial OpenECOMP MSO commit
[so.git] / bpmn / MSOCoreBPMN / src / main / java / org / openecomp / mso / bpmn / core / json / JsonUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * OPENECOMP - MSO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.mso.bpmn.core.json;
22
23 import java.util.Iterator;
24 import java.util.StringTokenizer;
25
26 import org.json.JSONArray;
27 import org.json.JSONException;
28 import org.json.JSONObject;
29 import org.json.XML;
30
31 //import org.openecomp.mso.bpmn.core.BPMNLogger;
32 import org.openecomp.mso.bpmn.core.xml.XmlTool;
33 import org.openecomp.mso.logger.MsoLogger;
34
35 /**
36  * Utility class for JSON processing
37  * 
38  * @version 1.0
39  */
40
41 public class JsonUtils {
42
43         private static MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL);
44         private static int MSOJsonIndentFactor = 3;
45
46         /**
47          * Uses the JSONObject static method to convert a XML doc to JSON.
48          *
49          * @param  xml          String containing the XML doc
50          * @param  pretty       flag to determine if the output should be formatted
51          * @return String containing the JSON translation
52          */
53         public static String xml2json(String xml, Boolean pretty) {
54 //              String isDebugLogEnabled = "true";
55                 try {
56                         // name spaces cause problems, so just remove them
57                         JSONObject jsonObj = XML.toJSONObject(XmlTool.removeNamespaces(xml));
58                         if (!pretty) {
59                                 return jsonObj.toString();
60                         } else {
61                                 // add an indent to make it 'pretty'
62                                 return jsonObj.toString(MSOJsonIndentFactor);
63                         }
64                 } catch (Exception e){
65                                 msoLogger.debug("xml2json(): unable to parse xml and convert to json. Exception was: " + e.toString());
66                                 return null;
67                 }
68         }
69
70         /**
71          * Invokes xml2json(String, Boolean) defaulting to 'pretty' output.
72          *
73          * @param  xml  String containing the XML doc
74          * @return String containing the JSON translation
75          */
76         public static String xml2json(String xml) {
77                 return xml2json(xml, true);
78         }
79
80         /**
81          * Uses the JSONObject static method to convert a JSON doc to XML.
82          * Note: this method will not generate valid XML if the JSONObject
83          * contains JSONArrays which are used to represent XML attributes
84          * in the JSON doc.
85          *
86          * @param  jsonStr      String containing the JSON doc
87          * @param  pretty       flag to determine if the output should be formatted
88          * @return String containing the XML translation
89          */
90         public static String json2xml(String jsonStr, Boolean pretty) {
91 //              String isDebugLogEnabled = "true";
92                 try {
93                         JSONObject jsonObj = new JSONObject(jsonStr);
94                         if (pretty) {
95                                 return XmlTool.normalize(XML.toString(jsonObj));
96                         } else {
97                                 return XML.toString(jsonObj);
98                         }
99                 } catch (Exception e){
100                                 msoLogger.debug("json2xml(): unable to parse json and convert to xml. Exception was: " + e.toString());
101                                 return null;
102                 }
103         }
104         
105         /**
106          * Invokes json2xml(String, Boolean) defaulting to 'pretty' output.
107          *
108          * @param  jsonStr      String containing the XML doc
109          * @return String containing the JSON translation
110          */
111         public static String json2xml(String jsonStr) {
112                 return json2xml(jsonStr, true);
113         }
114
115         /**
116          * Uses the JSONObject static method to convert a JSON doc to XML.
117          *
118          * @param  jsonStr      String containing the JSON doc
119          * @return Iterator over the JSON keys
120          */
121         public static Iterator <String> getJsonIterator(String jsonStr) {
122 //              String isDebugLogEnabled = "true";
123                 try {
124                         JSONObject json = new JSONObject(jsonStr);
125                         return json.keys();
126                         
127                 } catch (Exception e){
128                                 msoLogger.debug("getJsonIterator(): unable to parse json to retrieve the keys iterator. Exception was: " + e.toString());
129                                 return null;
130                 }
131         }
132
133         /**
134          * Invokes the getJsonRawValue() method and returns the String equivalent of
135          * the object returned.
136          * 
137          * TBD: May need separate methods for boolean, float, and integer fields if the
138          * String representation is not sufficient to meet client needs.
139          *
140          * @param  jsonStr      String containing the JSON doc
141          * @param  keys         full key path to the target value in the format of "key1.key2.key3..."
142          * @return String field value associated with keys
143          */
144         public static String getJsonValue(String jsonStr, String keys) {
145 //              String isDebugLogEnabled = "true";
146                 try {
147                                 Object rawValue = getJsonRawValue(jsonStr, keys);
148                                 if (rawValue == null) {
149                                         return null;
150                                 } else {
151                                         if (rawValue instanceof String) {
152                                                 msoLogger.debug("getJsonValue(): the raw value is a String Object=" + ((String) rawValue).toString());
153                                                 return (String) rawValue;
154                                         } else {
155                                                 msoLogger.debug("getJsonValue(): the raw value is NOT a String Object=" + rawValue.toString());
156                                                 return rawValue.toString();
157                                         }
158                                 }
159                 } catch (Exception e) {
160                                 msoLogger.debug("getJsonValue(): unable to parse json to retrieve value for field=" + keys + ". Exception was: " + e.toString());
161                 }
162                 return null;
163         }
164
165         /**
166          * Invokes the getJsonRawValue() method to obtain the JSONArray associated with
167          * the specified keys. The JSONArray is then walked to retrieve the content value of
168          * the specified field name.
169          *
170          * @param  jsonStr      String containing the JSON doc
171          * @param  keys         full key path to the target value in the format of "key1.key2.key3..."
172          * @param  name         field name for the param to be retrieved
173          * @return String param value associated with field name
174          */
175         public static String getJsonParamValue(String jsonStr, String keys, String name) {
176 //              String isDebugLogEnabled = "true";
177                 try {
178                         Object rawValue = getJsonRawValue(jsonStr, keys);
179                         if (rawValue == null) {
180                                 return null;
181                         } else {
182                                 if (rawValue instanceof JSONArray) {
183                                         msoLogger.debug("getJsonParamValue(): keys=" + keys + " points to JSONArray: " + ((JSONArray) rawValue).toString());
184                                         for (int i = 0; i < ((JSONArray) rawValue).length(); i++) {
185                                                 msoLogger.debug("getJsonParamValue(): index: " + i + ", value: " + ((JSONArray) rawValue).get(i).toString());
186                                                 if (((JSONArray) rawValue).get(i) instanceof JSONObject) {
187                                                         msoLogger.debug("getJsonParamValue(): index: " + i + " is a JSONObject");
188                                                         JSONObject jsonObj = (JSONObject)((JSONArray) rawValue).get(i);
189                                                         if (jsonObj.get("name").equals(name)) {
190                                                                 msoLogger.debug("getJsonParamValue(): found value: " + (String) jsonObj.get("content") + " for name: " + name);
191                                                                 return (String) jsonObj.get("content");
192                                                         }
193                                                 } else {
194                                                         msoLogger.debug("getJsonParamValue(): the JSONArray element is NOT a JSONObject=" + rawValue.toString());
195                                                         return null;
196                                                 }
197                                         }
198                                         msoLogger.debug("getJsonParamValue(): content value NOT found for name: " + name);
199                                         return null;
200                                 } else {
201                                         msoLogger.debug("getJsonParamValue(): the raw value is NOT a JSONArray Object=" + rawValue.toString());
202                                         return null;
203                                 }
204                         }
205                 } catch (JSONException je) {
206                                 // JSONObject::get() throws this exception if one of the specified keys is not found
207                                 msoLogger.debug("getJsonParamValue(): caught JSONException attempting to retrieve param value for keys:" + keys + ", name=" + name);
208                 } catch (Exception e) {
209                                 msoLogger.debug("getJsonParamValue(): unable to parse json to retrieve value for field=" + keys + ". Exception was: " + e.toString());
210                 }
211                 return null;
212         }
213
214         /**
215          * Wrapper to generate the JSONObject to pass to the getJsonValueForKey(JSONObject, String)
216          * method so that recursion over the subobjects can be supported there
217          *
218          * @param  jsonStr      String containing the JSON doc
219          * @param  key          key to the target value
220          * @return String field value associated with key
221          */
222         public static String getJsonValueForKey(String jsonStr, String key) {
223 //              String isDebugLogEnabled = "true";
224                 try {
225                         JSONObject jsonObj = new JSONObject(jsonStr);
226                         if (jsonObj != null) {
227                                 return getJsonValueForKey(jsonObj, key);
228                         }
229                 } catch (Exception e) {
230                                 msoLogger.debug("getJsonValueForKey(): unable to parse json to retrieve value for field=" + key + ". Exception was: " + e.toString());
231                 }
232                 return null;
233         }
234
235         /**
236          * Walks the JSONObject (and sub-objects recursively), searching for the first value associated with the
237          * single key/field name specified. Returns the associated value if found or null if the key is not found
238          *
239          * @param  jsonObj      JSONObject representation of the the JSON doc
240          * @param  key          key to the target value
241          * @return String field value associated with key
242          */
243         public static String getJsonValueForKey(JSONObject jsonObj, String key) {
244 //              String isDebugLogEnabled = "true";
245                 String keyValue = null;
246                 try {
247                         if (jsonObj.has(key)) {
248                                 msoLogger.debug("getJsonValueForKey(): found value for key=" + key);
249                                 return ((String) jsonObj.get(key));
250                         } else {
251                                 msoLogger.debug("getJsonValueForKey(): iterating over the keys");
252                                 Iterator <String> itr = jsonObj.keys();
253                                 while (itr.hasNext()) {
254                                         String nextKey = (String) itr.next();
255                                         Object obj = jsonObj.get(nextKey);
256                                         if (obj instanceof JSONObject) {
257                                                 msoLogger.debug("getJsonValueForKey(): key=" + nextKey + ", points to JSONObject, recursive call");
258                                                 keyValue = getJsonValueForKey((JSONObject) obj, key);
259                                                 if (keyValue != null) {
260                                                         msoLogger.debug("getJsonValueForKey(): found value=" + keyValue + ", for key=" + key);
261                                                         break;
262                                                 }
263                                         } else {
264                                                 msoLogger.debug("getJsonValueForKey(): key=" + nextKey + ", does not point to a JSONObject, next key");
265                                         }
266                                 }
267                         }
268                 } catch (JSONException je) {
269                                 // JSONObject::get() throws this exception if one of the specified keys is not found
270                                 msoLogger.debug("getJsonValueForKey(): caught JSONException attempting to retrieve value for key=" + key);
271                                 keyValue = null;
272                 } catch (Exception e) {
273                                 msoLogger.debug("getJsonValueForKey(): unable to parse json to retrieve value for field=" + key + ". Exception was: " + e.toString());
274                 }
275                 return keyValue;
276         }
277         
278         /**
279          * Boolean method to determine if a key path is valid for the JSON doc. Invokes
280          * getJsonValue().
281          *
282          * @param  jsonStr      String containing the JSON doc
283          * @param  keys         full key path to the target value in the format of "key1.key2.key3..."
284          * @return Boolean true if keys points to value in the JSON doc
285          */
286         public static Boolean jsonValueExists(String jsonStr, String keys) {
287                 if (getJsonRawValue(jsonStr, keys) == null) {
288                         return false;
289                 } else {
290                         return true;
291                 }
292         }
293         
294         /**
295          * Inserts the new key/value pair at the appropriate location in the JSON
296          * document after first determining if keyed field already exists. If
297          * it does exist, return the JSON unmodified, otherwise return the new JSON
298          * Note: this method currently only supports String value inserts.
299          *
300          * @param  jsonStr      String containing the JSON doc
301          * @param  keys         full key path to the value to be added in the format of "key1.key2.key3..."
302          * @return String containing the updated JSON doc
303          */
304         public static String addJsonValue(String jsonStr, String keys, String value) {
305 //              String isDebugLogEnabled = "true";
306                 // only attempt to insert the key/value pair if it does not exist
307                 if (!jsonValueExists(jsonStr, keys)) {
308                         return putJsonValue(jsonStr, keys, value);
309                 } else {
310                         msoLogger.debug("addJsonValue(): JSON add failed, key=" + keys + "/value=" + (String) value + " already exists");
311                         return jsonStr;
312                 }
313         }
314
315         /**
316          * Updates the value for the specified key in the JSON document
317          * after first determining if keyed field exists. If it does
318          * not exist, return the JSON unmodified, otherwise return the updated JSON.
319          * Note: this method currently only supports String value updates.
320          *
321          * @param  jsonStr      String containing the JSON doc
322          * @param  keys         full key path to the value to be updated in the format of "key1.key2.key3..."
323          * @return String containing the updated JSON doc
324          */
325         public static String updJsonValue(String jsonStr, String keys, String newValue) {
326 //              String isDebugLogEnabled = "true";
327                 // only attempt to modify the key/value pair if it exists
328                 if (jsonValueExists(jsonStr, keys)) {
329                         return putJsonValue(jsonStr, keys, newValue);
330                 } else {
331                         msoLogger.debug("updJsonValue(): JSON update failed, no value exists for key=" + keys);
332                         return jsonStr;
333                 }
334         }
335
336         /**
337          * Deletes the value for the specified key in the JSON document
338          * after first determining if keyed field exists. If it does
339          * not exist, return the JSON unmodified, otherwise return the updated JSON
340          *
341          * @param  jsonStr      String containing the JSON doc
342          * @param  keys         full key path to the value to be deleted in the format of "key1.key2.key3..."
343          * @return String containing the updated JSON doc
344          */
345         public static String delJsonValue(String jsonStr, String keys) {
346 //              String isDebugLogEnabled = "true";
347                 // only attempt to remove the key/value pair if it exists
348                 if (jsonValueExists(jsonStr, keys)) {
349                         // passing a null value results in a delete
350                         return putJsonValue(jsonStr, keys, null);
351                 } else {
352                         msoLogger.debug("delJsonValue(): JSON delete failed, no value exists for key=" + keys);
353                         return jsonStr;
354                 }
355         }
356
357         /**
358          * Walks the JSON doc using the full key path to retrieve the associated
359          * value. All but the last key points to the 'parent' object name(s) in order
360          * in the JSON hierarchy with the last key pointing to the target value.
361          * The value returned is a Java object.
362          *
363          * @param  jsonStr      String containing the JSON doc
364          * @param  keys         full key path to the target value in the format of "key1.key2.key3..."
365          * @return Object field value associated with keys
366          */
367         private static Object getJsonRawValue(String jsonStr, String keys) {
368 //              String isDebugLogEnabled = "true";
369                 String keyStr = "";
370                 try {
371                         JSONObject jsonObj = new JSONObject(jsonStr);
372                         StringTokenizer keyTokens = new StringTokenizer(keys, ".");
373                         while (keyTokens.hasMoreElements()) {
374                                 keyStr = keyTokens.nextToken();
375                                 Object keyValue = jsonObj.get(keyStr);
376                                 if (keyValue instanceof JSONObject) {
377                                         msoLogger.debug("getJsonRawValue(): key=" + keyStr + " points to json object");
378                                         jsonObj = (JSONObject) keyValue;
379                                 } else {
380                                         if (keyTokens.hasMoreElements()) {
381                                                 msoLogger.debug("getJsonRawValue(): value found prior to last key for key=" + keyStr);
382                                         }
383                                         return keyValue;
384                                 }
385                         }
386                         // we should not hit this point: either the key points to a valid value and
387                         // we return it above or the key is invalid and we handle the JSONException
388                         // below and return null
389                         return null;
390                         
391                 } catch (JSONException je) {
392                                 // JSONObject::get() throws this exception if one of the specified keys is not found
393                                 msoLogger.debug("getJsonRawValue(): caught JSONException attempting to retrieve raw value for key=" + keyStr);
394                 } catch (Exception e) {
395                                 msoLogger.debug("getJsonRawValue(): unable to parse json to retrieve value for field=" + keys + ". Exception was: " + e.toString());
396                 }
397                 return null;
398         }
399
400         /**
401          * Private method invoked by the public add, update, and delete methods.
402          *
403          * @param  jsonStr      String containing the JSON doc
404          * @param  keys         full key path to the value to be deleted in the format of "key1.key2.key3..."
405          * @return String containing the updated JSON doc
406          */
407         private static String putJsonValue(String jsonStr, String keys, String value) {         
408 //              String isDebugLogEnabled = "true";
409                 String keyStr = "";
410                 try {
411                         JSONObject jsonObj = new JSONObject(jsonStr);
412                         JSONObject jsonObjOut = jsonObj;
413                         StringTokenizer keyTokens = new StringTokenizer(keys, ".");
414                         while (keyTokens.hasMoreElements()) {
415                                 keyStr = keyTokens.nextToken();
416                                 if (keyTokens.hasMoreElements()) {
417                                         Object keyValue = jsonObj.get(keyStr);
418                                         if (keyValue instanceof JSONObject) {
419                                                 msoLogger.debug("putJsonValue(): key=" + keyStr + " points to json object");
420                                                 jsonObj = (JSONObject) keyValue;
421                                         } else {
422                                                 msoLogger.debug("putJsonValue(): key=" + keyStr + " not the last key but points to non-json object: " + (String) keyValue);
423                                                 return null;
424                                         }
425                                 } else { // at the last/new key value
426                                         jsonObj.put(keyStr, value);
427                                         return jsonObjOut.toString(3);
428                                 }
429                         }
430                         // should not hit this point if the key points to a valid key value
431                         return null;
432                         
433                 } catch (JSONException je) {
434                                 // JSONObject::get() throws this exception if one of the specified keys is not found
435                                 msoLogger.debug("putJsonValue(): caught JSONException attempting to retrieve value for key=" + keyStr);
436                                 return null;
437                 } catch (Exception e) {
438                                 msoLogger.debug("putJsonValue(): unable to parse json to put value for key=" + keys + ". Exception was: " + e.toString());
439                 }
440                 return null;
441         }
442 }
443