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