Assured message get works in a similar way to put. If a get message command is issued with a confirmId parameter greater than zero, the message is left locked on the queue on which it resides until a confirm flow is processed by the target queue manager. When a confirm flow is received, the message is deleted from the queue. Figure 6 describes a get of synchronous messages:
Figure 6. Assured get of synchronous messages
The following code is taken from examples.application.example6
boolean msgGet = false; /* get successful? */ boolean msgConfirm = false; /* confirm successful? */ MQeMsgObject msg = null; int maxRetry = 5; /* maximum number of retries */ long confirmId = MQe.uniqueValue(); int retry = 0; while( !msgGet && retry < maxRetry) { try { msg = qmgr.getMessage( "RemoteQMgr", "RemoteQueue", filter, null, confirmId ); msgGet = true; /* get succeeded */ } catch ( Exception e ) { /* handle any exceptions */ /* if the exception is of type Except_Q_NoMatchingMsg, meaning that */ /* the message is unavailable then throw the exception */ if ( e instanceof MQeException ) if ( ((MQeException)e).code() == Except_Q_NoMatchingMsg ) throw e; retry ++; /* increment retry count */ } } if ( !msgGet ) /* was the get successful? */ /* Number of retry attempts has exceeded the maximum allowed, so abort */ /* get message operation */ return; while( !msgConfirm && retry < maxRetry ) { try { qmgr.confirmGetMessage( "RemoteQMgr", "RemoteQueue", msg.getMsgUIDFields() ); msgConfirm = true; /* confirm succeeded */ } catch ( Exception e ) { /* handle any exceptions */ retry ++; /* increment retry count */ } }
MQEINT32 maxRetry = 5; rc = mqeQueueManager_getMessage(hQMgr, &exceptBlock, hQMgrName, hQName, hMsg, NULL, confirmId); /* if the get attempt fails, retry up to the maximum number of*/ /*retry times permitted, setting the re-send flag. */ while (MQERETURN_OK != rc && --maxRetry > 0 ) { rc = mqeFields_getBoolean(hMsg, &exceptBlock, MQE_MSG_RESEND, MQE_TRUE); if(MQERETURN_OK == rc) { rc = mqeQueueManager_getMessage(hQMgr, &exceptBlock, hQMgrName, hQName, hMsg, NULL, confirmId); } } if(MQERETURN_OK == rc) { MQeFieldsHndl hFilter; maxRetry = 5; rc = mqeFieldsHelper_getMsgUidFields(hMsg, &exceptBlock, &hFilter); if(MQERETURN_OK == rc) { rc = mqeQueueManager_confirmGetMessage(hQMgr, &exceptBlock, hQMgrName, hQName, hFilter); } while (MQERETURN_OK != rc && --maxRetry > 0 ) { rc = mqeQueueManager_confirmPutMessage(hQMgr, &exceptBlock, hQMgrName, hQName, hFilter); } }
The value passed as the confirmId parameter also has another use. The value is used to identify the message while it is locked and awaiting confirmation. If an error occurs during a get operation, it can potentially leave the message locked on the queue. This happens if the message is locked in response to the get command, but an error occurs before the application receives the message. If the application reissues the get in response to the exception, then it will be unable to obtain the same message because it is locked and invisible to WebSphere MQ Everyplace applications.
However, the application that issued the get command can restore the messages using the undo method. The application must supply the confirmId value that it supplied to the get message command. The undo command restores messages to the state they were in before the get command.
boolean msgGet = false; /* get successful? */ boolean msgConfirm = false; /* confirm successful? */ MQeMsgObject msg = null; int maxRetry = 5; /* maximum number of retries */ long confirmId = MQe.uniqueValue(); int retry = 0; while( !msgGet && retry < maxRetry ) { try { msg = qmgr.getMessage( "RemoteQMgr", "RemoteQueue", filter, null, confirmId ); msgGet = true; /* get succeeded */ } catch ( Exception e ) { /* handle any exceptions */ /* if the exception is of type Except_Q_NoMatchingMsg, meaning that */ /* the message is unavailable then throw the exception */ if ( e instanceof MQeException ) if ( ((MQeException)e).code() == Except_Q_NoMatchingMsg ) throw e; retry ++; /* increment retry count */ /* As a precaution, undo the message on the queue. This will remove */ /* any lock that may have been put on the message prior to the */ /* exception occurring */ myQM.undo( qMgrName, queueName, confirmId ); } } if ( !msgGet ) /* was the get successful? */ /* Number of retry attempts has exceeded the maximum allowed, so abort */ /* get message operation */ return; while( !msgConfirm && retry < maxRetry ) { try { qmgr.confirmGetMessage( "RemoteQMgr", "RemoteQueue", msg.getMsgUIDFields() ); msgConfirm = true; /* confirm succeeded */ } catch ( Exception e ) { /* handle any exceptions */ retry ++; /* increment retry count */ } }
MQeFieldsHndl hMsg; rc = mqeQueueManager_getMessage(hQMgr, &exceptBlock, &hMsg, hQMgrName, hQName, hFilter, NULL, confirmId); /* if unsuccessful, undo the operation */ if(MQERETURN_OK != rc) { rc = mqeQueueManager_undo(hQMgr, &exceptBlock, hQMgrName, hQName, confirmId); }
The undo command also has relevance for the putMessage and browseMessagesAndLock commands. As with get message, the undo command restores any messages locked by the browseMessagesandLock command to their previous state.
If an application issues an undo command after a failed putMessage command, then any message locked on the target queue awaiting confirmation is deleted.
The undo command works for operations on both local and remote queues.