2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights 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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
22 package org.onap.so.bpmn.core.json;
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
30 import java.util.StringTokenizer;
32 import org.camunda.bpm.engine.delegate.DelegateExecution;
33 import org.camunda.bpm.engine.runtime.Execution;
34 import org.json.JSONArray;
35 import org.json.JSONException;
36 import org.json.JSONObject;
38 import org.onap.so.bpmn.core.xml.XmlTool;
39 import org.onap.so.exceptions.ValidationException;
40 import org.onap.so.logger.MsoLogger;
42 import com.fasterxml.jackson.databind.JsonNode;
43 import com.github.fge.jackson.JsonLoader;
44 import com.github.fge.jsonschema.core.exceptions.ProcessingException;
45 import com.github.fge.jsonschema.core.report.ProcessingReport;
46 import com.github.fge.jsonschema.main.JsonSchemaFactory;
47 import com.github.fge.jsonschema.main.JsonValidator;
50 * Utility class for JSON processing
54 * Note: It was observed, that depending on the JSON implementation, an org.json.JSONException or a
55 * java.util.NoSuchElementException will be thrown in the event of the key value being "not found"
56 * in a JSON document. A general check has been added to the applicable catch blocks for this
57 * this type of behavior to reduce the amount of logging. As a key value not being found is
58 * expect behavior, it makes no sense to log the stack trace associated with this type of failure.
60 public class JsonUtils {
62 private static MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, JsonUtils.class);
63 private static int MSOJsonIndentFactor = 3;
66 * Uses the JSONObject static method to convert a XML doc to JSON.
68 * @param xml String containing the XML doc
69 * @param pretty flag to determine if the output should be formatted
70 * @return String containing the JSON translation
72 public static String xml2json(String xml, Boolean pretty) {
74 // name spaces cause problems, so just remove them
75 JSONObject jsonObj = XML.toJSONObject(XmlTool.removeNamespaces(xml));
77 return jsonObj.toString();
79 // add an indent to make it 'pretty'
80 return jsonObj.toString(MSOJsonIndentFactor);
82 } catch (Exception e){
83 msoLogger.debug("xml2json(): unable to parse xml and convert to json. Exception was: " + e.toString(), e);
89 * Invokes xml2json(String, Boolean) defaulting to 'pretty' output.
91 * @param xml String containing the XML doc
92 * @return String containing the JSON translation
94 public static String xml2json(String xml) {
95 return xml2json(xml, true);
99 * Uses the JSONObject static method to convert a JSON doc to XML.
100 * Note: this method may not generate valid XML if the JSONObject
101 * contains JSONArrays which are used to represent XML attributes
104 * @param jsonStr String containing the JSON doc
105 * @param pretty flag to determine if the output should be formatted
106 * @return String containing the XML translation
108 public static String json2xml(String jsonStr, Boolean pretty) {
111 JSONObject jsonObj = new JSONObject(jsonStr);
113 // return XmlTool.normalize(XML.toString(jsonObj));
114 // use the local class method which properly handles certain JSONArray content
115 return XmlTool.normalize(toXMLString(jsonObj, null));
117 // return XML.toString(jsonObj);
118 // use the local class method which properly handles certain JSONArray content
119 return toXMLString(jsonObj, null);
121 } catch (Exception e){
122 msoLogger.debug("json2xml(): unable to parse json and convert to xml. Exception was: " + e.toString(), e);
128 * Uses a modified version of the org.json.XML toString() algorithm
129 * to convert a JSONObject to an XML Doc. The intent of this is to
130 * correctly generate XML from JSON including TAGs for JSONArrays
132 * @param obj org.json.JSON object to be converted to XML
133 * @param tagName optional XML tagname supplied primarily during recursive calls
134 * @return String containing the XML translation
136 public static String toXMLString(Object obj, String tagName) throws JSONException {
137 StringBuilder strBuf = new StringBuilder();
142 Iterator<String> keys;
146 if (obj instanceof JSONObject) {
147 // msoLogger.debug("toXMLString(): is a JSONObject");
148 // append "<tagName>" to the XML output
149 if (tagName != null) {
150 // msoLogger.debug("toXMLString(): adding opening tagName: " + tagName);
152 strBuf.append(tagName);
155 // iterate thru the keys.
156 jsonObj = (JSONObject) obj;
157 keys = jsonObj.keys();
158 while (keys.hasNext()) {
160 // msoLogger.debug("toXMLString(): key is " + k);
161 curObj = jsonObj.opt(key);
162 if (curObj == null) {
165 if (curObj instanceof String) {
166 str = (String) curObj;
170 // append the content to the XML output
171 if ("content".equals(key)) {
172 if (curObj instanceof JSONArray) {
173 jsonArr = (JSONArray) curObj;
174 len = jsonArr.length();
175 for (i = 0; i < len; i += 1) {
179 strBuf.append(XML.escape(jsonArr.get(i).toString()));
182 strBuf.append(XML.escape(curObj.toString()));
184 // append an array of similar keys to the XML output
185 } else if (curObj instanceof JSONArray) {
186 jsonArr = (JSONArray) curObj;
187 len = jsonArr.length();
188 // msoLogger.debug("toXMLString(): found JSONArray: " + key + ", size: " + len);
189 for (i = 0; i < len; i += 1) {
190 curObj = jsonArr.get(i);
191 if (curObj instanceof JSONArray) {
192 // The XML tags for the nested array should be generated below when this method
193 // is called recursively and the JSONArray object is passed
194 // strBuf.append("<");
195 // strBuf.append(key);
196 // strBuf.append(">");
197 strBuf.append(toXMLString(curObj, null));
198 // strBuf.append("</");
199 // strBuf.append(key);
200 // strBuf.append(">");
202 // msoLogger.debug("toXMLString(): recursive call toXML() with tagName null");
203 // append the opening tag for the array (before 1st element)
209 // append the opening tag for the array
210 strBuf.append(toXMLString(curObj, null));
211 // append the closing tag for the array (after last element)
212 if (i == (len - 1)) {
219 } else if (curObj.equals("")) {
220 // append a closing tag "<key>" to the XML output
225 // msoLogger.debug("toXMLString(): recursive call toXMLString() with tagName: " + key);
226 strBuf.append(toXMLString(curObj, key));
228 // msoLogger.debug("toXML(): partial XML: " + strBuf.toString());
230 if (tagName != null) {
231 // append the closing tag "</tagName>" to the XML output
232 // msoLogger.debug("toXMLString(): adding closing tagName: " + tagName);
234 strBuf.append(tagName);
237 return strBuf.toString();
238 // XML does not have good support for arrays. If an array appears in a place
239 // where XML is lacking, synthesize an < array > element.
240 } else if (obj instanceof JSONArray) {
241 jsonArr = (JSONArray) obj;
242 len = jsonArr.length();
243 for (i = 0; i < len; ++i) {
244 curObj = jsonArr.opt(i);
245 strBuf.append(toXMLString(curObj, (tagName == null) ? "array"
248 return strBuf.toString();
250 // msoLogger.debug("toXML(): in else block with tagName: " + tagName);
251 str = (obj == null) ? "null" : XML.escape(obj.toString());
252 return (tagName == null) ? "\"" + str + "\""
253 : (str.length() == 0) ? "<" + tagName + "/>" : "<"
254 + tagName + ">" + str + "</" + tagName + ">";
259 * Invokes json2xml(String, Boolean) defaulting to 'pretty' output.
261 * @param jsonStr String containing the XML doc
262 * @return String containing the JSON translation
264 public static String json2xml(String jsonStr) {
265 return json2xml(jsonStr, true);
269 * Formats the JSON String using the value of MSOJsonIndentFactor.
271 * @param jsonStr String containing the JSON doc
272 * @return String containing the formatted JSON doc
274 public static String prettyJson(String jsonStr) {
275 // String isDebugLogEnabled = "true";
277 JSONObject jsonObj = new JSONObject(jsonStr);
278 return jsonObj.toString(MSOJsonIndentFactor);
279 } catch (Exception e){
280 msoLogger.debug("prettyJson(): unable to parse/format json input. Exception was: " + e.toString(), e);
286 * Returns an Iterator over the JSON keys in the specified JSON doc.
288 * @param jsonStr String containing the JSON doc
289 * @return Iterator over the JSON keys
290 * @throws JSONException if the doc cannot be parsed
292 public static Iterator <String> getJsonIterator(String jsonStr) throws JSONException {
293 return new JSONObject(jsonStr).keys();
297 * Returns the name of the "root" property in the specified JSON doc. The
298 * "root" property is the single top-level property in the JSON doc. An
299 * exception is thrown if the doc is empty or if it contains more than one
300 * top-level property.
302 * @param jsonStr String containing the JSON doc
303 * @return the name of the "root" property
304 * @throws JSONException if the doc cannot be parsed, or if it is empty, or if
305 * it contains more than one top-level property
307 public static String getJsonRootProperty(String jsonStr) throws JSONException {
308 Iterator<String> iter = getJsonIterator(jsonStr);
310 if (!iter.hasNext()) {
311 throw new JSONException("Empty JSON object");
314 String rootPropertyName = iter.next();
316 if (iter.hasNext()) {
317 throw new JSONException("JSON object has more than one root property");
320 return rootPropertyName;
324 * Invokes the getJsonRawValue() method and returns the String equivalent of
325 * the object returned.
327 * TBD: May need separate methods for boolean, float, and integer fields if the
328 * String representation is not sufficient to meet client needs.
330 * @param jsonStr String containing the JSON doc
331 * @param keys full key path to the target value in the format of "key1.key2.key3..."
332 * @return String field value associated with keys
334 public static String getJsonValue(String jsonStr, String keys) {
335 // String isDebugLogEnabled = "true";
337 Object rawValue = getJsonRawValue(jsonStr, keys);
338 if (rawValue == null) {
341 if (rawValue instanceof String) {
342 msoLogger.debug("getJsonValue(): the raw value is a String Object=" + rawValue);
343 return (String) rawValue;
345 msoLogger.debug("getJsonValue(): the raw value is NOT a String Object=" + rawValue.toString());
346 return rawValue.toString();
349 } catch (Exception e) {
350 msoLogger.debug("getJsonValue(): unable to parse json to retrieve value for field=" + keys + ". Exception was: " + e.toString(),e);
356 * Invokes the getJsonRawValue() method with the wrap flag set to true
357 * and returns the String equivalent of the json node object returned.
359 * @param jsonStr String containing the JSON doc
360 * @param keys full key path to the target value in the format of "key1.key2.key3..."
361 * @return String field value associated with keys
363 public static String getJsonNodeValue(String jsonStr, String keys) {
364 // String isDebugLogEnabled = "true";
366 Object rawValue = getJsonRawValue(jsonStr, keys, true);
367 if (rawValue == null) {
370 if (rawValue instanceof String) {
371 msoLogger.debug("getJsonNodeValue(): the raw value is a String Object=" + rawValue);
372 return (String) rawValue;
374 msoLogger.debug("getJsonNodeValue(): the raw value is NOT a String Object=" + rawValue.toString());
375 return rawValue.toString();
378 } catch (Exception e) {
379 msoLogger.debug("getJsonNodeValue(): unable to parse json to retrieve node for field=" + keys + ". Exception was: " + e.toString(), e);
385 * Invokes the getJsonRawValue() method and returns the String equivalent of
386 * the object returned.
388 * TBD: May need separate methods for boolean, float, and integer fields if the
389 * String representation is not sufficient to meet client needs.
391 * @param jsonStr String containing the JSON doc
392 * @param keys full key path to the target value in the format of "key1.key2.key3..."
393 * @return String field value associated with keys
395 public static int getJsonIntValue(String jsonStr, String keys) {
396 // String isDebugLogEnabled = "true";
398 Object rawValue = getJsonRawValue(jsonStr, keys);
399 if (rawValue == null) {
402 if (rawValue instanceof Integer) {
403 msoLogger.debug("getJsonIntValue(): the raw value is an Integer Object=" + ((String) rawValue).toString());
404 return (Integer) rawValue;
406 msoLogger.debug("getJsonIntValue(): the raw value is NOT an Integer Object=" + rawValue.toString());
410 } catch (Exception e) {
411 msoLogger.debug("getJsonIntValue(): unable to parse json to retrieve value for field=" + keys + ". Exception was: " + e.toString(), e);
417 * Invokes the getJsonRawValue() method and returns the boolean equivalent of
418 * the object returned.
420 * @param jsonStr String containing the JSON doc
421 * @param keys full key path to the target value in the format of "key1.key2.key3..."
422 * @return boolean field value associated with keys - default is false
424 public static boolean getJsonBooleanValue(String jsonStr, String keys) {
426 Object rawValue = getJsonRawValue(jsonStr, keys);
427 if (rawValue == null) {
430 if (rawValue instanceof Boolean) {
431 msoLogger.debug("getJsonBooleanValue(): the raw value is a Boolean Object=" + rawValue);
432 return (Boolean) rawValue;
434 msoLogger.debug("getJsonBooleanValue(): the raw value is NOT an Boolean Object=" + rawValue.toString());
438 } catch (Exception e) {
439 msoLogger.debug("getJsonBooleanValue(): unable to parse json to retrieve value for field=" + keys + ". Exception was: " + e.toString(),e);
445 * Invokes the getJsonParamValue() method to obtain the JSONArray associated with
446 * the specified keys. The JSONArray is then walked to retrieve the first array
447 * value associated with the specified field name (index=0).
449 * @param jsonStr String containing the JSON doc
450 * @param keys full key path to the target value in the format of "key1.key2.key3..."
451 * @param name field name for the param to be retrieved
452 * @return String param value associated with field name
454 public static String getJsonParamValue(String jsonStr, String keys, String name) {
455 return getJsonParamValue(jsonStr, keys, name, 0);
459 * Invokes the getJsonRawValue() method to obtain the JSONArray associated with
460 * the specified keys. The JSONArray is then walked to retrieve the nth array
461 * value associated with the specified field name and index.
463 * @param jsonStr String containing the JSON doc
464 * @param keys full key path to the target value in the format of "key1.key2.key3..."
465 * @param name field name for the param to be retrieved
466 * @param index the nth param associated with name starting at 0
467 * @return String param value associated with field name
469 public static String getJsonParamValue(String jsonStr, String keys, String name, int index) {
470 // String isDebugLogEnabled = "true";
472 Object rawValue = getJsonRawValue(jsonStr, keys);
473 if (rawValue == null) {
476 if (rawValue instanceof JSONArray) {
477 msoLogger.debug("getJsonParamValue(): keys=" + keys + " points to JSONArray: " + rawValue.toString());
478 int arrayLen = ((JSONArray) rawValue).length();
479 if (index < 0 || arrayLen < index+1) {
480 msoLogger.debug("getJsonParamValue(): index: " + index + " is out of bounds for array size of " + arrayLen);
484 for (int i = 0; i < arrayLen; i++) {
485 msoLogger.debug("getJsonParamValue(): index: " + i + ", value: " + ((JSONArray) rawValue).get(i).toString());
486 if (((JSONArray) rawValue).get(i) instanceof JSONObject) {
487 // msoLogger.debug("getJsonParamValue(): index: " + i + " is a JSONObject");
488 JSONObject jsonObj = (JSONObject)((JSONArray) rawValue).get(i);
489 String parmValue = jsonObj.get(name).toString();
490 if (parmValue != null) {
491 msoLogger.debug("getJsonParamValue(): found value: " + parmValue + " for name: " + name + " and index: " + i);
492 if (foundCnt == index) {
502 msoLogger.debug("getJsonParamValue(): the JSONArray element is NOT a JSONObject=" + rawValue.toString());
506 msoLogger.debug("getJsonParamValue(): content value NOT found for name: " + name);
509 msoLogger.debug("getJsonParamValue(): the raw value is NOT a JSONArray Object=" + rawValue.toString());
513 } catch (Exception e) {
514 // JSONObject::get() throws a "not found" exception if one of the specified keys is not found
515 if (e.getMessage().contains("not found")) {
516 msoLogger.debug("getJsonParamValue(): failed to retrieve param value for keys:" + keys + ", name=" + name + ": " + e.getMessage());
518 msoLogger.debug("getJsonParamValue(): unable to parse json to retrieve value for field=" + keys + ". Exception was: " + e.toString(), e);
525 * Wrapper to generate the JSONObject to pass to the getJsonValueForKey(JSONObject, String)
526 * method so that recursion over the subobjects can be supported there
528 * @param jsonStr String containing the JSON doc
529 * @param key key to the target value
530 * @return String field value associated with key
532 public static String getJsonValueForKey(String jsonStr, String key) {
535 JSONObject jsonObj = new JSONObject(jsonStr);
536 return getJsonValueForKey(jsonObj, key);
537 } catch (Exception e) {
538 msoLogger.debug("getJsonValueForKey(): unable to parse json to retrieve value for field=" + key + ". Exception was: " + e.toString(), e);
544 * Walks the JSONObject (and sub-objects recursively), searching for the first value associated with the
545 * single key/field name specified. Returns the associated value if found or null if the key is not found
547 * @param jsonObj JSONObject representation of the the JSON doc
548 * @param key key to the target value
549 * @return String field value associated with key
551 public static String getJsonValueForKey(JSONObject jsonObj, String key) {
553 String keyValue = null;
555 if (jsonObj.has(key)) {
556 Object value = jsonObj.get(key);
557 msoLogger.debug("getJsonValueForKey(): found value=" + (String) value + ", for key=" + key);
561 return ((String) value);
564 // msoLogger.debug("getJsonValueForKey(): iterating over the keys");
565 Iterator <String> itr = jsonObj.keys();
566 while (itr.hasNext()) {
567 String nextKey = itr.next();
568 Object obj = jsonObj.get(nextKey);
569 if (obj instanceof JSONObject) {
570 // msoLogger.debug("getJsonValueForKey(): key=" + nextKey + ", points to JSONObject, recursive call on: " +
571 // ((JSONObject) obj).toString(MSOJsonIndentFactor));
572 keyValue = getJsonValueForKey((JSONObject) obj, key);
573 if (keyValue != null) {
574 // msoLogger.debug("getJsonValueForKey(): found value=" + keyValue + ", for key=" + key);
578 msoLogger.debug("getJsonValueForKey(): key=" + nextKey + ", does not point to a JSONObject, next key");
582 } catch (Exception e) {
583 // JSONObject::get() throws a "not found" exception if one of the specified keys is not found
584 if (e.getMessage().contains("not found")) {
585 msoLogger.debug("getJsonValueForKey(): failed to retrieve param value for key=" + key + ": " + e.getMessage());
587 msoLogger.debug("getJsonValueForKey(): unable to parse json to retrieve value for field=" + key + ". Exception was: " + e.toString(), e);
595 * Walks the JSONObject (and sub-objects recursively), searching for the first value associated with the
596 * single key/field name specified. Returns the associated value if found or null if the key is not found
598 * @param jsonObj JSONObject representation of the the JSON doc
599 * @param key key to the target value
600 * @return String field value associated with key
602 public static Integer getJsonIntValueForKey(JSONObject jsonObj, String key) {
603 // String isDebugLogEnabled = "true";
604 Integer keyValue = null;
606 if (jsonObj.has(key)) {
607 Integer value = (Integer) jsonObj.get(key);
608 msoLogger.debug("getJsonIntValueForKey(): found value=" + value + ", for key=" + key);
611 // msoLogger.debug("getJsonIntValueForKey(): iterating over the keys");
612 Iterator <String> itr = jsonObj.keys();
613 while (itr.hasNext()) {
614 String nextKey = itr.next();
615 Object obj = jsonObj.get(nextKey);
616 if (obj instanceof JSONObject) {
617 // msoLogger.debug("getJsonIntValueForKey(): key=" + nextKey + ", points to JSONObject, recursive call");
618 keyValue = getJsonIntValueForKey((JSONObject) obj, key);
619 if (keyValue != null) {
620 // msoLogger.debug("getJsonIntValueForKey(): found value=" + keyValue + ", for key=" + key);
624 msoLogger.debug("getJsonIntValueForKey(): key=" + nextKey + ", does not point to a JSONObject, next key");
628 } catch (Exception e) {
629 // JSONObject::get() throws a "not found" exception if one of the specified keys is not found
630 if (e.getMessage().contains("not found")) {
631 msoLogger.debug("getJsonIntValueForKey(): failed to retrieve param value for key=" + key + ": " + e.getMessage());
633 msoLogger.debug("getJsonIntValueForKey(): unable to parse json to retrieve value for field=" + key + ". Exception was: " + e.toString(),e);
641 * Walks the JSONObject (and sub-objects recursively), searching for the first value associated with the
642 * single key/field name specified. Returns the associated value if found or null if the key is not found
644 * @param jsonObj JSONObject representation of the the JSON doc
645 * @param key key to the target value
646 * @return String field value associated with key
648 public static Boolean getJsonBooleanValueForKey(JSONObject jsonObj, String key) {
649 Boolean keyValue = null;
651 if (jsonObj.has(key)) {
652 Boolean value = (Boolean) jsonObj.get(key);
653 msoLogger.debug("getJsonBooleanValueForKey(): found value=" + value + ", for key=" + key);
656 // msoLogger.debug("getJsonBooleanValueForKey(): iterating over the keys");
657 Iterator <String> itr = jsonObj.keys();
658 while (itr.hasNext()) {
659 String nextKey = itr.next();
660 Object obj = jsonObj.get(nextKey);
661 if (obj instanceof JSONObject) {
662 // msoLogger.debug("getJsonBooleanValueForKey(): key=" + nextKey + ", points to JSONObject, recursive call");
663 keyValue = getJsonBooleanValueForKey((JSONObject) obj, key);
664 if (keyValue != null) {
665 // msoLogger.debug("getJsonBooleanValueForKey(): found value=" + keyValue + ", for key=" + key);
669 msoLogger.debug("getJsonBooleanValueForKey(): key=" + nextKey + ", does not point to a JSONObject, next key");
673 } catch (Exception e) {
674 // JSONObject::get() throws a "not found" exception if one of the specified keys is not found
675 if (e.getMessage().contains("not found")) {
676 msoLogger.debug("getJsonBooleanValueForKey(): failed to retrieve param value for key=" + key + ": " + e.getMessage());
678 msoLogger.debug("getJsonBooleanValueForKey(): unable to parse json to retrieve value for field=" + key + ". Exception was: " + e.toString(),e);
686 * Boolean method to determine if a key path is valid for the JSON doc. Invokes
689 * @param jsonStr String containing the JSON doc
690 * @param keys full key path to the target value in the format of "key1.key2.key3..."
691 * @return Boolean true if keys points to value in the JSON doc
693 public static Boolean jsonValueExists(String jsonStr, String keys) {
694 if (getJsonRawValue(jsonStr, keys) == null) {
702 * Inserts the new key/value pair at the appropriate location in the JSON
703 * document after first determining if keyed field already exists. If
704 * it does exist, return the JSON unmodified, otherwise return the new JSON
705 * Note: this method currently only supports String value inserts.
707 * @param jsonStr String containing the JSON doc
708 * @param keys full key path to the value to be added in the format of "key1.key2.key3..."
709 * @return String containing the updated JSON doc
711 public static String addJsonValue(String jsonStr, String keys, String value) {
713 // only attempt to insert the key/value pair if it does not exist
714 if (!jsonValueExists(jsonStr, keys)) {
715 return putJsonValue(jsonStr, keys, value);
717 msoLogger.debug("addJsonValue(): JSON add failed, key=" + keys + "/value=" + value + " already exists");
723 * Updates the value for the specified key in the JSON document
724 * after first determining if keyed field exists. If it does
725 * not exist, return the JSON unmodified, otherwise return the updated JSON.
726 * Note: this method currently only supports String value updates.
728 * @param jsonStr String containing the JSON doc
729 * @param keys full key path to the value to be updated in the format of "key1.key2.key3..."
730 * @return String containing the updated JSON doc
732 public static String updJsonValue(String jsonStr, String keys, String newValue) {
733 // String isDebugLogEnabled = "true";
734 // only attempt to modify the key/value pair if it exists
735 if (jsonValueExists(jsonStr, keys)) {
736 return putJsonValue(jsonStr, keys, newValue);
738 msoLogger.debug("updJsonValue(): JSON update failed, no value exists for key=" + keys);
744 * Deletes the value for the specified key in the JSON document
745 * after first determining if keyed field exists. If it does
746 * not exist, return the JSON unmodified, otherwise return the updated JSON
748 * @param jsonStr String containing the JSON doc
749 * @param keys full key path to the value to be deleted in the format of "key1.key2.key3..."
750 * @return String containing the updated JSON doc
752 public static String delJsonValue(String jsonStr, String keys) {
754 // only attempt to remove the key/value pair if it exists
755 if (jsonValueExists(jsonStr, keys)) {
756 // passing a null value results in a delete
757 return putJsonValue(jsonStr, keys, null);
759 msoLogger.debug("delJsonValue(): JSON delete failed, no value exists for key=" + keys);
765 * Walks the JSON doc using the full key path to retrieve the associated
766 * value. All but the last key points to the 'parent' object name(s) in order
767 * in the JSON hierarchy with the last key pointing to the target value.
768 * The value returned is a Java object.
770 * @param jsonStr String containing the JSON doc
771 * @param keys full key path to the target value in the format of "key1.key2.key3..."
772 * @return Object field value associated with keys
774 private static Object getJsonRawValue(String jsonStr, String keys) {
775 return getJsonRawValue(jsonStr, keys, false);
779 * Walks the JSON doc using the full key path to retrieve the associated
780 * value. All but the last key points to the 'parent' object name(s) in order
781 * in the JSON hierarchy with the last key pointing to the target value.
782 * The value returned is a Java object.
784 * @param jsonStr String containing the JSON doc
785 * @param keys full key path to the target value in the format of "key1.key2.key3..."
786 * @param wrap Boolean which determines if returned JSONObjects sould be "wrapped"
787 * Note: wrap does not apply to returned scalar values
788 * @return Object field value associated with keys
790 private static Object getJsonRawValue(String jsonStr, String keys, Boolean wrap) {
794 JSONObject jsonObj = new JSONObject(jsonStr);
795 StringTokenizer keyTokens = new StringTokenizer(keys, ".");
796 while (keyTokens.hasMoreElements()) {
797 keyStr = keyTokens.nextToken();
798 Object keyValue = jsonObj.get(keyStr);
799 if (keyValue instanceof JSONObject) {
800 // msoLogger.debug("getJsonRawValue(): key=" + keyStr + " points to json object");
801 jsonObj = (JSONObject) keyValue;
803 if (keyTokens.hasMoreElements()) {
804 msoLogger.debug("getJsonRawValue(): value found prior to last key for key=" + keyStr);
809 // return the json 'node' that the key points to
810 // note: since this is a json object and not a scalar value,
811 // use the wrap flag to determine if the object should
812 // be wrapped with a root node value
813 // (the last key in the keys String)
815 JSONObject wrappedJsonObj = new JSONObject();
816 wrappedJsonObj.put(keyStr, jsonObj);
817 return wrappedJsonObj.toString();
819 return jsonObj.toString();
822 } catch (Exception e) {
823 // JSONObject::get() throws a "not found" exception if one of the specified keys is not found
824 if (e.getMessage().contains("not found")) {
825 msoLogger.debug("getJsonRawValue(): failed to retrieve param value for key=" + keyStr + ": " + e.getMessage());
827 msoLogger.debug("getJsonRawValue(): unable to parse json to retrieve value for field=" + keys + ". Exception was: " + e.toString(),e);
834 * Private method invoked by the public add, update, and delete methods.
836 * @param jsonStr String containing the JSON doc
837 * @param keys full key path to the value to be deleted in the format of "key1.key2.key3..."
838 * @return String containing the updated JSON doc
840 private static String putJsonValue(String jsonStr, String keys, String value) {
844 JSONObject jsonObj = new JSONObject(jsonStr);
845 JSONObject jsonObjOut = jsonObj;
846 StringTokenizer keyTokens = new StringTokenizer(keys, ".");
847 while (keyTokens.hasMoreElements()) {
848 keyStr = keyTokens.nextToken();
849 if (keyTokens.hasMoreElements()) {
850 Object keyValue = jsonObj.get(keyStr);
851 if (keyValue instanceof JSONObject) {
852 // msoLogger.debug("putJsonValue(): key=" + keyStr + " points to json object");
853 jsonObj = (JSONObject) keyValue;
855 msoLogger.debug("putJsonValue(): key=" + keyStr + " not the last key but points to non-json object: " + keyValue);
858 } else { // at the last/new key value
859 jsonObj.put(keyStr, value);
860 return jsonObjOut.toString(3);
863 // should not hit this point if the key points to a valid key value
866 } catch (Exception e) {
867 // JSONObject::get() throws a "not found" exception if one of the specified keys is not found
868 if (e.getMessage().contains("not found")) {
869 msoLogger.debug("putJsonValue(): failed to put param value for key=" + keyStr + ": " + e.getMessage());
871 msoLogger.debug("putJsonValue(): unable to parse json to put value for key=" + keys + ". Exception was: " + e.toString(),e);
878 * This json util method converts a json array of Key Value
879 * pair objects into a Java Map.
882 * @param entryArray - the getJsonValue of a json Array of key/value pairs
884 * @return Map - a Map containing the entries
886 public Map<String, String> jsonStringToMap(DelegateExecution execution, String entry) {
887 msoLogger.debug("Started Json String To Map Method");
889 Map<String, String> map = new HashMap<>();
892 JSONObject obj = new JSONObject(entry);
894 /* Wildfly is pushing a version of org.json which does not
895 * auto cast to string. Leaving it as an object prevents
896 * a method not found exception at runtime.
898 final Iterator<String> keys = obj.keys();
899 while (keys.hasNext()) {
900 final String key = keys.next();
901 map.put(key, obj.getString(key));
903 msoLogger.debug("Outgoing Map is: " + map);
904 msoLogger.debug("Completed Json String To Map Method");
909 * This json util method converts a json array of Key Value
910 * pair objects into a Java Map.
913 * @param entryArray - the getJsonValue of a json Array of key/value pairs
914 * @param keyNode - the name of the node that represents the key
915 * @param valueNode - the name of the node that represents the value
916 * @return Map - a Map containing the entries
919 public Map<String, String> entryArrayToMap(DelegateExecution execution, String entryArray, String keyNode, String valueNode) {
920 msoLogger.debug("Started Entry Array To Map Util Method");
922 Map<String, String> map = new HashMap<>();
924 String entryListJson = "{ \"wrapper\":" + entryArray + "}";
925 JSONObject obj = new JSONObject(entryListJson);
926 JSONArray arr = obj.getJSONArray("wrapper");
927 for (int i = 0; i < arr.length(); i++){
928 JSONObject jo = arr.getJSONObject(i);
929 String key = jo.getString(keyNode);
930 String value = jo.getString(valueNode);
933 msoLogger.debug("Completed Entry Array To Map Util Method");
938 * This json util method converts a json array of Key Value pair objects into a Java Map.
940 * @param entryArray - the json Array of key/value pairs objects
941 * @param keyNode - the name of the node that represents the key
942 * @param valueNode - the name of the node that represents the value
943 * @return Map - a Map containing the entries
947 public Map<String, String> entryArrayToMap(String entryArray, String keyNode, String valueNode){
948 msoLogger.debug("Started Entry Array To Map Util Method");
950 Map<String, String> map = new HashMap<>();
951 String entryListJson = "{ \"wrapper\":" + entryArray + "}";
952 JSONObject obj = new JSONObject(entryListJson); // TODO just put in json array
953 JSONArray arr = obj.getJSONArray("wrapper");
954 for(int i = 0; i < arr.length(); i++){
955 JSONObject jo = arr.getJSONObject(i);
956 String key = jo.getString(keyNode);
957 String value = jo.getString(valueNode);
960 msoLogger.debug("Completed Entry Array To Map Util Method");
965 * This json util method converts a json Array of Strings to a Java List. It takes each
966 * String in the json Array and puts it in a Java List<String>.
969 * @param jsonArray - string value of a json array
970 * @return List - a java list containing the strings
974 public List<String> StringArrayToList(Execution execution, String jsonArray){
975 msoLogger.debug("Started String Array To List Util Method");
977 List<String> list = new ArrayList<>();
980 String stringListJson = "{ \"strings\":" + jsonArray + "}";
981 JSONObject obj = new JSONObject(stringListJson);
982 JSONArray arr = obj.getJSONArray("strings");
983 for(int i = 0; i < arr.length(); i++){
984 String s = arr.get(i).toString();
987 msoLogger.debug("Outgoing List is: " + list);
988 msoLogger.debug("Completed String Array To List Util Method");
993 * This json util method converts a json Array of Strings to a Java List. It takes each
994 * String in the json Array and puts it in a Java List<String>.
996 * @param jsonArray - string value of a json array
997 * @return List - a java list containing the strings
1001 public List<String> StringArrayToList(String jsonArray){
1002 msoLogger.debug("Started Json Util String Array To List");
1003 List<String> list = new ArrayList<>();
1005 JSONArray arr = new JSONArray(jsonArray);
1006 for(int i = 0; i < arr.length(); i++){
1007 String s = arr.get(i).toString();
1010 msoLogger.debug("Completed Json Util String Array To List");
1015 * This json util method converts a json Array of Strings to a Java List. It takes each
1016 * String in the json Array and puts it in a Java List<String>.
1018 * @param jsonArray - json array
1019 * @return List - a java list containing the strings
1023 public List<String> StringArrayToList(JSONArray jsonArray){
1024 msoLogger.debug("Started Json Util String Array To List");
1025 List<String> list = new ArrayList<>();
1027 for(int i = 0; i < jsonArray.length(); i++){
1028 String s = jsonArray.get(i).toString();
1031 msoLogger.debug("Completed Json Util String Array To List");
1037 * Invokes the getJsonRawValue() method to determine if the json element/variable exist.
1038 * Returns true if the json element exist
1040 * @param jsonStr - String containing the JSON doc
1041 * @param keys - full key path to the target value in the format of "key1.key2.key3..."
1042 * @return boolean field value associated with keys
1045 public static boolean jsonElementExist(String jsonStr, String keys){
1048 Object rawValue = getJsonRawValue(jsonStr, keys);
1050 return !(rawValue == null);
1052 } catch(Exception e){
1053 msoLogger.debug("jsonElementExist(): unable to determine if json element exist. Exception is: " + e.toString(), e);
1060 * Validates the JSON document against a schema file.
1062 * @param jsonStr String containing the JSON doc
1063 * @param jsonSchemaPath full path to a valid JSON schema file
1066 public static String jsonSchemaValidation(String jsonStr, String jsonSchemaPath) throws ValidationException {
1068 msoLogger.debug("JSON document to be validated: " + jsonStr);
1069 JsonNode document = JsonLoader.fromString(jsonStr);
1070 // JsonNode document = JsonLoader.fromFile(jsonDoc);
1071 JsonNode schema = JsonLoader.fromPath(jsonSchemaPath);
1073 JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
1074 JsonValidator validator = factory.getValidator();
1076 ProcessingReport report = validator.validate(schema, document);
1077 msoLogger.debug("JSON schema validation report: " + report.toString());
1078 return report.toString();
1079 } catch (IOException e) {
1080 msoLogger.debug("IOException performing JSON schema validation on document: " + e.toString());
1081 throw new ValidationException(e.getMessage());
1082 } catch (ProcessingException e) {
1083 msoLogger.debug("ProcessingException performing JSON schema validation on document: " + e.toString());
1084 throw new ValidationException(e.getMessage());