38c7fec6ae474098270f752be0a19577c89f0e12
[policy/gui.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019-2020 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 UPLOAD:
80                 return uploadModel(session);
81             case DELETE:
82                 return deleteModel(session);
83             default:
84                 return getUnsupportedCommandResultMessage(session, commandType, command);
85         }
86     }
87
88     /**
89      * {@inheritDoc}.
90      */
91     @Override
92     public ApexApiResult executeRestCommand(final RestSession session, final RestCommandType commandType,
93         final RestCommand command, final String jsonString) {
94         if (!RestCommandType.MODEL.equals(commandType)) {
95             return getUnsupportedCommandResultMessage(session, commandType, command);
96         }
97
98         switch (command) {
99             case LOAD:
100                 return loadFromString(session, jsonString);
101             case CREATE:
102                 return createModel(session, jsonString);
103             case UPDATE:
104                 return updateModel(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      * @return a result indicating if the upload was successful or not
280      */
281     private ApexApiResult uploadModel(final RestSession session) {
282         LOGGER.entry();
283
284         ApexApiResult result = session.uploadModel();
285
286         LOGGER.exit("Model/Download" + (result != null && result.isOk() ? OK : NOT_OK));
287         return result;
288     }
289
290     /**
291      * Delete the model for this session.
292      *
293      * @param session the Apex model editing session
294      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
295      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
296      */
297     private ApexApiResult deleteModel(final RestSession session) {
298         LOGGER.entry();
299
300         session.editModel();
301
302         ApexApiResult result = session.getApexModel().deleteModel();
303
304         session.finishSession(result.isOk());
305
306         LOGGER.exit("Model/Delete" + (result.isOk() ? OK : NOT_OK));
307         return result;
308     }
309
310     /**
311      * The json strings representing the objects listed, stored in result.messages[], does not contain the
312      * AxKeyInformation for that object. This utility method retrieves the AxKeyInfo for each object and adds it to the
313      * json for the object.
314      *
315      * @param session        the Apex model editing session
316      * @param incomingResult The list result, containing JSON representations of objects stored in its "messages" array
317      * @return The list result, containing JSON augmented representations of objects stored in its "messages" array
318      */
319     private ApexApiResult addKeyInfo2Messages(final RestSession session, final ApexApiResult incomingResult) {
320         final var result = new ApexApiResult(incomingResult.getResult());
321         result.setMessages(incomingResult.getMessages());
322
323         final List<String> messages = incomingResult.getMessages();
324         final List<String> augmentedMessages = new ArrayList<>(messages.size());
325
326         for (final String message : messages) {
327             augmentedMessages.add(addKeyInfo2Message(session, message));
328         }
329         result.setMessages(augmentedMessages);
330
331         if (messages.size() != augmentedMessages.size()) {
332             result.setResult(Result.OTHER_ERROR);
333             result.addMessage("Failed to add KeyInfo to all results. Results are not complete");
334         }
335
336         return result;
337     }
338
339     /**
340      * Augment a message with key information.
341      *
342      * @param session the Apex model editing session
343      * @param message The message to augment
344      * @return the augmented message
345      */
346     private String addKeyInfo2Message(final RestSession session, final String message) {
347         final var gson = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization().create();
348
349         var jsonObject = gson.fromJson(message, JsonObject.class);
350         if (jsonObject == null) {
351             return message;
352         }
353
354         String name = readFieldFromJsonObject(jsonObject, NAME, null);
355         String version = readFieldFromJsonObject(jsonObject, VERSION, null);
356
357         if (name == null && version == null) {
358             var newJsonObject = getSubJsonObject(jsonObject);
359
360             if (newJsonObject != null) {
361                 jsonObject = newJsonObject;
362                 name = readFieldFromJsonObject(jsonObject, NAME, name);
363                 version = readFieldFromJsonObject(jsonObject, VERSION, version);
364             }
365         }
366
367         if (name == null || version == null || !setUuidAndDescription(session, jsonObject, name, version)) {
368             jsonObject.addProperty(UUID, (String) null);
369             jsonObject.addProperty(DESCRIPTION, (String) null);
370         }
371
372         return gson.toJson(jsonObject);
373     }
374
375     /**
376      * Get an embedded JSON object for the given JSON object.
377      *
378      * @param jsonObject the input JSON object
379      * @return the embedded JSON object
380      */
381     private JsonObject getSubJsonObject(JsonObject jsonObject) {
382         if (jsonObject.entrySet() != null && !jsonObject.entrySet().isEmpty()) {
383             return (JsonObject) jsonObject.entrySet().iterator().next().getValue();
384         } else {
385             return null;
386         }
387     }
388
389     /**
390      * Condition a field so its key information can be looked up.
391      *
392      * @param jsonObject the object to query
393      * @param fieldTag   the tag of the field to condition
394      * @param value      the default value of the field to condition
395      * @return field read from the json
396      */
397     private String readFieldFromJsonObject(final JsonObject jsonObject, final String fieldTag, final String value) {
398         String lookedupValue = value;
399
400         if (jsonObject != null && jsonObject.get(KEY) != null && jsonObject.get(KEY).isJsonObject()
401             && jsonObject.getAsJsonObject(KEY).get(fieldTag) != null) {
402             lookedupValue = jsonObject.getAsJsonObject(KEY).get(fieldTag).getAsString();
403         } else if (jsonObject != null && jsonObject.get(POLICY_KEY) != null && jsonObject.get(POLICY_KEY).isJsonObject()
404             && jsonObject.getAsJsonObject(POLICY_KEY).get(fieldTag) != null) {
405             lookedupValue = jsonObject.getAsJsonObject(POLICY_KEY).get(fieldTag).getAsString();
406         }
407         return lookedupValue;
408     }
409
410     /**
411      * Look up the UUID and description in the key information for a concept.
412      *
413      * @param session    the Apex editor session
414      * @param jsonObject the JSON object to place the fields in
415      * @param name       the concept name to look up
416      * @param version    the concept version to look up
417      */
418     private boolean setUuidAndDescription(final RestSession session, JsonObject jsonObject, String name,
419         String version) {
420         // Look up the key information for the name and version
421         var keyInfoJsonObject = lookupKeyInfo(session, name, version);
422         if (keyInfoJsonObject == null || keyInfoJsonObject.get(APEX_KEY_INFO) != null) {
423             return false;
424         }
425
426         if (keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get("UUID") != null) {
427             jsonObject.addProperty(UUID,
428                 keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get("UUID").getAsString());
429         } else {
430             jsonObject.addProperty(UUID, (String) null);
431         }
432
433         if (keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get(DESCRIPTION) != null) {
434             jsonObject.addProperty(DESCRIPTION,
435                 keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get(DESCRIPTION).getAsString());
436         } else {
437             jsonObject.addProperty(DESCRIPTION, (String) null);
438         }
439
440         return true;
441     }
442
443     /**
444      * Look up the key information for the given concept name and value.
445      *
446      * @param session the Apex editor session
447      * @param name    the concept name to look up
448      * @param version the concept version to look up
449      * @return a JSON version of the concept key information
450      */
451     private JsonObject lookupKeyInfo(final RestSession session, final String name, final String version) {
452         final ApexApiResult keyInfoResult = session.getApexModel().listKeyInformation(name, version);
453         final List<String> keyInfoMessages = keyInfoResult.getMessages();
454
455         if (keyInfoResult.isNok() || keyInfoMessages == null || keyInfoMessages.isEmpty()) {
456             return null;
457         }
458
459         final var gson = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization().create();
460         final String keyInfoJson = keyInfoMessages.get(0);
461         return gson.fromJson(keyInfoJson, JsonObject.class);
462     }
463 }