blob: 3383ba9689a7d2073b6d535c41867424bffe5289 [file] [log] [blame]
/*
* Copyright 2015-present Open Networking Foundation
*
* 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 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;
import org.onosproject.ovsdb.rfc.exception.AbnormalJsonNodeException;
import org.onosproject.ovsdb.rfc.exception.UnsupportedException;
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 java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* 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() {
}
/**
* Verify whether the jsonNode is normal.
* @param jsonNode JsonNode
* @param nodeStr the node name of JsonNode
*/
private static void validateJsonNode(JsonNode jsonNode, String nodeStr) {
if (!jsonNode.isObject() || !jsonNode.has(nodeStr)) {
String message = "Abnormal DatabaseSchema JsonNode, it should contain " + nodeStr
+ " node but was not found";
throw new AbnormalJsonNodeException(message);
}
}
/**
* convert JsonNode into DatabaseSchema.
* @param dbName database name
* @param dbJson the JsonNode of get_schema result
* @return DatabaseSchema
* @throws AbnormalJsonNodeException this is an abnormal JsonNode exception
*/
public static DatabaseSchema jsonNodeToDbSchema(String dbName, JsonNode dbJson) {
validateJsonNode(dbJson, "tables");
validateJsonNode(dbJson, "version");
String dbVersion = dbJson.get("version").asText();
Map<String, TableSchema> tables = new HashMap<>();
Iterator<Map.Entry<String, JsonNode>> tablesIter = dbJson.get("tables").fields();
while (tablesIter.hasNext()) {
Map.Entry<String, JsonNode> table = tablesIter.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 tableJson table JsonNode
* @return TableSchema
* @throws AbnormalJsonNodeException this is an abnormal JsonNode exception
*/
private static TableSchema jsonNodeToTableSchema(String tableName, JsonNode tableJson) {
validateJsonNode(tableJson, "columns");
Map<String, ColumnSchema> columns = new HashMap<>();
Iterator<Map.Entry<String, JsonNode>> columnsIter = tableJson.get("columns").fields();
while (columnsIter.hasNext()) {
Map.Entry<String, JsonNode> column = columnsIter.next();
columns.put(column.getKey(), jsonNodeToColumnSchema(column.getKey(), column.getValue()));
}
return new TableSchema(tableName, columns);
}
/**
* convert JsonNode into ColumnSchema.
* @param name column name
* @param columnJson column JsonNode
* @return ColumnSchema
* @throws AbnormalJsonNodeException this is an abnormal JsonNode exception
*/
private static ColumnSchema jsonNodeToColumnSchema(String name, JsonNode columnJson) {
validateJsonNode(columnJson, "type");
return new ColumnSchema(name, ColumnTypeFactory.getColumnTypeFromJson(columnJson
.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 UnsupportedException this is an unsupported 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 UnsupportedException("does not support this rpc method" + methodName);
}
}
/**
* 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("jsonRpcResponse 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 UnsupportedException this is an unsupported 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 UnsupportedException("does not support this callback 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);
if (jsonNode != null && jsonNode.size() > 0) {
if (i >= operations.size()) {
OperationResult or = objectMapper.convertValue(jsonNode, OperationResult.class);
operationResults.add(or);
} else {
Operation operation = operations.get(i);
if (!operation.getOp().equals("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) {
validateJsonNode(rowsNode, "rows");
ArrayList<Row> rows = Lists.newArrayList();
for (JsonNode rowNode : rowsNode.get("rows")) {
rows.add(createRow(tableSchema, null, rowNode)); //FIXME null will throw exception
}
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();
Iterator<Map.Entry<String, JsonNode>> tableUpdatesItr = updatesJson.fields();
while (tableUpdatesItr.hasNext()) {
Map.Entry<String, JsonNode> entry = tableUpdatesItr.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 updateJson the table-update in params of Update Notification
* @return TableUpdate
*/
public static TableUpdate jsonNodeToTableUpdate(TableSchema tableSchema, JsonNode updateJson) {
Map<Uuid, RowUpdate> rows = Maps.newHashMap();
Iterator<Map.Entry<String, JsonNode>> tableUpdateItr = updateJson.fields();
while (tableUpdateItr.hasNext()) {
Map.Entry<String, JsonNode> oldNewRow = tableUpdateItr.next();
String uuidStr = oldNewRow.getKey();
Uuid uuid = Uuid.uuid(uuidStr);
JsonNode newR = oldNewRow.getValue().get("new");
JsonNode oldR = oldNewRow.getValue().get("old");
Row newRow = newR != null ? createRow(tableSchema, uuid, newR) : null;
Row oldRow = oldR != null ? createRow(tableSchema, uuid, 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, Uuid uuid, JsonNode rowNode) {
if (tableSchema == null) {
return null;
}
Map<String, Column> columns = Maps.newHashMap();
Iterator<Map.Entry<String, JsonNode>> rowIter = rowNode.fields();
while (rowIter.hasNext()) {
Map.Entry<String, JsonNode> next = rowIter.next();
ColumnSchema columnSchema = tableSchema.getColumnSchema(next.getKey());
if (columnSchema != null) {
String columnName = columnSchema.name();
Object obj = TransValueUtil.getValueFromJson(next.getValue(), columnSchema.type());
columns.put(columnName, new Column(columnName, obj));
}
}
return new Row(tableSchema.name(), uuid, columns);
}
}