/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.artemis.api.core;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonArrayBuilder;
import javax.json.JsonNumber;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonString;
import javax.json.JsonValue;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.activemq.artemis.core.client.ActiveMQClientMessageBundle;
import org.apache.activemq.artemis.utils.Base64;
import org.apache.activemq.artemis.utils.JsonLoader;
import org.apache.activemq.artemis.utils.ObjectInputStreamWithClassLoader;
import org.apache.activemq.artemis.utils.StringEscapeUtils;
public final class JsonUtil {
public static JsonArray toJSONArray(final Object[] array) throws Exception {
JsonArrayBuilder jsonArray = JsonLoader.createArrayBuilder();
for (Object parameter : array) {
if (parameter instanceof Map) {
Map<String, Object> map = (Map<String, Object>) parameter;
JsonObjectBuilder jsonObject = JsonLoader.createObjectBuilder();
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object val = entry.getValue();
if (val != null) {
if (val.getClass().isArray()) {
JsonArray objectArray = toJSONArray((Object[]) val);
jsonObject.add(key, objectArray);
} else {
addToObject(key, val, jsonObject);
}
}
}
jsonArray.add(jsonObject);
} else {
if (parameter != null) {
Class<?> clz = parameter.getClass();
if (clz.isArray()) {
Object[] innerArray = (Object[]) parameter;
if (innerArray instanceof CompositeData[]) {
JsonArrayBuilder innerJsonArray = JsonLoader.createArrayBuilder();
for (Object data : innerArray) {
String s = Base64.encodeObject((CompositeDataSupport) data);
innerJsonArray.add(s);
}
JsonObjectBuilder jsonObject = JsonLoader.createObjectBuilder();
jsonObject.add(CompositeData.class.getName(), innerJsonArray);
jsonArray.add(jsonObject);
} else {
jsonArray.add(toJSONArray(innerArray));
}
} else {
addToArray(parameter, jsonArray);
}
} else {
jsonArray.addNull();
}
}
}
return jsonArray.build();
}
public static Object[] fromJsonArray(final JsonArray jsonArray) throws Exception {
Object[] array = new Object[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
Object val = jsonArray.get(i);
if (val instanceof JsonArray) {
Object[] inner = fromJsonArray((JsonArray) val);
array[i] = inner;
} else if (val instanceof JsonObject) {
JsonObject jsonObject = (JsonObject) val;
Map<String, Object> map = new HashMap<>();
Set<String> keys = jsonObject.keySet();
for (String key : keys) {
Object innerVal = jsonObject.get(key);
if (innerVal instanceof JsonArray) {
innerVal = fromJsonArray(((JsonArray) innerVal));
} else if (innerVal instanceof JsonString) {
innerVal = ((JsonString) innerVal).getString();
} else if (innerVal == JsonValue.FALSE) {
innerVal = Boolean.FALSE;
} else if (innerVal == JsonValue.TRUE) {
innerVal = Boolean.TRUE;
} else if (innerVal instanceof JsonNumber) {
JsonNumber jsonNumber = (JsonNumber) innerVal;
if (jsonNumber.isIntegral()) {
innerVal = jsonNumber.longValue();
} else {
innerVal = jsonNumber.doubleValue();
}
} else if (innerVal instanceof JsonObject) {
Map<String, Object> innerMap = new HashMap<>();
JsonObject o = (JsonObject) innerVal;
Set<String> innerKeys = o.keySet();
for (String k : innerKeys) {
innerMap.put(k, o.get(k));
}
innerVal = innerMap;
}
if (CompositeData.class.getName().equals(key)) {
Object[] data = (Object[]) innerVal;
CompositeData[] cds = new CompositeData[data.length];
for (int i1 = 0; i1 < data.length; i1++) {
String dataConverted = convertJsonValue(data[i1], String.class).toString();
try (ObjectInputStreamWithClassLoader ois = new ObjectInputStreamWithClassLoader(new ByteArrayInputStream(Base64.decode(dataConverted)))) {
ois.setWhiteList("java.util,java.lang,javax.management");
cds[i1] = (CompositeDataSupport) ois.readObject();
}
}
innerVal = cds;
}
map.put(key, innerVal);
}
array[i] = map;
} else if (val instanceof JsonString) {
array[i] = ((JsonString) val).getString();
} else if (val == JsonValue.FALSE) {
array[i] = Boolean.FALSE;
} else if (val == JsonValue.TRUE) {
array[i] = Boolean.TRUE;
} else if (val instanceof JsonNumber) {
JsonNumber jsonNumber = (JsonNumber) val;
if (jsonNumber.isIntegral()) {
array[i] = jsonNumber.longValue();
} else {
array[i] = jsonNumber.doubleValue();
}
} else {
if (val == JsonValue.NULL) {
array[i] = null;
} else {
array[i] = val;
}
}
}
return array;
}
public static JsonValue nullSafe(String input) {
return new NullableJsonString(input);
}
public static void addToObject(final String key, final Object param, final JsonObjectBuilder jsonObjectBuilder) {
if (param instanceof Integer) {
jsonObjectBuilder.add(key, (Integer) param);
} else if (param instanceof Long) {
jsonObjectBuilder.add(key, (Long) param);
} else if (param instanceof Double) {
jsonObjectBuilder.add(key, (Double) param);
} else if (param instanceof String) {
jsonObjectBuilder.add(key, (String) param);
} else if (param instanceof Boolean) {
jsonObjectBuilder.add(key, (Boolean) param);
} else if (param instanceof Map) {
JsonObject mapObject = toJsonObject((Map<String, Object>) param);
jsonObjectBuilder.add(key, mapObject);
} else if (param instanceof Short) {
jsonObjectBuilder.add(key, (Short) param);
} else if (param instanceof Byte) {
jsonObjectBuilder.add(key, ((Byte) param).shortValue());
} else if (param instanceof SimpleString) {
jsonObjectBuilder.add(key, param.toString());
} else if (param == null) {
jsonObjectBuilder.addNull(key);
} else {
throw ActiveMQClientMessageBundle.BUNDLE.invalidManagementParam(param.getClass().getName());
}
}
public static void addToArray(final Object param, final JsonArrayBuilder jsonArrayBuilder) {
if (param instanceof Integer) {
jsonArrayBuilder.add((Integer) param);
} else if (param instanceof Long) {
jsonArrayBuilder.add((Long) param);
} else if (param instanceof Double) {
jsonArrayBuilder.add((Double) param);
} else if (param instanceof String) {
jsonArrayBuilder.add((String) param);
} else if (param instanceof Boolean) {
jsonArrayBuilder.add((Boolean) param);
} else if (param instanceof Map) {
JsonObject mapObject = toJsonObject((Map<String, Object>) param);
jsonArrayBuilder.add(mapObject);
} else if (param instanceof Short) {
jsonArrayBuilder.add((Short) param);
} else if (param instanceof Byte) {
jsonArrayBuilder.add(((Byte) param).shortValue());
} else if (param == null) {
jsonArrayBuilder.addNull();
} else {
throw ActiveMQClientMessageBundle.BUNDLE.invalidManagementParam(param.getClass().getName());
}
}
public static JsonArray toJsonArray(List<String> strings) {
JsonArrayBuilder array = JsonLoader.createArrayBuilder();
if (strings != null) {
for (String connector : strings) {
array.add(connector);
}
}
return array.build();
}
public static JsonObject toJsonObject(Map<String, Object> map) {
JsonObjectBuilder jsonObjectBuilder = JsonLoader.createObjectBuilder();
if (map != null) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
addToObject(entry.getKey(), entry.getValue(), jsonObjectBuilder);
}
}
return jsonObjectBuilder.build();
}
public static JsonArray readJsonArray(String jsonString) {
return Json.createReader(new StringReader(jsonString)).readArray();
}
public static JsonObject readJsonObject(String jsonString) {
return Json.createReader(new StringReader(jsonString)).readObject();
}
public static Object convertJsonValue(Object jsonValue, Class desiredType) {
if (jsonValue instanceof JsonNumber) {
JsonNumber number = (JsonNumber) jsonValue;
if (desiredType == null || desiredType == Long.class || desiredType == Long.TYPE) {
return number.longValue();
} else if (desiredType == Integer.class || desiredType == Integer.TYPE) {
return number.intValue();
} else if (desiredType == Double.class || desiredType == Double.TYPE) {
return number.doubleValue();
} else {
return number.longValue();
}
} else if (jsonValue instanceof JsonString) {
return ((JsonString) jsonValue).getString();
} else if (jsonValue instanceof JsonValue) {
if (jsonValue == JsonValue.TRUE) {
return true;
} else if (jsonValue == JsonValue.FALSE) {
return false;
} else {
return jsonValue.toString();
}
} else if (jsonValue instanceof Number) {
Number jsonNumber = (Number) jsonValue;
if (desiredType == Integer.TYPE || desiredType == Integer.class) {
return jsonNumber.intValue();
} else if (desiredType == Long.TYPE || desiredType == Long.class) {
return jsonNumber.longValue();
} else if (desiredType == Double.TYPE || desiredType == Double.class) {
return jsonNumber.doubleValue();
} else if (desiredType == Short.TYPE || desiredType == Short.class) {
return jsonNumber.shortValue();
} else {
return jsonValue;
}
} else if (jsonValue instanceof Object[]) {
Object[] array = (Object[]) jsonValue;
Object[] result;
if (desiredType != null) {
result = (Object[]) Array.newInstance(desiredType, array.length);
} else {
result = array;
}
for (int i = 0; i < array.length; i++) {
result[i] = convertJsonValue(array[i], desiredType);
}
return result;
} else {
return jsonValue;
}
}
private JsonUtil() {
}
private static class NullableJsonString implements JsonValue, JsonString {
private final String value;
private String escape;
NullableJsonString(String value) {
if (value == null || value.length() == 0) {
this.value = null;
} else {
this.value = value;
}
}
@Override
public ValueType getValueType() {
return value == null ? ValueType.NULL : ValueType.STRING;
}
@Override
public String getString() {
return this.value;
}
@Override
public CharSequence getChars() {
return getString();
}
@Override
public String toString() {
if (this.value == null) {
return null;
}
String s = this.escape;
if (s == null) {
s = '\"' + StringEscapeUtils.escapeString(this.value) + '\"';
this.escape = s;
}
return s;
}
}
}