/*
* This software is released under the GNU Lesser General Public License v3.
* For more information see http://www.gnu.org/licenses/lgpl.html
*
* Copyright (c) 2011, Peter Knego & Matjaz Tercelj
* All rights reserved.
*/
package com.leanengine;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.*;
/**
* Internal utility class for decoding REST messages.
*/
public class JsonDecode {
static LeanAccount accountFromJson(JSONObject json) throws LeanException {
Long id;
try {
id = json.getLong("id");
} catch (JSONException e) {
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: Entity JSON missing field 'id'.");
}
String providerId;
try {
providerId = json.getString("providerId");
} catch (JSONException e) {
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: Entity JSON missing field 'providerId'.");
}
String nickName;
try {
nickName = json.getString("nickName");
} catch (JSONException e) {
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: Entity JSON missing field 'nickName'.");
}
String provider;
try {
provider = json.getString("provider");
} catch (JSONException e) {
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: Entity JSON missing field 'provider'.");
}
JSONObject jsonProviderProperties;
Map<String, Object> providerProperties;
try {
jsonProviderProperties = json.getJSONObject("providerProperties");
providerProperties = accountPropsFromJson(jsonProviderProperties);
return new LeanAccount(id, nickName, providerId, provider, providerProperties);
} catch (JSONException e) {
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: Entity JSON missing field 'providerProperties'.");
}
}
private static Map<String, Object> accountPropsFromJson(JSONObject jsonNode) throws LeanException, JSONException {
Map<String, Object> props = new HashMap<String, Object>(jsonNode.length());
// must have some properties
if (jsonNode.length() == 0) throw new LeanException(LeanError.Type.ServerError,
"Malformed reply: JSON parameter 'providerProperties' must not be empty.");
Iterator fieldNames = jsonNode.keys();
while (fieldNames.hasNext()) {
String field = (String) fieldNames.next();
props.put(field, jsonNode.get(field));
}
return props;
}
static LeanEntity[] entityListFromJson(JSONObject json) throws LeanException {
try {
JSONArray array = json.getJSONArray("result");
LeanEntity[] result = new LeanEntity[array.length()];
for (int i = 0; i < array.length(); i++) {
JSONObject item = array.getJSONObject(i);
result[i] = entityFromJson(item);
}
return result;
} catch (JSONException e) {
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: " + e);
}
}
static LeanEntity entityFromJson(JSONObject json) throws LeanException {
String kind;
try {
kind = json.getString("_kind");
} catch (JSONException e) {
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: Entity JSON missing field '_kind'.");
}
Long id;
try {
id = json.getLong("_id");
} catch (JSONException e) {
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: Entity JSON missing field '_id'.");
}
Long accountId;
try {
accountId = json.getLong("_account");
} catch (JSONException e) {
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: Entity JSON missing field '_account'.");
}
LeanEntity entity = new LeanEntity(kind, id, accountId);
try {
entity.properties = entityPropertiesFromJson(json);
} catch (JSONException e) {
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: " + e);
}
return entity;
}
static Map<String, Object> entityPropertiesFromJson(JSONObject jsonNode) throws LeanException, JSONException {
Map<String, Object> props = new HashMap<String, Object>(jsonNode.length());
// must have some properties
if (jsonNode.length() == 0) throw new LeanException(LeanError.Type.ServerError, "Empty reply.");
Iterator fieldNames = jsonNode.keys();
while (fieldNames.hasNext()) {
String field = (String) fieldNames.next();
// skip LeanEngine system properties (starting with underscore '_')
if (field.startsWith("_")) continue;
Object subNode = jsonNode.get(field);
props.put(field, propertyFromJson(subNode));
}
return props;
}
static Object propertyFromJson(Object jsonNode) throws LeanException, JSONException {
if (jsonNode instanceof JSONObject) {
return typedObjectFromJson((JSONObject) jsonNode);
} else if (jsonNode instanceof JSONArray) {
return typedArrayFromJson((JSONArray) jsonNode);
}
return jsonNode;
}
private static List<Object> typedArrayFromJson(JSONArray arrayNode) throws LeanException, JSONException {
List<Object> result = new ArrayList<Object>(arrayNode.length());
for (int i = 0; i < arrayNode.length(); i++) {
Object node = arrayNode.getJSONObject(i);
if (node instanceof JSONObject) {
result.add(typedObjectFromJson((JSONObject) node));
} else {
result.add(node);
}
}
return result;
}
private static Object typedObjectFromJson(JSONObject node) throws LeanException, JSONException {
// must have 'type' field
String type = node.getString("type");
if (type == null) throw new LeanException(LeanError.Type.ServerError, "Malformed reply: Missing 'type' field.");
if ("date".equals(type)) {
return new Date(getLongFromValueNode("value", node));
} else if ("text".equals(type)) {
return new LeanText(getStringFromValueNode("value", node));
} else if ("geopt".equals(type)) {
throw new IllegalArgumentException("Value nodes of type 'geopt' are not yet implemented.");
} else if ("geohash".equals(type)) {
throw new IllegalArgumentException("Value nodes of type 'geohash' are not yet implemented.");
} else if ("blob".equals(type)) {
throw new IllegalArgumentException("Value nodes of type 'blob' are not yet implemented.");
} else if ("shortblob".equals(type)) {
throw new IllegalArgumentException("Value nodes of type 'shortblob' are not yet implemented.");
} else if ("reference".equals(type)) {
throw new IllegalArgumentException("Value nodes of type 'reference' are not yet implemented.");
} else {
//unknown node type
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: Unknown type '" + type + "'.");
}
}
private static long getLongFromValueNode(String fieldName, JSONObject node) throws LeanException {
try {
return node.getLong(fieldName);
} catch (JSONException e) {
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: Missing '" + fieldName + "' field.");
}
}
private static String getStringFromValueNode(String fieldName, JSONObject node) throws LeanException {
try {
return node.getString(fieldName);
} catch (JSONException e) {
throw new LeanException(LeanError.Type.ServerError, "Malformed reply: Missing '" + fieldName + "' field.");
}
}
}