/* | |
* 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 org.onosproject.ovsdb.rfc.error.AbnormalJsonNodeException; | |
import org.onosproject.ovsdb.rfc.error.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 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() { | |
} | |
/** | |
* 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); | |
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) { | |
validateJsonNode(rowsNode, "rows"); | |
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(); | |
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, 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) { | |
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(), columns); | |
} | |
} |