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