Do not allow DatabaseSchema name/version to be mutated
[ovsdb.git] / library / impl / src / main / java / org / opendaylight / ovsdb / lib / schema / DatabaseSchema.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.google.common.reflect.Invokable;
13 import java.lang.reflect.Constructor;
14 import java.lang.reflect.InvocationTargetException;
15 import java.util.HashMap;
16 import java.util.Iterator;
17 import java.util.Map;
18 import java.util.Set;
19 import org.opendaylight.ovsdb.lib.error.ParsingException;
20 import org.opendaylight.ovsdb.lib.notation.Version;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 /**
25  * Represents an ovsdb database schema, which is comprised of a set of tables.
26  */
27 public class DatabaseSchema {
28     private static final Logger LOG = LoggerFactory.getLogger(DatabaseSchema.class);
29
30     private final String name;
31     private final Version version;
32     private final Map<String, TableSchema> tables;
33
34     public DatabaseSchema(final String name, final Version version, final Map<String, TableSchema> tables) {
35         this.name = name;
36         this.version = version;
37         this.tables = tables;
38     }
39
40     public Set<String> getTables() {
41         return this.tables.keySet();
42     }
43
44     public boolean hasTable(final String table) {
45         return this.getTables().contains(table);
46     }
47
48     public <E extends TableSchema<E>> E table(final String tableName, final Class<E> clazz) {
49         TableSchema<E> table = tables.get(tableName);
50
51         if (clazz.isInstance(table)) {
52             return clazz.cast(table);
53         }
54
55         return createTableSchema(clazz, table);
56     }
57
58     protected <E extends TableSchema<E>> E createTableSchema(final Class<E> clazz, final TableSchema<E> table) {
59         Constructor<E> declaredConstructor;
60         try {
61             declaredConstructor = clazz.getDeclaredConstructor(TableSchema.class);
62         } catch (NoSuchMethodException e) {
63             String message = String.format("Class %s does not have public constructor that accepts TableSchema object",
64                     clazz);
65             throw new IllegalArgumentException(message, e);
66         }
67         Invokable<E, E> invokable = Invokable.from(declaredConstructor);
68         try {
69             return invokable.invoke(null, table);
70         } catch (InvocationTargetException | IllegalAccessException e) {
71             String message = String.format("Not able to create instance of class %s using public constructor "
72                     + "that accepts TableSchema object", clazz);
73             throw new IllegalArgumentException(message, e);
74         }
75     }
76
77     //todo : this needs to move to a custom factory
78     public static DatabaseSchema fromJson(final String dbName, final JsonNode json) {
79         if (!json.isObject() || !json.has("tables")) {
80             throw new ParsingException("bad DatabaseSchema root, expected \"tables\" as child but was not found");
81         }
82         if (!json.isObject() || !json.has("version")) {
83             throw new ParsingException("bad DatabaseSchema root, expected \"version\" as child but was not found");
84         }
85
86         Version dbVersion = Version.fromString(json.get("version").asText());
87
88         Map<String, TableSchema> tables = new HashMap<>();
89         for (Iterator<Map.Entry<String, JsonNode>> iter = json.get("tables").fields(); iter.hasNext(); ) {
90             Map.Entry<String, JsonNode> table = iter.next();
91             LOG.trace("Read schema for table[{}]:{}", table.getKey(), table.getValue());
92
93             //todo : this needs to done by a factory
94             tables.put(table.getKey(), GenericTableSchema.fromJson(table.getKey(), table.getValue()));
95         }
96
97         return new DatabaseSchema(dbName, dbVersion, tables);
98     }
99
100     public String getName() {
101         return name;
102     }
103
104     public Version getVersion() {
105         return version;
106     }
107
108     public void populateInternallyGeneratedColumns() {
109         for (TableSchema tableSchema : tables.values()) {
110             tableSchema.populateInternallyGeneratedColumns();
111         }
112     }
113 }