General Sonar clean-up
[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 org.opendaylight.ovsdb.lib.error.TyperException;
13 import org.opendaylight.ovsdb.lib.jsonrpc.JsonUtils;
14 import org.opendaylight.ovsdb.lib.notation.OvsdbMap;
15 import org.opendaylight.ovsdb.lib.notation.OvsdbSet;
16
17 import com.fasterxml.jackson.databind.JsonNode;
18
19
20 public abstract class ColumnType {
21     BaseType baseType;
22     long min = 1;
23     long max = 1;
24
25     public long getMin() {
26         return min;
27     }
28
29     void setMin(long min) {
30         this.min = min;
31     }
32
33     public long getMax() {
34         return max;
35     }
36
37     void setMax(long max) {
38         this.max = max;
39     }
40
41     private static ColumnType[] columns = new ColumnType[] {
42         new AtomicColumnType(),
43         new KeyValuedColumnType()
44     };
45
46
47     public ColumnType() {
48
49     }
50
51     public ColumnType(BaseType baseType) {
52         this.baseType = baseType;
53     }
54
55     public BaseType getBaseType() {
56         return baseType;
57     }
58
59     /**
60             "type": {
61                 "key": {
62                      "maxInteger": 4294967295,
63                      "minInteger": 0,
64                      "type": "integer"
65                 },
66                 "min": 0,
67                 "value": {
68                     "type": "uuid",
69                     "refTable": "Queue"
70                  },
71                  "max": "unlimited"
72             }
73      * @param json
74      * @return
75      */
76     public static ColumnType fromJson(JsonNode json) {
77         for (ColumnType colType : columns) {
78             ColumnType columnType = colType.fromJsonNode(json);
79             if (null != columnType) {
80                 return columnType;
81             }
82         }
83         //todo move to speicfic typed exception
84         throw new TyperException(String.format("could not find the right column type %s",
85                 JsonUtils.prettyString(json)));
86     }
87
88
89     /**
90      * Creates a ColumnType from the JsonNode if the implementation  knows how to, returns null otherwise
91      *
92      * @param json the JSONNode object that needs to converted
93      * @return a valid SubType or Null (if the JsonNode does not represent
94      * the subtype)
95      */
96     protected abstract ColumnType fromJsonNode(JsonNode json);
97
98     /*
99      * Per RFC 7047, Section 3.2 <type> :
100      * If "min" or "max" is not specified, each defaults to 1.  If "max" is specified as "unlimited",
101      * then there is no specified maximum number of elements, although the implementation will
102      * enforce some limit.  After considering defaults, "min" must be exactly 0 or
103      * exactly 1, "max" must be at least 1, and "max" must be greater than or equal to "min".
104      *
105      * If "min" and "max" are both 1 and "value" is not specified, the
106      * type is the scalar type specified by "key".
107      */
108     public boolean isMultiValued() {
109         return this.min != this.max;
110     }
111
112     public abstract Object valueFromJson(JsonNode value);
113
114     public abstract void validate(Object value);
115
116     @Override
117     public String toString() {
118         return "ColumnType{"
119                 + "baseType=" + baseType
120                 + ", min=" + min
121                 + ", max=" + max
122                 + '}';
123     }
124
125     @Override
126     public int hashCode() {
127         final int prime = 31;
128         int result = 1;
129         result = prime * result
130                 + ((baseType == null) ? 0 : baseType.hashCode());
131         result = prime * result + (int) (max ^ (max >>> 32));
132         result = prime * result + (int) (min ^ (min >>> 32));
133         return result;
134     }
135
136     @Override
137     public boolean equals(Object obj) {
138         if (this == obj) {
139             return true;
140         }
141         if (obj == null) {
142             return false;
143         }
144         if (getClass() != obj.getClass()) {
145             return false;
146         }
147         ColumnType other = (ColumnType) obj;
148         if (baseType == null) {
149             if (other.baseType != null) {
150                 return false;
151             }
152         } else if (!baseType.equals(other.baseType)) {
153             return false;
154         }
155         if (max != other.max) {
156             return false;
157         }
158         if (min != other.min) {
159             return false;
160         }
161         return true;
162     }
163
164     public static class AtomicColumnType extends ColumnType {
165         public AtomicColumnType() {
166         }
167
168         public AtomicColumnType(BaseType baseType1) {
169             super(baseType1);
170         }
171
172         @Override
173         public AtomicColumnType fromJsonNode(JsonNode json) {
174             if (json.isObject() && json.has("value")) {
175                 return null;
176             }
177             BaseType baseType = BaseType.fromJson(json, "key");
178
179             if (baseType != null) {
180
181                 AtomicColumnType atomicColumnType = new AtomicColumnType(baseType);
182
183                 JsonNode node;
184                 if ((node = json.get("min")) != null) {
185                     atomicColumnType.setMin(node.asLong());
186                 }
187
188                 if ((node = json.get("max")) != null) {
189                     if (node.isNumber()) {
190                         atomicColumnType.setMax(node.asLong());
191                     } else if ("unlimited".equals(node.asText())) {
192                         atomicColumnType.setMax(Long.MAX_VALUE);
193                     }
194                 }
195                 return atomicColumnType;
196             }
197
198             return null;
199         }
200
201         @Override
202         public Object valueFromJson(JsonNode value) {
203             if (isMultiValued()) {
204                 OvsdbSet<Object> result = new OvsdbSet<>();
205                 if (value.isArray()) {
206                     if (value.size() == 2) {
207                         if (value.get(0).isTextual() && "set".equals(value.get(0).asText())) {
208                             for (JsonNode node: value.get(1)) {
209                                 result.add(getBaseType().toValue(node));
210                             }
211                         } else {
212                             result.add(getBaseType().toValue(value));
213                         }
214                     }
215                 } else {
216                     result.add(getBaseType().toValue(value));
217                 }
218                 return result;
219             } else {
220                 return getBaseType().toValue(value);
221             }
222         }
223
224         @Override
225         public void validate(Object value) {
226             this.baseType.validate(value);
227         }
228
229     }
230
231     public static class KeyValuedColumnType extends ColumnType {
232         BaseType keyType;
233
234         public BaseType getKeyType() {
235             return keyType;
236         }
237
238         public KeyValuedColumnType() {
239         }
240
241         public KeyValuedColumnType(BaseType keyType, BaseType valueType) {
242             super(valueType);
243             this.keyType = keyType;
244         }
245
246         @Override
247         public KeyValuedColumnType fromJsonNode(JsonNode json) {
248             if (json.isValueNode() || !json.has("value")) {
249                 return null;
250             }
251             BaseType keyType = BaseType.fromJson(json, "key");
252             BaseType valueType = BaseType.fromJson(json, "value");
253
254             KeyValuedColumnType keyValueColumnType = new KeyValuedColumnType(keyType, valueType);
255             JsonNode node;
256             if ((node = json.get("min")) != null) {
257                 keyValueColumnType.setMin(node.asLong());
258             }
259
260             if ((node = json.get("max")) != null) {
261                 if (node.isLong()) {
262                     keyValueColumnType.setMax(node.asLong());
263                 } else if (node.isTextual() && "unlimited".equals(node.asText())) {
264                     keyValueColumnType.setMax(Long.MAX_VALUE);
265                 }
266             }
267
268             return keyValueColumnType;
269         }
270
271         @Override
272         public Object valueFromJson(JsonNode node) {
273             if (node.isArray()) {
274                 if (node.size() == 2) {
275                     if (node.get(0).isTextual() && "map".equals(node.get(0).asText())) {
276                         OvsdbMap<Object, Object> map = new OvsdbMap<>();
277                         for (JsonNode pairNode : node.get(1)) {
278                             if (pairNode.isArray() && node.size() == 2) {
279                                 Object key = getKeyType().toValue(pairNode.get(0));
280                                 Object value = getBaseType().toValue(pairNode.get(1));
281                                 map.put(key, value);
282                             }
283                         }
284                         return map;
285                     } else if (node.size() == 0) {
286                         return null;
287                     }
288                 }
289             }
290             return null;
291         }
292
293         @Override
294         public void validate(Object value) {
295             this.baseType.validate(value);
296         }
297
298         @Override
299         public String toString() {
300             return "KeyValuedColumnType [keyType=" + keyType + " " + super.toString() + "]";
301         }
302
303         @Override
304         public int hashCode() {
305             final int prime = 31;
306             int result = super.hashCode();
307             result = prime * result
308                     + ((keyType == null) ? 0 : keyType.hashCode());
309             return result;
310         }
311
312         @Override
313         public boolean equals(Object obj) {
314             if (this == obj) {
315                 return true;
316             }
317             if (!super.equals(obj)) {
318                 return false;
319             }
320             if (getClass() != obj.getClass()) {
321                 return false;
322             }
323             KeyValuedColumnType other = (KeyValuedColumnType) obj;
324             if (keyType == null) {
325                 if (other.keyType != null) {
326                     return false;
327                 }
328             } else if (!keyType.equals(other.keyType)) {
329                 return false;
330             }
331             return true;
332         }
333     }
334 }