Introduction
Query-response applications are very important in computer technology. We use them every day. In fact, you are using one now as you read this article. Your web browser sent a query to the servers at www.codeproject.com, it received the response in the form of text encoded as HTML, which your browser displays to you right now. Query-response applications aren’t just for the web, but for accessing a database server, or receiving files from a file server; even creating users in Windows 2000 and Windows XP uses a query response architecture.
SAFMQ is really a type of middleware, or software that works between two applications so they can communicate with each other. Although SAFMQ has Store and Forward Message Queuing, it also is tuned for query-response applications. Each message enqueued in the SAFMQ server is given a unique UUID (also known as GUID). This value is based off the MAC address of the server and the date and time it was created, (down to the millisecond) using RFC 4122 on UNIX systems, and Microsoft’s implementation on Windows based systems. This UUID is available to both the sender of the message and the receiver. In addition to the automatically generated UUID, a message also has a “Receipt ID,” which can be specified by the sender. Receivers can call a special version of Retrieve which specifies a Receipt ID, and causes the caller to wait until a message is retrievable with a matching Receipt ID.
Here’s a collaboration diagram that may help describe the Round-Trip Query-Response architecture:
Now, there are some special features that you can use with Round-Trip messaging. One is the ability to specify the amount of time a message may live on a queue. This value known as “Time To Live” tells the SAFMQ server to automatically remove the message from the queue if it has been on the queue too long. Also, a client can request that it be notified when a message expires, and the SAFMQ server will generate a response message in this case.
Background
If you aren’t familiar with SAFMQ, you can find out more about it here.
Using the code
Here’s a sample server and client:
#include <iostream>
#include "safmq.h"
#include "lib/MessageQueue.h"
#include "lib/MQFactory.h"
using namespace std;
using namespace safmq;
int main(int argc, char* argv[])
{
QueueMessage query, response;
try {
MessageQueue* query_que =
MQFactory::BuildQueueConnection("safmq:"
"//user:password@localhost/query","","");
MessageQueue* response_que =
MQFactory::BuildQueueConnection("safmq:"
"//user:password@localhost/response","","");
query.setTimeToLiveSeconds(5);
query.setTTLErrorWanted(true);
query.setResponseQueueName("safmq"
"://localhost/resposne");
query.setBodyType(BT_TEXT);
*query.getBufferStream() << "Hello";
query.setLabel("query");
ErrorCode ec = query_que->Enqueue(query);
if (ec == EC_NOERROR) {
uuid id = query.getMessageID();
ec = response_que->RetrieveID(true,
id,-1,response);
if (ec == EC_NOERROR) {
if (response.getMessageClass() ==
MC_SYSTEMERRMSG) {
cerr << response.getLabel() << endl;
} else {
cout << response.getBufferStream()->rdbuf()
<< endl;
}
} else {
cerr << "Retreiving the result gave ErrorCode:"
<< ec << endl;
}
} else {
cerr << "Sending the query gave ErrorCode:"
<< ec << endl;
}
delete query_que;
delete response_que;
} catch (ErrorCode e) {
cerr << "ErrorCode: " << e
<< " received." << endl;
} catch (exception& e) {
cerr << e.what() << endl;
}
return 0;
}
#include <iostream>
#include <string>
#include "safmq.h"
#include "lib/MessageQueue.h"
#include "lib/MQFactory.h"
using namespace std;
using namespace safmq;
int main(int argc, char* argv[])
{
QueueMessage query, response;
try {
MessageQueue* query_que =
MQFactory::BuildQueueConnection("safmq:"
"//user:password@localhost/query","","");
MessageQueue* response_que = NULL;
SAFMQ_WSTRING response_name;
ErrorCode ec = query_que->Retrieve(true,-1,query);
if (ec == EC_NOERROR) {
response.setLabel("response");
response.setReciptID(query.getMessageID());
response.setBodyType(BT_TEXT);
*response.getBufferStream() << "Hi!"
<< endl;
response.getResponseQueueName(response_name);
response_que =
MQFactory::BuildQueueConnection(response_name,
"user","password");
response_que->Enqueue(response);
delete response_que;
}
delete query_que;
} catch (ErrorCode e) {
cerr << "ErrorCode: " << e
<< " received." << endl;
} catch (exception& e) {
cerr << e.what() << endl;
}
return 0;
}
History
Updates and documentation for SAFMQ can be found at SourceForge.net.
A programmer for 20 years and professionaly employed for 12, I am currently Cheif Engineer for Pharmacy Chare Professionals, Inc., located in Omaha, NE.
My experience is in the area of OO Design, Application, and programming, technical team leadership, RDBMS applications, ISAM applications, Image Processing, Mathematical image generation, Client-Server business applications, eBusiness applications, XML & EDI B2B communications, Java application development, C/C++ application development, CFML/ASP/VB development, on systems like Win2K/NT/98/95, Linux, Irix, Solaris, and MacOS.