c865215a55aa43183fed2fb1907212082fe15e3b
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019 Nordix Foundation.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.apex.client.editor.rest.handling;
23
24 import com.google.gson.Gson;
25 import com.google.gson.GsonBuilder;
26 import com.google.gson.JsonObject;
27 import java.util.ArrayList;
28 import java.util.List;
29 import org.onap.policy.apex.client.editor.rest.handling.bean.BeanModel;
30 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
31 import org.onap.policy.apex.model.basicmodel.concepts.AxKeyInfo;
32 import org.onap.policy.apex.model.modelapi.ApexApiResult;
33 import org.onap.policy.apex.model.modelapi.ApexApiResult.Result;
34 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
35 import org.slf4j.ext.XLogger;
36 import org.slf4j.ext.XLoggerFactory;
37
38 /**
39  * This class handles commands on Apex models.
40  */
41 public class ModelHandler implements RestCommandHandler {
42
43     // Get a reference to the logger
44     private static final XLogger LOGGER = XLoggerFactory.getXLogger(ModelHandler.class);
45
46     // Recurring string constants
47     private static final String OK = ": OK";
48     private static final String NOT_OK = ": Not OK";
49     private static final String KEY = "key";
50     private static final String NAME = "name";
51     private static final String VERSION = "version";
52     private static final String UUID = "uuid";
53     private static final String DESCRIPTION = "description";
54     private static final String POLICY_KEY = "policyKey";
55     private static final String APEX_KEY_INFO = "apexKeyInfo";
56
57     /**
58      * {@inheritDoc}.
59      */
60     @Override
61     public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
62                     final RestCommand command) {
63         if (!RestCommandType.MODEL.equals(commandType)) {
64             return getUnsupportedCommandResultMessage(session, commandType, command);
65         }
66
67         switch (command) {
68             case ANALYSE:
69                 return analyse(session);
70             case VALIDATE:
71                 return validate(session);
72             case GET_KEY:
73                 return getModelKey(session);
74             case LIST:
75                 return listModel(session);
76             case DOWNLOAD:
77                 return downloadModel(session);
78             case DELETE:
79                 return deleteModel(session);
80             default:
81                 return getUnsupportedCommandResultMessage(session, commandType, command);
82         }
83     }
84
85     /**
86      * {@inheritDoc}.
87      */
88     @Override
89     public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
90                     final RestCommand command, final String jsonString) {
91         if (!RestCommandType.MODEL.equals(commandType)) {
92             return getUnsupportedCommandResultMessage(session, commandType, command);
93         }
94
95         switch (command) {
96             case LOAD:
97                 return loadFromString(session, jsonString);
98             case CREATE:
99                 return createModel(session, jsonString);
100             case UPDATE:
101                 return updateModel(session, jsonString);
102             default:
103                 return getUnsupportedCommandResultMessage(session, commandType, command);
104         }
105     }
106
107     /**
108      * {@inheritDoc}.
109      */
110     @Override
111     public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
112                     final RestCommand command, final String name, final String version) {
113         return getUnsupportedCommandResultMessage(session, commandType, command);
114     }
115
116     /**
117      * Load the model from a JSON string for this session.
118      *
119      * @param session the Apex model editing session
120      * @param jsonString the JSON string to be parsed. The returned value(s) will be similar to {@link AxPolicyModel},
121      *        with merged {@linkplain AxKeyInfo} for the root object.
122      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
123      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
124      */
125     private ApexApiResult loadFromString(final RestSession session, final String jsonString) {
126         LOGGER.entry(jsonString);
127
128         session.editModel();
129
130         ApexApiResult result = session.getApexModelEdited().loadFromString(jsonString);
131
132         session.finishSession(result.isOk());
133
134         LOGGER.exit("Model/Load" + (result != null && result.isOk() ? OK : NOT_OK));
135         return result;
136     }
137
138     /**
139      * Analyse the model and return analysis results. If successful the analysis results will be available in the
140      * messages in the result.
141      *
142      * @param session the Apex model editing session
143      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
144      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
145      */
146     private ApexApiResult analyse(final RestSession session) {
147         LOGGER.entry();
148
149         ApexApiResult result = session.getApexModel().analyse();
150
151         LOGGER.exit("Model/Analyse" + (result != null && result.isOk() ? OK : NOT_OK));
152         return result;
153     }
154
155     /**
156      * Validate the model and return validation results. If successful the validation results will be available in the
157      * messages in the result.
158      *
159      * @param session the Apex model editing session
160      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
161      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
162      */
163     private ApexApiResult validate(final RestSession session) {
164         LOGGER.entry();
165
166         ApexApiResult result = session.getApexModel().validate();
167
168         LOGGER.exit("Model/Validate" + (result != null && result.isOk() ? OK : NOT_OK));
169         return result;
170     }
171
172     /**
173      * Creates the new model model for this session.
174      *
175      * @param session the Apex model editing session
176      * @param jsonString the JSON string to be parsed containing the new model. See {@linkplain BeanModel}
177      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
178      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
179      */
180     private ApexApiResult createModel(final RestSession session, final String jsonString) {
181         LOGGER.entry(jsonString);
182
183         final BeanModel jsonbean = RestUtils.getJsonParameters(jsonString, BeanModel.class);
184
185         session.editModel();
186
187         ApexApiResult result = session.getApexModelEdited().createModel(jsonbean.getName(), jsonbean.getVersion(),
188                         jsonbean.getUuid(), jsonbean.getDescription());
189
190         session.finishSession(result.isOk());
191
192         LOGGER.exit("Model/Create" + (result != null && result.isOk() ? OK : NOT_OK));
193         return result;
194     }
195
196     /**
197      * Update the model for this session.
198      *
199      * @param session the Apex model editing session
200      * @param jsonString the JSON string to be parsed containing the updated model. See {@linkplain BeanModel}
201      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
202      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
203      */
204     private ApexApiResult updateModel(final RestSession session, final String jsonString) {
205         LOGGER.entry(jsonString);
206
207         final BeanModel jsonbean = RestUtils.getJsonParameters(jsonString, BeanModel.class);
208
209         session.editModel();
210
211         ApexApiResult result = session.getApexModelEdited().updateModel(jsonbean.getName(), jsonbean.getVersion(),
212                         jsonbean.getUuid(), jsonbean.getDescription());
213
214         session.finishSession(result.isOk());
215
216         LOGGER.exit("Model/Update" + (result != null && result.isOk() ? OK : NOT_OK));
217         return result;
218     }
219
220     /**
221      * Gets the key for the model for this session. If successful the model key will be available in the first message
222      * in the result. See {@linkplain AxKey}
223      *
224      * @param session the Apex model editing session
225      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
226      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
227      */
228     private ApexApiResult getModelKey(final RestSession session) {
229         LOGGER.entry();
230
231         ApexApiResult result = session.getApexModel().getModelKey();
232
233         LOGGER.exit("Model/GetKey" + (result != null && result.isOk() ? OK : NOT_OK));
234         return result;
235     }
236
237     /**
238      * Retrieve the model for this session. If successful the model will be available in the first message in the
239      * result. The returned value will be similar to a {@link AxPolicyModel}, with merged {@linkplain AxKeyInfo} for the
240      * root object.
241      *
242      * @param session the Apex model editing session
243      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
244      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
245      */
246     private ApexApiResult listModel(final RestSession session) {
247         LOGGER.entry();
248
249         ApexApiResult result = session.getApexModel().listModel();
250
251         result = addKeyInfo2Messages(session, result);
252
253         LOGGER.exit("Model/Get" + (result != null && result.isOk() ? OK : NOT_OK));
254         return result;
255     }
256
257     /**
258      * Download the model for this session as a String.
259      *
260      * @param session the Apex model editing session
261      * @return the model represented as a JSON string. See {@linkplain AxPolicyModel}
262      */
263     private ApexApiResult downloadModel(final RestSession session) {
264         LOGGER.entry();
265
266         ApexApiResult result = session.getApexModel().listModel();
267
268         LOGGER.exit("Model/Download" + (result != null && result.isOk() ? OK : NOT_OK));
269         return result;
270     }
271
272     /**
273      * Delete the model for this session.
274      *
275      * @param session the Apex model editing session
276      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
277      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
278      */
279     private ApexApiResult deleteModel(final RestSession session) {
280         LOGGER.entry();
281
282         session.editModel();
283
284         ApexApiResult result = session.getApexModel().deleteModel();
285
286         session.finishSession(result.isOk());
287
288         LOGGER.exit("Model/Delete" + (result != null && result.isOk() ? OK : NOT_OK));
289         return result;
290     }
291
292     /**
293      * The json strings representing the objects listed, stored in result.messages[], does not contain the
294      * AxKeyInformation for that object. This utility method retrieves the AxKeyInfo for each object and adds it to the
295      * json for the object.
296      *
297      * @param session the Apex model editing session
298      * @param incomingResult The list result, containing JSON representations of objects stored in its "messages" array
299      * @return The list result, containing JSON augmented representations of objects stored in its "messages" array
300      */
301     private ApexApiResult addKeyInfo2Messages(final RestSession session, final ApexApiResult incomingResult) {
302         final ApexApiResult result = new ApexApiResult(incomingResult.getResult());
303         result.setMessages(incomingResult.getMessages());
304
305         final List<String> messages = incomingResult.getMessages();
306         final List<String> augmentedMessages = new ArrayList<>(messages.size());
307
308         for (final String message : messages) {
309             augmentedMessages.add(addKeyInfo2Message(session, message));
310         }
311         result.setMessages(augmentedMessages);
312
313         if (messages.size() != augmentedMessages.size()) {
314             result.setResult(Result.OTHER_ERROR);
315             result.addMessage("Failed to add KeyInfo to all results. Results are not complete");
316         }
317
318         return result;
319     }
320
321     /**
322      * Augment a message with key information.
323      *
324      * @param session the Apex model editing session
325      * @param message The message to augment
326      * @return the augmented message
327      */
328     private String addKeyInfo2Message(final RestSession session, final String message) {
329         final Gson gson = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization().create();
330
331         JsonObject jsonObject = gson.fromJson(message, JsonObject.class);
332         if (jsonObject == null) {
333             return message;
334         }
335
336         String name = readFieldFromJsonObject(jsonObject, NAME, null);
337         String version = readFieldFromJsonObject(jsonObject, VERSION, null);
338
339         if (name == null && version == null) {
340             JsonObject newJsonObject = getSubJsonObject(jsonObject);
341
342             if (newJsonObject != null) {
343                 jsonObject = newJsonObject;
344                 name = readFieldFromJsonObject(jsonObject, NAME, name);
345                 version = readFieldFromJsonObject(jsonObject, VERSION, version);
346             }
347         }
348
349         if (name == null || version == null || !setUuidAndDescription(session, jsonObject, name, version)) {
350             jsonObject.addProperty(UUID, (String) null);
351             jsonObject.addProperty(DESCRIPTION, (String) null);
352         }
353
354         return gson.toJson(jsonObject);
355     }
356
357     /**
358      * Get an embedded JSON object for the given JSON object.
359      *
360      * @param jsonObject the input JSON object
361      * @return the embedded JSON object
362      */
363     private JsonObject getSubJsonObject(JsonObject jsonObject) {
364         if (jsonObject.entrySet() != null && !jsonObject.entrySet().isEmpty()) {
365             return (JsonObject) jsonObject.entrySet().iterator().next().getValue();
366         } else {
367             return null;
368         }
369     }
370
371     /**
372      * Condition a field so its key information can be looked up.
373      *
374      * @param jsonObject the object to query
375      * @param fieldTag the tag of the field to condition
376      * @param fieldValue the value of the field to condition
377      * @return field read from the json
378      */
379     private String readFieldFromJsonObject(final JsonObject jsonObject, final String fieldTag, final String value) {
380         String lookedupValue = value;
381
382         if (jsonObject != null && jsonObject.get(KEY) != null && jsonObject.get(KEY).isJsonObject()
383                         && jsonObject.getAsJsonObject(KEY).get(fieldTag) != null) {
384             lookedupValue = jsonObject.getAsJsonObject(KEY).get(fieldTag).getAsString();
385         } else if (jsonObject != null && jsonObject.get(POLICY_KEY) != null && jsonObject.get(POLICY_KEY).isJsonObject()
386                         && jsonObject.getAsJsonObject(POLICY_KEY).get(fieldTag) != null) {
387             lookedupValue = jsonObject.getAsJsonObject(POLICY_KEY).get(fieldTag).getAsString();
388         }
389         return lookedupValue;
390     }
391
392     /**
393      * Look up the UUID and description in the key information for a concept.
394      *
395      * @param session the Apex editor session
396      * @param jsonObject the JSON object to place the fields in
397      * @param name the concept name to look up
398      * @param version the concept version to look up
399      */
400     private boolean setUuidAndDescription(final RestSession session, JsonObject jsonObject, String name,
401                     String version) {
402         // Look up the key information for the name and version
403         JsonObject keyInfoJsonObject = lookupKeyInfo(session, name, version);
404         if (keyInfoJsonObject == null || keyInfoJsonObject.get(APEX_KEY_INFO) != null) {
405             return false;
406         }
407
408         if (keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get("UUID") != null) {
409             jsonObject.addProperty(UUID,
410                             keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get("UUID").getAsString());
411         } else {
412             jsonObject.addProperty(UUID, (String) null);
413         }
414
415         if (keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get(DESCRIPTION) != null) {
416             jsonObject.addProperty(DESCRIPTION,
417                             keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get(DESCRIPTION).getAsString());
418         } else {
419             jsonObject.addProperty(DESCRIPTION, (String) null);
420         }
421
422         return true;
423     }
424
425     /**
426      * Look up the key information for the given concept name and value.
427      *
428      * @param session the Apex editor session
429      * @param name the concept name to look up
430      * @param version the concept version to look up
431      * @return a JSON version of the concept key information
432      */
433     private JsonObject lookupKeyInfo(final RestSession session, final String name, final String version) {
434         final ApexApiResult keyInfoResult = session.getApexModel().listKeyInformation(name, version);
435         final List<String> keyInfoMessages = keyInfoResult.getMessages();
436
437         if (keyInfoResult.isNok() || keyInfoMessages == null || keyInfoMessages.isEmpty()) {
438             return null;
439         }
440
441         final Gson gson = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization().create();
442         final String keyInfoJson = keyInfoMessages.get(0);
443         return gson.fromJson(keyInfoJson, JsonObject.class);
444     }
445 }