Connecting Apama Applications to External Components > Developing Custom Clients > The C Client Software Development Kit > Using the C SDK
Using the C SDK
Note that the C SDK comes in two ‘flavors’ – one for pure C-only compilers, and one for C++ compilers. If you need to use the C SDK because your C++ compiler is not ISO compatible or is not supported by Apama, then you might find the C++ guise of the C SDK easier to work with. Both are available in the header file engine_client_c.h. This header file determines what kind of compiler is in use and defines its contents accordingly. engine_client_c.h can be located in the include folder.
While the reader is referred directly to the header file engine_client_c.h as a reference, this topic introduces the C SDK primarily through inspection of one of the included examples. There are two examples that use the C SDK in the samples\engine_client folder. They are c\engine_client.c and cpp\engine_client_c.cpp. Both use the C SDK, but while engine_client.c is intended as a pure C program written with a C only compiler, engine_client_c.cpp can be compiled with a C++ compiler.
This section concentrates on c\engine_client.c.
The first step is to initialize the Apama client-side library;
  AP_EngineInit();
  if (AP_CheckException()) {
    exThrown = 1;
    break;
  }
Note the explicit ‘exception’ handling. As in C there is no notion of exceptions, the C SDK provides an analogous means of verifying that a method has succeeded. It is important that the developer use this mechanism with the majority of functions provided in its API.
Note: For clarity, the rest of these example code snippets do not include exception handling.
The next step is to connect to a remote correlator (or engine). As with the other development kits this method takes the host and port of the correlator to connect to.
engine = AP_ConnectToEngine(argv[1], atoi(argv[2]));
At this stage the example creates an ‘event consumer’ entity to connect to the correlator. It needs to register a function that will be invoked whenever the correlator emits event alerts.
To achieve this;
consumer = (AP_EventConsumer*)malloc(sizeof(AP_EventConsumer));
consumer->functions = &receiveConsumer_Functions;
supplier = engine->functions->connectEventConsumer(engine, consumer,
NULL);
The first line above creates a ‘consumer’ structure. This contains a pointer to a table of callback functions, which in this release of the SDK can in fact contain only one function, the function to be called when event alerts are generated. In fact if we go backwards to the beginning of the example, the following definitions were made before main();
/**
* Receive a batch of events, log to stdout.
*/
static void AP_ENGINE_CLIENT_CALL
receiveConsumer_sendEvents(AP_EventConsumer* consumer,
AP_Event** events) {
AP_Event** event;
for (event = events; *event; event++) {
printf("%s\n", (*event)->functions->getText(*event));
}
}

/**
* Function table for our event consumer.
*/
static struct AP_EventConsumer_Functions
receiveConsumer_Functions = {
receiveConsumer_sendEvents
};
The second definition above, the structure receiveConsumer_Functions, is largely boilerplate code and a function similar to it needs to be defined for every consumer. It defines the table of callback functions (which in fact can only contain one function at present). The callback function itself is the first function above, here called receiveConsumer_sendEvents, which just prints out the alerts received.
The next part of the example defines and injects some EPL controlling code into the correlator;
/* Inject some MonitorScript (don't forget to delete it when done) */
script = AP_CreateMonitorScript(
"event TestEvent {"
" string text;"
"}"
""
"monitor Echo {"
""
" TestEvent test;"
""
" action onload {"
" on all TestEvent(*):test {"
" emit TestEvent(test.text);"
" }"
" }"
"}");

engine->functions->injectMonitorScript(engine, script);

AP_DeleteMonitorScript(script);
Note how first you define a string of EPL code, then inject it into the correlator, and finally delete it.
The example then proceeds to query the correlator as to its present runtime status, and then injects some events;
events[0] = AP_CreateEvent(
"TestEvent(\"Hello, World\")");
events[1] = AP_CreateEvent(
"TestEvent(\"Welcome to Apama\")");
events[2] = NULL;

engine->s_EventConsumer->functions->
sendEvents(engine->s_EventConsumer, events);
AP_DeleteEvent(events[0]);
AP_DeleteEvent(events[1]);
In this instance two events are going to be injected. The injection method always takes in a batch of events in a structure. Injecting events in batches results in greater event throughput as it lessens the overhead of making the underlying process-to-process call. Typically a batch size of one hundred produces optimal performance, although this varies according to the size of the individual events.
Note how the events themselves are deleted at the end of the above code.
These events will match with the monitor injected earlier, so the correlator will produce an alert for each and call the callback function registered earlier.
The next steps in the main body of the example are to delete the monitor and event type definitions made earlier from the correlator and then recheck its status to verify that the types are no longer defined.
Finally it is cleanup time. The steps here are to disconnect the consumer structure from the correlator, and then destroy it.
  supplier->functions->disconnect(supplier);
  free((void*)consumer);
The next and final steps are to disconnect the SDK library from the correlator and delete (or shutdown) the library itself.
  AP_DisconnectFromEngine(engine);  

AP_EngineShutdown();
This concludes this very simple example. The whole example, complete with exception and error handling is given below.
As described in Logging in C++ for the C++ SDK, the C SDK can output extensive logging information. The author of a C client need not bother with the standard logging unless they want to modify its operating parameters.
By default, the log level is set to WARN, where only significant warnings and errors are displayed in the log. The whole list of log levels is OFF (i.e. no logging at all), CRIT, FATAL, ERROR, WARN, INFO, DEBUG and TRACE. These levels are listed in order of decreasing importance, and conversely in the order of least likely occurrence. A very large volume of information is output at DEBUG level.
To change the logging, three functions are provided in the C SDK; AP_SetLogLevel(), AP_SetLogFile(), and AP_SetLogFD().
As described in Thread-safety for the C++ SDK, the C SDK is thread-safe.
Copyright © 2013-2015 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA, and/or its subsidiaries and/or its affiliates and/or their licensors.
Use, reproduction, transfer, publication or disclosure is prohibited except as specifically provided for in your License Agreement with Software AG.