5319d763e9eefe0b8311f707531aba422334854c
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019-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.service.parameters.engineservice;
23
24 import com.google.gson.JsonDeserializationContext;
25 import com.google.gson.JsonDeserializer;
26 import com.google.gson.JsonElement;
27 import com.google.gson.JsonObject;
28 import com.google.gson.JsonParseException;
29 import com.google.gson.JsonSerializationContext;
30 import com.google.gson.JsonSerializer;
31 import java.lang.reflect.Type;
32 import java.util.ArrayList;
33 import java.util.List;
34 import java.util.Map.Entry;
35 import org.onap.policy.apex.context.impl.schema.java.JavaSchemaHelperParameters;
36 import org.onap.policy.apex.context.parameters.ContextParameters;
37 import org.onap.policy.apex.context.parameters.DistributorParameters;
38 import org.onap.policy.apex.context.parameters.LockManagerParameters;
39 import org.onap.policy.apex.context.parameters.PersistorParameters;
40 import org.onap.policy.apex.context.parameters.SchemaHelperParameters;
41 import org.onap.policy.apex.context.parameters.SchemaParameters;
42 import org.onap.policy.apex.core.engine.EngineParameters;
43 import org.onap.policy.apex.core.engine.ExecutorParameters;
44 import org.onap.policy.apex.core.engine.TaskParameters;
45 import org.onap.policy.common.parameters.ParameterGroup;
46 import org.onap.policy.common.parameters.ParameterRuntimeException;
47 import org.onap.policy.common.utils.coder.CoderException;
48 import org.onap.policy.common.utils.coder.StandardCoder;
49 import org.slf4j.ext.XLogger;
50 import org.slf4j.ext.XLoggerFactory;
51
52 /**
53  * This class deserializes engine service parameters from JSON format. The class produces an
54  * {@link EngineServiceParameters} instance from incoming JSON read from a configuration file in JSON format.
55  *
56  * @author Liam Fallon (liam.fallon@ericsson.com)
57  */
58 public class EngineServiceParametersJsonAdapter
59                 implements JsonSerializer<EngineParameters>, JsonDeserializer<EngineParameters> {
60     private static final XLogger LOGGER = XLoggerFactory.getXLogger(EngineServiceParametersJsonAdapter.class);
61
62     private static final String PARAMETER_CLASS_NAME = "parameterClassName";
63
64     // @formatter:off
65     private static final String CONTEXT_PARAMETERS      = "contextParameters";
66     private static final String DISTRIBUTOR_PARAMETERS  = "distributorParameters";
67     private static final String LOCK_MANAGER_PARAMETERS = "lockManagerParameters";
68     private static final String PERSISTOR_PARAMETERS    = "persistorParameters";
69     private static final String SCHEMA_PARAMETERS       = "schemaParameters";
70     private static final String EXECUTOR_PARAMETERS     = "executorParameters";
71     // @formatter:on
72
73     private static StandardCoder standardCoder = new StandardCoder();
74
75     /**
76      * {@inheritDoc}.
77      */
78     @Override
79     public JsonElement serialize(final EngineParameters src, final Type typeOfSrc,
80                     final JsonSerializationContext context) {
81         final String returnMessage = "serialization of Apex parameters to Json is not supported";
82         LOGGER.error(returnMessage);
83         throw new ParameterRuntimeException(returnMessage);
84     }
85
86     /**
87      * {@inheritDoc}.
88      */
89     @Override
90     public EngineParameters deserialize(final JsonElement json, final Type typeOfT,
91                     final JsonDeserializationContext context) {
92         final JsonObject engineParametersJsonObject = json.getAsJsonObject();
93
94         final EngineParameters engineParameters = new EngineParameters();
95
96         // Deserialise context parameters, they may be a subclass of the ContextParameters class
97         engineParameters.setContextParameters(
98                         (ContextParameters) context.deserialize(engineParametersJsonObject, ContextParameters.class));
99
100         // Context parameter wrangling
101         getContextParameters(engineParametersJsonObject, engineParameters, context);
102
103         // Executor parameter wrangling
104         getExecutorParameters(engineParametersJsonObject, engineParameters, context);
105
106         // Task parameter wrangling
107         getTaskParametersList(engineParametersJsonObject, engineParameters);
108         return engineParameters;
109     }
110
111     /**
112      * Method to get the task parameters list for Apex.
113      *
114      * @param engineParametersJsonObject The input JSON
115      * @param engineParameters The output parameters
116      */
117     private void getTaskParametersList(JsonObject engineParametersJsonObject, EngineParameters engineParameters) {
118         final JsonElement parametersElement = engineParametersJsonObject.get("taskParameters");
119
120         // configurable parameters are optional so if the element does not exist, just return
121         if (parametersElement == null) {
122             return;
123         }
124         List<TaskParameters> parametersList = new ArrayList<>();
125         parametersElement.getAsJsonArray().forEach(taskParam -> {
126             TaskParameters parameters = null;
127             try {
128                 parameters = standardCoder.decode(standardCoder.encode(taskParam), TaskParameters.class);
129             } catch (CoderException e) {
130                 throw new ParameterRuntimeException("Error reading taskParameters from the config json provided.");
131             }
132             parametersList.add(parameters);
133         });
134         engineParameters.setTaskParameters(parametersList);
135     }
136
137     /**
138      * Get the context parameters for Apex.
139      *
140      * @param engineParametersJsonObject The input JSON
141      * @param engineParameters The output parameters
142      * @param context the JSON context
143      */
144     private void getContextParameters(final JsonObject engineParametersJsonObject,
145                     final EngineParameters engineParameters, final JsonDeserializationContext context) {
146         final JsonElement contextParametersElement = engineParametersJsonObject.get(CONTEXT_PARAMETERS);
147
148         // Context parameters are optional so if the element does not exist, just return
149         if (contextParametersElement == null) {
150             return;
151         }
152
153         // We do this because the JSON parameters may be for a subclass of ContextParameters
154         final ContextParameters contextParameters = (ContextParameters) deserializeParameters(CONTEXT_PARAMETERS,
155                         contextParametersElement, context);
156
157         // We know this will work because if the context parameters was not a Json object, the
158         // previous deserializeParameters() call would not have worked
159         final JsonObject contextParametersObject = engineParametersJsonObject.get(CONTEXT_PARAMETERS).getAsJsonObject();
160
161         // Now get the distributor, lock manager, and persistence parameters
162         final JsonElement distributorParametersElement = contextParametersObject.get(DISTRIBUTOR_PARAMETERS);
163         if (distributorParametersElement != null) {
164             contextParameters.setDistributorParameters((DistributorParameters) deserializeParameters(
165                             DISTRIBUTOR_PARAMETERS, distributorParametersElement, context));
166         }
167
168         final JsonElement lockManagerParametersElement = contextParametersObject.get(LOCK_MANAGER_PARAMETERS);
169         if (lockManagerParametersElement != null) {
170             contextParameters.setLockManagerParameters((LockManagerParameters) deserializeParameters(
171                             LOCK_MANAGER_PARAMETERS, lockManagerParametersElement, context));
172         }
173
174         final JsonElement persistorParametersElement = contextParametersObject.get(PERSISTOR_PARAMETERS);
175         if (persistorParametersElement != null) {
176             contextParameters.setPersistorParameters((PersistorParameters) deserializeParameters(PERSISTOR_PARAMETERS,
177                             persistorParametersElement, context));
178         }
179
180         // Schema Handler parameter wrangling
181         getSchemaHandlerParameters(contextParametersObject, contextParameters, context);
182
183         // Get the engine plugin parameters
184         engineParameters.setContextParameters(contextParameters);
185     }
186
187     /**
188      * Get the executor parameters for Apex.
189      *
190      * @param engineParametersJsonObject The input JSON
191      * @param engineParameters The output parameters
192      * @param context the JSON context
193      */
194     private void getExecutorParameters(final JsonObject engineParametersJsonObject,
195                     final EngineParameters engineParameters, final JsonDeserializationContext context) {
196         final JsonElement executorParametersElement = engineParametersJsonObject.get(EXECUTOR_PARAMETERS);
197
198         // Executor parameters are mandatory so if the element does not exist throw an exception
199         if (executorParametersElement == null) {
200             final String returnMessage = "no \"" + EXECUTOR_PARAMETERS
201                             + "\" entry found in parameters, at least one executor parameter entry must be specified";
202             LOGGER.error(returnMessage);
203             throw new ParameterRuntimeException(returnMessage);
204         }
205
206         // Deserialize the executor parameters
207         final JsonObject executorParametersJsonObject = engineParametersJsonObject.get(EXECUTOR_PARAMETERS)
208                         .getAsJsonObject();
209
210         for (final Entry<String, JsonElement> executorEntries : executorParametersJsonObject.entrySet()) {
211             final ExecutorParameters executorParameters = (ExecutorParameters) deserializeParameters(
212                             EXECUTOR_PARAMETERS + ':' + executorEntries.getKey(), executorEntries.getValue(), context);
213             engineParameters.getExecutorParameterMap().put(executorEntries.getKey(), executorParameters);
214         }
215     }
216
217     /**
218      * Get the schema parameters for Apex.
219      *
220      * @param contextParametersJsonObject The input JSON
221      * @param contextParameters The output parameters
222      * @param context the JSON context
223      */
224     private void getSchemaHandlerParameters(final JsonObject contextParametersJsonObject,
225                     final ContextParameters contextParameters, final JsonDeserializationContext context) {
226         final JsonElement schemaParametersElement = contextParametersJsonObject.get(SCHEMA_PARAMETERS);
227
228         // Insert the default Java schema helper
229         contextParameters.getSchemaParameters().getSchemaHelperParameterMap()
230                         .put(SchemaParameters.DEFAULT_SCHEMA_FLAVOUR, new JavaSchemaHelperParameters());
231
232         // Context parameters are optional so if the element does not exist, just return
233         if (schemaParametersElement == null) {
234             return;
235         }
236
237         // Deserialize the executor parameters
238         final JsonObject schemaHelperParametersJsonObject = contextParametersJsonObject.get(SCHEMA_PARAMETERS)
239                         .getAsJsonObject();
240
241         for (final Entry<String, JsonElement> schemaHelperEntries : schemaHelperParametersJsonObject.entrySet()) {
242             contextParameters.getSchemaParameters().getSchemaHelperParameterMap().put(schemaHelperEntries.getKey(),
243                             (SchemaHelperParameters) deserializeParameters(
244                                             SCHEMA_PARAMETERS + ':' + schemaHelperEntries.getKey(),
245                                             schemaHelperEntries.getValue(), context));
246         }
247     }
248
249     /**
250      * Deserialize a parameter object that's a superclass of the AbstractParameters class.
251      *
252      * @param parametersLabel Label to use for error messages
253      * @param parametersElement The JSON object holding the parameters
254      * @param context The GSON context
255      * @return the parameters
256      * @throws ParameterRuntimeException on errors reading the parameters
257      */
258     private ParameterGroup deserializeParameters(final String parametersLabel, final JsonElement parametersElement,
259                     final JsonDeserializationContext context) {
260         JsonObject parametersObject = null;
261
262         // Check that the JSON element is a JSON object
263         if (parametersElement.isJsonObject()) {
264             parametersObject = parametersElement.getAsJsonObject();
265         } else {
266             final String returnMessage = "value of \"" + parametersLabel + "\" entry is not a parameter JSON object";
267             LOGGER.error(returnMessage);
268             throw new ParameterRuntimeException(returnMessage);
269         }
270
271         // Get the parameter class name for instantiation in deserialization
272         final JsonElement parameterClassNameElement = parametersObject.get(PARAMETER_CLASS_NAME);
273         if (parameterClassNameElement == null) {
274             final String returnMessage = "could not find field \"" + PARAMETER_CLASS_NAME + "\" in \"" + parametersLabel
275                             + "\" entry";
276             LOGGER.error(returnMessage);
277             throw new ParameterRuntimeException(returnMessage);
278         }
279
280         // Check the parameter is a JSON primitive
281         if (!parameterClassNameElement.isJsonPrimitive()) {
282             final String returnMessage = "value for field \"" + PARAMETER_CLASS_NAME + "\" of \"" + parametersLabel
283                             + "\" entry is not a plain string";
284             LOGGER.error(returnMessage);
285             throw new ParameterRuntimeException(returnMessage);
286         }
287
288         // Check the parameter has a value
289         final String parameterClassName = parameterClassNameElement.getAsString();
290         if (parameterClassName == null || parameterClassName.trim().length() == 0) {
291             final String returnMessage = "value for field \"" + PARAMETER_CLASS_NAME + "\" in \"" + parametersLabel
292                             + "\" entry is not specified or is blank";
293             LOGGER.error(returnMessage);
294             throw new ParameterRuntimeException(returnMessage);
295         }
296
297         // Deserialize the parameters using GSON
298         ParameterGroup parameters = null;
299         try {
300             parameters = context.deserialize(parametersObject, Class.forName(parameterClassName));
301         } catch (JsonParseException | ClassNotFoundException e) {
302             final String returnMessage = "failed to deserialize the parameters for \"" + parametersLabel + "\" "
303                             + "to parameter class \"" + parameterClassName + "\"\n" + e.getClass().getName() + ": "
304                             + e.getMessage();
305             LOGGER.error(returnMessage, e);
306             throw new ParameterRuntimeException(returnMessage, e);
307         }
308
309         return parameters;
310     }
311 }