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