55a2e70ca626cb39e3d95ec74febe93e6f6fd819
[ovsdb.git] / library / impl / src / main / java / org / opendaylight / ovsdb / lib / schema / TableSchema.java
1 /*
2  * Copyright (c) 2014, 2015 EBay Software Foundation and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.ovsdb.lib.schema;
10
11 import com.fasterxml.jackson.databind.JsonNode;
12 import com.fasterxml.jackson.databind.node.ObjectNode;
13 import java.lang.reflect.Constructor;
14 import java.lang.reflect.InvocationTargetException;
15 import java.util.ArrayList;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.Set;
21 import org.opendaylight.ovsdb.lib.message.TableUpdate;
22 import org.opendaylight.ovsdb.lib.notation.Column;
23 import org.opendaylight.ovsdb.lib.notation.Row;
24 import org.opendaylight.ovsdb.lib.notation.UUID;
25 import org.opendaylight.ovsdb.lib.operations.Insert;
26 import org.opendaylight.ovsdb.lib.schema.BaseType.UuidBaseType;
27 import org.opendaylight.ovsdb.lib.schema.ColumnType.AtomicColumnType;
28
29
30 public abstract class TableSchema<E extends TableSchema<E>> {
31
32     private String name;
33     private Map<String, ColumnSchema> columns;
34
35     public TableSchema() {
36     }
37
38     protected TableSchema(String name) {
39         this.name = name;
40     }
41
42     public TableSchema(String name, Map<String, ColumnSchema> columns) {
43         this.name = name;
44         this.columns = columns;
45     }
46
47     public Set<String> getColumns() {
48         return this.columns.keySet();
49     }
50
51     public Map<String, ColumnSchema> getColumnSchemas() {
52         return columns;
53     }
54
55     public boolean hasColumn(String column) {
56         return this.getColumns().contains(column);
57     }
58
59
60     public ColumnType getColumnType(String column) {
61         return this.columns.get(column).getType();
62     }
63
64     public <E extends TableSchema<E>> E as(Class<E> clazz) {
65         try {
66             Constructor<E> instance = clazz.getConstructor(TableSchema.class);
67             return instance.newInstance(this);
68         } catch (InstantiationException | IllegalAccessException
69                 | InvocationTargetException | NoSuchMethodException e) {
70             throw new RuntimeException("exception constructing instance of clazz " + clazz, e);
71         }
72     }
73
74     public Insert<E> insert() {
75         return new Insert<>(this);
76     }
77
78     public <D> ColumnSchema<E, Set<D>> multiValuedColumn(String column, Class<D> type) {
79         //todo exception handling
80
81         ColumnSchema<E, Set<D>> columnSchema = columns.get(column);
82         columnSchema.validateType(type);
83         return columnSchema;
84     }
85
86     public <K,V> ColumnSchema<E, Map<K,V>> multiValuedColumn(String column, Class<K> keyType, Class<V> valueType) {
87         //todo exception handling
88
89         ColumnSchema<E, Map<K, V>> columnSchema = columns.get(column);
90         columnSchema.validateType(valueType);
91         return columnSchema;
92     }
93
94     public <D> ColumnSchema<E, D> column(String column, Class<D> type) {
95         //todo exception handling
96
97         ColumnSchema<E, D> columnSchema = columns.get(column);
98         if (columnSchema != null) {
99             columnSchema.validateType(type);
100         }
101         return columnSchema;
102     }
103
104     public ColumnSchema column(String column) {
105         return this.columns.get(column);
106     }
107
108
109     public String getName() {
110         return name;
111     }
112
113     protected void setName(String name) {
114         this.name = name;
115     }
116
117     protected void setColumns(Map<String, ColumnSchema> columns) {
118         this.columns = columns;
119     }
120
121     public TableUpdate<E> updatesFromJson(JsonNode value) {
122         TableUpdate<E> tableUpdate = new TableUpdate<>();
123         Iterator<Entry<String, JsonNode>> fields = value.fields();
124         while (fields.hasNext()) {
125             Map.Entry<String, JsonNode> idOldNew = fields.next();
126             String uuid = idOldNew.getKey();
127
128             ObjectNode newObjectNode = (ObjectNode) idOldNew.getValue().get("new");
129             ObjectNode oldObjectNode = (ObjectNode) idOldNew.getValue().get("old");
130
131             Row<E> newRow = newObjectNode != null ? createRow(newObjectNode) : null;
132             Row<E> oldRow = oldObjectNode != null ? createRow(oldObjectNode) : null;
133
134             tableUpdate.addRow(new UUID(uuid), oldRow, newRow);
135         }
136         return tableUpdate;
137     }
138
139     public Row<E> createRow(ObjectNode rowNode) {
140         List<Column<E, ?>> newColumns = new ArrayList<>();
141         for (Iterator<Map.Entry<String, JsonNode>> iter = rowNode.fields(); iter.hasNext();) {
142             Map.Entry<String, JsonNode> next = iter.next();
143             ColumnSchema<E, Object> schema = column(next.getKey(), Object.class);
144             /*
145              * Ideally the ColumnSchema shouldn't be null at this stage. But there can be cases in which
146              * the OVSDB manager Schema implementation might decide to include some "hidden" columns that
147              * are NOT reported in getSchema, but decide to report it in unfiltered monitor.
148              * Hence adding some safety checks around that.
149              */
150             if (schema != null) {
151                 Object value = schema.valueFromJson(next.getValue());
152                 newColumns.add(new Column<>(schema, value));
153             }
154         }
155         return new Row<>(this, newColumns);
156     }
157
158     public List<Row<E>> createRows(JsonNode rowsNode) {
159         List<Row<E>> rows = new ArrayList<>();
160         for (JsonNode rowNode : rowsNode.get("rows")) {
161             rows.add(createRow((ObjectNode)rowNode));
162         }
163
164         return rows;
165     }
166
167     /*
168      * RFC 7047 Section 3.2 specifies 2 internally generated columns in each table
169      * namely _uuid and _version which are not exposed in get_schema call.
170      * Since these 2 columns are extremely useful for Mutate, update and select operations,
171      * the ColumnSchema for these 2 columns are manually populated.
172      *
173      * It is to be noted that these 2 columns are specified as part of the RFC7047 and not
174      * a specific Schema implementation detail & hence adding it by default in the Library
175      * for better application experience using the library.
176      */
177     public void populateInternallyGeneratedColumns() {
178         columns.put("_uuid", new ColumnSchema("_uuid", new AtomicColumnType(new UuidBaseType())));
179         columns.put("_version", new ColumnSchema("_version", new AtomicColumnType(new UuidBaseType())));
180     }
181 }