Changes for checkstyle 8.32
[policy/apex-pdp.git] / services / services-engine / src / main / java / org / onap / policy / apex / service / engine / event / impl / jsonprotocolplugin / Apex2JsonEventConverter.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019 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.engine.event.impl.jsonprotocolplugin;
23
24 import com.google.gson.Gson;
25 import com.google.gson.GsonBuilder;
26 import com.google.gson.JsonElement;
27 import com.google.gson.JsonObject;
28 import com.google.gson.internal.LinkedTreeMap;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.List;
32 import org.onap.policy.apex.context.SchemaHelper;
33 import org.onap.policy.apex.context.impl.schema.SchemaHelperFactory;
34 import org.onap.policy.apex.model.basicmodel.service.ModelService;
35 import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
36 import org.onap.policy.apex.model.eventmodel.concepts.AxEvents;
37 import org.onap.policy.apex.model.eventmodel.concepts.AxField;
38 import org.onap.policy.apex.service.engine.event.ApexEvent;
39 import org.onap.policy.apex.service.engine.event.ApexEventException;
40 import org.onap.policy.apex.service.engine.event.ApexEventProtocolConverter;
41 import org.onap.policy.apex.service.engine.event.ApexEventRuntimeException;
42 import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters;
43 import org.slf4j.ext.XLogger;
44 import org.slf4j.ext.XLoggerFactory;
45
46 /**
47  * The Class Apex2JSONEventConverter converts {@link ApexEvent} instances to and from JSON string representations of
48  * Apex events.
49  *
50  * @author Liam Fallon (liam.fallon@ericsson.com)
51  */
52 public class Apex2JsonEventConverter implements ApexEventProtocolConverter {
53     private static final XLogger LOGGER = XLoggerFactory.getXLogger(Apex2JsonEventConverter.class);
54
55     // Recurring string constants
56     private static final String ERROR_PARSING = "error parsing ";
57     private static final String ERROR_CODING = "error coding ";
58
59     // The parameters for the JSON event protocol
60     private JsonEventProtocolParameters jsonPars;
61
62     /**
63      * {@inheritDoc}.
64      */
65     @Override
66     public void init(final EventProtocolParameters parameters) {
67         // Check and get the JSON parameters
68         if (!(parameters instanceof JsonEventProtocolParameters)) {
69             final String errorMessage = "specified consumer properties are not applicable to the JSON event protocol";
70             LOGGER.warn(errorMessage);
71             throw new ApexEventRuntimeException(errorMessage);
72         }
73
74         jsonPars = (JsonEventProtocolParameters) parameters;
75     }
76
77     /**
78      * {@inheritDoc}.
79      */
80     @Override
81     public List<ApexEvent> toApexEvent(final String eventName, final Object eventObject) throws ApexEventException {
82         // Check the event eventObject
83         if (eventObject == null) {
84             LOGGER.warn("event processing failed, event is null");
85             throw new ApexEventException("event processing failed, event is null");
86         }
87
88         // Cast the event to a string, if our conversion is correctly configured, this cast should
89         // always work
90         String jsonEventString = null;
91         try {
92             jsonEventString = (String) eventObject;
93         } catch (final Exception e) {
94             final String errorMessage = "error converting event \"" + eventObject + "\" to a string";
95             LOGGER.debug(errorMessage, e);
96             throw new ApexEventRuntimeException(errorMessage, e);
97         }
98
99         // The list of events we will return
100         final List<ApexEvent> eventList = new ArrayList<>();
101
102         try {
103             // We may have a single JSON object with a single event or an array of JSON objects
104             final Object decodedJsonObject = new GsonBuilder().serializeNulls().create().fromJson(jsonEventString,
105                             Object.class);
106
107             // Check if we have a list of objects
108             if (decodedJsonObject instanceof List) {
109                 eventList.addAll(decodeEventList(eventName, jsonEventString, decodedJsonObject));
110             } else {
111                 eventList.add(jsonStringApexEvent(eventName, jsonEventString));
112             }
113         } catch (final Exception e) {
114             final String errorString = "Failed to unmarshal JSON event: " + e.getMessage() + ", event="
115                             + jsonEventString;
116             LOGGER.warn(errorString, e);
117             throw new ApexEventException(errorString, e);
118         }
119
120         // Return the list of events we have unmarshalled
121         return eventList;
122     }
123
124     /**
125      * Decode a list of Apex events.
126      *
127      * @param eventName the name of the incoming events
128      * @param jsonEventString the JSON representation of the event list
129      * @param decodedJsonObject The JSON list object
130      * @return a list of decoded Apex events
131      * @throws ApexEventException on event decoding errors
132      */
133     private Collection<? extends ApexEvent> decodeEventList(final String eventName, String jsonEventString,
134                     final Object decodedJsonObject) throws ApexEventException {
135
136         final List<ApexEvent> eventList = new ArrayList<>();
137
138         // Check if it's a list of JSON objects or a list of strings
139         @SuppressWarnings("unchecked")
140         final List<Object> decodedJsonList = (List<Object>) decodedJsonObject;
141
142         // Decode each of the list elements in sequence
143         for (final Object jsonListObject : decodedJsonList) {
144             if (jsonListObject instanceof String) {
145                 eventList.add(jsonStringApexEvent(eventName, (String) jsonListObject));
146             } else if (jsonListObject instanceof JsonObject) {
147                 eventList.add(jsonObject2ApexEvent(eventName, (JsonObject) jsonListObject));
148             } else if (jsonListObject instanceof LinkedTreeMap) {
149                 eventList.add(jsonObject2ApexEvent(eventName, new Gson().toJsonTree(jsonListObject).getAsJsonObject()));
150             } else {
151                 throw new ApexEventException("incoming event (" + jsonEventString
152                                 + ") is a JSON object array containing an invalid object " + jsonListObject);
153             }
154         }
155
156         return eventList;
157     }
158
159     /**
160      * {@inheritDoc}.
161      */
162     @Override
163     public Object fromApexEvent(final ApexEvent apexEvent) throws ApexEventException {
164         // Check the Apex event
165         if (apexEvent == null) {
166             LOGGER.warn("event processing failed, Apex event is null");
167             throw new ApexEventException("event processing failed, Apex event is null");
168         }
169
170         if (jsonPars.getPojoField() == null) {
171             return fromApexEventWithFields(apexEvent);
172         } else {
173             return fromApexEventPojo(apexEvent);
174         }
175     }
176
177     /**
178      * Serialise an Apex event to a JSON string field by field.
179      *
180      * @param apexEvent the event to Serialise
181      * @return the Serialise event as JSON
182      * @throws ApexEventException exceptions on marshaling to JSON
183      */
184     private Object fromApexEventWithFields(final ApexEvent apexEvent) {
185         // Get the event definition for the event from the model service
186         final AxEvent eventDefinition = ModelService.getModel(AxEvents.class).get(apexEvent.getName(),
187                         apexEvent.getVersion());
188
189         // Use a GSON Json object to marshal the Apex event to JSON
190         final Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create();
191         final JsonObject jsonObject = new JsonObject();
192
193         jsonObject.addProperty(ApexEvent.NAME_HEADER_FIELD, apexEvent.getName());
194         jsonObject.addProperty(ApexEvent.VERSION_HEADER_FIELD, apexEvent.getVersion());
195         jsonObject.addProperty(ApexEvent.NAMESPACE_HEADER_FIELD, apexEvent.getNameSpace());
196         jsonObject.addProperty(ApexEvent.SOURCE_HEADER_FIELD, apexEvent.getSource());
197         jsonObject.addProperty(ApexEvent.TARGET_HEADER_FIELD, apexEvent.getTarget());
198
199         if (apexEvent.getExceptionMessage() != null) {
200             jsonObject.addProperty(ApexEvent.EXCEPTION_MESSAGE_HEADER_FIELD, apexEvent.getExceptionMessage());
201         }
202
203         for (final AxField eventField : eventDefinition.getFields()) {
204             final String fieldName = eventField.getKey().getLocalName();
205
206             if (!apexEvent.containsKey(fieldName)) {
207                 if (!eventField.getOptional()) {
208                     final String errorMessage = ERROR_CODING + eventDefinition.getId() + " event to Json. " + "Field \""
209                                     + fieldName + "\" is missing, but is mandatory. Fields: " + apexEvent;
210                     LOGGER.debug(errorMessage);
211                     throw new ApexEventRuntimeException(errorMessage);
212                 }
213                 continue;
214             }
215
216             final Object fieldValue = apexEvent.get(fieldName);
217
218             // Get the schema helper
219             final SchemaHelper fieldSchemaHelper = new SchemaHelperFactory().createSchemaHelper(eventField.getKey(),
220                             eventField.getSchema());
221             jsonObject.add(fieldName, (JsonElement) fieldSchemaHelper.marshal2Object(fieldValue));
222         }
223
224         // Output JSON string in a pretty format
225         return gson.toJson(jsonObject);
226     }
227
228     /**
229      * Serialise an Apex event to a JSON string as a single POJO.
230      *
231      * @param apexEvent the event to Serialise
232      * @return the Serialise event as JSON
233      * @throws ApexEventException exceptions on marshaling to JSON
234      */
235     private Object fromApexEventPojo(ApexEvent apexEvent) throws ApexEventException {
236         // Get the event definition for the event from the model service
237         final AxEvent eventDefinition = ModelService.getModel(AxEvents.class).get(apexEvent.getName(),
238                         apexEvent.getVersion());
239
240         if (eventDefinition.getFields().isEmpty()) {
241             final String errorMessage = ERROR_CODING + eventDefinition.getId() + " event to Json, Field "
242                             + jsonPars.getPojoField() + " not found, no fields defined on event.";
243             LOGGER.debug(errorMessage);
244             throw new ApexEventException(errorMessage);
245         }
246
247         if (eventDefinition.getFields().size() != 1) {
248             final String errorMessage = ERROR_CODING + eventDefinition.getId() + " event to Json, Field "
249                             + jsonPars.getPojoField() + ", "
250                             + " one and only one field may be defined on a POJO event definition.";
251             LOGGER.debug(errorMessage);
252             throw new ApexEventException(errorMessage);
253         }
254
255         AxField pojoFieldDefinition = eventDefinition.getFields().iterator().next();
256
257         if (!jsonPars.getPojoField().equals(pojoFieldDefinition.getKey().getLocalName())) {
258             final String errorMessage = ERROR_CODING + eventDefinition.getId() + " event to Json. Field "
259                             + jsonPars.getPojoField() + " not found on POJO event definition.";
260             LOGGER.debug(errorMessage);
261             throw new ApexEventException(errorMessage);
262         }
263
264         final Object fieldValue = apexEvent.get(jsonPars.getPojoField());
265
266         // Get the schema helper
267         final SchemaHelper fieldSchemaHelper = new SchemaHelperFactory()
268                         .createSchemaHelper(pojoFieldDefinition.getKey(), pojoFieldDefinition.getSchema());
269
270         return fieldSchemaHelper.marshal2String(fieldValue);
271     }
272
273     /**
274      * This method converts a JSON object into an Apex event.
275      *
276      * @param eventName the name of the event
277      * @param jsonEventString the JSON string that holds the event
278      * @return the apex event that we have converted the JSON object into
279      * @throws ApexEventException thrown on unmarshaling exceptions
280      */
281     private ApexEvent jsonStringApexEvent(final String eventName, final String jsonEventString)
282                     throws ApexEventException {
283         // Use GSON to read the event string
284         final JsonObject jsonObject = new GsonBuilder().serializeNulls().create().fromJson(jsonEventString,
285                         JsonObject.class);
286
287         if (jsonObject == null || !jsonObject.isJsonObject()) {
288             throw new ApexEventException(
289                             "incoming event (" + jsonEventString + ") is not a JSON object or an JSON object array");
290         }
291
292         return jsonObject2ApexEvent(eventName, jsonObject);
293     }
294
295     /**
296      * This method converts a JSON object into an Apex event.
297      *
298      * @param eventName the name of the event
299      * @param jsonObject the JSON object that holds the event
300      * @return the apex event that we have converted the JSON object into
301      * @throws ApexEventException thrown on unmarshaling exceptions
302      */
303     private ApexEvent jsonObject2ApexEvent(final String eventName, final JsonObject jsonObject)
304                     throws ApexEventException {
305         // Process the mandatory Apex header
306         final ApexEvent apexEvent = processApexEventHeader(eventName, jsonObject);
307
308         // Get the event definition for the event from the model service
309         final AxEvent eventDefinition = ModelService.getModel(AxEvents.class).get(apexEvent.getName(),
310                         apexEvent.getVersion());
311
312         if (jsonPars.getPojoField() == null) {
313             jsonObject2ApexEventWithFields(jsonObject, apexEvent, eventDefinition);
314         } else {
315             jsonObject2ApexEventPojo(jsonObject, apexEvent, eventDefinition);
316         }
317
318         return apexEvent;
319     }
320
321     /**
322      * Decode an Apex event field by field.
323      *
324      * @param jsonObject the JSON representation of the event
325      * @param apexEvent the incoming event header
326      * @param eventDefinition the definition of the event from the model
327      * @throws ApexEventException on decode errors
328      */
329     private void jsonObject2ApexEventWithFields(final JsonObject jsonObject, final ApexEvent apexEvent,
330                     final AxEvent eventDefinition) throws ApexEventException {
331         // Iterate over the input fields in the event
332         for (final AxField eventField : eventDefinition.getFields()) {
333             final String fieldName = eventField.getKey().getLocalName();
334             if (!hasJsonField(jsonObject, fieldName)) {
335                 if (!eventField.getOptional()) {
336                     final String errorMessage = ERROR_PARSING + eventDefinition.getId() + " event from Json. "
337                                     + "Field \"" + fieldName + "\" is missing, but is mandatory.";
338                     LOGGER.debug(errorMessage);
339                     throw new ApexEventException(errorMessage);
340                 }
341                 continue;
342             }
343
344             final JsonElement fieldValue = getJsonField(jsonObject, fieldName, null, !eventField.getOptional());
345
346             if (fieldValue != null && !fieldValue.isJsonNull()) {
347                 // Get the schema helper
348                 final SchemaHelper fieldSchemaHelper = new SchemaHelperFactory().createSchemaHelper(eventField.getKey(),
349                                 eventField.getSchema());
350                 apexEvent.put(fieldName, fieldSchemaHelper.createNewInstance(fieldValue));
351             } else {
352                 apexEvent.put(fieldName, null);
353             }
354         }
355     }
356
357     /**
358      * Decode an Apex event as a single POJO.
359      *
360      * @param jsonObject the JSON representation of the event
361      * @param apexEvent the incoming event header
362      * @param eventDefinition the definition of the event from the model
363      * @throws ApexEventException on decode errors
364      */
365     private void jsonObject2ApexEventPojo(JsonObject jsonObject, ApexEvent apexEvent, AxEvent eventDefinition)
366                     throws ApexEventException {
367
368         if (eventDefinition.getFields().isEmpty()) {
369             final String errorMessage = ERROR_PARSING + eventDefinition.getId() + " event from Json, Field "
370                             + jsonPars.getPojoField() + " not found, no fields defined on event.";
371             LOGGER.debug(errorMessage);
372             throw new ApexEventException(errorMessage);
373         }
374
375         if (eventDefinition.getFields().size() != 1) {
376             final String errorMessage = ERROR_PARSING + eventDefinition.getId() + " event from Json, Field "
377                             + jsonPars.getPojoField()
378                             + ", one and only one field may be defined on a POJO event definition.";
379             LOGGER.debug(errorMessage);
380             throw new ApexEventException(errorMessage);
381         }
382
383         AxField pojoFieldDefinition = eventDefinition.getFields().iterator().next();
384
385         if (!jsonPars.getPojoField().equals(pojoFieldDefinition.getKey().getLocalName())) {
386             final String errorMessage = ERROR_PARSING + eventDefinition.getId() + " event from Json. Field "
387                             + jsonPars.getPojoField() + " not found on POJO event definition.";
388             LOGGER.debug(errorMessage);
389             throw new ApexEventException(errorMessage);
390         }
391
392         // Get the schema helper
393         final SchemaHelper fieldSchemaHelper = new SchemaHelperFactory()
394                         .createSchemaHelper(pojoFieldDefinition.getKey(), pojoFieldDefinition.getSchema());
395         apexEvent.put(jsonPars.getPojoField(), fieldSchemaHelper.createNewInstance(jsonObject));
396     }
397
398     /**
399      * This method processes the event header of an Apex event.
400      *
401      * @param parameterEventName the name of the event from the parameters
402      * @param jsonObject the JSON object containing the JSON representation of the incoming event
403      * @return an apex event constructed using the header fields of the event
404      * @throws ApexEventRuntimeException the apex event runtime exception
405      * @throws ApexEventException on invalid events with missing header fields
406      */
407     private ApexEvent processApexEventHeader(final String parameterEventName, final JsonObject jsonObject)
408                     throws ApexEventException {
409
410         final String eventName = getHeaderName(jsonObject, parameterEventName);
411
412         String eventVersion = getHeaderVersion(jsonObject);
413
414         final AxEvent eventDefinition = ModelService.getModel(AxEvents.class).get(eventName, eventVersion);
415
416         if (eventDefinition == null) {
417             if (eventVersion == null) {
418                 throw new ApexEventRuntimeException(
419                                 "an event definition for an event named \"" + eventName + "\" not found in Apex model");
420             } else {
421                 throw new ApexEventRuntimeException("an event definition for an event named \"" + eventName
422                                 + "\" with version \"" + eventVersion + "\" not found in Apex model");
423             }
424         }
425
426         // Use the defined event version if no version is specified on the incoming fields
427         if (eventVersion == null) {
428             eventVersion = eventDefinition.getKey().getVersion();
429         }
430
431         final String eventNamespace = getHeaderNamespace(jsonObject, eventName, eventDefinition);
432         final String eventSource = getHeaderSource(jsonObject, eventDefinition);
433         final String eventTarget = getHeaderTarget(jsonObject, eventDefinition);
434
435         return new ApexEvent(eventName, eventVersion, eventNamespace, eventSource, eventTarget);
436     }
437
438     /**
439      * Determine the name field of the event header.
440      *
441      * @param jsonObject the event in JSON format
442      * @param parameterEventName the configured event name from the parameters
443      * @return the event name to use on the event header
444      */
445     private String getHeaderName(final JsonObject jsonObject, final String parameterEventName) {
446         final String jsonEventName = getJsonStringField(jsonObject, ApexEvent.NAME_HEADER_FIELD,
447                         jsonPars.getNameAlias(), ApexEvent.NAME_REGEXP, false);
448
449         // Check that an event name has been specified
450         if (jsonEventName == null && parameterEventName == null) {
451             throw new ApexEventRuntimeException(
452                             "event received without mandatory parameter \"name\" on configuration or on event");
453         }
454
455         // Check if an event name was specified on the event parameters
456         if (jsonEventName != null) {
457             if (parameterEventName != null && !parameterEventName.equals(jsonEventName)) {
458                 LOGGER.warn("The incoming event name \"{}\" does not match the configured event name \"{}\","
459                                 + " using configured event name", jsonEventName, parameterEventName);
460             }
461             return jsonEventName;
462         } else {
463             return parameterEventName;
464         }
465     }
466
467     /**
468      * Determine the version field of the event header.
469      *
470      * @param jsonObject the event in JSON format
471      * @return the event version
472      */
473     private String getHeaderVersion(final JsonObject jsonObject) {
474         // Find the event definition in the model service. If version is null, the newest event
475         // definition in the model service is used
476         return getJsonStringField(jsonObject, ApexEvent.VERSION_HEADER_FIELD, jsonPars.getVersionAlias(),
477                         ApexEvent.VERSION_REGEXP, false);
478     }
479
480     /**
481      * Determine the name space field of the event header.
482      *
483      * @param jsonObject the event in JSON format
484      * @param eventName the name of the event
485      * @param eventDefinition the definition of the event structure
486      * @return the event version
487      */
488     private String getHeaderNamespace(final JsonObject jsonObject, final String name, final AxEvent eventDefinition) {
489         // Check the name space is OK if it is defined, if not, use the name space from the model
490         String namespace = getJsonStringField(jsonObject, ApexEvent.NAMESPACE_HEADER_FIELD,
491                         jsonPars.getNameSpaceAlias(), ApexEvent.NAMESPACE_REGEXP, false);
492         if (namespace != null) {
493             if (!namespace.equals(eventDefinition.getNameSpace())) {
494                 throw new ApexEventRuntimeException("namespace \"" + namespace + "\" on event \"" + name
495                                 + "\" does not match namespace \"" + eventDefinition.getNameSpace()
496                                 + "\" for that event in the Apex model");
497             }
498         } else {
499             namespace = eventDefinition.getNameSpace();
500         }
501         return namespace;
502     }
503
504     /**
505      * Determine the source field of the event header.
506      *
507      * @param jsonObject the event in JSON format
508      * @param eventDefinition the definition of the event structure
509      * @return the event version
510      */
511     private String getHeaderSource(final JsonObject jsonObject, final AxEvent eventDefinition) {
512         // For source, use the defined source only if the source is not found on the incoming event
513         String source = getJsonStringField(jsonObject, ApexEvent.SOURCE_HEADER_FIELD, jsonPars.getSourceAlias(),
514                         ApexEvent.SOURCE_REGEXP, false);
515         if (source == null) {
516             source = eventDefinition.getSource();
517         }
518         return source;
519     }
520
521     /**
522      * Determine the target field of the event header.
523      *
524      * @param jsonObject the event in JSON format
525      * @param eventDefinition the definition of the event structure
526      * @return the event version
527      */
528     private String getHeaderTarget(final JsonObject jsonObject, final AxEvent eventDefinition) {
529         // For target, use the defined source only if the source is not found on the incoming event
530         String target = getJsonStringField(jsonObject, ApexEvent.TARGET_HEADER_FIELD, jsonPars.getTargetAlias(),
531                         ApexEvent.TARGET_REGEXP, false);
532         if (target == null) {
533             target = eventDefinition.getTarget();
534         }
535         return target;
536     }
537
538     /**
539      * This method gets an event string field from a JSON object.
540      *
541      * @param jsonObject the JSON object containing the JSON representation of the incoming event
542      * @param fieldName the field name to find in the event
543      * @param fieldAlias the alias for the field to find in the event, overrides the field name if it is not null
544      * @param fieldRegexp the regular expression to check the field against for validity
545      * @param mandatory true if the field is mandatory
546      * @return the value of the field in the JSON object or null if the field is optional
547      * @throws ApexEventRuntimeException the apex event runtime exception
548      */
549     private String getJsonStringField(final JsonObject jsonObject, final String fieldName, final String fieldAlias,
550                     final String fieldRegexp, final boolean mandatory) {
551         // Get the JSON field for the string field
552         final JsonElement jsonField = getJsonField(jsonObject, fieldName, fieldAlias, mandatory);
553
554         // Null strings are allowed
555         if (jsonField == null || jsonField.isJsonNull()) {
556             return null;
557         }
558
559         // Check if this is a string field
560         String fieldValueString = null;
561         try {
562             fieldValueString = jsonField.getAsString();
563         } catch (final Exception e) {
564             // The element is not a string so throw an error
565             throw new ApexEventRuntimeException("field \"" + fieldName + "\" with type \""
566                             + jsonField.getClass().getName() + "\" is not a string value", e);
567         }
568
569         // Is regular expression checking required
570         if (fieldRegexp == null) {
571             return fieldValueString;
572         }
573
574         // Check the event field against its regular expression
575         if (!fieldValueString.matches(fieldRegexp)) {
576             throw new ApexEventRuntimeException(
577                             "field \"" + fieldName + "\" with value \"" + fieldValueString + "\" is invalid");
578         }
579
580         return fieldValueString;
581     }
582
583     /**
584      * This method gets an event field from a JSON object.
585      *
586      * @param jsonObject the JSON object containing the JSON representation of the incoming event
587      * @param fieldName the field name to find in the event
588      * @param fieldAlias the alias for the field to find in the event, overrides the field name if it is not null
589      * @param mandatory true if the field is mandatory
590      * @return the value of the field in the JSON object or null if the field is optional
591      * @throws ApexEventRuntimeException the apex event runtime exception
592      */
593     private JsonElement getJsonField(final JsonObject jsonObject, final String fieldName, final String fieldAlias,
594                     final boolean mandatory) {
595
596         // Check if we should use the alias for this field
597         String fieldToFind = fieldName;
598         if (fieldAlias != null) {
599             fieldToFind = fieldAlias;
600         }
601
602         // Get the event field
603         final JsonElement eventElement = jsonObject.get(fieldToFind);
604         if (eventElement == null) {
605             if (!mandatory) {
606                 return null;
607             } else {
608                 throw new ApexEventRuntimeException("mandatory field \"" + fieldToFind + "\" is missing");
609             }
610         }
611
612         return eventElement;
613     }
614
615     /**
616      * This method if a JSON object has a named field.
617      *
618      * @param jsonObject the JSON object containing the JSON representation of the incoming event
619      * @param fieldName the field name to find in the event
620      * @return true if the field is present
621      * @throws ApexEventRuntimeException the apex event runtime exception
622      */
623     private boolean hasJsonField(final JsonObject jsonObject, final String fieldName) {
624         // check for the field
625         return jsonObject.has(fieldName);
626     }
627 }