Commit de9ea0d2 authored by Ryan Berkheimer's avatar Ryan Berkheimer
Browse files

FEATURE COMPLETION - completed native conditions with associated test.

parent 90eb8011
Pipeline #5983 failed with stage
in 0 seconds
......@@ -51,6 +51,8 @@ build-c_cpp:
@make -C $(C_MAIN_BUILD_DIR)
@echo "Building C/C++ binary for native transformation tests."
@make -C $(C_TEST_BUILD_DIR)/transformation
@echo "Building C/C++ binary for native condition tests."
@make -C $(C_TEST_BUILD_DIR)/condition
@echo "Building C/C++ binary for native endpoint tests."
@make -C $(C_TEST_BUILD_DIR)/endpoint
@echo "Building C/C++ binary for native session tests."
......
{
"fields": [
{
"id": "int-field",
"required": true,
"type": "integer"
}
],
"conditions": [
{
"id": "int-condition-test",
"type": "comparison",
"operator": "gov.noaa.messageapi.conditions.NativeCondition",
"constructor": {
"native-library": "/workspaces/messageapi/libs/test/c/condition/libConditionDemo.so"
},
"field": "int-field",
"value": 5
}
],
"collections": [
{
"id": "collection-1",
"fields": ["int-field"],
"conditions": ["int-condition-test"]
},
{
"id": "collection-2",
"fields": ["int-field"]
}
],
"endpoints": [
{
"plugin": "gov.noaa.messageapi.EvaluationEndpoint",
"connections": [{
"id": "conn-1",
"constructor": {},
"collections": ["collection-1", "collection-2"]
}]
}
]
}
\ No newline at end of file
......@@ -55,7 +55,8 @@ C_FQ_SRC_FILES=$(addprefix $(C_DIR), $(C_SRC_FILES))
C_H_FILES=structs/messageapi_structs.h
C_FULL_H_FILES=wrappers/endpoint/gov_noaa_messageapi_endpoints_NativeEndpoint.h \
wrappers/transformation/gov_noaa_messageapi_transformations_NativeTransformation.h
wrappers/transformation/gov_noaa_messageapi_transformations_NativeTransformation.h \
wrappers/condition/gov_noaa_messageapi_conditions_NativeCondition.h
C_FQ_H_FILES=$(addprefix $(C_DIR), $(C_H_FILES))
......@@ -63,14 +64,17 @@ C_FQ_FULL_H_FILES=$(addprefix $(C_DIR), $(C_FULL_H_FILES))
CPP_DIR=$(PROJECT_ROOT)/src/cpp/main/
#These files are involved in the native session, which is why they are separate
CPP_SRC_FILES=utils/general/jni/JniUtils.cpp utils/general/type/TypeUtils.cpp utils/general/list/ListUtils.cpp \
utils/general/map/MapUtils.cpp utils/api/condition/ConditionUtils.cpp utils/api/field/FieldUtils.cpp \
utils/api/records/schema/RecordUtils.cpp utils/api/rejection/RejectionUtils.cpp utils/api/packet/PacketUtils.cpp \
utils/api/session/SessionUtils.cpp utils/api/request/RequestUtils.cpp utils/api/response/ResponseUtils.cpp \
api/session/MessageApiSession.cpp libs/session/MessageApiSessionLib.cpp
#These files do not need to be included in native session.
CPP_FULL_SRC_FILES=utils/api/endpoint/EndpointUtils.cpp utils/api/records/protocol/ProtocolRecordUtils.cpp \
utils/api/transformation/TransformationUtils.cpp api/endpoint/MessageApiEndpoint.cpp \
utils/api/condition/NativeConditionUtils.cpp api/condition/MessageApiCondition.cpp libs/condition/MessageApiConditionLib.cpp \
api/transformation/MessageApiTransformation.cpp libs/endpoint/MessageApiEndpointLib.cpp \
libs/transformation/MessageApiTransformationLib.cpp
......@@ -86,6 +90,7 @@ api/session/MessageApiSession.h libs/session/MessageApiSessionLib.h
CPP_FULL_H_FILES=utils/api/endpoint/EndpointUtils.h utils/api/records/protocol/ProtocolRecordUtils.h \
utils/api/transformation/TransformationUtils.h api/endpoint/MessageApiEndpoint.h \
utils/api/condition/NativeConditionUtils.h api/condition/MessageApiCondition.h libs/condition/MessageApiConditionLib.h \
api/transformation/MessageApiTransformation.h libs/endpoint/MessageApiEndpointLib.h \
libs/transformation/MessageApiTransformationLib.h
......
### This Makefile can be used as a template for writing MessageAPI compatible C/C++ conditions that extend the
# NativeCondition.
# Note that the goal of native condition production is to create a shared library,
# as shared libraries are used by the Java code. Once produced, the fully-qualified shared library should just be referenced in the
# config map for the condition itself. If you are reading this, you most likely understand what is necessary, but if not, see the example
# 'native condition' in the MessageAPI source code 'test' namespace with associated parameter map.
# The majority of this Makefile is standard, with only six user specified variables. These are denoted by the comment USER SPECIFIED.
# All user specified variables are at the top of this makefile. The build process is standardized to automatically include MessageAPI resources,
# So if there is an issue at first, make sure you have installed the library correctly (need $MESSAGEAPI_SRC and $MESSAGEAPI_HEADERS env vars).
# There are a few other system-specific requirements and other notable things to keep in mind when using this Makefile:
## 1. You must have a JDK installed (not JRE). This library requires the jni.h and jnimd.h headers included in your jdk.
## 2. JAVA_HOME must be set to your JDK home directory (one level above the java binary). This Makefile references JAVA_HOME in looking for jni.h and jnimd.h
#USER SPECIFIED - Specify where the library will build to. The library itself will be placed in $BUILD_DIR/compile
BUILD_DIR=
#USER SPECIFIED - Specify the base name of the lib (e.g., if lib to be built as libMyCondition.so, put MyCondition here)
LIBRARY_NAME=
#USER SPECIFIED - Specify The next two lines with Fully Qualified paths to your C source (if any) and headers (if any) in dependency order.
#he last C file should correspond to the Messageapi endpoint wrapper (the header is in the $MESSAGEAPI_HEADERS dir and is auto-included).
#This C file is the entry point for the library. See $MESSAGEAPI_HEADERS/gov_noaa_messageapi_conditions_NativeCondition.h for the signature of
#the class that must be wrapped.
USER_C_SRC_FILES=
USER_C_H_FILES=
#USER SPECIFIED - Specify The next two lines with Fully Qualified paths to your C++ source (if any) and headers (if any) in dependency order.
USER_CPP_SRC_FILES=
USER_CPP_H_FILES=
############### The next sections are usually default. You can also contact the MessageAPI maintainers for help if there are issues. ###################
COMPILE_DIR=$(BUILD_DIR)/compile#.o and .so files produced here
HEADER_DIR=$(BUILD_DIR)/headers#.h files copied here before build (for central include path)
SO_NAME=lib$(LIBRARY_NAME).so
#The following represent directories for JNI Libraries that must be included during C and CPP compilation.
#The following represent a standard RHEL 7/8 system with OpenJDK.
JNIDIR=$(JAVA_HOME)/include
JNIMDDIR=$(JAVA_HOME)/include/linux
#compilers
CXX=g++
CC=gcc
MAPI_C_H_FILES=/messageapi_structs.h /gov_noaa_messageapi_conditions_NativeCondition.h
MAPI_C_FQ_H_FILES=$(addprefix $(MESSAGEAPI_HEADERS), $(MAPI_C_H_FILES))
MAPI_CPP_SRC_FILES=/JniUtils.cpp /TypeUtils.cpp /MapUtils.cpp \
/ListUtils.cpp /ConditionUtils.cpp /NativeConditionUtils.cpp /FieldUtils.cpp \
/MessageApiCondition.cpp /MessageApiConditionLib.cpp
MAPI_CPP_FQ_SRC_FILES=$(addprefix $(MESSAGEAPI_SRC), $(MAPI_CPP_SRC_FILES))
MAPI_CPP_H_FILES=/JniUtils.h /TypeUtils.h /MapUtils.h \
/ListUtils.h /ConditionUtils.h \
/FieldUtils.h /NativeConditionUtils.h \
/MessageApiCondition.h /MessageApiConditionLib.h
MAPI_CPP_FQ_H_FILES=$(addprefix $(MESSAGEAPI_SRC), $(MAPI_CPP_H_FILES))
all: check_sys prep build
.PHONY : check_sys prep build
check_sys:
@echo "Checking OS type"
ifneq ($(shell uname),Linux)
@echo "This makefile is for building shared libraries on linux, OS is $(shell uname). Terminating."
@exit 1
endif
@echo "System OS is Linux, continuing build."
prep:
@echo "Preparing system for build."
@rm -rf $(BUILD_DIR)
@mkdir -p $(BUILD_DIR)
@mkdir -p $(COMPILE_DIR)
@mkdir -p $(HEADER_DIR)
build:
@echo "Building $(LIBRARY_NAME) as $(SO_NAME) in $(COMPILE_DIR)"
@echo "Copying all headers to include path."
@cp $(MAPI_C_FQ_H_FILES) $(HEADER_DIR)
@cp $(MAPI_CPP_FQ_H_FILES) $(HEADER_DIR)
@cp $(USER_C_H_FILES) $(HEADER_DIR)
@cp $(USER_CPP_H_FILES) $(HEADER_DIR)
@echo "Compiling C++ object files with position independent code."
@echo ""
@-cd $(COMPILE_DIR) && $(CXX) -I$(HEADER_DIR) -I$(JNIDIR) -I$(JNIMDDIR) -fPIC -c $(MAPI_CPP_FQ_SRC_FILES) $(USER_CPP_SRC_FILES)
@echo ""
@echo "Compiling C object files with position independent code."
@echo ""
@-cd $(COMPILE_DIR) && $(CC) -I$(HEADER_DIR) -I$(JNIDIR) -I$(JNIMDDIR) -fPIC -std=c99 -c $(MAPI_C_FQ_SRC_FILES) $(USER_C_SRC_FILES)
@echo ""
@echo "Creating shared library."
@echo ""
@-cd $(COMPILE_DIR) && $(CXX) -shared -fPIC -std=c99 *.o -o $(SO_NAME)
@echo "Build success for $(LIBRARY_NAME) as $(COMPILE_DIR)/$(SO_NAME)"
\ No newline at end of file
### This Makefile can be used as a template for writing MessageAPI compatible C/C++ conditions that extend the
# NativeCondition.
# Note that the goal of native condition production is to create a shared library,
# as shared libraries are used by the Java code. Once produced, the fully-qualified shared library should just be referenced in the
# config map for the condition itself. If you are reading this, you most likely understand what is necessary, but if not, see the example
# 'native condition' in the MessageAPI source code 'test' namespace with associated parameter map.
# The majority of this Makefile is standard, with only six user specified variables. These are denoted by the comment USER SPECIFIED.
# All user specified variables are at the top of this makefile. The build process is standardized to automatically include MessageAPI resources,
# So if there is an issue at first, make sure you have installed the library correctly (need $MESSAGEAPI_SRC and $MESSAGEAPI_HEADERS env vars).
# There are a few other system-specific requirements and other notable things to keep in mind when using this Makefile:
## 1. You must have a JDK installed (not JRE). This library requires the jni.h and jnimd.h headers included in your jdk.
## 2. JAVA_HOME must be set to your JDK home directory (one level above the java binary). This Makefile references JAVA_HOME in looking for jni.h and jnimd.h
#The following is used to bootstrap the PROJECT_ROOT
CURRENT_DIR=$(PWD)
#The following represents the root project path. In this tailored example, we use a relative path to the project root.
#In your own Makefile, this variable can be set directly.
PROJECT_ROOT=$(firstword $(subst /scripts/build/c/test, ,$(CURRENT_DIR)))
#Set target directories - this is where the library will build from/to.
BUILD_DIR=$(PROJECT_ROOT)/build/c/test/condition
COMPILE_DIR=$(BUILD_DIR)/compile#.o files produced here
HEADER_DIR=$(BUILD_DIR)/headers#.h files copied here before build (for central include path)
LIB_DIR=$(PROJECT_ROOT)/libs/test/c/condition#.so moved here before test
#USER SPECIFIED - Specify the base name of the lib (e.g., if lib to be built as libMyCondition.so, put MyCondition here)
LIBRARY_NAME=ConditionDemo
SO_NAME=lib$(LIBRARY_NAME).so
#The following represent directories for JNI Libraries that must be included during C and CPP compilation.
#The following represent a standard RHEL 7/8 system with OpenJDK.
JNIDIR=$(JAVA_HOME)/include
JNIMDDIR=$(JAVA_HOME)/include/linux
#compilers
CXX=g++
CC=gcc
C_DIR=$(PROJECT_ROOT)/src/c/
C_SRC_FILES=test/conditions/condition_lib/ConditionWrapper.c
C_FQ_SRC_FILES=$(addprefix $(C_DIR), $(C_SRC_FILES))
C_H_FILES=main/structs/messageapi_structs.h main/wrappers/condition/gov_noaa_messageapi_conditions_NativeCondition.h
C_FQ_H_FILES=$(addprefix $(C_DIR), $(C_H_FILES))
CPP_DIR=$(PROJECT_ROOT)/src/cpp/main/
CPP_SRC_FILES=utils/general/jni/JniUtils.cpp utils/general/type/TypeUtils.cpp utils/general/map/MapUtils.cpp \
utils/general/list/ListUtils.cpp utils/api/condition/ConditionUtils.cpp utils/api/condition/NativeConditionUtils.cpp \
utils/api/field/FieldUtils.cpp api/condition/MessageApiCondition.cpp libs/condition/MessageApiConditionLib.cpp
CPP_FQ_SRC_FILES=$(addprefix $(CPP_DIR), $(CPP_SRC_FILES))
CPP_H_FILES=utils/general/jni/JniUtils.h utils/general/type/TypeUtils.h utils/general/map/MapUtils.h \
utils/general/list/ListUtils.h utils/api/condition/ConditionUtils.h utils/api/condition/NativeConditionUtils.h \
utils/api/field/FieldUtils.h api/condition/MessageApiCondition.h libs/condition/MessageApiConditionLib.h
CPP_FQ_H_FILES=$(addprefix $(CPP_DIR), $(CPP_H_FILES))
all: check_sys prep build
.PHONY : check_sys prep build
check_sys:
@echo "Checking OS type"
ifneq ($(shell uname),Linux)
@echo "This makefile is for building shared libraries on linux, OS is $(shell uname). Terminating."
@exit 1
endif
@echo "System OS is Linux, continuing build."
prep:
@echo "Preparing system for build."
@rm -rf $(BUILD_DIR)
@mkdir -p $(BUILD_DIR)
@mkdir -p $(COMPILE_DIR)
@mkdir -p $(HEADER_DIR)
@mkdir -p $(LIB_DIR)
build:
@echo "Building $(LIBRARY_NAME) as $(SO_NAME) in $(LIB_DIR)"
@echo "Copying all headers to include path."
@cp $(C_FQ_H_FILES) $(HEADER_DIR)
@cp $(CPP_FQ_H_FILES) $(HEADER_DIR)
@echo "Compiling C++ object files with position independent code."
@echo ""
@-cd $(COMPILE_DIR) && $(CXX) -I$(HEADER_DIR) -I$(JNIDIR) -I$(JNIMDDIR) -fPIC -c $(CPP_FQ_SRC_FILES)
@echo ""
@echo "Compiling C object files with position independent code."
@echo ""
@-cd $(COMPILE_DIR) && $(CC) -I$(HEADER_DIR) -I$(JNIDIR) -I$(JNIMDDIR) -fPIC -std=c99 -c $(C_FQ_SRC_FILES)
@echo ""
@echo "Creating shared library."
@echo ""
@-cd $(COMPILE_DIR) && $(CXX) -shared -fPIC -std=c99 *.o -o $(SO_NAME)
@-cd $(COMPILE_DIR) && mv $(SO_NAME) $(LIB_DIR)
@echo "Build success for $(LIBRARY_NAME) as $(LIB_DIR)/$(SO_NAME)"
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class gov_noaa_messageapi_conditions_NativeCondition */
#ifndef _Included_gov_noaa_messageapi_conditions_NativeCondition
#define _Included_gov_noaa_messageapi_conditions_NativeCondition
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: gov_noaa_messageapi_conditions_NativeCondition
* Method: compare
* Signature: (J)Z
*/
JNIEXPORT bool JNICALL Java_gov_noaa_messageapi_conditions_NativeCondition_compare
(JNIEnv *, jobject, jlong);
/*
* Class: gov_noaa_messageapi_conditions_NativeCondition
* Method: create
* Signature: (Z;Z)J
*/
JNIEXPORT jlong JNICALL Java_gov_noaa_messageapi_conditions_NativeCondition_create
(JNIEnv *, jobject, jobject, jobject);
/*
* Class: gov_noaa_messageapi_conditions_NativeCondition
* Method: release
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_gov_noaa_messageapi_conditions_NativeCondition_release
(JNIEnv *, jobject, jlong);
#ifdef __cplusplus
}
#endif
#endif
#include <jni.h>
#include <stdio.h>
#include "messageapi_structs.h"
#include "MessageApiConditionLib.h"
#include "gov_noaa_messageapi_conditions_NativeCondition.h"
/*
* Class: gov_noaa_messageapi_conditions_NativeCondition
* Method: compare
* Signature: (J)Z
* @author Ryan Berkheimer
*/
JNIEXPORT bool JNICALL Java_gov_noaa_messageapi_conditions_NativeCondition_compare(JNIEnv *env, jobject nativeCondition, jlong message)
{
printf("In our native condition comparison test!\n");
fflush(stdout);
condition *condition = getCondition(message);
field *field = getField(message);
int fieldVal = getFieldIntVal(message, field);
int condVal = getConditionIntVal(message, condition);
if (fieldVal >= condVal) {
printf("The field val was greater than or equal to the cond val, passed condition test!\n");
fflush(stdout);
return true;
} else {
printf("The field val was less than the condition val, failed the condition test!\n");
fflush(stdout);
return false;
}
}
#include "MessageApiCondition.h"
#include <iostream>
#include <string>
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
Constructor for the MessageApiCondition object. Takes a JNI environment pointer, a condition context (this refers to
the condition class that's instantiating the object), a field object, and a condition object.
*/
MessageApiCondition::MessageApiCondition(JNIEnv *env, jobject jNativeCondition, jobject jField, jobject jCondition)
{
this->jvm = env;
this->nativeCondition = this->jvm->NewGlobalRef(jNativeCondition);
this->field = this->jvm->NewGlobalRef(jField);
this->condition = this->jvm->NewGlobalRef(jCondition);
this->typeUtils = new TypeUtils(this->jvm);
this->listUtils = new ListUtils(this->jvm, typeUtils);
this->mapUtils = new MapUtils(this->jvm, typeUtils);
this->fieldUtils = new FieldUtils(this->jvm, this->typeUtils, this->listUtils, this->mapUtils);
this->conditionUtils = new ConditionUtils(this->jvm, this->typeUtils, this->listUtils, this->mapUtils);
this->nativeConditionUtils = new NativeConditionUtils(this->jvm, this->nativeCondition);
}
MessageApiCondition::~MessageApiCondition()
{
try
{
delete this->fieldUtils;
delete this->conditionUtils;
delete this->nativeConditionUtils;
delete this->listUtils;
delete this->mapUtils;
delete this->typeUtils;
this->jvm->DeleteGlobalRef(this->field);
this->jvm->DeleteGlobalRef(this->condition);
this->jvm->DeleteGlobalRef(this->nativeCondition);
}
catch (const std::exception &e)
{
std::cout << e.what();
}
}
FieldUtils *MessageApiCondition::getFieldUtils()
{
return this->fieldUtils;
}
ConditionUtils *MessageApiCondition::getConditionUtils()
{
return this->conditionUtils;
}
NativeConditionUtils *MessageApiCondition::getNativeConditionUtils()
{
return this->nativeConditionUtils;
}
ListUtils *MessageApiCondition::getListUtils()
{
return this->listUtils;
}
MapUtils *MessageApiCondition::getMapUtils()
{
return this->mapUtils;
}
TypeUtils *MessageApiCondition::getTypeUtils()
{
return this->typeUtils;
}
#ifndef _Included_MessageApiCondition
#define _Included_MessageApiCondition
#include <jni.h>
#include <stdbool.h>
#include "messageapi_structs.h"
#ifdef __cplusplus
#include <iostream>
#include <string>
#include "JniUtils.h"
#include "MapUtils.h"
#include "ListUtils.h"
#include "FieldUtils.h"
#include "ConditionUtils.h"
#include "NativeConditionUtils.h"
/**
* This is the header for the MessageApiCondition class - this class is the native side facility
* for doing condition comparison processing and communicating back with the java side. This class holds
* four private vars - a pointer to the jvm where the call originated from, a pointer to the
* condition class instance (jobject), a pointer to the field on which the comparison is being called,
* and a pointer to the condition containing a value for comparison.
*
* To use the MessageApiCondition natively, users can write any logic that can use the passed field
* and passed condition to extract values and do arbitrary comparison. Returning a true boolean will
* mean the condition passed, while returning a false value will mean the condition failed.
*
* To the user of the MessageApiCondition library in the native side,
* they will see the entire library as a single jlong. This jlong holds a pointer to this class,
* making it easier for implementors to ignore most of the details of implementation.
* @author Ryan Berkheimer
*/
class MessageApiCondition
{
public:
/*Default constructor/destructors*/
MessageApiCondition(JNIEnv* javaEnv, jobject jNativeCondition, jobject jField, jobject jCondition);
~MessageApiCondition();
/*Utils Accessors*/
FieldUtils *getFieldUtils();
ConditionUtils *getConditionUtils();
NativeConditionUtils *getNativeConditionUtils();
TypeUtils *getTypeUtils();
ListUtils *getListUtils();
MapUtils *getMapUtils();
private :
/*Global References*/
JNIEnv *jvm;
jobject nativeCondition;
jobject field;
jobject condition;
FieldUtils *fieldUtils;
ConditionUtils *conditionUtils;
NativeConditionUtils *nativeConditionUtils;
TypeUtils *typeUtils;
ListUtils *listUtils;
MapUtils *mapUtils;
};
extern "C"
{
#endif
#ifdef __cplusplus
}
#endif
#endif
#include "MessageApiConditionLib.h"
#include "MessageApiCondition.h"
#include "gov_noaa_messageapi_conditions_NativeCondition.h"
/**
* Creates a C++ object and returns a pointer to it cast as a long. This allows the NativeCondition method
* to hold onto it and manipulate it during the process method while preventing potential conflicts with
* other threads or conditions using the same native library. This is used inside the Java process method.
* The Native process method should be implemented in a separate User class wrapper.
*/
JNIEXPORT jlong JNICALL Java_gov_noaa_messageapi_conditions_NativeCondition_create(JNIEnv* env, jobject nativeCondition, jobject field, jobject condition)
{
return reinterpret_cast<jlong>(new MessageApiCondition(env, nativeCondition, field, condition));
}
/**
* Deletes the C++ pointer (calls C++ destructor)) that references the object created during condition construction.
* This call is made automatically by the Java process method after native processing has completed.
*/
JNIEXPORT void JNICALL Java_gov_noaa_messageapi_conditions_NativeCondition_release(JNIEnv* env, jobject nativeCondition, jlong conditionLib)
{
delete reinterpret_cast<MessageApiCondition *>(conditionLib);
}
extern "C"
{
val_map *getConstructor(jlong message)
{
return reinterpret_cast<MessageApiCondition *>(message)->getNativeConditionUtils()->getConstructor();
}
field *getField(jlong message)
{
return reinterpret_cast<MessageApiCondition *>(message)->getNativeConditionUtils()->getField();
}
condition *getCondition(jlong message)
{
return reinterpret_cast<MessageApiCondition *>(message)->getNativeConditionUtils()->getCondition();
}
/*Field Methods*/
const char *getFieldId(jlong message, field *field)
{
return reinterpret_cast<MessageApiCondition *>(message)->getFieldUtils()->getId(field);
}
const char *getFieldType(jlong message, field *field)
{
return reinterpret_cast<MessageApiCondition *>(message)->getFieldUtils()->getType(field);
}
bool getFieldIsValid(jlong message, field *field)
{
return reinterpret_cast<MessageApiCondition *>(message)->getFieldUtils()->isValid(field);
}
bool getFieldIsRequired(jlong message, field *field)
{
return reinterpret_cast<MessageApiCondition *>(message)->getFieldUtils()->isRequired(field);
}
bool getFieldIsNull(jlong message, field *field)
{
return reinterpret_cast<MessageApiCondition *>(message)->getFieldUtils()->isNull(field);
}