Search code examples
ibm-mq

Issue with reading MQ segmented message


I wrote a client to read segmented message sent via MQ but getting error message. Below code work perfectly fine but it read single message at time, Application has to concatenate the segmented message which is not what I wanted

public void getMessage(){

        try {

           MQEnvironment.hostname = ""; 
           MQEnvironment.channel = ""; 
           MQEnvironment.port = ;

           MQQueueManager QMgr = new MQQueueManager("MQManager");

           MQGetMessageOptions gmo = new MQGetMessageOptions();

           gmo.options =  MQConstants.MQOO_INPUT_AS_Q_DEF|
                         MQConstants.MQGMO_WAIT|
                         MQConstants.MQGMO_ALL_SEGMENTS_AVAILABLE|
                         MQConstants.MQGMO_LOGICAL_ORDER;

           gmo.matchOptions = MQConstants.MQMO_NONE;
           gmo.waitInterval = MQConstants.MQWI_UNLIMITED;

           MQMessage message = new MQMessage();
           MQQueue queue = QMgr.accessQueue("QName",
                                           gmo.options);

           while(true){

            queue.get(message, gmo);
            int dataLength = message.getDataLength();           
            System.out.println(message.readStringOfCharLength(dataLength));
            message.clearMessage();
           }
        } catch (Exception e) {

            e.printStackTrace();
        }
    }

When I added MQGMO_SYNCPOINT to options, it fails with com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2046'.

Not sure why this fails, if I can atleast get this to work, I will be able to commit after safely processing all segmented message in the application.

public void getMessage(){

        try {

           MQEnvironment.hostname = ""; 
           MQEnvironment.channel = ""; 
           MQEnvironment.port = ;

           MQQueueManager QMgr = new MQQueueManager("MQManager");

           MQGetMessageOptions gmo = new MQGetMessageOptions();

           gmo.options =  MQConstants.MQOO_INPUT_AS_Q_DEF|
                         MQConstants.MQGMO_WAIT|
                         MQConstants.MQGMO_ALL_SEGMENTS_AVAILABLE|
                         MQConstants.MQGMO_LOGICAL_ORDER|
                         MQConstants.MQGMO_SYNCPOINT;

           gmo.matchOptions = MQConstants.MQMO_NONE;
           gmo.waitInterval = MQConstants.MQWI_UNLIMITED;

           MQMessage message = new MQMessage();
           MQQueue queue = QMgr.accessQueue("QName",
                                           gmo.options);

           while(true){

               queue.get(message, gmo);
                int dataLength = message.getDataLength();           
                System.out.println(message.readStringOfCharLength(dataLength));
                QMgr.commit();
                message.clearMessage();
           }
        } catch (Exception e) {

            e.printStackTrace();
        }
    }

When I try to read segmented message as a single message; it fails with com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2046'.

I would appreciate if some could help solve this issue; I am not really sure what is wrong with the below code. This is my preferred way to read the segmented message.

public void getMessage(){


        try {

           MQEnvironment.hostname = ""; 
           MQEnvironment.channel = ""; 
           MQEnvironment.port = ;

           MQQueueManager QMgr = new MQQueueManager("MQManager");

           MQGetMessageOptions gmo = new MQGetMessageOptions();

           gmo.options =  MQConstants.MQOO_INPUT_AS_Q_DEF|
                         MQConstants.MQGMO_WAIT|
                         MQConstants.MQGMO_COMPLETE_MSG;

           gmo.matchOptions = MQConstants.MQMO_NONE;
           gmo.waitInterval = MQConstants.MQWI_UNLIMITED;

           MQMessage message = new MQMessage();
           MQQueue queue = QMgr.accessQueue("QName",
                                           gmo.options);

           while(true){

               queue.get(message, gmo);
                int dataLength = message.getDataLength();           
                System.out.println(message.readStringOfCharLength(dataLength));
               message.clearMessage();
           }
        } catch (Exception e) {

            e.printStackTrace();
        }
    }

Solution

  • The issue is that you are using gmo.options as the open options for the accessQueue method and the get message options for the get. You are mixing both open options and get message options into this field.

    Each option is represented by a bit in the options field. When you use that field as the open options the bits are being interpreted by MQ as open options even if you specify get message options, conversely when you use the field as the get message options they are being interpreted by MQ as get message options.


    Lets look at the values of each option you are specifying in the your samples represented as hex along with the equivalent open or get option based on the value:

    MQOO_INPUT_AS_Q_DEF            0x00000001
    MQGMO_WAIT                     0x00000001
    
    MQOO_INPUT_SHARED              0x00000002
    MQGMO_SYNCPOINT                0x00000002
    
    MQOO_RESOLVE_NAMES             0x00010000
    MQGMO_COMPLETE_MSG             0x00010000
    
    MQOO_BIND_NOT_FIXED            0x00008000
    MQGMO_LOGICAL_ORDER            0x00008000
    
    MQOO_RESOLVE_LOCAL_Q           0x00040000
    MQOO_RESOLVE_LOCAL_TOPIC       0x00040000
    MQGMO_ALL_SEGMENTS_AVAILABLE   0x00040000
    

    Because you are incorrectly using this as open options with QMgr.accessQueue("QName",gmo.options); MQ is interpreting this in unexpected ways.


    For your first "working" example, the open options would be interpreted as specified below, these specific open options together would not cause any problems for local queues, this is why it is "working" even though it is not correct:

    MQOO_INPUT_AS_Q_DEF            0x00000001
    MQOO_INPUT_AS_Q_DEF            0x00000001 //MQGMO_WAIT
    MQOO_RESOLVE_LOCAL_Q           0x00040000 //MQGMO_ALL_SEGMENTS_AVAILABLE
    MQOO_RESOLVE_LOCAL_TOPIC       0x00040000 //MQGMO_ALL_SEGMENTS_AVAILABLE
    MQOO_BIND_NOT_FIXED            0x00008000 //MQGMO_LOGICAL_ORDER
    

    In your second example that fails with 2046 (MQRC_OPTIONS_ERROR) it is because the options are being interpreted as specified below. You cannot have MQOO_INPUT_AS_Q_DEF and MQOO_INPUT_SHARED together in the open options, this causes the 2046:

    MQOO_INPUT_AS_Q_DEF            0x00000001
    MQOO_INPUT_AS_Q_DEF            0x00000001 //MQGMO_WAIT
    MQOO_RESOLVE_LOCAL_Q           0x00040000 //MQGMO_ALL_SEGMENTS_AVAILABLE
    MQOO_RESOLVE_LOCAL_TOPIC       0x00040000 //MQGMO_ALL_SEGMENTS_AVAILABLE
    MQOO_BIND_NOT_FIXED            0x00008000 //MQGMO_LOGICAL_ORDER
    MQOO_INPUT_SHARED              0x00000002 //MQGMO_SYNCPOINT
    

    In your third example that fails with 2046 (MQRC_OPTIONS_ERROR) it is because the options are being interpreted as specified below. MQOO_RESOLVE_NAMES is documented as valid only in the MQ C++ APIs, this causes the 2046:

    MQOO_INPUT_AS_Q_DEF            0x00000001
    MQOO_INPUT_AS_Q_DEF            0x00000001 //MQGMO_WAIT
    MQOO_RESOLVE_NAMES             0x00010000 //MQGMO_COMPLETE_MSG
    

    Using the MQOO_INPUT_AS_Q_DEF as a get message option is not causing any issues because it has the same value as MQGMO_WAIT which you already have in each of your examples, having this is not changing the behavior of the get message options.

    MQGMO_WAIT                     0x00000001 //MQOO_INPUT_AS_Q_DEF
    MQGMO_WAIT                     0x00000001
    

    The following based on your second and third examples should work:

    public void getMessage(){
    
    
            try {
    
               MQEnvironment.hostname = ""; 
               MQEnvironment.channel = ""; 
               MQEnvironment.port = ;
    
               MQQueueManager QMgr = new MQQueueManager("MQManager");
    
               // Set up the options on the queue we wish to open
               int openOptions = MQConstants.MQOO_INPUT_AS_Q_DEF;
    
               MQGetMessageOptions gmo = new MQGetMessageOptions();
    
               gmo.options =  MQConstants.MQGMO_WAIT|
                              MQConstants.MQGMO_ALL_SEGMENTS_AVAILABLE|
                              MQConstants.MQGMO_LOGICAL_ORDER|
                              MQConstants.MQGMO_SYNCPOINT|
                              MQConstants.MQGMO_COMPLETE_MSG;
    
               gmo.matchOptions = MQConstants.MQMO_NONE;
               gmo.waitInterval = MQConstants.MQWI_UNLIMITED;
    
               MQMessage message = new MQMessage();
               MQQueue queue = QMgr.accessQueue("QName", openOptions);
    
               while(true){
    
                   queue.get(message, gmo);
                   int dataLength = message.getDataLength();           
                   System.out.println(message.readStringOfCharLength(dataLength));
                   QMgr.commit();
                   message.clearMessage();
               }
            } catch (Exception e) {
    
                e.printStackTrace();
            }
        }
    

    If you run the mqrc utility that comes with full MQ client installs you can find out what the error code translates to:

    $mqrc 2046
    
          2046  0x000007fe  MQRC_OPTIONS_ERROR