aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/ovsdb/rfc/src/main/java/org/onosproject/ovsdb/rfc/utils/FromJsonUtil.java
blob: 1dcf48f3b42145ef3fb7d301ae9a1b02d2a39605 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
/*
 * 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 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);
            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, 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);
    }

}