Resolved the Serialization and Deserialization issues for MultiValued Columns with...
[ovsdb.git] / library / src / main / java / org / opendaylight / ovsdb / lib / schema / ColumnType.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.util.Set;
13
14 import org.opendaylight.ovsdb.lib.jsonrpc.JsonUtils;
15 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
16
17 import com.fasterxml.jackson.databind.JsonNode;
18 import com.google.common.collect.Sets;
19
20
21 public abstract class ColumnType {
22     BaseType baseType;
23     long min = 1;
24     long max = 1;
25
26     public long getMin() {
27         return min;
28     }
29
30     void setMin(long min) {
31         this.min = min;
32     }
33
34     public long getMax() {
35         return max;
36     }
37
38     void setMax(long max) {
39         this.max = max;
40     }
41
42     private static ColumnType columns[] = new ColumnType[]{
43             new AtomicColumnType(),
44             new KeyValuedColumnType()
45     };
46
47
48     public ColumnType() {
49
50     }
51
52     public ColumnType(BaseType baseType) {
53         this.baseType = baseType;
54     }
55
56     public BaseType getBaseType() {
57         return baseType;
58     }
59
60     /**
61             "type": {
62                 "key": {
63                      "maxInteger": 4294967295,
64                      "minInteger": 0,
65                      "type": "integer"
66                 },
67                 "min": 0,
68                 "value": {
69                     "type": "uuid",
70                     "refTable": "Queue"
71                  },
72                  "max": "unlimited"
73             }
74      * @param json
75      * @return
76      */
77     public static ColumnType fromJson(JsonNode json) {
78         for (ColumnType colType : columns) {
79             ColumnType columnType = colType.fromJsonNode(json);
80             if (null != columnType) {
81                 return columnType;
82             }
83         }
84         //todo move to speicfic typed exception
85         throw new RuntimeException(String.format("could not find the right column type %s",
86                 JsonUtils.prettyString(json)));
87     }
88
89
90     /**
91      * Creates a ColumnType from the JsonNode if the implementation  knows how to, returns null otherwise
92      *
93      * @param json the JSONNode object that needs to converted
94      * @return a valid SubType or Null (if the JsonNode does not represent
95      * the subtype)
96      */
97     protected abstract ColumnType fromJsonNode(JsonNode json);
98
99     public boolean isMultiValued() {
100         //todo check if this is the right logic
101         return this.min != this.max && this.min != 1;
102     }
103
104     public abstract Object valueFromJson(JsonNode value);
105
106     public abstract void validate(Object value);
107
108     @Override
109     public String toString() {
110         return "ColumnType{" +
111                 "baseType=" + baseType +
112                 ", min=" + min +
113                 ", max=" + max +
114                 '}';
115     }
116
117     public static class AtomicColumnType extends ColumnType {
118
119         public AtomicColumnType() {
120         }
121
122         public AtomicColumnType(BaseType baseType1) {
123             super(baseType1);
124         }
125
126         @Override
127         public AtomicColumnType fromJsonNode(JsonNode json) {
128             if (json.isObject() && json.has("value")) {
129                 return null;
130             }
131             BaseType baseType = BaseType.fromJson(json, "key");
132
133             if (baseType != null) {
134
135                 AtomicColumnType atomicColumnType = new AtomicColumnType(baseType);
136
137                 JsonNode node = null;
138                 if ((node = json.get("min")) != null) {
139                     atomicColumnType.setMin(node.asLong());
140                 }
141
142                 if ((node = json.get("max")) != null) {
143                     if (node.isLong()){
144                         atomicColumnType.setMax(node.asLong());
145                     } else if (node.isTextual() && "unlimited".equals(node.asText())) {
146                         max = Long.MAX_VALUE;
147                     }
148                 }
149                 return atomicColumnType;
150             }
151
152             return null;
153         }
154
155         @Override
156         public Object valueFromJson(JsonNode value) {
157             if (isMultiValued()) {
158                 Set<Object> result = Sets.newHashSet();
159                if(value.isArray()) {
160                      if (value.size() == 2) {
161                          if (value.get(0).isTextual() && "set".equals(value.get(0).asText())) {
162                               for(JsonNode node: value.get(1)) {
163                                  result.add(getBaseType().toValue(node));
164                               }
165                          }
166                      }
167                } else {
168                    result.add(getBaseType().toValue(value));
169                }
170                 return result;
171             } else {
172                 return getBaseType().toValue(value);
173             }
174         }
175
176         @Override
177         public void validate(Object value) {
178             this.baseType.validate(value);
179         }
180
181     }
182
183     public static class KeyValuedColumnType extends ColumnType {
184         BaseType keyType;
185
186         public BaseType getKeyType() {
187             return keyType;
188         }
189
190         public KeyValuedColumnType() {
191         }
192
193         public KeyValuedColumnType(BaseType keyType, BaseType valueType) {
194             super(valueType);
195             this.keyType = keyType;
196         }
197
198         @Override
199         public KeyValuedColumnType fromJsonNode(JsonNode json) {
200             if (json.isValueNode() || !json.has("value")) {
201                 return null;
202             }
203             BaseType keyType = BaseType.fromJson(json, "key");
204             BaseType valueType = BaseType.fromJson(json, "value");
205
206             KeyValuedColumnType keyValueColumnType = new KeyValuedColumnType(keyType, valueType);
207             JsonNode node = null;
208             if ((node = json.get("min")) != null) {
209                 keyValueColumnType.setMin(node.asLong());
210             }
211
212             if ((node = json.get("max")) != null) {
213                 if (node.isLong()){
214                     keyValueColumnType.setMax(node.asLong());
215                 } else if (node.isTextual() && "unlimited".equals(node.asText())) {
216                     max = Long.MAX_VALUE;
217                 }
218             }
219
220             return keyValueColumnType;
221         }
222
223         @Override
224         public Object valueFromJson(JsonNode node) {
225             if (node.isArray()) {
226                 if (node.size() == 2) {
227                     if (node.get(0).isTextual() && "map".equals(node.get(0).asText())) {
228                         OvsDBMap<Object, Object> map = new OvsDBMap<Object, Object>();
229                         for (JsonNode pairNode : node.get(1)) {
230                             if (pairNode.isArray() && node.size() == 2) {
231                                 Object key = getKeyType().toValue(pairNode.get(0));
232                                 Object value = getBaseType().toValue(pairNode.get(1));
233                                 map.put(key, value);
234                             }
235                         }
236                         return map;
237                     } else if (node.size() == 0) {
238                         return null;
239                     }
240                 }
241             }
242             return null;
243         }
244
245         @Override
246         public void validate(Object value) {
247             this.baseType.validate(value);
248         }
249     }
250 }