blob: 858a1fc337a2bdbe33cfe46f518a0c750957354a [file] [log] [blame]
Sho SHIMIZUe4efe452015-08-26 15:06:55 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Sho SHIMIZUe4efe452015-08-26 15:06:55 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.ovsdb.rfc.utils;
17
andreaed976a42015-10-05 14:38:25 -070018import com.fasterxml.jackson.core.JsonProcessingException;
19import com.fasterxml.jackson.databind.JsonNode;
20import com.fasterxml.jackson.databind.ObjectMapper;
21import com.google.common.collect.Lists;
22import com.google.common.collect.Maps;
Sho SHIMIZU8700d422015-08-26 18:13:44 -070023import org.onosproject.ovsdb.rfc.exception.AbnormalJsonNodeException;
24import org.onosproject.ovsdb.rfc.exception.UnsupportedException;
Sho SHIMIZUe4efe452015-08-26 15:06:55 -070025import org.onosproject.ovsdb.rfc.jsonrpc.Callback;
26import org.onosproject.ovsdb.rfc.jsonrpc.JsonRpcResponse;
27import org.onosproject.ovsdb.rfc.message.OperationResult;
28import org.onosproject.ovsdb.rfc.message.RowUpdate;
29import org.onosproject.ovsdb.rfc.message.TableUpdate;
30import org.onosproject.ovsdb.rfc.message.TableUpdates;
31import org.onosproject.ovsdb.rfc.message.UpdateNotification;
32import org.onosproject.ovsdb.rfc.notation.Column;
33import org.onosproject.ovsdb.rfc.notation.Row;
Jonathan Hart51539b82015-10-29 09:53:04 -070034import org.onosproject.ovsdb.rfc.notation.Uuid;
Sho SHIMIZUe4efe452015-08-26 15:06:55 -070035import org.onosproject.ovsdb.rfc.operations.Operation;
36import org.onosproject.ovsdb.rfc.schema.ColumnSchema;
37import org.onosproject.ovsdb.rfc.schema.DatabaseSchema;
38import org.onosproject.ovsdb.rfc.schema.TableSchema;
39import org.onosproject.ovsdb.rfc.schema.type.ColumnTypeFactory;
40import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42
andreaed976a42015-10-05 14:38:25 -070043import java.util.ArrayList;
44import java.util.HashMap;
45import java.util.Iterator;
46import java.util.List;
47import java.util.Map;
Sho SHIMIZUe4efe452015-08-26 15:06:55 -070048
49/**
50 * JsonNode utility class. convert JsonNode into Object.
51 */
52public final class FromJsonUtil {
53
54 private static final Logger log = LoggerFactory.getLogger(FromJsonUtil.class);
55
56 /**
57 * Constructs a FromJsonUtil object. Utility classes should not have a
58 * public or default constructor, otherwise IDE will compile unsuccessfully.
59 * This class should not be instantiated.
60 */
61 private FromJsonUtil() {
62 }
63
64 /**
65 * Verify whether the jsonNode is normal.
66 * @param jsonNode JsonNode
67 * @param nodeStr the node name of JsonNode
68 */
69 private static void validateJsonNode(JsonNode jsonNode, String nodeStr) {
70 if (!jsonNode.isObject() || !jsonNode.has(nodeStr)) {
71 String message = "Abnormal DatabaseSchema JsonNode, it should contain " + nodeStr
72 + " node but was not found";
73 throw new AbnormalJsonNodeException(message);
74 }
75 }
76
77 /**
78 * convert JsonNode into DatabaseSchema.
79 * @param dbName database name
80 * @param dbJson the JsonNode of get_schema result
81 * @return DatabaseSchema
82 * @throws AbnormalJsonNodeException this is an abnormal JsonNode exception
83 */
84 public static DatabaseSchema jsonNodeToDbSchema(String dbName, JsonNode dbJson) {
85 validateJsonNode(dbJson, "tables");
86 validateJsonNode(dbJson, "version");
87 String dbVersion = dbJson.get("version").asText();
88 Map<String, TableSchema> tables = new HashMap<>();
89 Iterator<Map.Entry<String, JsonNode>> tablesIter = dbJson.get("tables").fields();
90 while (tablesIter.hasNext()) {
91 Map.Entry<String, JsonNode> table = tablesIter.next();
92 tables.put(table.getKey(), jsonNodeToTableSchema(table.getKey(), table.getValue()));
93 }
94 return new DatabaseSchema(dbName, dbVersion, tables);
95 }
96
97 /**
98 * convert JsonNode into TableSchema.
99 * @param tableName table name
100 * @param tableJson table JsonNode
101 * @return TableSchema
102 * @throws AbnormalJsonNodeException this is an abnormal JsonNode exception
103 */
104 private static TableSchema jsonNodeToTableSchema(String tableName, JsonNode tableJson) {
105 validateJsonNode(tableJson, "columns");
106 Map<String, ColumnSchema> columns = new HashMap<>();
107 Iterator<Map.Entry<String, JsonNode>> columnsIter = tableJson.get("columns").fields();
108 while (columnsIter.hasNext()) {
109 Map.Entry<String, JsonNode> column = columnsIter.next();
110 columns.put(column.getKey(), jsonNodeToColumnSchema(column.getKey(), column.getValue()));
111 }
112 return new TableSchema(tableName, columns);
113 }
114
115 /**
116 * convert JsonNode into ColumnSchema.
117 * @param name column name
118 * @param columnJson column JsonNode
119 * @return ColumnSchema
120 * @throws AbnormalJsonNodeException this is an abnormal JsonNode exception
121 */
122 private static ColumnSchema jsonNodeToColumnSchema(String name, JsonNode columnJson) {
123 validateJsonNode(columnJson, "type");
124 return new ColumnSchema(name, ColumnTypeFactory.getColumnTypeFromJson(columnJson
125 .get("type")));
126 }
127
128 /**
129 * convert JsonNode into the returnType of methods in OvsdbRPC class.
130 * @param resultJsonNode the result JsonNode
131 * @param methodName the method name of methods in OvsdbRPC class
132 * @param objectMapper ObjectMapper entity
133 * @return Object
134 * @throws UnsupportedException this is an unsupported exception
135 */
136 private static Object convertResultType(JsonNode resultJsonNode, String methodName,
137 ObjectMapper objectMapper) {
138 switch (methodName) {
139 case "getSchema":
140 case "monitor":
141 return resultJsonNode;
142 case "echo":
143 case "listDbs":
144 return objectMapper.convertValue(resultJsonNode, objectMapper.getTypeFactory()
145 .constructParametricType(List.class, String.class));
146 case "transact":
147 return objectMapper.convertValue(resultJsonNode, objectMapper.getTypeFactory()
148 .constructParametricType(List.class, JsonNode.class));
149 default:
150 throw new UnsupportedException("does not support this rpc method" + methodName);
151 }
152 }
153
154 /**
155 * convert JsonNode into the returnType of methods in OvsdbRPC class.
156 * @param jsonNode the result JsonNode
157 * @param methodName the method name of methods in OvsdbRPC class
158 * @return Object
159 */
160 public static Object jsonResultParser(JsonNode jsonNode, String methodName) {
161 ObjectMapper objectMapper = ObjectMapperUtil.getObjectMapper();
162 JsonNode error = jsonNode.get("error");
163 if (error != null && !error.isNull()) {
164 log.error("jsonRpcResponse error : {}", error.toString());
165 }
166 JsonNode resultJsonNode = jsonNode.get("result");
167 Object result = convertResultType(resultJsonNode, methodName, objectMapper);
168 return result;
169 }
170
171 /**
172 * When monitor the ovsdb tables, if a table update, ovs send update
173 * notification, then call callback function.
174 * @param jsonNode the result JsonNode
175 * @param callback the callback function
176 * @throws UnsupportedException this is an unsupported exception
177 */
178 public static void jsonCallbackRequestParser(JsonNode jsonNode, Callback callback) {
179 ObjectMapper objectMapper = ObjectMapperUtil.getObjectMapper();
180 JsonNode params = jsonNode.get("params");
181 Object param = null;
182 String methodName = jsonNode.get("method").asText();
183 switch (methodName) {
184 case "update":
185 param = objectMapper.convertValue(params, UpdateNotification.class);
186 callback.update((UpdateNotification) param);
187 break;
188 default:
189 throw new UnsupportedException("does not support this callback method: " + methodName);
190 }
191 }
192
193 /**
194 * Ovs send echo request to keep the heart, need we return echo result.
195 * @param jsonNode the result JsonNode
196 * @return JsonRpcResponse String
197 */
198 public static String getEchoRequestStr(JsonNode jsonNode) {
199 ObjectMapper objectMapper = ObjectMapperUtil.getObjectMapper();
200 String str = null;
201 if (jsonNode.get("method").asText().equals("echo")) {
202 JsonRpcResponse response = new JsonRpcResponse(jsonNode.get("id").asText());
203 try {
204 str = objectMapper.writeValueAsString(response);
205 } catch (JsonProcessingException e) {
206 log.error("JsonProcessingException while converting JsonNode into string: ", e);
207 }
208 }
209 return str;
210 }
211
212 /**
213 * Convert the List of Operation result into List of OperationResult .
214 * @param input the List of JsonNode
215 * @param operations the List of Operation
216 * @return the List of OperationResult
217 */
218 public static List<OperationResult> jsonNodeToOperationResult(List<JsonNode> input,
219 List<Operation> operations) {
220 ObjectMapper objectMapper = ObjectMapperUtil.getObjectMapper(false);
kdarapufce5abb2018-05-10 19:37:53 +0530221 List<OperationResult> operationResults = new ArrayList<>();
Sho SHIMIZUe4efe452015-08-26 15:06:55 -0700222 for (int i = 0; i < input.size(); i++) {
223 JsonNode jsonNode = input.get(i);
debanshurb5cf6d22018-03-21 19:09:48 +0530224
Sho SHIMIZUe4efe452015-08-26 15:06:55 -0700225 if (jsonNode != null && jsonNode.size() > 0) {
debanshurb5cf6d22018-03-21 19:09:48 +0530226 if (i >= operations.size()) {
Sho SHIMIZUe4efe452015-08-26 15:06:55 -0700227 OperationResult or = objectMapper.convertValue(jsonNode, OperationResult.class);
228 operationResults.add(or);
229 } else {
debanshurb5cf6d22018-03-21 19:09:48 +0530230 Operation operation = operations.get(i);
231 if (!operation.getOp().equals("select")) {
232 OperationResult or = objectMapper.convertValue(jsonNode, OperationResult.class);
233 operationResults.add(or);
234 } else {
235 List<Row> rows = createRows(operation.getTableSchema(), jsonNode);
236 OperationResult or = new OperationResult(rows);
237 operationResults.add(or);
238 }
Sho SHIMIZUe4efe452015-08-26 15:06:55 -0700239 }
240 }
241 }
242 return operationResults;
243 }
244
245 /**
246 * Convert Operation JsonNode into Rows.
247 * @param tableSchema TableSchema entity
248 * @param rowsNode JsonNode
249 * @return ArrayList<Row> the List of Row
250 */
251 private static ArrayList<Row> createRows(TableSchema tableSchema, JsonNode rowsNode) {
252 validateJsonNode(rowsNode, "rows");
253 ArrayList<Row> rows = Lists.newArrayList();
254 for (JsonNode rowNode : rowsNode.get("rows")) {
andreaed976a42015-10-05 14:38:25 -0700255 rows.add(createRow(tableSchema, null, rowNode)); //FIXME null will throw exception
Sho SHIMIZUe4efe452015-08-26 15:06:55 -0700256 }
257 return rows;
258 }
259
260 /**
261 * convert the params of Update Notification into TableUpdates.
262 * @param updatesJson the params of Update Notification
263 * @param dbSchema DatabaseSchema entity
264 * @return TableUpdates
265 */
266 public static TableUpdates jsonNodeToTableUpdates(JsonNode updatesJson, DatabaseSchema dbSchema) {
267 Map<String, TableUpdate> tableUpdateMap = Maps.newHashMap();
268 Iterator<Map.Entry<String, JsonNode>> tableUpdatesItr = updatesJson.fields();
269 while (tableUpdatesItr.hasNext()) {
270 Map.Entry<String, JsonNode> entry = tableUpdatesItr.next();
271 TableSchema tableSchema = dbSchema.getTableSchema(entry.getKey());
272 TableUpdate tableUpdate = jsonNodeToTableUpdate(tableSchema, entry.getValue());
273 tableUpdateMap.put(entry.getKey(), tableUpdate);
274 }
275 return TableUpdates.tableUpdates(tableUpdateMap);
276 }
277
278 /**
279 * convert the params of Update Notification into TableUpdate.
280 * @param tableSchema TableSchema entity
281 * @param updateJson the table-update in params of Update Notification
282 * @return TableUpdate
283 */
284 public static TableUpdate jsonNodeToTableUpdate(TableSchema tableSchema, JsonNode updateJson) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700285 Map<Uuid, RowUpdate> rows = Maps.newHashMap();
Sho SHIMIZUe4efe452015-08-26 15:06:55 -0700286 Iterator<Map.Entry<String, JsonNode>> tableUpdateItr = updateJson.fields();
287 while (tableUpdateItr.hasNext()) {
288 Map.Entry<String, JsonNode> oldNewRow = tableUpdateItr.next();
289 String uuidStr = oldNewRow.getKey();
Jonathan Hart51539b82015-10-29 09:53:04 -0700290 Uuid uuid = Uuid.uuid(uuidStr);
Sho SHIMIZUe4efe452015-08-26 15:06:55 -0700291 JsonNode newR = oldNewRow.getValue().get("new");
292 JsonNode oldR = oldNewRow.getValue().get("old");
andreaed976a42015-10-05 14:38:25 -0700293 Row newRow = newR != null ? createRow(tableSchema, uuid, newR) : null;
294 Row oldRow = oldR != null ? createRow(tableSchema, uuid, oldR) : null;
Sho SHIMIZUe4efe452015-08-26 15:06:55 -0700295 RowUpdate rowUpdate = new RowUpdate(uuid, oldRow, newRow);
296 rows.put(uuid, rowUpdate);
297 }
298 return TableUpdate.tableUpdate(rows);
299 }
300
301 /**
302 * Convert Operation JsonNode into Row.
303 * @param tableSchema TableSchema entity
304 * @param rowNode JsonNode
305 * @return Row
306 */
Jonathan Hart51539b82015-10-29 09:53:04 -0700307 private static Row createRow(TableSchema tableSchema, Uuid uuid, JsonNode rowNode) {
Sho SHIMIZUe4efe452015-08-26 15:06:55 -0700308 if (tableSchema == null) {
309 return null;
310 }
311 Map<String, Column> columns = Maps.newHashMap();
312 Iterator<Map.Entry<String, JsonNode>> rowIter = rowNode.fields();
313 while (rowIter.hasNext()) {
314 Map.Entry<String, JsonNode> next = rowIter.next();
315 ColumnSchema columnSchema = tableSchema.getColumnSchema(next.getKey());
316 if (columnSchema != null) {
317 String columnName = columnSchema.name();
318 Object obj = TransValueUtil.getValueFromJson(next.getValue(), columnSchema.type());
319 columns.put(columnName, new Column(columnName, obj));
320 }
321 }
andreaed976a42015-10-05 14:38:25 -0700322 return new Row(tableSchema.name(), uuid, columns);
Sho SHIMIZUe4efe452015-08-26 15:06:55 -0700323 }
324
325}