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