Rework tosca converter
[clamp.git] / src / main / java / org / onap / clamp / clds / tosca / update / ParserToJson.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP CLAMP
4  * ================================================================================
5  * Copyright (C) 2020 AT&T Intellectual Property. All rights
6  *                             reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END============================================
20  * ===================================================================
21  *
22  */
23
24 package org.onap.clamp.clds.tosca.update;
25
26 import com.google.gson.JsonArray;
27 import com.google.gson.JsonObject;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.LinkedHashMap;
31 import java.util.Map.Entry;
32
33 public class ParserToJson {
34     private LinkedHashMap<String, Component> components;
35     private LinkedHashMap<String, Template> templates;
36
37     public ParserToJson(LinkedHashMap<String, Component> components, LinkedHashMap<String, Template> templates) {
38         this.components = components;
39         this.templates = templates;
40     }
41
42     /**
43      * For a given component, launch process to parse it in Json.
44      *
45      * @param nameComponent name components
46      * @return return
47      */
48     public JsonObject getJsonProcess(String nameComponent) {
49         JsonObject glob = this.getGeneralField(matchComponent(nameComponent));
50         if (templates.get("object").hasFields("required")) {
51             glob.add("required", this.getRequirements(nameComponent));
52         }
53         if (templates.get("object").hasFields("properties")) {
54             glob.add("properties", this.deploy(nameComponent));
55         }
56         return glob;
57     }
58
59     /**
60      * Return the classical/general fields of the component, & launch the properties deployment.
61      *
62      * @param component the compo
63      * @return a json object
64      */
65     public JsonObject getGeneralField(Component component) {
66
67         JsonObject globalFields = new JsonObject();
68         if (templates.get("object").hasFields("title")) {
69             globalFields.addProperty("title", component.getName());
70         }
71         if (templates.get("object").hasFields("type")) {
72             globalFields.addProperty("type", "object");
73         }
74         if (templates.get("object").hasFields("description")) {
75             if (component.getDescription() != null) {
76                 globalFields.addProperty("description", component.getDescription());
77             }
78         }
79         return globalFields;
80     }
81
82     /**
83      * Get the required properties of the Component, including the parents properties requirements.
84      *
85      * @param nameComponent name component
86      * @return a json array
87      */
88     public JsonArray getRequirements(String nameComponent) {
89         JsonArray requirements = new JsonArray();
90         Component toParse = components.get(nameComponent);
91         //Check for a father component, and launch the same process
92         if (!toParse.getDerivedFrom().equals("tosca.datatypes.Root")
93                 && !toParse.getDerivedFrom().equals("tosca.policies.Root")) {
94             requirements.addAll(getRequirements(toParse.getDerivedFrom()));
95         }
96         //Each property is checked, and add to the requirement array if it's required
97         Collection<Property> properties = toParse.getProperties().values();
98         for (Property property : properties) {
99             if (property.getItems().containsKey("required")
100                     && property.getItems().get("required").equals(true)) {
101                 requirements.add(property.getName());
102             }
103         }
104         return requirements;
105     }
106
107     /**
108      * The beginning of the recursive process. Get the parents (or not) to launch the same process, and otherwise
109      * deploy and parse the properties.
110      *
111      * @param nameComponent name component
112      * @return a json object
113      */
114     public JsonObject deploy(String nameComponent) {
115         JsonObject jsonSchema = new JsonObject();
116         Component toParse = components.get(nameComponent);
117         //Check for a father component, and launch the same process
118         if (!toParse.getDerivedFrom().equals("tosca.datatypes.Root")
119                 && !toParse.getDerivedFrom().equals("tosca.policies.Root")) {
120             jsonSchema = this.getParent(toParse.getDerivedFrom());
121         }
122         //For each component property, check if its a complex properties (a component) or not. In that case,
123         //launch the analyse of the property.
124         for (Entry<String, Property> property : toParse.getProperties().entrySet()) {
125             if (matchComponent((String) property.getValue().getItems().get("type")) != null) {
126                 jsonSchema.add(property.getValue().getName(),
127                         this.getJsonProcess((String) property.getValue().getItems().get("type")));
128             }
129             else {
130                 jsonSchema.add(property.getValue().getName(), this.complexParse(property.getValue()));
131             }
132         }
133         return jsonSchema;
134     }
135
136     /**
137      * If a component has a parent, it is deploy in the same way.
138      *
139      * @param nameComponent name component
140      * @return a json object
141      */
142     public JsonObject getParent(String nameComponent) {
143         return deploy(nameComponent);
144     }
145
146     /**
147      * to be done.
148      *
149      * @param property property
150      * @return a json object
151      */
152     @SuppressWarnings("unchecked")
153     public JsonObject complexParse(Property property) {
154         JsonObject propertiesInJson = new JsonObject();
155         Template currentPropertyTemplate;
156         String typeProperty = (String) property.getItems().get("type");
157         if (typeProperty.toLowerCase().equals("list") || typeProperty.toLowerCase().equals("map")) {
158             currentPropertyTemplate = templates.get("object");
159         }
160         else {
161             String propertyType = (String) property.getItems().get("type");
162             currentPropertyTemplate = templates.get(propertyType.toLowerCase());
163         }
164         //Each "special" field is analysed, and has a specific treatment
165         for (String propertyField : property.getItems().keySet()) {
166             switch (propertyField) {
167                 case "type":
168                     if (currentPropertyTemplate.hasFields(propertyField)) {
169                         switch ((String) property.getItems().get(propertyField)) {
170                             case "list":
171                             case "map":
172                                 propertiesInJson.addProperty("type", "object");
173                                 break;
174                             case "scalar-unit.time":
175                             case "scalar-unit.frequency":
176                             case "scalar-unit.size":
177                                 propertiesInJson.addProperty("type", "string");
178                                 break;
179                             case "timestamp":
180                                 propertiesInJson.addProperty("type", "string");
181                                 propertiesInJson.addProperty("format", "date-time");
182                                 break;
183                             case "range":
184                                 propertiesInJson.addProperty("type", "integer");
185                                 if (!checkConstraintPresence(property, "greater_than")
186                                         && currentPropertyTemplate.hasFields("exclusiveMinimum")) {
187                                     propertiesInJson.addProperty("exclusiveMinimum", false);
188                                 }
189                                 if (!checkConstraintPresence(property, "less_than")
190                                         && currentPropertyTemplate.hasFields("exclusiveMaximum")) {
191                                     propertiesInJson.addProperty("exclusiveMaximum", false);
192                                 }
193                                 break;
194                             default:
195                                 propertiesInJson.addProperty("type", currentPropertyTemplate.getName());
196                                 break;
197                         }
198                     }
199                     break;
200                 case "metadata":
201                     break;
202                 case "constraints":
203                     property.addConstraintsAsJson(propertiesInJson,
204                             (ArrayList<Object>) property.getItems().get("constraints"),
205                             currentPropertyTemplate);
206                     break;
207                 case "entry_schema":
208                     if (matchComponent(this.extractSpecificFieldFromMap(property, "entry_schema")) != null) {
209                         ParserToJson child = new ParserToJson(components, templates);
210                         JsonObject componentAsProperty =
211                                 child.getJsonProcess(this.extractSpecificFieldFromMap(property, "entry_schema"));
212                         JsonObject propertiesContainer = new JsonObject();
213                         propertiesContainer
214                                 .add(this.extractSpecificFieldFromMap(property, "entry_schema"), componentAsProperty);
215                         if (currentPropertyTemplate.hasFields("properties")) {
216                             propertiesInJson.add("properties", propertiesContainer);
217                         }
218                     }
219                     break;
220                 default://Each classical field : type, description, default..
221                     if (currentPropertyTemplate.hasFields(propertyField) && !propertyField.equals("required")) {
222                         property.addFieldToJson(propertiesInJson, propertyField,
223                                 property.getItems().get(propertyField));
224                     }
225                     break;
226             }
227         }
228         return propertiesInJson;
229     }
230
231     /**
232      * Look for a matching Component for the name paramater, in the components list.
233      *
234      * @param name the name
235      * @return a component
236      */
237     public Component matchComponent(String name) {
238         Component correspondingComponent = null;
239         Collection<Component> listofComponent = components.values();
240         for (Component component : listofComponent) {
241             if (component.getName().equals(name)) {
242                 correspondingComponent = component;
243             }
244         }
245         return correspondingComponent;
246     }
247
248     /**
249      * Simple method to extract quickly a type field from particular property item.
250      *
251      * @param property  the property
252      * @param fieldName the fieldname
253      * @return a string
254      */
255     @SuppressWarnings("unchecked")
256     public String extractSpecificFieldFromMap(Property property, String fieldName) {
257         LinkedHashMap<String, String> entrySchemaFields =
258                 (LinkedHashMap<String, String>) property.getItems().get(fieldName);
259         return entrySchemaFields.get("type");
260     }
261
262     /**
263      * Check if a constraint, for a specific property, is there.
264      *
265      * @param property       property
266      * @param nameConstraint name constraint
267      * @return a flag boolean
268      */
269     public boolean checkConstraintPresence(Property property, String nameConstraint) {
270         boolean presentConstraint = false;
271         if (property.getItems().containsKey("constraints")) {
272             ArrayList<Object> constraints = (ArrayList) property.getItems().get("constraints");
273             for (Object constraint : constraints) {
274                 if (constraint instanceof LinkedHashMap) {
275                     if (((LinkedHashMap) constraint).containsKey(nameConstraint)) {
276                         presentConstraint = true;
277                     }
278                 }
279             }
280         }
281         return presentConstraint;
282     }
283 }