In this chapter, samples have been used to explain the use of CRTL. In addition to the basic send and receive functionality of the C Runtime Libraries, these samples have been designed to demonstrate features such as
- asynchronous receive
- transacted session
These samples also demonstrate the use of ExceptionListener on a connection and handling error conditions while programming with CRTL. While using these samples, note how the memory allocated for different objects is freed. Similar format can be followed in the user applications as well.
The source code of the sample is a follows.
#include <stdio.h>
#include <jms.h>
//Message Listener callback
void OnMessage(Message msg);//ExceptionListener callbackvoid OnException(char* exception,void* param);
InitialContextic=NULL;QueueConnectionFactoryqcf=NULL;Queue queue= NULL;QueueConnectionqc=NULL;QueueSessionsendqs=NULL,
recvqs= NULL;QueueSenderqsender=NULL;QueueReceiver qreceiver = NULL;TextMessagetmsg= NULL;
/**
- Free up the memory allocated to the objects and also
- close the connections, sessions etc. */
void cleanup(){
/** - Call the corresponding _free functions for freeing
- any object not the free() function
*/IC_free(ic);Q_free(queue);QCF_free(qcf);QSNDR_close(qsender);QRCVR_close(qreceiver);QS_close(sendqs);QS_close(recvqs);QC_close(qc);QSNDR_free(qsender);QRCVR_free(qreceiver);QS_free(sendqs);QS_free(recvqs);QC_free(qc);}
/** - The function which is set as the message listener
*/void OnMessage(Message msg){
static mqint msgcount = 0;++msgcount;printf("Received Message %d : %s\n", msgcount, FTMSG_getText(msg));//Commit after receiving every message from the serverQS_commit(recvqs);
MSG_free(msg);}
/** - The function which is set as the exception listener
/void OnException(char exception,void* param){
mqstring code = (mqstring)param;//Print the exception trace and the param and//cleanup all objects.
printf("Received Message %s : %s\n", param, exception);cleanup();exit(-1);
}
/** - After a call to any API, a check should be done for any error * occurred in that call. In this example, if any error occurs
- anywhere in the application, the program will exit */
void main()
{mqint count = 0;//Create InitialContext
if((ic = newInitialContextDefaultParams()) == NULL)
{MqPrintException();MqExceptionClear();cleanup();exit(-1);
}printf("Created the Initial Context\n");//Lookup for the primaryQCF object on the serverif((qcf = IC_Lookup(ic,"primaryQCF")) == NULL){
MqPrintException();MqExceptionClear();cleanup();exit(-1);
}printf("Looked up primaryQCF\n");
//Lookup for the primaryQueue object on the serverif((queue = IC_Lookup(ic,"primaryQueue")) == NULL){
MqPrintException();MqExceptionClear();cleanup();exit(-1);
}printf("Looked up primaryQueue\n");//Create a Queue Connection with default parametersif((qc = QCF_createQueueConnectionDefParams(qcf)) == NULL){
MqPrintException();MqExceptionClear();cleanup();exit(-1);
}printf("Created the QueueConnection\n");//Set the ExceptionListener on the connection]if(QC_setExceptionListener(qc,OnException,"JMSException occurred.") == FALSE)
{MqPrintException();MqExceptionClear();cleanup();exit(-1);
}//Create a transacted, Auto acknowledgement Queue Sessionif((sendqs = QC_createQueueSession(qc, TRUE,
AUTO_ACKNOWLEDGE)) == NULL)
{MqPrintException();MqExceptionClear();cleanup();exit(-1);
}
//Create a transacted, Auto acknowledgement Queue Sessionif((recvqs = QC_createQueueSession(qc, TRUE, AUTO_ACKNOWLEDGE)) == NULL)
{MqPrintException();MqExceptionClear();cleanup();exit(-1);
}
//Create a Sender to send messages on the primaryQueueif((qsender = QS_createSender(sendqs, queue)) == NULL){
MqPrintException();MqExceptionClear();cleanup();exit(-1);
}printf("Created a sender to send messages on primary-Queue\n");
//Create a Receiver to receive messages on the primaryQueueif((qreceiver = QS_createReceiver(recvqs, queue)) == NULL){
MqPrintException();MqExceptionClear();cleanup();exit(-1);
}
//Starting the Connection, essential to start receiving
messagesif(!QC_start(qc)){
MqPrintException();MqExceptionClear();cleanup();exit(-1);
}//Create a TextMessage without any text in itif((tmsg = QS_createTextMessage(sendqs)) == NULL){
MqPrintException();MqExceptionClear();cleanup();exit(-1);
}
//Send 10 Text Messages using the qsenderfor(count = 0; count < 10; count ++){
if(!FTMSG_setText(tmsg, "FioranoMQ"))
{MqPrintException();MqExceptionClear();cleanup();
exit(-1);}
// Sending a message using the Senderif(!QSNDR_send(qsender, tmsg)){
MqPrintException();MqExceptionClear();cleanup();exit(-1);
}}
MSG_free(tmsg);
// Commit the send session so that all the messages are sent
to // the FMQ Serverif(!QS_commit(sendqs)){
MqPrintException();MqExceptionClear();cleanup();exit(-1);
}printf("***** Commit the sender session *****\n");//Waiting for 5 messages on the Queue (Synchronous receive)for(count = 0; count < 5; count++){
if((tmsg = QRCVR_receive(qreceiver)) == NULL)
{MqPrintException();MqExceptionClear();cleanup();exit(-1);
}printf("Received message : %s\n", FTMSG_getText(tmsg));MSG_free(tmsg);
}
//Rollback the Receiver Session, so that all the messages /
/received are rolled-backif(!QS_rollback(recvqs)){
MqPrintException();MqExceptionClear();cleanup();exit(-1);
}printf("*****Rollback the receiver session *****\n");
//Setting a message listener, for asynchronous receiveif(!QRCVR_setMessageListener(qreceiver, OnMessage)){
MqPrintException();MqExceptionClear();cleanup();
exit(-1);}
//Wait for the messages to be received by the message lis-
tenerSleep(10000);//Cleanup all the resources allocated in the samplecleanup();
}
The following steps explain the sequence of calls taking place in the sample: - Declare callback functions for both the MessageListener and the Exception-Listener.
- An InitialContext is created to lookup the Queue and QueueConnectionFactory objects from the FioranoMQ server.
- The QueueConnectionFactory is used to create a QueueConnection.
- The ExceptionListener callback declared earlier is set as the exception listener for the QueueConnection with a constant mqstring as the parameter.
- The QueueConnection is then used to create two sessions, one for sending the messages and the other for receiving the messages. The sessions are created in transacted mode, to use the commit/rollback feature.
- A QueueSender is created on the queue "primaryqueue" using one of the sessions.
- A QueueReceiver is created on the queue "primaryqueue" using the other session.
- The QueueSender is used to send 10 messages. After sending the messages, the sender session is committed, so as to send all the messages to the FioranoMQ server.
- Then the QueueReceiver is used to receive 5 messages, using the QRCVR_receive() API, which is the synchronous way of receiving messages.
- The messages received by the receiver are rolled-back, when the QS_rollback() API is invoked for the receiver session.
- The message listener callback declared earlier is set on the receiver, which receives 10 messages, since the first 5 messages were rolled-back.
- The receiver session commits after receiving every message.
- The user should destroy all the resources allocated in the application, used the corresponding APIs defined by CRTL. So this is accomplished by Cleanup() API, which closes the connection, sessions, senders and receivers, and destroy the various objects.
For more sample applications check the \c\samples directory of the FioranoMQ installation.
Organization of Samples Provided
The CRTL samples provided in the FioranoMQ installation are organized into the following directories that can be found in the /crtl/samples directory of the installation.
ptp
- basic Demonstrates the basic JMS Send/Receive functionality
- browser Demonstrates the use of QueueBrowser
- transaction Demonstrates the commit/rollback functionality in QueueSession
- http Demonstrates the use of http
- https Demonstrates the use of https
- msgsel Demonstrates the use of message properties and message selectors
- reqrep Demonstrates the use of the JMS request/reply API (the request() and replyTo() APIs)
- ssl Demonstrates the use of ssl
pubsub
- basic Demonstrates the basic JMS publish/subscribe functionality
- reqrep Demonstrates the Request/Reply mechanism
- msgsel Demonstrates the use of message properties and message selectors
- transaction Demonstrates the commit/rollback functionality in TopicSession
- dursub Demonstrates the basic Durable Subscriber functionality
- http Demonstrates the use of http
- https Demonstrates the use of https
- ssl Demonstrates the use of ssl
Compiling and Running the Samples
The following sections contain the procedures for compiling and running the samples. The samples on WIndows and Solaris.
On Windows
Compiling the samples
The samples provided with CRTL can be compiled using the script cclientbuild.bat, provided along with the C-runtime package. The following variables in the script file should be set to the appropriate paths:
- VC_DIR The root directory of the Microsoft Visual C++ installation
- INCLUDE_PATH The directory where all the header files of CRTL exist
- CRTL_LIB The directory where the fmq-crtl.lib file and other required libraries exist.
Libraries required for compiling the CRTL samples (apart from the default VC libs):
- Advapi32.lib
- ws2_32.lib
- fmq-crtl.lib
- crtl_https.lib (only for SSL and HTTP/HTTPS samples)
- pthreadVC.lib
- libeay32.lib (only for SSL samples)
- ssleay32.lib (only for SSL samples)
- http.lib (only for HTTP/HTTPS samples)
- gnu_regex.lib (only for HTTP/HTTPS samples)
- zlib.lib (only for HTTP/HTTPS samples)
Use the Multi-threaded option for Code generation in the project.
The following example illustrates how to compile a sample using cclientbuild.bat file:
cclientbuild Sample.c
After compilation a Win32 executable is formed that can be executed as explained in the following section.
For more details on compiling and running the samples, please read the readme.txt files provided in c\samples folder of FioranoMQ installation.
Running the Samples
After compiling the samples as explained above, they can be executed by using the corresponding executable file generated.
Sample [<arg1> <arg2> ... ]
The following DLLs need to in the system PATH for running the compiled WIN32 executable:
- pthreadVC.dll
- libeay32.dll (only for SSL samples)
- ssleay32.dll (only for SSL samples)
- gnu_regex.dll (only for HTTP/HTTPS samples)
- zlib.dll (only for HTTP/HTTPS samples)
On Solaris
Compiling the samples
The samples provided with CRTL can be compiled using the script cclientbuild.sh, provided along with the C-runtime package. This script file uses the GCC compiler and assumes that the same is available on the concerned Solaris machine.
The following variables in the script file should be set to the appropriate paths:
- CRTL_HOME The base directory of the CRTL package in the FioranoMQ installation
Libraries required for compiling the CRTL samples:
- libsocket.so
- libpthread.so
- libnsl.so
- libcrtl.so
- libcrtl_https.so (only for SSL and HTTP/HTTPS samples)
- libhttp.so (only for HTTP/HTTPS samples)
- libcrypto.a (only for HTTP/HTTPS samples)
- libssl.a (only for SSL and HTTP/HTTPS samples)
The following example illustrates how to compile a sample using cclientbuild.sh file:
cclientbuild.sh Sample.c
After compilation, a bin file (Sample.bin in the above example) is formed that can be executed as explained in the following section.
Running the Samples
The bin file formed after compilation can be executed from the console as follows.
Sample.bin [<arg1> <arg2> ... ]