blob: 8ccecbe57ae7d99a92c2fe1ccb27f83d42b12589 [file] [log] [blame]
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed 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.onosproject.ovsdb.rfc.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.onosproject.ovsdb.rfc.error.AbnormalSchemaException;
import org.onosproject.ovsdb.rfc.error.JsonParsingException;
import org.onosproject.ovsdb.rfc.error.UnknownResultException;
import org.onosproject.ovsdb.rfc.jsonrpc.Callback;
import org.onosproject.ovsdb.rfc.jsonrpc.JsonRpcResponse;
import org.onosproject.ovsdb.rfc.message.OperationResult;
import org.onosproject.ovsdb.rfc.message.RowUpdate;
import org.onosproject.ovsdb.rfc.message.TableUpdate;
import org.onosproject.ovsdb.rfc.message.TableUpdates;
import org.onosproject.ovsdb.rfc.message.UpdateNotification;
import org.onosproject.ovsdb.rfc.notation.Column;
import org.onosproject.ovsdb.rfc.notation.Row;
import org.onosproject.ovsdb.rfc.notation.UUID;
import org.onosproject.ovsdb.rfc.operations.Operation;
import org.onosproject.ovsdb.rfc.schema.ColumnSchema;
import org.onosproject.ovsdb.rfc.schema.DatabaseSchema;
import org.onosproject.ovsdb.rfc.schema.TableSchema;
import org.onosproject.ovsdb.rfc.schema.type.ColumnTypeFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* JsonNode utility class. convert JsonNode into Object.
*/
public final class FromJsonUtil {
private static final Logger log = LoggerFactory
.getLogger(FromJsonUtil.class);
/**
* Constructs a FromJsonUtil object. Utility classes should not have a
* public or default constructor, otherwise IDE will compile unsuccessfully. This
* class should not be instantiated.
*/
private FromJsonUtil() {
}
/**
* convert JsonNode into DatabaseSchema.
* @param dbName database name
* @param json the JsonNode of get_schema result
* @return DatabaseSchema
* @throws JsonParsingException this is a JsonNode parse exception
*/
public static DatabaseSchema jsonNodeToDbSchema(String dbName, JsonNode json) {
if (!json.isObject() || !json.has("tables")) {
throw new JsonParsingException(
"bad DatabaseSchema root, expected \"tables\" as child but was not found");
}
if (!json.isObject() || !json.has("version")) {
throw new JsonParsingException(
"bad DatabaseSchema root, expected \"version\" as child but was not found");
}
String dbVersion = json.get("version").asText();
Map<String, TableSchema> tables = new HashMap<>();
for (Iterator<Map.Entry<String, JsonNode>> iter = json.get("tables")
.fields(); iter.hasNext();) {
Map.Entry<String, JsonNode> table = iter.next();
tables.put(table.getKey(),
jsonNodeToTableSchema(table.getKey(), table.getValue()));
}
return new DatabaseSchema(dbName, dbVersion, tables);
}
/**
* convert JsonNode into TableSchema.
* @param tableName table name
* @param json table JsonNode
* @return TableSchema
* @throws AbnormalSchemaException this is an abnormal schema exception
*/
private static TableSchema jsonNodeToTableSchema(String tableName,
JsonNode json) {
if (!json.isObject() || !json.has("columns")) {
throw new AbnormalSchemaException(
"bad tableschema root, expected \"columns\" as child");
}
Map<String, ColumnSchema> columns = new HashMap<>();
for (Iterator<Map.Entry<String, JsonNode>> iter = json.get("columns")
.fields(); iter.hasNext();) {
Map.Entry<String, JsonNode> column = iter.next();
columns.put(column.getKey(),
jsonNodeToColumnSchema(column.getKey(),
column.getValue()));
}
return new TableSchema(tableName, columns);
}
/**
* convert JsonNode into ColumnSchema.
* @param name column name
* @param json JsonNode
* @return ColumnSchema
* @throws AbnormalSchemaException this is an abnormal schema exception
*/
private static ColumnSchema jsonNodeToColumnSchema(String name,
JsonNode json) {
if (!json.isObject() || !json.has("type")) {
throw new AbnormalSchemaException(
"bad column schema root, expected \"type\" as child");
}
return new ColumnSchema(name,
ColumnTypeFactory.getColumnTypeFromJson(json
.get("type")));
}
/**
* convert JsonNode into the returnType of methods in OvsdbRPC class.
* @param resultJsonNode the result JsonNode
* @param methodName the method name of methods in OvsdbRPC class
* @param objectMapper ObjectMapper entity
* @return Object
* @throws UnknownResultException this is an unknown result exception
*/
private static Object convertResultType(JsonNode resultJsonNode,
String methodName,
ObjectMapper objectMapper) {
switch (methodName) {
case "getSchema":
case "monitor":
return resultJsonNode;
case "echo":
case "listDbs":
return objectMapper
.convertValue(resultJsonNode, objectMapper.getTypeFactory()
.constructParametricType(List.class, String.class));
case "transact":
return objectMapper
.convertValue(resultJsonNode,
objectMapper
.getTypeFactory()
.constructParametricType(List.class,
JsonNode.class));
default:
throw new UnknownResultException("Don't know how to handle this");
}
}
/**
* convert JsonNode into the returnType of methods in OvsdbRPC class.
* @param jsonNode the result JsonNode
* @param methodName the method name of methods in OvsdbRPC class
* @return Object
*/
public static Object jsonResultParser(JsonNode jsonNode, String methodName) {
ObjectMapper objectMapper = ObjectMapperUtil.getObjectMapper();
JsonNode error = jsonNode.get("error");
if (error != null && !error.isNull()) {
log.error("Error : {}", error.toString());
}
JsonNode resultJsonNode = jsonNode.get("result");
Object result = convertResultType(resultJsonNode, methodName,
objectMapper);
return result;
}
/**
* When monitor the ovsdb tables, if a table update, ovs send update
* notification, then call callback function.
* @param jsonNode the result JsonNode
* @param callback the callback function
* @throws UnknownResultException this is an unknown result exception
*/
public static void jsonCallbackRequestParser(JsonNode jsonNode,
Callback callback) {
ObjectMapper objectMapper = ObjectMapperUtil.getObjectMapper();
JsonNode params = jsonNode.get("params");
Object param = null;
String methodName = jsonNode.get("method").asText();
switch (methodName) {
case "update":
param = objectMapper.convertValue(params, UpdateNotification.class);
callback.update((UpdateNotification) param);
break;
default:
throw new UnknownResultException("Cannot handle this method: "
+ methodName);
}
}
/**
* Ovs send echo request to keep the heart, need we return echo result.
* @param jsonNode the result JsonNode
* @return JsonRpcResponse String
*/
public static String getEchoRequestStr(JsonNode jsonNode) {
ObjectMapper objectMapper = ObjectMapperUtil.getObjectMapper();
String str = null;
if (jsonNode.get("method").asText().equals("echo")) {
JsonRpcResponse response = new JsonRpcResponse(jsonNode.get("id")
.asText());
try {
str = objectMapper.writeValueAsString(response);
} catch (JsonProcessingException e) {
log.error("JsonProcessingException while converting JsonNode into string ", e);
}
}
return str;
}
/**
* Convert the List of Operation result into List of OperationResult .
* @param input the List of JsonNode
* @param operations the List of Operation
* @return the List of OperationResult
*/
public static List<OperationResult> jsonNodeToOperationResult(List<JsonNode> input,
List<Operation> operations) {
ObjectMapper objectMapper = ObjectMapperUtil.getObjectMapper(false);
List<OperationResult> operationResults = new ArrayList<OperationResult>();
for (int i = 0; i < input.size(); i++) {
JsonNode jsonNode = input.get(i);
Operation operation = operations.get(i);
if (jsonNode != null && jsonNode.size() > 0) {
if (i >= operations.size() || operation.getOp() != "select") {
OperationResult or = objectMapper.convertValue(jsonNode,
OperationResult.class);
operationResults.add(or);
} else {
List<Row> rows = createRows(operation.getTableSchema(), jsonNode);
OperationResult or = new OperationResult(rows);
operationResults.add(or);
}
}
}
return operationResults;
}
/**
* Convert Operation JsonNode into Rows.
* @param tableSchema TableSchema entity
* @param rowsNode JsonNode
* @return ArrayList<Row> the List of Row
*/
private static ArrayList<Row> createRows(TableSchema tableSchema,
JsonNode rowsNode) {
ArrayList<Row> rows = Lists.newArrayList();
for (JsonNode rowNode : rowsNode.get("rows")) {
rows.add(createRow(tableSchema, rowNode));
}
return rows;
}
/**
* convert the params of Update Notification into TableUpdates.
* @param updatesJson the params of Update Notification
* @param dbSchema DatabaseSchema entity
* @return TableUpdates
*/
public static TableUpdates jsonNodeToTableUpdates(JsonNode updatesJson,
DatabaseSchema dbSchema) {
Map<String, TableUpdate> tableUpdateMap = Maps.newHashMap();
for (Iterator<Map.Entry<String, JsonNode>> itr = updatesJson.fields(); itr
.hasNext();) {
Map.Entry<String, JsonNode> entry = itr.next();
TableSchema tableSchema = dbSchema.getTableSchema(entry.getKey());
TableUpdate tableUpdate = jsonNodeToTableUpdate(tableSchema,
entry.getValue());
tableUpdateMap.put(entry.getKey(), tableUpdate);
}
return TableUpdates.tableUpdates(tableUpdateMap);
}
/**
* convert the params of Update Notification into TableUpdate.
* @param tableSchema TableSchema entity
* @param value the table-update in params of Update Notification
* @return TableUpdate
*/
public static TableUpdate jsonNodeToTableUpdate(TableSchema tableSchema,
JsonNode value) {
Map<UUID, RowUpdate> rows = Maps.newHashMap();
Iterator<Entry<String, JsonNode>> fields = value.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> idOldNew = fields.next();
String uuidStr = idOldNew.getKey();
UUID uuid = UUID.uuid(uuidStr);
JsonNode newR = idOldNew.getValue().get("new");
JsonNode oldR = idOldNew.getValue().get("old");
Row newRow = newR != null ? createRow(tableSchema, newR) : null;
Row oldRow = oldR != null ? createRow(tableSchema, oldR) : null;
RowUpdate rowUpdate = new RowUpdate(uuid, oldRow, newRow);
rows.put(uuid, rowUpdate);
}
return TableUpdate.tableUpdate(rows);
}
/**
* Convert Operation JsonNode into Row.
* @param tableSchema TableSchema entity
* @param rowNode JsonNode
* @return Row
*/
private static Row createRow(TableSchema tableSchema, JsonNode rowNode) {
List<Column> columns = Lists.newArrayList();
for (Iterator<Map.Entry<String, JsonNode>> iter = rowNode.fields(); iter
.hasNext();) {
Map.Entry<String, JsonNode> next = iter.next();
ColumnSchema schema = tableSchema.getColumnSchema(next.getKey());
if (schema != null) {
Object o = TransValueUtil.getValueFromJson(next.getValue(), schema.type());
columns.add(new Column(schema, o));
}
}
return new Row(tableSchema, columns);
}
}