Unit test fails due to cleanup
[clamp.git] / src / main / java / org / onap / clamp / policy / operational / LegacyOperationalPolicy.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP CLAMP
4  * ================================================================================
5  * Copyright (C) 2019 AT&T Intellectual Property. All rights
6  *                             reserved.
7  * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END============================================
21  * ===================================================================
22  *
23  */
24
25 package org.onap.clamp.policy.operational;
26
27 import com.google.gson.GsonBuilder;
28 import com.google.gson.JsonElement;
29 import com.google.gson.JsonObject;
30
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Map.Entry;
35 import java.util.TreeMap;
36
37 import org.apache.commons.lang3.math.NumberUtils;
38 import org.onap.clamp.loop.Loop;
39 import org.yaml.snakeyaml.DumperOptions;
40 import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
41 import org.yaml.snakeyaml.Yaml;
42
43 /**
44  * This class contains the code required to support the sending of Legacy
45  * operational payload to policy engine. This will probably disappear in El
46  * Alto.
47  */
48 public class LegacyOperationalPolicy {
49
50     private static final String ACTOR = "actor";
51     private static final String RECIPE = "recipe";
52     private static final String POLICIES = "policies";
53     private static final String PAYLOAD = "payload";
54
55     private LegacyOperationalPolicy() {
56
57     }
58
59     private static void translateStringValues(String jsonKey, String stringValue, JsonElement parentJsonElement) {
60         if (stringValue.equalsIgnoreCase("true") || stringValue.equalsIgnoreCase("false")) {
61             parentJsonElement.getAsJsonObject().addProperty(jsonKey, Boolean.valueOf(stringValue));
62
63         } else if (NumberUtils.isParsable(stringValue)) {
64             parentJsonElement.getAsJsonObject().addProperty(jsonKey, Long.parseLong(stringValue));
65         }
66     }
67
68     private static JsonElement removeAllQuotes(JsonElement jsonElement) {
69         if (jsonElement.isJsonArray()) {
70             for (JsonElement element : jsonElement.getAsJsonArray()) {
71                 removeAllQuotes(element);
72             }
73         } else if (jsonElement.isJsonObject()) {
74             for (Entry<String, JsonElement> entry : jsonElement.getAsJsonObject().entrySet()) {
75                 if (entry.getValue().isJsonPrimitive() && entry.getValue().getAsJsonPrimitive().isString()) {
76                     translateStringValues(entry.getKey(), entry.getValue().getAsString(), jsonElement);
77                 } else {
78                     removeAllQuotes(entry.getValue());
79                 }
80             }
81         }
82         return jsonElement;
83     }
84
85     /**
86      * This method rework the payload attribute (yaml) that is normally wrapped in a
87      * string when coming from the UI.
88      *
89      * @param policyJson The operational policy json config
90      * @return The same object reference but modified
91      */
92     public static JsonElement reworkPayloadAttributes(JsonElement policyJson) {
93         for (JsonElement policy : policyJson.getAsJsonObject().get("policies").getAsJsonArray()) {
94             JsonElement payloadElem = policy.getAsJsonObject().get("payload");
95             String payloadString = payloadElem != null ? payloadElem.getAsString() : "";
96             if (!payloadString.isEmpty()) {
97                 Map<String, String> testMap = new Yaml().load(payloadString);
98                 String json = new GsonBuilder().create().toJson(testMap);
99                 policy.getAsJsonObject().add("payload", new GsonBuilder().create().fromJson(json, JsonElement.class));
100             }
101         }
102         return policyJson;
103     }
104
105     private static void replacePropertiesIfEmpty(JsonElement policy, String key, String valueIfEmpty) {
106         JsonElement payloadElem = policy.getAsJsonObject().get(key);
107         String payloadString = payloadElem != null ? payloadElem.getAsString() : "";
108         if (payloadString.isEmpty()) {
109             policy.getAsJsonObject().addProperty(key, valueIfEmpty);
110         }
111     }
112
113     private static JsonElement fulfillPoliciesTreeField(JsonElement policyJson) {
114         for (JsonElement policy : policyJson.getAsJsonObject().get("policies").getAsJsonArray()) {
115             replacePropertiesIfEmpty(policy, "success", "final_success");
116             replacePropertiesIfEmpty(policy, "failure", "final_failure");
117             replacePropertiesIfEmpty(policy, "failure_timeout", "final_failure_timeout");
118             replacePropertiesIfEmpty(policy, "failure_retries", "final_failure_retries");
119             replacePropertiesIfEmpty(policy, "failure_exception", "final_failure_exception");
120             replacePropertiesIfEmpty(policy, "failure_guard", "final_failure_guard");
121             // Again special case for payload, should remove it if it's there but empty
122             // otherwise policy crashes
123             JsonElement payloadElem = policy.getAsJsonObject().get("payload");
124             if (payloadElem != null && payloadElem.isJsonPrimitive() && payloadElem.getAsString().isEmpty()) {
125                 policy.getAsJsonObject().remove("payload");
126             }
127         }
128         return policyJson;
129     }
130
131     private static Map<String, Object> createMap(JsonElement jsonElement) {
132         Map<String, Object> mapResult = new TreeMap<>();
133
134         if (jsonElement.isJsonObject()) {
135             for (Entry<String, JsonElement> entry : jsonElement.getAsJsonObject().entrySet()) {
136                 if (entry.getValue().isJsonPrimitive() && entry.getValue().getAsJsonPrimitive().isString()) {
137                     mapResult.put(entry.getKey(), entry.getValue().getAsString());
138                 } else if (entry.getValue().isJsonPrimitive() && entry.getValue().getAsJsonPrimitive().isBoolean()) {
139                     mapResult.put(entry.getKey(), entry.getValue().getAsBoolean());
140                 } else if (entry.getValue().isJsonPrimitive() && entry.getValue().getAsJsonPrimitive().isNumber()) {
141                     // Only int ro long normally, we don't need float here
142                     mapResult.put(entry.getKey(), entry.getValue().getAsLong());
143                 } else if (entry.getValue().isJsonArray()) {
144                     List<Map<String, Object>> newArray = new ArrayList<>();
145                     mapResult.put(entry.getKey(), newArray);
146                     for (JsonElement element : entry.getValue().getAsJsonArray()) {
147                         newArray.add(createMap(element));
148                     }
149                 } else if (entry.getValue().isJsonObject()) {
150                     mapResult.put(entry.getKey(), createMap(entry.getValue()));
151                 }
152             }
153         }
154         return mapResult;
155     }
156
157     /**
158      * This method transforms the configuration json to a Yaml format.
159      *
160      * @param operationalPolicyJsonElement The operational policy json config
161      * @return The Yaml as string
162      */
163     public static String createPolicyPayloadYamlLegacy(JsonElement operationalPolicyJsonElement) {
164         DumperOptions options = new DumperOptions();
165         options.setDefaultScalarStyle(ScalarStyle.PLAIN);
166         options.setIndent(2);
167         options.setPrettyFlow(true);
168         // Policy can't support { } in the yaml
169         options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
170         return (new Yaml(options)).dump(createMap(fulfillPoliciesTreeField(
171                 removeAllQuotes(reworkActorAttributes(operationalPolicyJsonElement.getAsJsonObject().deepCopy())))));
172     }
173
174     /**
175      * This method load mandatory field in the operational policy configuration
176      * JSON.
177      *
178      * @param configurationsJson The operational policy JSON
179      * @param loop               The parent loop object
180      */
181     public static void preloadConfiguration(JsonObject configurationsJson, Loop loop) {
182         if (configurationsJson != null && configurationsJson.entrySet().isEmpty()) {
183             JsonObject controlLoopName = new JsonObject();
184             controlLoopName.addProperty("controlLoopName",
185                     loop != null ? loop.getName() : "Empty (NO loop loaded yet)");
186             JsonObject controlLoop = new JsonObject();
187             controlLoop.add("controlLoop", controlLoopName);
188             configurationsJson.add("operational_policy", controlLoop);
189         }
190     }
191
192     /**
193      * This method rework on the actor/recipe and payload attribute.
194      *
195      * @param policyJson The operational policy json config
196      * @return The same object reference but modified
197      */
198     public static JsonElement reworkActorAttributes(JsonElement policyJson) {
199         for (JsonElement policy : policyJson.getAsJsonObject().get(POLICIES).getAsJsonArray()) {
200             JsonObject actor = policy.getAsJsonObject().get(ACTOR).getAsJsonObject();
201             policy.getAsJsonObject().remove(ACTOR);
202             String actorStr = actor.getAsJsonObject().get(ACTOR).getAsString();
203             policy.getAsJsonObject().addProperty(ACTOR, actorStr);
204
205             if ("CDS".equalsIgnoreCase(actorStr)) {
206                 policy.getAsJsonObject().addProperty(RECIPE, getRecipe(actor));
207                 addCdsPayloadAttributes(actor.getAsJsonObject(RECIPE), policy);
208             } else {
209                 policy.getAsJsonObject().addProperty(RECIPE,
210                                                      actor.getAsJsonObject().get(RECIPE).getAsString());
211                 addPayloadAttributes(actor, policy);
212             }
213         }
214         return policyJson;
215     }
216
217     private static void addPayloadAttributes(JsonObject jsonObject,
218                                              JsonElement policy) {
219         JsonElement payloadElem = jsonObject.getAsJsonObject().get(PAYLOAD);
220         String payloadString = payloadElem != null ? payloadElem.getAsString() : "";
221         if (!payloadString.isEmpty()) {
222             Map<String, String> testMap = new Yaml().load(payloadString);
223             String json = new GsonBuilder().create().toJson(testMap);
224             policy.getAsJsonObject().add(PAYLOAD,
225                                          new GsonBuilder().create().fromJson(json, JsonElement.class));
226         } else {
227             policy.getAsJsonObject().addProperty(PAYLOAD, "");
228         }
229     }
230
231     private static void addCdsPayloadAttributes(JsonObject jsonObject,
232                                              JsonElement policy) {
233         JsonElement payloadElem = jsonObject.getAsJsonObject().get(PAYLOAD);
234         JsonObject payloadObject = payloadElem != null ?
235                 payloadElem.getAsJsonObject() : null;
236         if (payloadObject != null) {
237             /* Since policy expects payload to be map of string,
238                converting data object to string. */
239             JsonObject dataObject = payloadObject.get("data").getAsJsonObject();
240             payloadObject.remove("data");
241             payloadObject.addProperty("data", dataObject.toString());
242             policy.getAsJsonObject().add(PAYLOAD,
243                                          payloadObject);
244         } else {
245             policy.getAsJsonObject().addProperty(PAYLOAD, "");
246         }
247     }
248
249     private static String getRecipe(JsonObject actor) {
250         return actor.getAsJsonObject().get("recipe").getAsJsonObject().get("recipe").getAsString();
251     }
252 }