07cf7811eba3996205c668a574e6ba2d9202bd58
[policy/apex-pdp.git] / services / services-engine / src / main / java / org / onap / policy / apex / service / parameters / ApexParameters.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  * 
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  * 
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.apex.service.parameters;
22
23 import java.util.Arrays;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.LinkedHashMap;
27 import java.util.Map;
28 import java.util.Map.Entry;
29 import java.util.Set;
30
31 import org.onap.policy.apex.service.parameters.engineservice.EngineServiceParameters;
32 import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerParameters;
33 import org.onap.policy.apex.service.parameters.eventhandler.EventHandlerPeeredMode;
34 import org.onap.policy.common.parameters.GroupValidationResult;
35 import org.onap.policy.common.parameters.ParameterGroup;
36 import org.onap.policy.common.parameters.ValidationStatus;
37 import org.onap.policy.common.utils.validation.ParameterValidationUtils;
38
39 /**
40  * The main container parameter class for an Apex service.
41  * 
42  * <p>The following parameters are defined: <ol> <li>engineServiceParameters: The parameters for the Apex engine service
43  * itself, such as the number of engine threads to run and the deployment port number to use. <li>eventOutputParameters:
44  * A map of parameters for event outputs that Apex will use to emit events. Apex emits events on all outputs
45  * <li>eventInputParameters: A map or parameters for event inputs from which Apex will consume events. Apex reads events
46  * from all its event inputs. </ol>
47  *
48  * @author Liam Fallon (liam.fallon@ericsson.com)
49  */
50 public class ApexParameters implements ParameterGroup {
51     // Parameter group name
52     private String name;
53
54     // Constants for recurring strings
55     private static final String JAVA_PROPERTIES = "javaProperties";
56     private static final String PEER_STRING = "peer ";
57     private static final String EVENT_INPUT_PARAMETERS_STRING = "eventInputParameters";
58     private static final String EVENT_OUTPUT_PARAMETERS_STRING = "eventOutputParameters";
59     private static final String FOR_PEERED_MODE_STRING = " for peered mode ";
60
61     // Properties for the Java JVM
62     private String[][] javaProperties = null;
63
64     // Parameters for the engine service and the engine threads in the engine service
65     private EngineServiceParameters engineServiceParameters;
66
67     // Parameters for the event outputs that Apex will use to send events on its outputs
68     private Map<String, EventHandlerParameters> eventOutputParameters = new LinkedHashMap<>();
69
70     // Parameters for the event inputs that Apex will use to receive events on its inputs
71     private Map<String, EventHandlerParameters> eventInputParameters = new LinkedHashMap<>();
72
73     /**
74      * Constructor to create an apex parameters instance and register the instance with the parameter service.
75      */
76     public ApexParameters() {
77         super();
78
79         // Set the name for the parameters
80         this.name = ApexParameterConstants.MAIN_GROUP_NAME;
81     }
82
83     /**
84      * Gets the parameters for the Apex engine service.
85      *
86      * @return the engine service parameters
87      */
88     public EngineServiceParameters getEngineServiceParameters() {
89         return engineServiceParameters;
90     }
91
92     /**
93      * Sets the engine service parameters.
94      *
95      * @param engineServiceParameters the engine service parameters
96      */
97     public void setEngineServiceParameters(final EngineServiceParameters engineServiceParameters) {
98         this.engineServiceParameters = engineServiceParameters;
99     }
100
101     /**
102      * Gets the event output parameter map.
103      *
104      * @return the parameters for all event outputs
105      */
106     public Map<String, EventHandlerParameters> getEventOutputParameters() {
107         return eventOutputParameters;
108     }
109
110     /**
111      * Sets the event output parameters.
112      *
113      * @param eventOutputParameters the event outputs parameters
114      */
115     public void setEventOutputParameters(final Map<String, EventHandlerParameters> eventOutputParameters) {
116         this.eventOutputParameters = eventOutputParameters;
117     }
118
119     /**
120      * Gets the event input parameter map.
121      *
122      * @return the parameters for all event inputs
123      */
124     public Map<String, EventHandlerParameters> getEventInputParameters() {
125         return eventInputParameters;
126     }
127
128     /**
129      * Sets the event input parameters.
130      *
131      * @param eventInputParameters the event input parameters
132      */
133     public void setEventInputParameters(final Map<String, EventHandlerParameters> eventInputParameters) {
134         this.eventInputParameters = eventInputParameters;
135     }
136
137     @Override
138     public String getName() {
139         return name;
140     }
141
142     @Override
143     public void setName(final String name) {
144         this.name = name;
145     }
146
147     /**
148      * Check if Java properties have been specified.
149      *
150      * @return true if Java properties have been specified
151      */
152     public boolean checkJavaPropertiesSet() {
153         return javaProperties != null && javaProperties.length > 0;
154     }
155
156     /**
157      * Gets the Java properties that have been specified.
158      *
159      * @return the Java properties that have been specified
160      */
161     public String[][] getJavaProperties() {
162         return javaProperties;
163     }
164
165     @Override
166     public GroupValidationResult validate() {
167         GroupValidationResult result = new GroupValidationResult(this);
168
169         validateJavaProperties(result);
170
171         if (engineServiceParameters == null) {
172             result.setResult("engineServiceParameters", ValidationStatus.INVALID,
173                 "engine service parameters are not specified");
174         } else {
175             result.setResult("engineServiceParameters", engineServiceParameters.validate());
176         }
177
178         // Sanity check, we must have an entry in both output and input maps
179         if (eventInputParameters.isEmpty()) {
180             result.setResult(EVENT_INPUT_PARAMETERS_STRING, ValidationStatus.INVALID,
181                 "at least one event input must be specified");
182         }
183
184         if (eventOutputParameters.isEmpty()) {
185             result.setResult(EVENT_OUTPUT_PARAMETERS_STRING, ValidationStatus.INVALID,
186                 "at least one event output must be specified");
187         }
188
189         // Validate that the values of all parameters are ok
190         validateEventHandlerMap(EVENT_INPUT_PARAMETERS_STRING, result, eventInputParameters);
191         validateEventHandlerMap(EVENT_OUTPUT_PARAMETERS_STRING, result, eventOutputParameters);
192
193         // Only do peer mode validate if there are no other errors
194         if (result.isValid()) {
195             for (final EventHandlerPeeredMode peeredMode : EventHandlerPeeredMode.values()) {
196                 validatePeeredMode(result, peeredMode);
197             }
198         }
199
200         return result;
201     }
202
203     /**
204      * This method validates the java properties variable if it is present.
205      *
206      * @param result the result of the validation
207      */
208     private void validateJavaProperties(GroupValidationResult result) {
209         if (javaProperties == null) {
210             return;
211         }
212
213         StringBuilder errorMessageBuilder = new StringBuilder();
214         for (String[] javaProperty : javaProperties) {
215             if (javaProperty == null) {
216                 errorMessageBuilder.append("java properties array entry is null\n");
217             } else if (javaProperty.length != 2) {
218                 errorMessageBuilder.append("java properties array entries must have one key and one value: "
219                     + Arrays.deepToString(javaProperty) + "\n");
220             } else if (!ParameterValidationUtils.validateStringParameter(javaProperty[0])) {
221                 errorMessageBuilder
222                     .append("java properties key is null or blank: " + Arrays.deepToString(javaProperty) + "\n");
223             } else if (!ParameterValidationUtils.validateStringParameter(javaProperty[1])) {
224                 errorMessageBuilder
225                     .append("java properties value is null or blank: " + Arrays.deepToString(javaProperty) + "\n");
226             }
227         }
228
229         if (errorMessageBuilder.length() > 0) {
230             result.setResult(JAVA_PROPERTIES, ValidationStatus.INVALID, errorMessageBuilder.toString());
231         }
232     }
233
234     /**
235      * This method validates the parameters in an event handler map.
236      * 
237      * @param eventHandlerType the type of the event handler to use on error messages
238      * @param result the result object to use to return validation messages
239      * @param parsForValidation The event handler parameters to validate (input or output)
240      */
241     private void validateEventHandlerMap(final String eventHandlerType, final GroupValidationResult result,
242         final Map<String, EventHandlerParameters> parsForValidation) {
243         for (final Entry<String, EventHandlerParameters> parameterEntry : parsForValidation.entrySet()) {
244             if (parameterEntry.getKey() == null || parameterEntry.getKey().trim().isEmpty()) {
245                 result.setResult(eventHandlerType, parameterEntry.getKey(), ValidationStatus.INVALID,
246                     "invalid " + eventHandlerType + " name \"" + parameterEntry.getKey() + "\"");
247             } else if (parameterEntry.getValue() == null) {
248                 result.setResult(eventHandlerType, parameterEntry.getKey(), ValidationStatus.INVALID,
249                     "invalid/Null event input prameters specified for " + eventHandlerType + " name \""
250                         + parameterEntry.getKey() + "\" ");
251             } else {
252                 result.setResult(eventHandlerType, parameterEntry.getKey(), parameterEntry.getValue().validate());
253             }
254
255             parameterEntry.getValue().setName(parameterEntry.getKey());
256
257             // Validate parameters for peered mode settings
258             for (final EventHandlerPeeredMode peeredMode : EventHandlerPeeredMode.values()) {
259                 validatePeeredModeParameters(eventHandlerType, result, parameterEntry, peeredMode);
260             }
261         }
262     }
263
264     /**
265      * Validate parameter values for event handlers in a peered mode.
266      * 
267      * @param eventHandlerType The event handler type we are checking
268      * @param result The result object to which to append any error messages
269      * @param parameterEntry The entry to check the peered mode on
270      * @param peeredMode The mode to check
271      */
272     private void validatePeeredModeParameters(final String eventHandlerType, final GroupValidationResult result,
273         final Entry<String, EventHandlerParameters> parameterEntry, final EventHandlerPeeredMode peeredMode) {
274         final String messagePreamble = "specified peered mode \"" + peeredMode + "\"";
275         final String peer = parameterEntry.getValue().getPeer(peeredMode);
276
277         if (parameterEntry.getValue().isPeeredMode(peeredMode)) {
278             if (peer == null || peer.trim().isEmpty()) {
279                 result.setResult(eventHandlerType, parameterEntry.getKey(), ValidationStatus.INVALID,
280                     messagePreamble + " mandatory parameter not specified or is null");
281             }
282             if (parameterEntry.getValue().getPeerTimeout(peeredMode) < 0) {
283                 result.setResult(eventHandlerType, parameterEntry.getKey(), ValidationStatus.INVALID,
284                     messagePreamble + " timeout value \"" + parameterEntry.getValue().getPeerTimeout(peeredMode)
285                         + "\" is illegal, specify a non-negative timeout value in milliseconds");
286             }
287         } else {
288             if (peer != null) {
289                 result.setResult(eventHandlerType, parameterEntry.getKey(), ValidationStatus.INVALID, messagePreamble
290                     + " peer is illegal on " + eventHandlerType + " \"" + parameterEntry.getKey() + "\" ");
291             }
292             if (parameterEntry.getValue().getPeerTimeout(peeredMode) != 0) {
293                 result.setResult(eventHandlerType, parameterEntry.getKey(), ValidationStatus.INVALID, messagePreamble
294                     + " timeout is illegal on " + eventHandlerType + " \"" + parameterEntry.getKey() + "\"");
295             }
296         }
297     }
298
299     /**
300      * This method validates that the settings are valid for the given peered mode.
301      * 
302      * @param result The result object to which to append any error messages
303      * @param peeredMode The peered mode to check
304      */
305     private void validatePeeredMode(final GroupValidationResult result, final EventHandlerPeeredMode peeredMode) {
306         // Find the input and output event handlers that use this peered mode
307         final Map<String, EventHandlerParameters> inputParametersUsingMode = new HashMap<>();
308         final Map<String, EventHandlerParameters> outputParametersUsingMode = new HashMap<>();
309
310         // Find input and output parameters using this mode
311         for (final Entry<String, EventHandlerParameters> inputParameterEntry : eventInputParameters.entrySet()) {
312             if (inputParameterEntry.getValue().isPeeredMode(peeredMode)) {
313                 inputParametersUsingMode.put(inputParameterEntry.getKey(), inputParameterEntry.getValue());
314             }
315         }
316         for (final Entry<String, EventHandlerParameters> outputParameterEntry : eventOutputParameters.entrySet()) {
317             if (outputParameterEntry.getValue().isPeeredMode(peeredMode)) {
318                 outputParametersUsingMode.put(outputParameterEntry.getKey(), outputParameterEntry.getValue());
319             }
320         }
321
322         // Validate the parameters for each side of the peered mode parameters
323         validatePeeredModePeers(EVENT_INPUT_PARAMETERS_STRING, result, peeredMode, inputParametersUsingMode,
324             outputParametersUsingMode);
325         validatePeeredModePeers(EVENT_OUTPUT_PARAMETERS_STRING, result, peeredMode, outputParametersUsingMode,
326             inputParametersUsingMode);
327     }
328
329     /**
330      * This method validates that the settings are valid for the event handlers on one.
331      * 
332      * @param handlerMapVariableName the variable name of the map on which the paired parameters are being checked
333      * @param result The result object to which to append any error messages
334      * @param leftModeParameters The mode parameters being checked
335      * @param rightModeParameters The mode parameters being referenced by the checked parameters
336      */
337     private void validatePeeredModePeers(final String handlerMapVariableName, final GroupValidationResult result,
338         final EventHandlerPeeredMode peeredMode, final Map<String, EventHandlerParameters> leftModeParameterMap,
339         final Map<String, EventHandlerParameters> rightModeParameterMap) {
340
341         // These sets are used to check for duplicate references on the both sides
342         final Set<String> leftCheckDuplicateSet = new HashSet<>();
343         final Set<String> rightCheckDuplicateSet = new HashSet<>();
344
345         // Check for missing peers, all peers are set because we have checked them previously so no
346         // need for null checks
347         for (final Entry<String, EventHandlerParameters> leftModeParameterEntry : leftModeParameterMap.entrySet()) {
348             final String leftSidePeer = leftModeParameterEntry.getValue().getPeer(peeredMode);
349
350             final EventHandlerParameters leftModeParameters = leftModeParameterEntry.getValue();
351             final EventHandlerParameters rightModeParameters = rightModeParameterMap.get(leftSidePeer);
352
353             // Check that the peer reference is OK
354             if (rightModeParameters == null) {
355                 result.setResult(handlerMapVariableName, leftModeParameterEntry.getKey(), ValidationStatus.INVALID,
356                     PEER_STRING + '"' + leftModeParameters.getPeer(peeredMode) + FOR_PEERED_MODE_STRING + peeredMode
357                         + " does not exist or is not defined with the same peered mode");
358                 continue;
359             }
360
361             // Now check that the right side peer is the left side event handler
362             final String rightSidePeer = rightModeParameters.getPeer(peeredMode);
363             if (!rightSidePeer.equals(leftModeParameterEntry.getKey())) {
364                 result.setResult(handlerMapVariableName, leftModeParameterEntry.getKey(), ValidationStatus.INVALID,
365                     PEER_STRING + '"' + leftModeParameters.getPeer(peeredMode) + FOR_PEERED_MODE_STRING + peeredMode
366                         + ", value \"" + rightSidePeer + "\" on peer \"" + leftSidePeer
367                         + "\" does not equal event handler \"" + leftModeParameterEntry.getKey() + "\"");
368             } else {
369                 // Check for duplicates
370                 if (!leftCheckDuplicateSet.add(leftSidePeer)) {
371                     result.setResult(handlerMapVariableName, leftModeParameterEntry.getKey(), ValidationStatus.INVALID,
372                         PEER_STRING + '"' + leftModeParameters.getPeer(peeredMode) + FOR_PEERED_MODE_STRING + peeredMode
373                             + ", peer value \"" + leftSidePeer + "\" on event handler \""
374                             + leftModeParameterEntry.getKey() + "\" is used more than once");
375                 }
376                 if (!rightCheckDuplicateSet.add(rightSidePeer)) {
377                     result.setResult(handlerMapVariableName, leftModeParameterEntry.getKey(), ValidationStatus.INVALID,
378                         PEER_STRING + '"' + leftModeParameters.getPeer(peeredMode) + FOR_PEERED_MODE_STRING + peeredMode
379                             + ", peer value \"" + rightSidePeer + "\" on peer \"" + leftSidePeer
380                             + "\" on event handler \"" + leftModeParameterEntry.getKey() + "\" is used more than once");
381                 }
382             }
383
384             if (!crossCheckPeeredTimeoutValues(leftModeParameters, rightModeParameters, peeredMode)) {
385                 result.setResult(handlerMapVariableName, leftModeParameterEntry.getKey(), ValidationStatus.INVALID,
386                     PEER_STRING + '"' + leftModeParameters.getPeer(peeredMode) + FOR_PEERED_MODE_STRING + peeredMode
387                         + " timeout " + leftModeParameters.getPeerTimeout(peeredMode) + " on event handler \""
388                         + leftModeParameters.getName() + "\" does not equal timeout "
389                         + rightModeParameters.getPeerTimeout(peeredMode) + " on event handler \""
390                         + rightModeParameters.getName() + "\"");
391
392             }
393         }
394     }
395
396     /**
397      * Validate the timeout values on two peers.
398      * 
399      * @param leftModeParameters The parameters of the left hand peer
400      * @param peeredMode The peered mode being checked
401      * @return true if the timeout values are cross checked as being OK
402      */
403     private boolean crossCheckPeeredTimeoutValues(final EventHandlerParameters leftModeParameters,
404         final EventHandlerParameters rightModeParameters, final EventHandlerPeeredMode peeredMode) {
405         // Cross-set the timeouts if they are not specified
406         if (leftModeParameters.getPeerTimeout(peeredMode) != 0) {
407             if (rightModeParameters.getPeerTimeout(peeredMode) != 0) {
408                 if (leftModeParameters.getPeerTimeout(peeredMode) != rightModeParameters.getPeerTimeout(peeredMode)) {
409                     return false;
410                 }
411             } else {
412                 rightModeParameters.setPeerTimeout(peeredMode, leftModeParameters.getPeerTimeout(peeredMode));
413             }
414         } else {
415             if (rightModeParameters.getPeerTimeout(peeredMode) != 0) {
416                 leftModeParameters.setPeerTimeout(peeredMode, rightModeParameters.getPeerTimeout(peeredMode));
417             }
418         }
419         return true;
420     }
421 }