976a3ae3d74462e5c55a27b7dd99d48ea26f7419
[policy/apex-pdp.git] / services / services-engine / src / main / java / org / onap / policy / apex / service / engine / event / impl / jsonprotocolplugin / Apex2JsonEventConverter.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019-2021 Nordix Foundation.
5  *  Modifications Copyright (C) 2021-2022 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.impl.schema.SchemaHelperFactory;
34 import org.onap.policy.apex.model.basicmodel.service.ModelService;
35 import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
36 import org.onap.policy.apex.model.eventmodel.concepts.AxEvents;
37 import org.onap.policy.apex.model.eventmodel.concepts.AxField;
38 import org.onap.policy.apex.service.engine.event.ApexEvent;
39 import org.onap.policy.apex.service.engine.event.ApexEventException;
40 import org.onap.policy.apex.service.engine.event.ApexEventProtocolConverter;
41 import org.onap.policy.apex.service.engine.event.ApexEventRuntimeException;
42 import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters;
43 import org.slf4j.ext.XLogger;
44 import org.slf4j.ext.XLoggerFactory;
45
46 /**
47  * The Class Apex2JSONEventConverter converts {@link ApexEvent} instances to and from JSON string representations of
48  * Apex events.
49  *
50  * @author Liam Fallon (liam.fallon@ericsson.com)
51  */
52 public class Apex2JsonEventConverter implements ApexEventProtocolConverter {
53     private static final XLogger LOGGER = XLoggerFactory.getXLogger(Apex2JsonEventConverter.class);
54
55     // Recurring string constants
56     private static final String ERROR_PARSING = "error parsing ";
57     private static final String ERROR_CODING = "error coding ";
58
59     // The parameters for the JSON event protocol
60     private JsonEventProtocolParameters jsonPars;
61
62     /**
63      * {@inheritDoc}.
64      */
65     @Override
66     public void init(final EventProtocolParameters parameters) {
67         // Check and get the JSON parameters
68         if (!(parameters instanceof JsonEventProtocolParameters)) {
69             final var errorMessage = "specified consumer properties are not applicable to the JSON event protocol";
70             throw new ApexEventRuntimeException(errorMessage);
71         }
72
73         jsonPars = (JsonEventProtocolParameters) parameters;
74     }
75
76     /**
77      * {@inheritDoc}.
78      */
79     @Override
80     public List<ApexEvent> toApexEvent(final String eventName, final Object eventObject) throws ApexEventException {
81         // Check the event eventObject
82         if (eventObject == null) {
83             throw new ApexEventException("event processing failed, event is null");
84         }
85
86         // Cast the event to a string, if our conversion is correctly configured, this cast should
87         // always work
88         String jsonEventString = null;
89         try {
90             jsonEventString = (String) eventObject;
91         } catch (final Exception e) {
92             final String errorMessage = "error converting event \"" + eventObject + "\" to a string";
93             throw new ApexEventRuntimeException(errorMessage, e);
94         }
95
96         // The list of events we will return
97         final List<ApexEvent> eventList = new ArrayList<>();
98
99         try {
100             // We may have a single JSON object with a single event or an array of JSON objects
101             final var decodedJsonObject = new GsonBuilder().serializeNulls().create().fromJson(jsonEventString,
102                             Object.class);
103
104             // Check if we have a list of objects
105             if (decodedJsonObject instanceof List) {
106                 eventList.addAll(decodeEventList(eventName, jsonEventString, decodedJsonObject));
107             } else {
108                 eventList.add(jsonStringApexEvent(eventName, jsonEventString));
109             }
110         } catch (final Exception e) {
111             throw new ApexEventException("Failed to unmarshal JSON event, event=" + jsonEventString, e);
112         }
113
114         // Return the list of events we have unmarshalled
115         return eventList;
116     }
117
118     /**
119      * Decode a list of Apex events.
120      *
121      * @param eventName the name of the incoming events
122      * @param jsonEventString the JSON representation of the event list
123      * @param decodedJsonObject The JSON list object
124      * @return a list of decoded Apex events
125      * @throws ApexEventException on event decoding errors
126      */
127     private Collection<? extends ApexEvent> decodeEventList(final String eventName, String jsonEventString,
128                     final Object decodedJsonObject) throws ApexEventException {
129
130         final List<ApexEvent> eventList = new ArrayList<>();
131
132         // Check if it's a list of JSON objects or a list of strings
133         @SuppressWarnings("unchecked")
134         final List<Object> decodedJsonList = (List<Object>) decodedJsonObject;
135
136         // Decode each of the list elements in sequence
137         for (final Object jsonListObject : decodedJsonList) {
138             if (jsonListObject instanceof String) {
139                 eventList.add(jsonStringApexEvent(eventName, (String) jsonListObject));
140             } else if (jsonListObject instanceof JsonObject) {
141                 eventList.add(jsonObject2ApexEvent(eventName, (JsonObject) jsonListObject));
142             } else if (jsonListObject instanceof LinkedTreeMap) {
143                 eventList.add(jsonObject2ApexEvent(eventName, new Gson().toJsonTree(jsonListObject).getAsJsonObject()));
144             } else {
145                 throw new ApexEventException("incoming event (" + jsonEventString
146                                 + ") is a JSON object array containing an invalid object " + jsonListObject);
147             }
148         }
149
150         return eventList;
151     }
152
153     /**
154      * {@inheritDoc}.
155      */
156     @Override
157     public Object fromApexEvent(final ApexEvent apexEvent) throws ApexEventException {
158         // Check the Apex event
159         if (apexEvent == null) {
160             throw new ApexEventException("event processing failed, Apex event is null");
161         }
162
163         if (jsonPars.getPojoField() == null) {
164             return fromApexEventWithFields(apexEvent);
165         } else {
166             return fromApexEventPojo(apexEvent);
167         }
168     }
169
170     /**
171      * Serialise an Apex event to a JSON string field by field.
172      *
173      * @param apexEvent the event to Serialise
174      * @return the Serialise event as JSON
175      * @throws ApexEventException exceptions on marshaling to JSON
176      */
177     private Object fromApexEventWithFields(final ApexEvent apexEvent) {
178         // Get the event definition for the event from the model service
179         final AxEvent eventDefinition = ModelService.getModel(AxEvents.class).get(apexEvent.getName(),
180                         apexEvent.getVersion());
181
182         // Use a GSON Json object to marshal the Apex event to JSON
183         final var gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create();
184         final var jsonObject = new JsonObject();
185
186         jsonObject.addProperty(ApexEvent.NAME_HEADER_FIELD, apexEvent.getName());
187         jsonObject.addProperty(ApexEvent.VERSION_HEADER_FIELD, apexEvent.getVersion());
188         jsonObject.addProperty(ApexEvent.NAMESPACE_HEADER_FIELD, apexEvent.getNameSpace());
189         jsonObject.addProperty(ApexEvent.SOURCE_HEADER_FIELD, apexEvent.getSource());
190         jsonObject.addProperty(ApexEvent.TARGET_HEADER_FIELD, apexEvent.getTarget());
191         jsonObject.addProperty(ApexEvent.TOSCA_POLICY_STATE_HEADER_FIELD, apexEvent.getToscaPolicyState());
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 var 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 var 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 var 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 var 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 var 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 var 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         final String eventStatus = getHeaderToscaPolicyState(jsonObject, eventDefinition);
421
422         return new ApexEvent(eventName, eventVersion, eventNamespace, eventSource, eventTarget, eventStatus);
423     }
424
425     /**
426      * Determine the name field of the event header.
427      *
428      * @param jsonObject the event in JSON format
429      * @param parameterEventName the configured event name from the parameters
430      * @return the event name to use on the event header
431      */
432     private String getHeaderName(final JsonObject jsonObject, final String parameterEventName) {
433         final var jsonEventName = getJsonStringField(jsonObject, ApexEvent.NAME_HEADER_FIELD,
434                         jsonPars.getNameAlias(), ApexEvent.NAME_REGEXP, false);
435
436         // Check that an event name has been specified
437         if (jsonEventName == null && parameterEventName == null) {
438             throw new ApexEventRuntimeException(
439                             "event received without mandatory parameter \"name\" on configuration or on event");
440         }
441
442         // Check if an event name was specified on the event parameters
443         if (jsonEventName != null) {
444             if (parameterEventName != null && !parameterEventName.equals(jsonEventName)) {
445                 LOGGER.warn("The incoming event name \"{}\" does not match the configured event name \"{}\","
446                                 + " using configured event name", jsonEventName, parameterEventName);
447             }
448             return jsonEventName;
449         } else {
450             return parameterEventName;
451         }
452     }
453
454     /**
455      * Determine the version field of the event header.
456      *
457      * @param jsonObject the event in JSON format
458      * @return the event version
459      */
460     private String getHeaderVersion(final JsonObject jsonObject) {
461         // Find the event definition in the model service. If version is null, the newest event
462         // definition in the model service is used
463         return getJsonStringField(jsonObject, ApexEvent.VERSION_HEADER_FIELD, jsonPars.getVersionAlias(),
464                         ApexEvent.VERSION_REGEXP, false);
465     }
466
467     /**
468      * Determine the name space field of the event header.
469      *
470      * @param jsonObject the event in JSON format
471      * @param name the name of the event
472      * @param eventDefinition the definition of the event structure
473      * @return the event version
474      */
475     private String getHeaderNamespace(final JsonObject jsonObject, final String name, final AxEvent eventDefinition) {
476         // Check the name space is OK if it is defined, if not, use the name space from the model
477         var namespace = getJsonStringField(jsonObject, ApexEvent.NAMESPACE_HEADER_FIELD,
478                         jsonPars.getNameSpaceAlias(), ApexEvent.NAMESPACE_REGEXP, false);
479         if (namespace != null) {
480             if (!namespace.equals(eventDefinition.getNameSpace())) {
481                 throw new ApexEventRuntimeException("namespace \"" + namespace + "\" on event \"" + name
482                                 + "\" does not match namespace \"" + eventDefinition.getNameSpace()
483                                 + "\" for that event in the Apex model");
484             }
485         } else {
486             namespace = eventDefinition.getNameSpace();
487         }
488         return namespace;
489     }
490
491     /**
492      * Determine the source field of the event header.
493      *
494      * @param jsonObject the event in JSON format
495      * @param eventDefinition the definition of the event structure
496      * @return the event version
497      */
498     private String getHeaderSource(final JsonObject jsonObject, final AxEvent eventDefinition) {
499         // For source, use the defined source only if the source is not found on the incoming event
500         var source = getJsonStringField(jsonObject, ApexEvent.SOURCE_HEADER_FIELD, jsonPars.getSourceAlias(),
501                         ApexEvent.SOURCE_REGEXP, false);
502         if (source == null) {
503             source = eventDefinition.getSource();
504         }
505         return source;
506     }
507
508     /**
509      * Determine the target field of the event header.
510      *
511      * @param jsonObject the event in JSON format
512      * @param eventDefinition the definition of the event structure
513      * @return the event version
514      */
515     private String getHeaderTarget(final JsonObject jsonObject, final AxEvent eventDefinition) {
516         // For target, use the defined source only if the source is not found on the incoming event
517         var target = getJsonStringField(jsonObject, ApexEvent.TARGET_HEADER_FIELD, jsonPars.getTargetAlias(),
518                         ApexEvent.TARGET_REGEXP, false);
519         if (target == null) {
520             target = eventDefinition.getTarget();
521         }
522         return target;
523     }
524
525     /**
526      * Determine the status field of the event header.
527      *
528      * @param jsonObject the event in JSON format
529      * @param eventDefinition the definition of the event structure
530      * @return the event toscaPolicyState
531      */
532     private String getHeaderToscaPolicyState(final JsonObject jsonObject, final AxEvent eventDefinition) {
533         // For toscaPolicyState, use defined value from model only if value is not found on the incoming event
534         var toscaPolicyState = getJsonStringField(jsonObject, ApexEvent.TOSCA_POLICY_STATE_HEADER_FIELD,
535                 jsonPars.getToscaPolicyStateAlias(), null, false);
536         if (toscaPolicyState == null) {
537             toscaPolicyState = eventDefinition.getToscaPolicyState();
538         }
539         return toscaPolicyState;
540     }
541
542     /**
543      * This method gets an event string field from a JSON object.
544      *
545      * @param jsonObject the JSON object containing the JSON representation of the incoming event
546      * @param fieldName the field name to find in the event
547      * @param fieldAlias the alias for the field to find in the event, overrides the field name if it is not null
548      * @param fieldRegexp the regular expression to check the field against for validity
549      * @param mandatory true if the field is mandatory
550      * @return the value of the field in the JSON object or null if the field is optional
551      * @throws ApexEventRuntimeException the apex event runtime exception
552      */
553     private String getJsonStringField(final JsonObject jsonObject, final String fieldName, final String fieldAlias,
554                     final String fieldRegexp, final boolean mandatory) {
555         // Get the JSON field for the string field
556         final JsonElement jsonField = getJsonField(jsonObject, fieldName, fieldAlias, mandatory);
557
558         // Null strings are allowed
559         if (jsonField == null || jsonField.isJsonNull()) {
560             return null;
561         }
562
563         // Check if this is a string field
564         String fieldValueString = null;
565         try {
566             fieldValueString = jsonField.getAsString();
567         } catch (final Exception e) {
568             // The element is not a string so throw an error
569             throw new ApexEventRuntimeException("field \"" + fieldName + "\" with type \""
570                             + jsonField.getClass().getName() + "\" is not a string value", e);
571         }
572
573         // Is regular expression checking required
574         if (fieldRegexp == null) {
575             return fieldValueString;
576         }
577
578         // Check the event field against its regular expression
579         if (!fieldValueString.matches(fieldRegexp)) {
580             throw new ApexEventRuntimeException(
581                             "field \"" + fieldName + "\" with value \"" + fieldValueString + "\" is invalid");
582         }
583
584         return fieldValueString;
585     }
586
587     /**
588      * This method gets an event field from a JSON object.
589      *
590      * @param jsonObject the JSON object containing the JSON representation of the incoming event
591      * @param fieldName the field name to find in the event
592      * @param fieldAlias the alias for the field to find in the event, overrides the field name if it is not null
593      * @param mandatory true if the field is mandatory
594      * @return the value of the field in the JSON object or null if the field is optional
595      * @throws ApexEventRuntimeException the apex event runtime exception
596      */
597     private JsonElement getJsonField(final JsonObject jsonObject, final String fieldName, final String fieldAlias,
598                     final boolean mandatory) {
599
600         // Check if we should use the alias for this field
601         String fieldToFind = fieldName;
602         if (fieldAlias != null) {
603             fieldToFind = fieldAlias;
604         }
605
606         // Get the event field
607         final JsonElement eventElement = jsonObject.get(fieldToFind);
608         if (eventElement == null) {
609             if (!mandatory) {
610                 return null;
611             } else {
612                 throw new ApexEventRuntimeException("mandatory field \"" + fieldToFind + "\" is missing");
613             }
614         }
615
616         return eventElement;
617     }
618
619     /**
620      * This method if a JSON object has a named field.
621      *
622      * @param jsonObject the JSON object containing the JSON representation of the incoming event
623      * @param fieldName the field name to find in the event
624      * @return true if the field is present
625      * @throws ApexEventRuntimeException the apex event runtime exception
626      */
627     private boolean hasJsonField(final JsonObject jsonObject, final String fieldName) {
628         // check for the field
629         return jsonObject.has(fieldName);
630     }
631 }