blob: 2a94deaf31e235864cc3a906c89e31e25c1a5461 [file] [log] [blame]
// 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 com.cloud.bridge.util;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.cloud.bridge.service.exception.InternalErrorException;
/**
* JsonAccessor provides the functionality to allow navigating JSON object graph using simple expressions,
* for example, following property access expressions are all valid ones
*
* rootobj.level1obj[1].property
* this[0].level1obj[1].property
*
*/
public class JsonAccessor {
private JsonElement _json;
Pattern _arrayAccessorMatcher = Pattern.compile("(.*)\\[(\\d+)\\]");
public JsonAccessor(JsonElement json) {
assert (json != null);
_json = json;
}
public BigDecimal getAsBigDecimal(String propPath) {
JsonElement jsonElement = eval(propPath);
return jsonElement.getAsBigDecimal();
}
public BigInteger getAsBigInteger(String propPath) {
JsonElement jsonElement = eval(propPath);
return jsonElement.getAsBigInteger();
}
public boolean getAsBoolean(String propPath) {
JsonElement jsonElement = eval(propPath);
return jsonElement.getAsBoolean();
}
public byte getAsByte(String propPath) {
JsonElement jsonElement = eval(propPath);
return jsonElement.getAsByte();
}
public char getAsCharacter(String propPath) {
JsonElement jsonElement = eval(propPath);
return jsonElement.getAsCharacter();
}
public double getAsDouble(String propPath) {
JsonElement jsonElement = eval(propPath);
return jsonElement.getAsDouble();
}
public float getAsFloat(String propPath) {
JsonElement jsonElement = eval(propPath);
return jsonElement.getAsFloat();
}
public int getAsInt(String propPath) {
JsonElement jsonElement = eval(propPath);
return jsonElement.getAsInt();
}
public long getAsLong(String propPath) {
JsonElement jsonElement = eval(propPath);
return jsonElement.getAsLong();
}
public Number getAsNumber(String propPath) {
JsonElement jsonElement = eval(propPath);
return jsonElement.getAsNumber();
}
public short getAsShort(String propPath) {
JsonElement jsonElement = eval(propPath);
return jsonElement.getAsShort();
}
public String getAsString(String propPath) {
JsonElement jsonElement = eval(propPath);
return jsonElement.getAsString();
}
public boolean isBoolean(String propPath) {
JsonElement jsonElement = eval(propPath);
if (jsonElement instanceof JsonPrimitive)
return ((JsonPrimitive)jsonElement).isBoolean();
return false;
}
public boolean isNumber(String propPath) {
JsonElement jsonElement = eval(propPath);
if (jsonElement instanceof JsonPrimitive)
return ((JsonPrimitive)jsonElement).isNumber();
return false;
}
public boolean isString(String propPath) {
JsonElement jsonElement = eval(propPath);
if (jsonElement instanceof JsonPrimitive)
return ((JsonPrimitive)jsonElement).isString();
return false;
}
/*
* Return
* -1 : property expression can not be resolved
* 0 : match to a null JSON object
* 1+ : matched, for array element, the count of the elements inside the array
*/
public int getMatchCount(String propPath) {
JsonElement jsonElement = tryEval(propPath);
if (jsonElement == null)
return -1;
if (jsonElement.isJsonNull())
return 0;
if (jsonElement.isJsonArray())
return ((JsonArray)jsonElement).size();
return 1;
}
public JsonElement eval(String propPath) {
JsonElement jsonElement = tryEval(propPath);
if (jsonElement == null)
throw new InternalErrorException("Property " + propPath + " is resolved to null JSON element on object: " + _json.toString());
return jsonElement;
}
public JsonElement tryEval(String propPath) {
assert (propPath != null);
String[] tokens = propPath.split("\\.");
ArrayList<Resolver> resolverChain = new ArrayList<Resolver>();
for (String token : tokens) {
Matcher matcher = _arrayAccessorMatcher.matcher(token);
if (matcher.find()) {
String propStr = matcher.group(1);
String indexStr = matcher.group(2);
resolverChain.add(new ArrayPropertyResolver(propStr, Integer.parseInt(indexStr)));
} else {
resolverChain.add(new PropertyResolver(token));
}
}
JsonElement jsonElementToResolveAt = _json;
for (Resolver resolver : resolverChain) {
jsonElementToResolveAt = resolver.resolve(jsonElementToResolveAt);
if (jsonElementToResolveAt == null)
break;
}
return jsonElementToResolveAt;
}
//
// Property resolvers
//
private static interface Resolver {
public JsonElement resolve(JsonElement jsonElementToResolveAt);
}
private static class PropertyResolver implements Resolver {
protected String _propName;
public PropertyResolver(String propName) {
_propName = propName;
}
public JsonElement resolve(JsonElement jsonElementToResolveAt) {
if ("this".equals(_propName))
return jsonElementToResolveAt;
if (jsonElementToResolveAt.isJsonObject())
return ((JsonObject)jsonElementToResolveAt).get(_propName);
if (jsonElementToResolveAt.isJsonNull())
throw new NullPointerException(String.format("Property %s points to a null element on object: %s", _propName, jsonElementToResolveAt.toString()));
throw new InternalErrorException("Unable to evaluate JSON accessor property: " + _propName + ", on object: " + jsonElementToResolveAt.toString());
}
}
private static class ArrayPropertyResolver extends PropertyResolver {
protected int _index;
public ArrayPropertyResolver(String propName, int index) {
super(propName);
_index = index;
}
public JsonElement resolve(JsonElement jsonElementToResolveAt) {
if (!"this".equals(_propName)) {
if (jsonElementToResolveAt.isJsonObject()) {
jsonElementToResolveAt = ((JsonObject)jsonElementToResolveAt).get(_propName);
} else {
if (jsonElementToResolveAt.isJsonNull())
throw new NullPointerException(String.format("Property %s points to a null element on object: %s", _propName, jsonElementToResolveAt.toString()));
throw new InternalErrorException("Unable to evaluate JSON accessor property: " + _propName + ", on object: " + jsonElementToResolveAt.toString());
}
}
if (jsonElementToResolveAt instanceof JsonArray) {
return ((JsonArray)jsonElementToResolveAt).get(_index);
}
if (jsonElementToResolveAt.isJsonNull())
throw new NullPointerException(String.format("Property %s points to a null element on object: %s", _propName, jsonElementToResolveAt.toString()));
throw new InternalErrorException("Unable to evaluate JSON accessor property: " + _propName + ", on object: " + jsonElementToResolveAt.toString());
}
}
}