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