/***************************************************************************/ /* */ /* (c) Copyright IBM Corp. 2002 All rights reserved. */ /* */ /* This sample program is owned by International Business Machines */ /* Corporation or one of its subsidiaries ("IBM") and is copyrighted */ /* and licensed, not sold. */ /* */ /* You may copy, modify, and distribute this sample program in any */ /* form without payment to IBM, for any purpose including developing, */ /* using, marketing or distributing programs that include or are */ /* derivative works of the sample program. */ /* */ /* The sample program is provided to you on an "AS IS" basis, without */ /* warranty of any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, */ /* EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */ /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* Some jurisdictions do not allow for the exclusion or limitation of */ /* implied warranties, so the above limitations or exclusions may not */ /* apply to you. IBM shall not be liable for any damages you suffer as */ /* a result of using, modifying or distributing the sample program or */ /* its derivatives. */ /* */ /***************************************************************************/ /* */ /* Program name: mqsrvro */ /* */ /* Description: Sample C++ program that shows how to set the message id */ /* and correlation id when the requester has set instructions */ /* in the message header report field. It also shows how to */ /* handle bad messages when exception reporting is */ /* requested. Mqsrvro terminates when it receives an */ /* application defined termination or there are no new */ /* messages received for 5 minutes. */ /* */ /* This program should be used in conjunction with the */ /* mqreqro sample program. */ /* */ /* The best way to use the mqreqro and mqsrvro samples is to */ /* start them in separate MS-DOS Prompt windows. They need */ /* to run against the same queue and queue manager. Mqreqro */ /* initiates a request and mqsrvro replies. A part of the */ /* reply is handling the message id and correlation id as */ /* requested by mqreqro. */ /* */ /* */ /* Build: */ /* This program has been tested with Microsoft Visual C++ 6.0 */ /* and MQSeries V5.2 and Websphere MQ 5.3 on Windows/2000. */ /* Compile it with: */ /* */ /* cl -MT mqsrvro.cpp imqb23vn.lib imqs23vn.lib */ /* */ /* Note: Use imqc23vn.lib instead of imqs23vn.lib for a client */ /* connection. */ /* */ /* */ /* Execution: */ /* mqsrvro queuename */ /* */ /* where queuename is a required queue name */ /* and queuemgrname is an optional queue manager name */ /* */ /***************************************************************************/ #include #include #include #include #include const char * TERMINATE = "TERMINATE"; void replyToRequest(ImqMessage &msg, ImqQueueManager &qmgr); void sendExceptionReply(ImqMessage &msg, ImqQueueManager &qmgr); int main(int argc, char **argv) { ImqQueueManager qmgr; ImqQueue qServer; ImqMessage msg; ImqGetMessageOptions gmo; MQBYTE24 MsgId; MQBYTE24 CorrelId; MQLONG qCC; cout << "Program " << argv[0] << " started." << endl; if ( argc < 2 ) { cerr << "Required parameter missing - queue name" << endl; exit(99); } /***************************************************************/ /* Connect to queue manager */ /***************************************************************/ if ( argc > 2 ) { qmgr.setName(argv[2]); } if ( !qmgr.connect() ) { cerr << "ImqQueueManager::connect failed with reason code " << qmgr.reasonCode() << endl; exit(99); } /*************************************************************/ /* Get the queue name that will be used and open it for both */ /* input and output. */ /*************************************************************/ qServer.setConnectionReference(qmgr); qServer.setName(argv[1] ); qServer.setOpenOptions(MQOO_INPUT_AS_Q_DEF + MQOO_INQUIRE + MQOO_FAIL_IF_QUIESCING ); qServer.open(); /***************************************************************/ /* If there was an error opening the queue, print it out. */ /***************************************************************/ if (qServer.reasonCode()) { cerr << "ImqQueue::open ended with reason code " << qServer.reasonCode() << endl; } if (qServer.completionCode()) { cerr << "Unable to open server queue for input" << endl; } qCC = qServer.completionCode(); while ( qCC != MQCC_FAILED ) { // Let MQ automatically manage the receive buffer msg.useEmptyBuffer(0,0); gmo.setOptions(MQGMO_WAIT | /* wait for new messages */ MQGMO_FAIL_IF_QUIESCING); gmo.setWaitInterval(300000 ); /* terminate after 5 inactive min */ /**************************************************************/ /* Set message id and correlation id to null so the program */ /* will get the next available message on the queue. */ /**************************************************************/ msg.setMessageId(); msg.setCorrelationId(); if ( qServer.get(msg, gmo) ) { MQLONG msgType = msg.messageType(); int i=0; switch (msgType) { // application defined type to signal end of processing case MQMT_APPL_FIRST: if ( memcmp(msg.bufferPointer(),TERMINATE, strlen(TERMINATE))==0 ) { cout << "Terminate command received. Exit." << endl; qCC = MQCC_FAILED; } else { sendExceptionReply(msg, qmgr); } break; case MQMT_REQUEST: replyToRequest(msg, qmgr); break; default: sendExceptionReply(msg, qmgr); break; } } else { if ( qServer.reasonCode() == MQRC_NO_MSG_AVAILABLE ) { cout << endl; cout << "No more messages to process. Exit program" << endl; } else { cerr << "ImqQueue::get ended with reason code" << (long)qServer.reasonCode() << endl; } qCC = qServer.completionCode(); } } /****************************************************************/ /* Close the target queue (if it was opened) */ /****************************************************************/ if ( !qServer.close()) { cerr << "ImqQueue::close ended with reason code " << qServer.reasonCode( ) << endl; } /****************************************************************/ /* Disconnect from MQM if not already connected */ /****************************************************************/ if (!qmgr.disconnect()) { cerr << "ImqQueueManager::disconnect ended with reason code " << qmgr.reasonCode( ) << endl; } return(0); } /***************************************************************************/ /* Function name: replyToRequest */ /* */ /* Description: This functions reports the contents of the incoming */ /* Message ID and Correlation ID. Then it reads the reply */ /* to queue and queuemanager to see who to send the reply */ /* back to. */ /* Next it reads the report options to see how the */ /* requester wants the Message ID and Correlation ID set in */ /* the reply and sets them accordingly as well as reporting */ /* what the requester asked for. */ /* Finally, it reports the outgoing Message ID and */ /* Correlation ID for comparison and then sends the reply */ /***************************************************************************/ void replyToRequest(ImqMessage &msg, ImqQueueManager &qmgr) { ImqQueue qReply; ImqMessage msgReply; ImqPutMessageOptions pmo; MQBYTE24 MsgId; MQBYTE24 CorrelId; MQLONG reportOpts = msg.report(); MQLONG pmoOpts; cout << endl << " Request received:" << endl << " Message ID from get: "; msg.messageId().copyOut(MsgId, MQ_MSG_ID_LENGTH, 0); cout.setf(ios::hex); for (int i=0; i < MQ_MSG_ID_LENGTH; i++) { cout << (int)MsgId[i]; } cout << endl; cout.unsetf(ios::hex); cout << " Correlation ID from get: "; msg.correlationId().copyOut(CorrelId, MQ_MSG_ID_LENGTH, 0); cout.setf(ios::hex); for (i=0; i < MQ_MSG_ID_LENGTH; i++) { cout << (int)CorrelId[i]; } cout << endl; cout.unsetf(ios::hex); cout << endl; qReply.setConnectionReference( qmgr ); qReply.setName( msg.replyToQueueName() ); qReply.setQueueManagerName( msg.replyToQueueManagerName() ); qReply.setOpenOptions( MQOO_OUTPUT + MQOO_FAIL_IF_QUIESCING ); qReply.open(); /***************************************************************/ /* If there was an error opening the queue, print it out. */ /***************************************************************/ if (qReply.reasonCode() || qReply.completionCode() ) { cerr << "ImqQueue::Reply queue open ended with reason code " << qReply.reasonCode( ) << " and completion code " << qReply.completionCode() << endl; } else { pmoOpts = 0; msgReply.setMessageType(MQMT_REPLY); msgReply.useEmptyBuffer(0,0); if (reportOpts & MQRO_PASS_MSG_ID) { cout << " Requester asked for the existing message id to be passed back." << endl; msgReply.setMessageId(msg.messageId()); } else { cout << " Requester asked for a new message id to be generated." << endl; msgReply.setMessageId(); pmoOpts |= MQPMO_NEW_MSG_ID; } if (reportOpts & MQRO_PASS_CORREL_ID) { cout << " Requester asked for the existing correlation id to be passed back." << endl; msgReply.setCorrelationId(msg.correlationId()); } else { cout << " Requester asked for the existing message id to be passed back as the correlation id." << endl; msgReply.setCorrelationId(msg.messageId()); } /***************************************************************/ /* Use the overloaded ImqItem copyOut method to write the */ /* ImqString object to the automatic buffer and cause the */ /* format to be set to MQFMT_STRING. */ /***************************************************************/ ImqString replyStr("mqsrvro reply message"); replyStr.copyOut(msgReply); msgReply.setMessageLength(replyStr.length()); pmo.setOptions(pmoOpts); if (!qReply.put(msgReply, pmo)) { cerr << "ImqQueue::reply put ended with reason code " << qReply.reasonCode() << endl; } else { cout << endl << " Message ID from put: "; msgReply.messageId().copyOut(MsgId, MQ_MSG_ID_LENGTH, 0); cout.setf(ios::hex); for (int i=0; i < MQ_MSG_ID_LENGTH; i++) { cout << (int)MsgId[i]; } cout << endl; cout.unsetf(ios::hex); cout << " Correlation ID from put: "; msgReply.correlationId().copyOut(CorrelId, MQ_MSG_ID_LENGTH, 0); cout.setf(ios::hex); for (i=0; i < MQ_MSG_ID_LENGTH; i++) { cout << (int)CorrelId[i]; } cout.unsetf(ios::hex); cout << endl; } if ( !qReply.close()) { cerr << "ImqQueue::close ended with reason code " << qReply.reasonCode() << endl; } } } /***************************************************************************/ /* Function name: sendExceptionReply */ /* */ /* Description: This functions checks the report options to see if the */ /* requester asked for exception reporting. If yes, then */ /* it sets the Message ID and Correlation ID according to */ /* what the requester asked for in the report options. */ /* Next it reads the report options to see how much of the */ /* original data the requester wants returned in the */ /* exception message and copies the data accordingly. */ /* Then it sends the exception message. */ /***************************************************************************/ void sendExceptionReply(ImqMessage &msg, ImqQueueManager &qmgr) { ImqQueue qReply; ImqMessage msgReply; ImqPutMessageOptions pmo; MQLONG reportOpts = msg.report(); MQLONG pmoOpts; MQLONG buflen; MQBYTE24 MsgId; MQBYTE24 CorrelId; cout << endl << " Unexpected message type received!" << endl; if ( !(reportOpts & MQRO_EXCEPTION_WITH_FULL_DATA) ) { // User did not request exception reporting cout << " Requester did not ask for exception processing; nothing to do" << endl; return; } qReply.setConnectionReference( qmgr ); qReply.setQueueManagerName( msg.replyToQueueManagerName() ); qReply.setName( msg.replyToQueueName() ); qReply.setOpenOptions( MQOO_OUTPUT + MQOO_FAIL_IF_QUIESCING ); qReply.open(); /***************************************************************/ /* If there was an error opening the queue, print it out. */ /***************************************************************/ if (qReply.reasonCode() || qReply.completionCode() ) { cerr << "ImqQueue::Reply queue open ended with reason code " << qReply.reasonCode( ) << " and completion code " << qReply.completionCode() << endl; } else { pmoOpts = 0; /***************************************************************/ /* Indicate the reply is reporting an exception by setting */ /* the type to MQMT_REPORT and setting a user defined return */ /* code in the Feedback field. The other attributes are copied */ /* from the request message. */ /***************************************************************/ msgReply.useEmptyBuffer(0,0); msgReply.setMessageType(MQMT_REPORT); msgReply.setReport(MQRO_NONE); msgReply.setFeedback(MQFB_APPL_FIRST); msgReply.setEncoding(msg.encoding()); msgReply.setCharacterSet(msg.characterSet()); msgReply.setFormat(msg.format()); msgReply.setPriority(msg.priority()); msgReply.setPersistence(msg.persistence()); /***************************************************************/ /* Message ID and Correl ID are set according to request */ /* report options. */ /***************************************************************/ if (reportOpts & MQRO_PASS_MSG_ID) { msgReply.setMessageId(msg.messageId()); } else { msgReply.setMessageId(); pmoOpts |= MQPMO_NEW_MSG_ID; } if (reportOpts & MQRO_PASS_CORREL_ID) { msgReply.setCorrelationId(msg.correlationId() ); } else { msgReply.setCorrelationId(msg.messageId() ); } /***************************************************************/ /* The amount of data returned is determined by the exception */ /* option the requester specified. */ /***************************************************************/ if ( (reportOpts & MQRO_EXCEPTION_WITH_FULL_DATA) == MQRO_EXCEPTION_WITH_FULL_DATA) { // return full message from request msgReply.write(msg.messageLength(), msg.bufferPointer()); } else if ( (reportOpts & MQRO_EXCEPTION_WITH_DATA) == MQRO_EXCEPTION_WITH_DATA ) { // return original message up to 100 bytes msgReply.write( (msg.messageLength() > 100) ? 100 : msg.messageLength(), msg.bufferPointer()); } else { // no message body, only the message header msgReply.setMessageLength(0); } pmo.setOptions(pmoOpts); if (!qReply.put(msgReply, pmo)) { cerr << "ImqQueue::reply put ended with reason code " << qReply.reasonCode( ) << endl; } if ( !qReply.close()) { cerr << "ImqQueue::close ended with reason code " << qReply.reasonCode( ) << endl; } } }