49163ab8477c9842ec54e26b867d2da9a57dbe01
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2020 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         if (result != null) {
133             session.finishSession(result.isOk());
134             LOGGER.exit("Model/Load" + (result.isOk() ? OK : NOT_OK));
135         }
136
137         return result;
138     }
139
140     /**
141      * Analyse the model and return analysis results. If successful the analysis results will be available in the
142      * messages in the result.
143      *
144      * @param session the Apex model editing session
145      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
146      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
147      */
148     private ApexApiResult analyse(final RestSession session) {
149         LOGGER.entry();
150
151         ApexApiResult result = session.getApexModel().analyse();
152
153         LOGGER.exit("Model/Analyse" + (result != null && result.isOk() ? OK : NOT_OK));
154         return result;
155     }
156
157     /**
158      * Validate the model and return validation results. If successful the validation results will be available in the
159      * messages in the result.
160      *
161      * @param session the Apex model editing session
162      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
163      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
164      */
165     private ApexApiResult validate(final RestSession session) {
166         LOGGER.entry();
167
168         ApexApiResult result = session.getApexModel().validate();
169
170         LOGGER.exit("Model/Validate" + (result != null && result.isOk() ? OK : NOT_OK));
171         return result;
172     }
173
174     /**
175      * Creates the new model model for this session.
176      *
177      * @param session the Apex model editing session
178      * @param jsonString the JSON string to be parsed containing the new model. See {@linkplain BeanModel}
179      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
180      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
181      */
182     private ApexApiResult createModel(final RestSession session, final String jsonString) {
183         LOGGER.entry(jsonString);
184
185         final BeanModel jsonbean = RestUtils.getJsonParameters(jsonString, BeanModel.class);
186
187         session.editModel();
188
189         ApexApiResult result = session.getApexModelEdited().createModel(jsonbean.getName(), jsonbean.getVersion(),
190                         jsonbean.getUuid(), jsonbean.getDescription());
191
192         if (result != null) {
193             session.finishSession(result.isOk());
194             LOGGER.exit("Model/Create" + (result.isOk() ? OK : NOT_OK));
195         }
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 BeanModel 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         if (result != null) {
218             session.finishSession(result.isOk());
219             LOGGER.exit("Model/Update" + (result.isOk() ? OK : NOT_OK));
220         }
221
222         return result;
223     }
224
225     /**
226      * Gets the key for the model for this session. If successful the model key will be available in the first message
227      * in the result. See {@linkplain AxKey}
228      *
229      * @param session the Apex model editing session
230      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
231      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
232      */
233     private ApexApiResult getModelKey(final RestSession session) {
234         LOGGER.entry();
235
236         ApexApiResult result = session.getApexModel().getModelKey();
237
238         LOGGER.exit("Model/GetKey" + (result != null && result.isOk() ? OK : NOT_OK));
239         return result;
240     }
241
242     /**
243      * Retrieve the model for this session. If successful the model will be available in the first message in the
244      * result. The returned value will be similar to a {@link AxPolicyModel}, with merged {@linkplain AxKeyInfo} for the
245      * root object.
246      *
247      * @param session the Apex model editing session
248      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
249      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
250      */
251     private ApexApiResult listModel(final RestSession session) {
252         LOGGER.entry();
253
254         ApexApiResult result = session.getApexModel().listModel();
255
256         if (result != null) {
257             result = addKeyInfo2Messages(session, result);
258             LOGGER.exit("Model/Get" + (result.isOk() ? OK : NOT_OK));
259         }
260         return result;
261     }
262
263     /**
264      * Download the model for this session as a String.
265      *
266      * @param session the Apex model editing session
267      * @return the model represented as a JSON string. See {@linkplain AxPolicyModel}
268      */
269     private ApexApiResult downloadModel(final RestSession session) {
270         LOGGER.entry();
271
272         ApexApiResult result = session.getApexModel().listModel();
273
274         LOGGER.exit("Model/Download" + (result != null && result.isOk() ? OK : NOT_OK));
275         return result;
276     }
277
278     /**
279      * Delete the model for this session.
280      *
281      * @param session the Apex model editing session
282      * @return an ApexAPIResult object. If successful then {@link ApexApiResult#isOk()} will return true. Any
283      *         messages/errors can be retrieved using {@link ApexApiResult#getMessages()}
284      */
285     private ApexApiResult deleteModel(final RestSession session) {
286         LOGGER.entry();
287
288         session.editModel();
289
290         ApexApiResult result = session.getApexModel().deleteModel();
291
292         if (result != null) {
293             session.finishSession(result.isOk());
294             LOGGER.exit("Model/Delete" + (result.isOk() ? OK : NOT_OK));
295         }
296
297         return result;
298     }
299
300     /**
301      * The json strings representing the objects listed, stored in result.messages[], does not contain the
302      * AxKeyInformation for that object. This utility method retrieves the AxKeyInfo for each object and adds it to the
303      * json for the object.
304      *
305      * @param session the Apex model editing session
306      * @param incomingResult The list result, containing JSON representations of objects stored in its "messages" array
307      * @return The list result, containing JSON augmented representations of objects stored in its "messages" array
308      */
309     private ApexApiResult addKeyInfo2Messages(final RestSession session, final ApexApiResult incomingResult) {
310         final ApexApiResult result = new ApexApiResult(incomingResult.getResult());
311         result.setMessages(incomingResult.getMessages());
312
313         final List<String> messages = incomingResult.getMessages();
314         final List<String> augmentedMessages = new ArrayList<>(messages.size());
315
316         for (final String message : messages) {
317             augmentedMessages.add(addKeyInfo2Message(session, message));
318         }
319         result.setMessages(augmentedMessages);
320
321         if (messages.size() != augmentedMessages.size()) {
322             result.setResult(Result.OTHER_ERROR);
323             result.addMessage("Failed to add KeyInfo to all results. Results are not complete");
324         }
325
326         return result;
327     }
328
329     /**
330      * Augment a message with key information.
331      *
332      * @param session the Apex model editing session
333      * @param message The message to augment
334      * @return the augmented message
335      */
336     private String addKeyInfo2Message(final RestSession session, final String message) {
337         final Gson gson = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization().create();
338
339         JsonObject jsonObject = gson.fromJson(message, JsonObject.class);
340         if (jsonObject == null) {
341             return message;
342         }
343
344         String name = readFieldFromJsonObject(jsonObject, NAME, null);
345         String version = readFieldFromJsonObject(jsonObject, VERSION, null);
346
347         if (name == null && version == null) {
348             JsonObject newJsonObject = getSubJsonObject(jsonObject);
349
350             if (newJsonObject != null) {
351                 jsonObject = newJsonObject;
352                 name = readFieldFromJsonObject(jsonObject, NAME, name);
353                 version = readFieldFromJsonObject(jsonObject, VERSION, version);
354             }
355         }
356
357         if (name == null || version == null || !setUuidAndDescription(session, jsonObject, name, version)) {
358             jsonObject.addProperty(UUID, (String) null);
359             jsonObject.addProperty(DESCRIPTION, (String) null);
360         }
361
362         return gson.toJson(jsonObject);
363     }
364
365     /**
366      * Get an embedded JSON object for the given JSON object.
367      *
368      * @param jsonObject the input JSON object
369      * @return the embedded JSON object
370      */
371     private JsonObject getSubJsonObject(JsonObject jsonObject) {
372         if (jsonObject.entrySet() != null && !jsonObject.entrySet().isEmpty()) {
373             return (JsonObject) jsonObject.entrySet().iterator().next().getValue();
374         } else {
375             return null;
376         }
377     }
378
379     /**
380      * Condition a field so its key information can be looked up.
381      *
382      * @param jsonObject the object to query
383      * @param fieldTag the tag of the field to condition
384      * @param fieldValue the value of the field to condition
385      * @return field read from the json
386      */
387     private String readFieldFromJsonObject(final JsonObject jsonObject, final String fieldTag, final String value) {
388         String lookedupValue = value;
389
390         if (jsonObject != null && jsonObject.get(KEY) != null && jsonObject.get(KEY).isJsonObject()
391                         && jsonObject.getAsJsonObject(KEY).get(fieldTag) != null) {
392             lookedupValue = jsonObject.getAsJsonObject(KEY).get(fieldTag).getAsString();
393         } else if (jsonObject != null && jsonObject.get(POLICY_KEY) != null && jsonObject.get(POLICY_KEY).isJsonObject()
394                         && jsonObject.getAsJsonObject(POLICY_KEY).get(fieldTag) != null) {
395             lookedupValue = jsonObject.getAsJsonObject(POLICY_KEY).get(fieldTag).getAsString();
396         }
397         return lookedupValue;
398     }
399
400     /**
401      * Look up the UUID and description in the key information for a concept.
402      *
403      * @param session the Apex editor session
404      * @param jsonObject the JSON object to place the fields in
405      * @param name the concept name to look up
406      * @param version the concept version to look up
407      */
408     private boolean setUuidAndDescription(final RestSession session, JsonObject jsonObject, String name,
409                     String version) {
410         // Look up the key information for the name and version
411         JsonObject keyInfoJsonObject = lookupKeyInfo(session, name, version);
412         if (keyInfoJsonObject == null || keyInfoJsonObject.get(APEX_KEY_INFO) != null) {
413             return false;
414         }
415
416         if (keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get("UUID") != null) {
417             jsonObject.addProperty(UUID,
418                             keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get("UUID").getAsString());
419         } else {
420             jsonObject.addProperty(UUID, (String) null);
421         }
422
423         if (keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get(DESCRIPTION) != null) {
424             jsonObject.addProperty(DESCRIPTION,
425                             keyInfoJsonObject.get(APEX_KEY_INFO).getAsJsonObject().get(DESCRIPTION).getAsString());
426         } else {
427             jsonObject.addProperty(DESCRIPTION, (String) null);
428         }
429
430         return true;
431     }
432
433     /**
434      * Look up the key information for the given concept name and value.
435      *
436      * @param session the Apex editor session
437      * @param name the concept name to look up
438      * @param version the concept version to look up
439      * @return a JSON version of the concept key information
440      */
441     private JsonObject lookupKeyInfo(final RestSession session, final String name, final String version) {
442         final ApexApiResult keyInfoResult = session.getApexModel().listKeyInformation(name, version);
443         final List<String> keyInfoMessages = keyInfoResult.getMessages();
444
445         if (keyInfoResult.isNok() || keyInfoMessages == null || keyInfoMessages.isEmpty()) {
446             return null;
447         }
448
449         final Gson gson = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization().create();
450         final String keyInfoJson = keyInfoMessages.get(0);
451         return gson.fromJson(keyInfoJson, JsonObject.class);
452     }
453 }