DCAE-D be initial commit
[sdc/dcae-d/dt-be-main.git] / dcaedt_be / src / main / java / org / onap / sdc / dcae / ves / VesDataTypeDefinition.java
1 package org.onap.sdc.dcae.ves;
2
3 import com.google.gson.JsonElement;
4 import com.google.gson.annotations.SerializedName;
5 import org.apache.commons.collections.CollectionUtils;
6 import org.apache.commons.collections.MapUtils;
7 import org.apache.commons.lang.StringUtils;
8
9 import java.util.*;
10
11 public class VesDataTypeDefinition {
12
13         private static final String jsonReferencePrefix = "#/definitions/";
14         private String type;
15         private String description;
16         private String format;
17         private String title;
18         private Map<String, VesDataTypeDefinition> properties;
19         private List<String> required = new ArrayList<>();
20         @SerializedName("enum")
21         private List<String> enums;
22         @SerializedName("default")
23         private JsonElement defaultValue;
24         private VesDataItemsDefinition items;
25         @SerializedName("$ref")
26         private String ref;
27
28         public String getType() {
29                 return type;
30         }
31
32         public void setType(String type) {
33                 this.type = type;
34         }
35
36         public String getDescription() {
37                 return description;
38         }
39
40         public void setDescription(String description) {
41                 this.description = description;
42         }
43
44         public String getFormat() {
45                 return format;
46         }
47
48         public void setFormat(String format) {
49                 this.format = format;
50         }
51
52         public String getTitle() {
53                 return title;
54         }
55
56         public void setTitle(String title) {
57                 this.title = title;
58         }
59
60         public Map<String, VesDataTypeDefinition> getProperties() {
61                 return properties;
62         }
63
64         public void setProperties(Map<String, VesDataTypeDefinition> properties) {
65                 this.properties = properties;
66         }
67
68         public List<String> getRequired() {
69                 return required;
70         }
71
72         public void setRequired(List<String> required) {
73                 this.required = required;
74         }
75
76         public List<String> getEnums() {
77                 return enums;
78         }
79
80         public void setEnums(List<String> enums) {
81                 this.enums = enums;
82         }
83
84         public JsonElement getDefaultValue() {
85                 return defaultValue;
86         }
87
88         public void setDefaultValue(JsonElement defaultValue) {
89                 this.defaultValue = defaultValue;
90         }
91
92         public VesDataItemsDefinition getItems() {
93                 return items;
94         }
95
96         public void setItems(VesDataItemsDefinition items) {
97                 this.items = items;
98         }
99
100         public String getRef() {
101                 return ref;
102         }
103
104         public void setRef(String ref) {
105                 this.ref = ref;
106         }
107
108         protected boolean hasReference() {
109                 return StringUtils.isNotBlank(getRef());
110         }
111
112         protected boolean itemsContainReference() {
113                 return CollectionUtils.isNotEmpty(getItems()) && getItems().stream().anyMatch(VesDataTypeDefinition::containsAnyReferenceItem);
114         }
115
116         protected boolean propertiesContainReference() {
117                 return MapUtils.isNotEmpty(getProperties()) && getProperties().values().stream().anyMatch(VesDataTypeDefinition::containsAnyReferenceItem);
118         }
119
120         protected boolean containsAnyReferenceItem() {
121                 return hasReference() || itemsContainReference() || propertiesContainReference();
122         }
123
124         protected String getJsonRefPointer() {
125                 return getRef().replace(jsonReferencePrefix, "");
126         }
127
128         private void addReferenceItem(Set<String> allRefs) {
129                 if (hasReference()) {
130                         allRefs.add(getJsonRefPointer());
131                 }
132         }
133
134         private Set<String> extractAllReferenceTokens() {
135                 Set<String> allRefs = new HashSet<>();
136                 extractReferenceTokens(allRefs);
137                 return allRefs;
138         }
139
140         private void extractReferenceTokens(Set<String> allRefs) {
141
142                 addReferenceItem(allRefs);
143                 if (itemsContainReference()) {
144                         getItems().forEach(item -> item.extractReferenceTokens(allRefs));
145                 }
146                 if (propertiesContainReference()) {
147                         getProperties().values().forEach(property -> property.extractReferenceTokens(allRefs));
148                 }
149         }
150
151         protected boolean isResolvable(Map<String, VesDataTypeDefinition> resolvedTypes) {
152                 return resolvedTypes.keySet().containsAll(extractAllReferenceTokens());
153         }
154
155         private void resolveReference(Map<String, VesDataTypeDefinition> resolvedTypes) {
156                 if (hasReference()) {
157                         VesDataTypeDefinition other = resolvedTypes.get(getJsonRefPointer());
158                         setType(other.getType());
159                         setRef(other.getRef());
160                         setDefaultValue(other.getDefaultValue());
161                         setDescription(other.getDescription());
162                         setEnums(other.getEnums());
163                         setProperties(other.getProperties());
164                         setFormat(other.getFormat());
165                         setRequired(other.getRequired());
166                         setItems(other.getItems());
167                         setTitle(other.getTitle());
168                 }
169         }
170
171         private void resolveItemReferences(Map<String, VesDataTypeDefinition> resolvedTypes) {
172                 if (itemsContainReference()) {
173                         for (VesDataTypeDefinition item : getItems()) {
174                                 item.resolveAllReferences(resolvedTypes);
175                         }
176                 }
177         }
178
179         private void resolvePropertyReferences(Map<String, VesDataTypeDefinition> resolvedTypes) {
180                 if (propertiesContainReference()) {
181                         for (VesDataTypeDefinition property : getProperties().values()) {
182                                 property.resolveAllReferences(resolvedTypes);
183                         }
184                 }
185         }
186
187         // the reference resolver is called on each VesDataTypeDefinition after it passes the 'isResolvable' validation, affirming that all its references(direct/properties/items) point to a resolved VesDataTypeDefinition (has no references)
188         protected void resolveAllReferences(Map<String, VesDataTypeDefinition> resolvedTypes) {
189                 resolveReference(resolvedTypes);
190                 resolveItemReferences(resolvedTypes);
191                 resolvePropertyReferences(resolvedTypes);
192         }
193
194         private String validateType() {
195                 return null == type? null : VesSimpleTypesEnum.getSimpleTypes().contains(type) ? null : "invalid type declaration: " + type;
196         }
197
198         private String validateRequired() {
199                 String invalid = null == type? null : !type.equals(VesSimpleTypesEnum.OBJECT.getType()) ? null : required.stream().filter(r -> !properties.keySet().contains(r)).findAny().orElse(null);
200                 return StringUtils.isBlank(invalid) ? invalid : "invalid required entry: " + invalid;
201         }
202
203         // returns error message detailing invalid 'type' or 'required' fields (null for success)
204         protected String validate() {
205                 String error = validateType();
206                 if (StringUtils.isBlank(error))
207                         error = validateRequired();
208                 if (StringUtils.isBlank(error) && CollectionUtils.isNotEmpty(items))
209                         error = validateItems();
210                 if(StringUtils.isBlank(error) && MapUtils.isNotEmpty(properties))
211                         error = validateProperties();
212                 return error;
213         }
214
215         private String validateItems(){
216                 String error = null;
217                 for (VesDataTypeDefinition def : items) {
218                         if (StringUtils.isBlank(error))
219                                 error = def.validate();
220                         else
221                                 break;
222                 }
223                 return error;
224         }
225
226         private String validateProperties(){
227                 String error = null;
228                 for (VesDataTypeDefinition def : properties.values()) {
229                         if (StringUtils.isBlank(error))
230                                 error = def.validate();
231                         else
232                                 break;
233                 }
234                 return error;
235         }
236
237
238         @Override
239         public boolean equals(Object obj) {
240                 if (obj == this)
241                         return true;
242                 if (null == obj || getClass() != obj.getClass())
243                         return false;
244                 VesDataTypeDefinition other = (VesDataTypeDefinition) obj;
245                 return Objects.equals(type, other.type) &&
246                                 Objects.equals(description, other.description) &&
247                                 Objects.equals(format, other.format) &&
248                                 Objects.equals(title, other.title) &&
249                                 Objects.equals(required, other.required) &&
250                                 Objects.equals(enums, other.enums) &&
251                                 Objects.equals(defaultValue, other.defaultValue) &&
252                                 Objects.equals(items, other.items) &&
253                                 Objects.equals(properties, other.properties) &&
254                                 Objects.equals(ref, other.ref);
255         }
256
257         @Override public int hashCode() {
258                 int result = type != null ? type.hashCode() : 0;
259                 result = 31 * result + (description != null ? description.hashCode() : 0);
260                 result = 31 * result + (format != null ? format.hashCode() : 0);
261                 result = 31 * result + (title != null ? title.hashCode() : 0);
262                 result = 31 * result + (properties != null ? properties.hashCode() : 0);
263                 result = 31 * result + (required != null ? required.hashCode() : 0);
264                 result = 31 * result + (enums != null ? enums.hashCode() : 0);
265                 result = 31 * result + (defaultValue != null ? defaultValue.hashCode() : 0);
266                 result = 31 * result + (items != null ? items.hashCode() : 0);
267                 result = 31 * result + (ref != null ? ref.hashCode() : 0);
268                 return result;
269         }
270 }