Working with JSON CCDT files

A recent feature added to IBM MQ are Client Channel Definition Table (CCDT) files in JSON format.

One of the features of MQSCX is to work with CCDT files, both the binary format, and now (since MQSCX V9.2.0) the JSON format.

With MQSCX you can display or create/alter a JSON CCDT file using familiar MQSC commands. Your tried and tested scripts for creating binary format CCDT files, can be used to create the same in JSON format.

For example, this file:

DEFINE CHANNEL(MQG1.SVRCONN) CHLTYPE(CLNTCONN) +
       CONNAME('gemmvs(1701)') QMNAME(MQG1)
DEFINE CHANNEL(MQG2.SVRCONN) CHLTYPE(CLNTCONN) +
       CONNAME('gemmvs(1702)') QMNAME(MQG2)

ClientChls.mqs

Run with this command:

mqscx -j -i ClientChls.mqs

Will produce a JSON CCDT file like this where the MQCHLLIB and MQCHLTAB environment variables point:

ClientChls.json
{
  "channel":
  [
    {
      "name": "MQG1.SVRCONN",
      "type": "clientConnection",
      "clientConnection":
      {
        "connection": 
        [
          {
            "host": "gemmvs",
            "port": 1701
          }
        ],
        "queueManager": "MQG1"
      }
    },
    {
      "name": "MQG2.SVRCONN",
      "type": "clientConnection",
      "clientConnection":
      {
        "connection": 
        [
          {
            "host": "gemmvs",
            "port": 1702
          }
        ],
        "queueManager": "MQG2"
      }
    }
  ]
}

You can also use MQSCX interactively and type in these familiar MQSC commands, using TAB auto-complete to assist, and create a JSON CCDT that way too.

Validation

One of the benefits of using a JSON format CCDT is that it is a text file instead of the proprietary binary file. So why do you need a tool like MQSCX to create one? Well the answer is validation. If you create a JSON CCDT file by hand, you may have a typo or spelling error in any of the field names. If you do this and display your file using runmqsc, or run it using an MQ Client, neither will inform you of your typo because they are designed to be future proof. There is no versioning on a JSON CCDT file, so if the MQ Client uses one that is from a newer version of MQ, it just ignores anything that it doesn’t recognise. This includes your misspelled attributes, that you actually wanted it to use!

Misspelled attributes

Here’s an example JSON CCDT with a typo:

{
  "channel":
  [
    {
      "name": "MQGEM.SVRCONN",
      "type": "clientConnection",
      "clientConnection":
      {
        "connection":
        [
          {
            "host": "localhost",
            "port": 1701
          }
        ]
      },
      "connectionManagement":
      {
         "hbInterval": 60
      }
    }
  ]
}

HBintClnt.json

If I use runmqsc to look at it, it won’t complain and it will tell me that my heartbeat interval value is 300.

Note: runmqsc can be used to display the contents of the JSON CCDT file, but not to create or edit its contents.

runmqsc -n
5724-H72 (C) Copyright IBM Corp. 1994, 2019.
Starting local MQSC for 'HBintClnt.json'.
DISPLAY CHANNEL(*) HBINT
     1 : DISPLAY CHANNEL(*) HBINT
AMQ8414I: Display Channel details.
   CHANNEL(MQGEM.SVRCONN)                  CHLTYPE(CLNTCONN)
   HBINT(300) 

With a SVRCONN defined with HBINT(60), a client running using this CCDT, which should be using 60 seconds for the heartbeat interval, will actually use 300, and so the running SVRCONN will end up with 300 as well.

AMQ8417I: Display Channel Status details.
   CHANNEL(MQGEM.SVRCONN)                  CHLTYPE(SVRCONN)
   CONNAME(127.0.0.1)                      CURRENT
   HBINT(300)                              STATUS(RUNNING)
   SUBSTATE(RECEIVE)                    

Running MQSCX to look at this JSON CCDT file, will show the following:

MQSCX Extended MQSC Program – Version 9.2.0

At line 20 of file ‘C:\MQGem\HBintClnt.json’, unrecognised field name ‘hbInterval’ found

CCDT file ‘C:\MQGem\HBintClnt.json’, 1 channels read

Licenced to Paul Clarke

Licence Location: Head Office

So, you are immediately aware of the issue in your CCDT file.

Missing mandatory attributes

There aren’t many mandatory attributes on a client channel definition, but those that are, are important!

If you omit a mandatory attribute, again runmqsc won’t complain, but of course the client channel will when it tries to make a connection.

Here’s an example JSON CCDT with a channel that hasn’t specified a connection name:

{
  "channel":
  [
    {
      "name": "MQGEM.SVRCONN",
      "type": "clientConnection",
    }
  ]
}

ConnameClnt.json

When a client application attempts to run using this, you’ll get something like the following in your client AMQERR01.LOG:

AMQ9203E: A configuration error for TCP/IP occurred.

EXPLANATION:
Error in configuration for communications to host ' '.  Allocation of
a TCP/IP conversation to host ' ' was not possible.

Running MQSCX to view, and therefore validate, this JSON CCDT file, will show the following:

MQSCX Extended MQSC Program – Version 9.2.0

The channel definition ending at line 7 of file ‘C:\MQGem\ConnameClnt.json’ has not specified a connection name

CCDT file ‘C:\MQGem\ConnameClnt.json’, 1 channels read

Licenced to Paul Clarke

Licence Location: Head Office

Enhanced Filtering

In addition to the above, using MQSCX to view and manipulate your CCDTs (both binary and JSON) allows you to utilise the power of MQSCX filtering. For example you can use a command like the following, which wouldn’t be allowed through runmqsc.

DISPLAY CHANNEL(*MQGEM*)

Or you could use enhanced WHERE clauses that are more powerful than the IBM MQ supplied WHERE clause. For example, you can use a command like the following:

DISPLAY CHANNEL(*) =WHERE(NOT(SCYEXIT AND SCYDATA))

Re-ordering your JSON defined channels

The order that an MQ client will pick channels to use from your JSON CCDT is dependant on the order they are in the file, and you control that order. In the binary CCDT, the file was always internally ordered alphabetically, but with a text file like the JSON CCDT you are in complete control.

As it is a text file, you can just use your favourite editor to copy the lines around, just make sure you have all the right brackets and commas in place. Alternatively, you can use MQSCX to reorder your file just how you want it as follows.

MOVE CHANNEL(MQG1.SVRCONN) POSITION(1) NEWPOS(2)

You can also indicate the position in the file for a channel definition at the time you create it, for example, using a command like this to make the new channel first in the file:

DEFINE CHANNEL(MQG1.SVRCONN) CHLTYPE(CLNTCONN) +
       CONNAME('gemmvs(1701)') QMNAME(MQG1) INDEX(BEFORE)

JSON file format

You also have some control over the contents of the JSON CCDT file that is created by MQSCX with three options on how the fields are output.

  • =set jsonfields(all)
    This option will create a JSON CCDT file with all the values output, even those that just contain the default or blank values. This makes your JSON CCDT file bigger of course, but might be useful if you need to manually edit it later and you are unsure of the field names.
  • =set jsonfields(date)
    This option will create a JSON CCDT file with the minimum set of fields (see below) and additionally the alteration date/time field. The MQ Client does not make use the of this date information, so it is only added if you ask for it. We assume, since it is in the JSON CCDT schema that someone might want it for something.
  • =set jsonfields(min)
    This is the default setting, and only outputs the channel fields are have non-default or non-blank values. This will make your JSON CCDT file much smaller than you would get with jsonfields(all), and is the minimum the MQ Client needs to work with.

Summary

So if you’re starting to look into using JSON CCDT files, perhaps for their ability to define channels with the same name within one CCDT, and you’re not a JSON format expert, take a look at MQSCX to produce your CCDTs and ensure that you always have a valid format CCDT file to use with your MQ Clients.


If you don’t already have MQSCX and you’d like to try it out, please email support@mqgem.com to request a trial licence. You can download MQSCX from our website.

MQSCX on z/OS

The recent release of MQSCX V9.2 included the provision of MQSCX to run natively on the z/OS platform.

All those features of MQSCX that you have been able to use on your distributed platforms, such as report writing, functions, foreach loops (and all the other great MQSCX control language features); namelist processing and more, are now available natively on z/OS

MQSCX can be run interactively in a number of environments on your z/OS system. Type in a command and immediately get responses back. Additionally in these environments you can also run scripts that are stored in MVS files or HFS files.

  • z/OS UNIX (TTY)
    In this environment, you are running with a TTY terminal and MQSCX will look and feel very similar to the experience you have on a Unix or Windows platform. You have tab auto-complete for commands and object names, and scrolling of output.
  • z/OS UNIX (z/OS shell)

    From TSO/E, use the OMVS command to run the z/OS shell. You can use the MQSCX program interactively in this environment.

    GEMUSER:/u/gemuser/mqscx: >mqscx -m MQG1   
    MQSCX Extended MQSC Program - Version 9.2.0 
    Licenced to MQGem Software Limited          
    Licence Location: Any location               
                                                 
    Connected to 'MQG1'                          
    MQG1>DISPLAY QMGR VERSION                 
    CSQM409I %MQG1                               
    QMNAME(MQG1)        VERSION(09010500)        
    MQG1>
     ===> =import file(//MQSCX.SCRIPTS(AGE)) 
                                                                        INPUT
    ESC=¢  1=Help     2=SubCmd   3=HlpRetrn  4=Top      5=Bottom   6=TSO
           7=BackScr  8=Scroll   9=NextSess 10=Refresh 11=FwdRetr 12=Retrieve
  • TSO/E

    From the TSO READY prompt, or from the ISPF command processor panel (aka Option 6), you can use the MQSCX program interactively. You must remember to tell the CALL command that you don’t want its default behaviour of upper casing the parameter string.

       Menu  List  Mode  Functions  Utilities  Help             
     ─────────────────────────────────────────────────────────────────────
                                   ISPF Command Shell           
     Enter TSO or Workstation commands below:                   
                                                                
     ===> CALL USER.LOAD(MQSCX) '-m MQG1' ASIS                            
                                                                          
                                                                          
                                                                
     Place cursor on choice and press enter to Retrieve command 
                                                                
     => CALL USER.LOAD(MQSCX) '-m MQG1' ASIS                    
     =>                                                         
     MQSCX Extended MQSC Program - Version 9.2.0                
     Licenced to MQGem Software Limited                         
     Licence Location: Any location                             
                                                                
     Connected to 'MQG1'                                        
     MQG1>                                                      
    DISPLAY QMGR VERSION                                        
     CSQM409I %MQG1                                             
     QMNAME(MQG1) VERSION(09010500)                             
     MQG1>                                                      
    =import file(//MQSCX.SCRIPTS(AGE))

As well are providing an interactive MQSC experience, MQSCX can also run scripts in interactive mode, as shown above, and also from batch in JCL jobs.

  • JCL to run a script from a file

    While it is possible to provide the file name directly when running a script, it is much simpler (and shorter) to use a DD name in JCL. This DD name can point to an MVS file or an HFS file as the two example DD names show below.

    //MQSCX    JOB                                                         
    //*********************************************************************
    //* Run an MQSCX script                                                
    //*********************************************************************
    //MQSCX    EXEC PGM=MQSCX,                                             
    //         PARM=('-m MQG1 -i DD:SCRIPT')                               
    //STEPLIB  DD   DSN=GEMUSER.USER.LOAD,DISP=SHR                         
    //         DD   DSN=IBM.MQ.SCSQAUTH,DISP=SHR                           
    //         DD   DSN=IBM.MQ.SCSQANLE,DISP=SHR                           
    //SYSPRINT DD   SYSOUT=*                                               
    //SYSOUT   DD   SYSOUT=*                                               
    //MQGEML   DD   DSN=GEMUSER.MQGEM.LIC,DISP=SHR                         
    //SCRIPT   DD   DSN=GEMUSER.MQSCX.SCRIPTS(AGE),DISP=SHR                
    //SCRIPT2  DD   PATH='/u/gemuser/mqscx/scripts/Age.mqx',
    //         PATHOPTS=(ORDONLY)                            
    //
  • JCL to run a script inline

    While developing your script, you might find it easier to have it inline in the same JCL job you use to submit it. You can either use the SYSIN DD card, or provide a DD name as above, and inline that DD card.

    //MQSCX    JOB                                                         
    //*********************************************************************
    //* Run an MQSCX script                                                
    //*********************************************************************
    //MQSCX    EXEC PGM=MQSCX,                                             
    //         PARM=('-m MQG1')                               
    //STEPLIB  DD   DSN=GEMUSER.USER.LOAD,DISP=SHR                         
    //         DD   DSN=IBM.MQ.SCSQAUTH,DISP=SHR                           
    //         DD   DSN=IBM.MQ.SCSQANLE,DISP=SHR                           
    //SYSPRINT DD   SYSOUT=*                                               
    //SYSOUT   DD   SYSOUT=*                                               
    //MQGEML   DD   DSN=GEMUSER.MQGEM.LIC,DISP=SHR                         
    //SYSIN    DD   *                          
    foreach(DISPLAY QLOCAL(*) CURDEPTH)        
      if (CURDEPTH > 0)                        
        print QUEUE,"has",CURDEPTH,"messages!" 
      endif                                    
    endfor   
    /*                                         
    //

We have endeavoured to make MQSCX work appropriately in each environment on z/OS, but would of course value any feedback users have to improve how MQSCX operates in any and all of these environments.


You can download MQSCX for z/OS from the MQSCX Download Page. If you’d like to try out MQSCX on z/OS, please email support@mqgem.com and a 1-month trial licence will be sent to you.

MQSCX version 9.2.0 is released

MQGem Software is pleased to announce that a new version of MQSCX, our command line extended MQSC tool for IBM MQ, is now available.

The main features of the release are as follows:-

JSON CCDT editing

MQSCX has always been able to create and edit the IBM MQ binary CCDT files. However, now you can display, edit and create CCDT files using the JSON format. This is extremely useful to more easily create valid JSON CCDT files, knowing that you haven’t misspelled an attribute, or put an attribute in the wrong place in the schema. You can create JSON CCDT files using the familiar MQSC commands DEFINE CHANNEL, just as before, with one or two additional attributes to handle those times when there are multiple channels of the same name, or when you want to change the order of the channels in the JSON CCDT file.

Read more about this new feature here.

MQSCX control language updates

  • New and changed expression functions
    The MQSCX control language has some new and changed expression functions in this new release.

    • New: valueof()
      String function to parse files in the format FIELD(VALUE)This could be very useful for parsing optional parameters into a function. For example, you could imagine having the string
      QMGR(MQG1) PRINT(N) REPEAT(10)
      and then using the following script to use those parameters to control how a function might work.

      func Report(ParmStr)
        @qmgr   = valueof("QMGR", @ParmStr)
        @print  = valueof("PRINT", @ParmStr)
        @repeat = eval(valueof("REPEAT", @ParmStr))
        if (!exists(@repeat))
          @repeat = 2
        endif
        :
      endfunc
    • New: power(x,y)
      Mathematical function returning the value of xy.For example power(10,2) = 100.00
       
    • Changed: system()
      The system() function now has an optional second parameter to determine whether to run the invoked command synchronously or asynchronously.This can be especially useful if you need to know that your command has completed before you continue with the rest of the script.

      @CmdStr = "q -m " + _qmgr + ' -o LOG.Q -M"Job Done!"'
      system(@CmdStr, const.SYNC)
  • New and updated system variables
    The MQSCX control language has some new and changed system variables in this new release.

    • New: _lastcmdresp
      This system variable will contain any error message associated with the last command issued. For example:

      foreach(RESET QSTATS(*))
        :
      endfor
      if (_numEach = 0)
        print _lastcmdresp
      endif
    • Server O/SUpdated: _os
      This can now contain the value “MVS” when running MQSCX on z/OS. Read this post for more on this system variable.
       
  • Command substitution improvements
    Previously you could not use an array value in a command substitution. That restriction has now been lifted. For example, you can now do this.

    @Name[1] = "Q1"
    @Name[2] = "Q2"
    @index = 2
    DISPLAY QLOCAL(<@Name[@index]>)

Force the config file to be written

Previously, the config was not saved when you ran in file mode. This was to avoid any settings used by an imported script file from changing your setup. However, there are times when you want an imported script to save the changes, for example if redefining synonyms. So now, there is a new flag, -S that will force the config to be saved regardless.

Remove weak cipher values

IBM MQ is strongly discouraging users from selecting weak CipherSpec values on their channels. All deprecated CipherSpec values will now not be shown to MQSCX users when tabbing through all the possibilities on the SSLCIPH attribute. You can change this behaviour using the =set weakciph(on | off) command.

z/OS Support

MQSCX is now available to run locally on the z/OS platform. To enable this you require a z/OS specific licence. A distributed platform MQSCX licence will not enable MQSCX on z/OS to run. For more on this read this blog post: MQSCX on z/OS

Command Level support up to 920

MQSCX now supports queue managers up to the most recently released command level of 920.


The new version can be downloaded from the MQSCX Download Page. Any current licensed users of MQSCX can run the new version on their existing licence. If you don’t have a licence and would like to try out MQSCX then send a note to support@mqgem.com and a 1-month trial licence will be sent to you.

Simple Scripting of the Current Queue Depth

On StackOverflow, someone asked a question about determining when a queue’s current depth is the same as maximum depth. Roger, from Capitalware, and I agree on one thing here and that is sed and awk are likely to be able to do it, but that we’d rather do it another way.

Roger provided a Java program to get both the current and maximum depths and compare the values – he has supplied his source code here.

I would do it by using our MQSCX tool. In that case it is possible to issue the following command (which in fact is exactly what the Original Poster was trying to do with runmqsc). The difference being I am using the MQSCX =WHERE clause which is very much more powerful than the IBM MQ supplied WHERE clause.

DIS QL(*) =WHERE(CURDEPTH EQ MAXDEPTH)

Also, if you want to find all those queues that are fuller than the Queue-High threshold, then you could use a command like this.

DIS QL(*) =WHERE(CURDEPTH GT MAXDEPTH * QDEPTHHI/100)

In fact any arithmetic you need with any selection of object attributes can be put together in an =WHERE clause.


If you don’t already have MQSCX and you’d like to try it out, please email support@mqgem.com to request a trial licence. You can download MQSCX from our website.

Long Running UoWs

You can discover long running units of work using the IBM MQ command DISPLAY CONN. This shows you the time a UoW first wrote to the log, and comparing that to the time it is now allows you to discover any long running transactions. When looking at the start time of a UoW, please bear this quirk in mind.

Use a command like the following to show all connections that have an uncommitted UoW that has actually involved the log.

DISPLAY CONN(*) TYPE(CONN) ALL WHERE(UOWLOGTI NE ' ')

If you want to look for the long UoWs, then you need to compare the two fields UOWLOGDA and UOWLOGTI with the current time to see how old the UoW is.

This is easy to do with a simple MQSCX script.

foreach(DISPLAY CONN(*) TYPE(CONN) ALL WHERE(UOWLOGTI NE ' '))
  @uowage = _time - mqtime(UOWLOGDA,UOWLOGTI)
  if (@uowage > 120)
    print _lastresp
  endif
endfor

LongUoW.mqx

Run this script with the following command in MQSCX.

=import file(LongUoW.mqx)

In the above example, this script very simply prints out the complete responses (_lastresp) from DISPLAY CONN that have transactions exceeding the age specified (120 seconds in this example), giving output something like this:-

CONN(B69F715E0555C820) EXTCONN(414D51434D5147312020202020202020) TYPE(CONN) PID(35920) TID(1) APPLDESC() APPLTAG(d:\nttools\q.exe) APPLTYPE(USER) ASTATE(NONE) CHANNEL() CLIENTID() CONNAME() CONNOPTS(MQCNO_SHARED_BINDING) USERID(mqgemusr) UOWLOG(S0000309.LOG) UOWSTDA(2020-03-22) UOWSTTI(20.19.17) UOWLOGDA(2020-03-22) UOWLOGTI(20.19.17) URTYPE(QMGR) EXTURID(XA_FORMATID[] XA_GTRID[] XA_BQUAL[]) QMURID(0.45064) UOWSTATE(ACTIVE) CONNTAG(MQCTB69F715E0555C820MQG1_2019-03-23_18.03.31 d:\nttools\q.exe)

Now of course, you can print out whatever you want, you don’t have to print out the MQSC output. Below we have enhanced the same script to print out just the fields we care about, making it easier to read, and to make it clear when there are none to show, rather than printing nothing at all.

@ageboundary = 120
@countUoW    = 0

foreach(DISPLAY CONN(*) TYPE(CONN) ALL WHERE(UOWLOGTI NE ' '))
  @uowage = _time - mqtime(UOWLOGDA,UOWLOGTI)
  if (@uowage > @ageboundary)
    @countUoW = @countUoW + 1
    print "Long-running UoW (",:n:@uowage,"seconds) for application", :s:APPLTAG
    if (CHANNEL)
      print "over channel", CHANNEL, "from IP address", :s:CONNAME
    endif
    print "from user", USERID
  endif
endfor
if (@countUoW = 0)
  print "No long-running UoW older than", @ageboundary, "seconds"
endif

LongUoW.mqx

Now you’ll see output like this:-

Long-running UoW (3362 seconds) for application d:\nttools\q.exe from user mqgemusr

At the moment this script has a hard-coded value for the age beyond which we are interested in these long-running transactions. In the next step, we alter the script to add this as a parameter.

if (!exists(@_Parm[1]))
  print "Usage: LongUoW Age-in-seconds"
  leave
endif
@ageboundary = eval(@_Parm[1])
@countUoW    = 0

foreach(DISPLAY CONN(*) TYPE(CONN) ALL WHERE(UOWLOGTI NE ' '))
  @uowage = _time - mqtime(UOWLOGDA,UOWLOGTI)
  if (@uowage > @ageboundary
    @countUoW = @countUoW + 1
    print "Long-running UoW (",:n:@uowage,"seconds) for application", :s:APPLTAG
    if (CHANNEL)
      print "over channel", CHANNEL, "from IP address", :s:CONNAME
    endif
    print "from user", USERID
  endif
endfor
if (@countUoW = 0)
  print "No long-running UoW older than", @ageboundary, "seconds"
endif

LongUoW.mqx

Run this script with the following command in MQSCX.

=import file(LongUoW.mqx) parms(120)

Now if this is too long a command to type in (although mitigated by command recall of course), you can set up a synonym for it so you have much less to type.

=syn(UOW) cmd(=import file(LongUoW.mqx) parms(120))

So now you just need to type UOW in MQSCX to run the command to find any long-running transactions that are older than 120 seconds.


This post was prompted by a question on mqseries.net.


If you don’t already have MQSCX and you’d like to try it out, please email support@mqgem.com to request a trial licence. You can download MQSCX from our website.

MQGem tools on Linux on Little Endian Power

MQGem is pleased to announce the availability of three of its products on the Linux on Little Endian Power platform.

We have had these products available on Linux on Power for a number of years, and now have added the Little Endian platform to the list.

Thanks to those customers who requested it.

You cannot run a Big Endian application on a Little Endian platform and vice versa. Ensure you download the appropriate version of the tool for the platform you are using. For example, if you try to run the Big Endian version on a Little Endian platform, you will see an error something like this:-

-bash: ./mqscx: cannot execute binary file

If you are not sure which platform you are using, try one of the following commands:-

lscpu

which will show you output similar to:

Architecture:          ppc64le
Byte Order:            Little Endian
CPU(s):                ...

Or if you have an older version of Linux, which doesn’t provide that command, try:-

uname -a

which might give you hint.

Linux gemlnx4.mqgem.com 3.10.0-327.36.3.el7.ppc64le #1 SMP Thu Oct 20 04:58:48 EDT 2016 ppc64le ppc64le ppc64le GNU/Linux

Extra Reading Material


The new versions can be downloaded from the website from the links given above. Any current licensed users of these products can run them on the new platform using their existing licence. If you don’t have a licence and would like to try out any of our products then send an email to support@mqgem.com and a 1-month trial licence will be sent to you.

Check MQ attributes meet standards using MQSCX

Colin Paice and I worked together in IBM Hursley for nearly 20 years. Now we’re both outside IBM, but still both doing things with MQ. I watch his blog posts with interest as he learns new things and writes about them. Recently he has been learning Python and loving it – he is impressed by how few lines of code he needs to achieve his task.

Object Standards

A recent task was to check queue definitions against a set of ‘standards’, for example:

  • Maximum Queue Depth must be at least 100
  • Put and Get must both be enabled
  • Queue Depth events must be enabled

I wondered how a script to do this task using MQSCX would look so I wrote it.

=echo resp(no) cmds(no)

@QlocalStandards = "MAXDEPTH > 100,    +
                    PUT = 'ENABLED',   +
                    GET = 'ENABLED',   +
                    QDPLOEV = 'ENABLED' OR QDPHIEV = 'ENABLED'"

foreach(DISPLAY QLOCAL(*) ALL)
  foritem(@QlocalStandards)
    if (!eval(_item))
      print "Queue", QUEUE, "does not meet standard", _item
    endif
  endfor
endfor

It is nicely compact – I wonder if it has few enough lines of code to impress Colin?

It gives output like this:-

Queue SMALL.Q does not meet standard MAXDEPTH > 100

When adding other standards to check for, you simply use MQSC keywords and values which are nice and familiar. The standards are just one very long string, with each ‘standard’ separated by a comma. I have formatted it over a number of lines using the ‘+’ continuation character to make it easier to see. If you add to it, ensure you have a comma between each individual standard, and end the string with a double quote. When comparing an attribute value to a string like ‘ENABLED’ remember to quote those strings.

I extended it a little to turn it into a function so you could use it for any object type, and ended up with this.

*********************************************************************
* FUNCTION: checkOBJs                                               *
*           This function checks whether all objects                *
*           of a specific type match the values                     *
*           defined as standards to be followed.                    *
*********************************************************************
func checkOBJs(Object, ObjType, Standard)
  foreach(DISPLAY <@Object>(*) <@ObjType> ALL)
    foritem(@Standard)
      if (!eval(_item))
        print @Object, eval(@Object), "does not meet standard", _item
      endif
    endfor
  endfor
endfunc

@QlocalStandards = "MAXDEPTH > 100,    +
                    PUT = 'ENABLED',   +
                    GET = 'ENABLED',   +
                    DESCR NE '',       +
                    QDPLOEV = 'ENABLED' OR QDPHIEV = 'ENABLED'"
@SenderStandards = "HBINT < DISCINT,   +
                    DESCR NE ''"

checkOBJs("Queue",   "TYPE(QLOCAL)", @QlocalStandards)
checkOBJs("Channel", "CHLTYPE(SDR)", @SenderStandards)

You don’t need to turn off the command and response output when in a function as that is the default setting anyway. Three parameters are used to create the DISPLAY command and to formulate the printed output, but otherwise the logic is the same.

In my sender channel example I have added a standard that compares the values of two attributes – haven’t we always told you that Heartbeat Interval (HBINT) should be less than the Disconnect Interval (DISCINT)?

If you find building a long string a bit tricky – can’t get the plus signs and commas in the right places, you can instead build up the list of standards into a global string variable in this way:-

*********************************************************************
* FUNCTION: Add (AddStandard)
*           Build the standard list without worrying about
*           commas and plus signs.
*********************************************************************
func Add(Standard)
  @Standards = @Standards + "," + @Standard
endfunc

=echo input(no)

@Standards = "";
Add("MAXDEPTH > 100")
Add("PUT = 'ENABLED'")
Add("GET = 'ENABLED'")
Add("DESCR NE ''")
Add("QDPLOEV = 'ENABLED' OR QDPHIEV = 'ENABLED'")

checkOBJs("Queue",   "TYPE(QLOCAL)", @Standards)

@Standards = "";
Add("HBINT < DISCINT")
Add("DESCR NE ''")

checkOBJs("Channel", "CHLTYPE(SDR)", @Standards)

If you don’t already have MQSCX and you’d like to try it out, please email support@mqgem.com to request a trial licence.

Use MQGem tools with IBM MQ on IBM Cloud

You may have seen the recent announcement from IBM about the experimental IBM MQ service running on IBM Cloud.
IBM Cloud

You can learn more with these resources:-

When you read the description of this new service in the Bluemix catalog, you’ll see it says the following:-

Manage MQ your way

Manage your cloud-based queue managers with the tools you know and love – including MQ Explorer, the MQ Console, or via MQ Script Commands (MQSC).

This blog post is here to assure you that the tools you know and love from MQGem Software; MO71, MQSCX, MQEdit and QLOAD can all also be used with IBM MQ running on IBM Cloud.

Once you have created your MQ on IBM Cloud Service and Queue Manager, as shown in the above video, and your queue manager is up and running, you’ll have a view something like this.

IBM Cloud QM List

A list showing my Running queue manager

Click on the three vertical dots on the right of your queue manager to “Download Connection info”, or alternatively view the details of your queue manager and then there is a button there too which allows you to download the “Connection Information”. Either way, you’ll be presented with a pop-up which allows you to download a plain text file which contains the queue manager name, hostname, port number and a couple of channel names, one called an Application Channel and one called an Administration Channel.

IBM Cloud Download Connection info

IBM Cloud Download Connection info

In order to remotely connect to your IBM Cloud queue manager you will also need to be able to log in. As the MQ on IBM Cloud documentation describes here, you need the API key as your password to go with the user id ‘admin’. Follow the instructions on that page to obtain your API key.

Now you have all the pieces of information you need to set up any of the MQGem Software tools to administer your queue manager on IBM Cloud. As a reminder, these are the things you will need.

Item From where
Queue Manager Name You invented it when you created the queue manager. If you’ve forgotten it, it’s also in the text file you downloaded with the connection information.
Channel Name The “Administration channel name” can be found in the text file you downloaded with the connection information.
Connection Name This is built by concatenating the “Hostname” and “Listener port” details (with brackets round the port number) that can be found in the text file you downloaded with the connection information.
User ID This is ‘admin’
Password This is the API Key that you created by following the linked instructions.

On the pages that follow, we cover how to use the above information you have gathered in your table to configure each of our tools to connect to your IBM MQ in IBM Cloud Queue Manager. Go directly to the page for the tool you want to use, or page through each one in turn.

  1. MO71
  2. MQEdit
  3. MQSCX
  4. QLOAD

If you don’t have a licence and would like to try out any of our tools then send an email, noting which tool you’d like to try, to support@mqgem.com and a 1-month trial licence will be sent to you.

MQSCX version 9.0.1 is released

MQGem Software is pleased to announce that a new version of MQSCX, our command line extended MQSC tool for IBM MQ, is now available.

This is a mini-release, specifically to release the first of the below features. But then we added a couple more things at the same time!

Issue RESET QSTATS as an MQSC command

Sparked by a conversation on MQSeries.net we were intrigued when one user asked us whether it would be possible to provide RESET QSTATS as an MQSC command on the distributed platforms using MQSCX. Turns out it is possible!

Support certlabl on connect

The =conn command provides for a number of client channel configuration attributes, and now certlabl is among them.

The Any Key

Press Any Key?

Provide a simple way of getting user key input

This version introduces the getkey() function which will return the next key pressed by the user. This can be useful to, for example, navigate your way through a script menu, or to exit from a while loop in a script at the user’s command.


The new version can be downloaded from the MQSCX Download Page. Any current licensed users of MQSCX can run the new version on their existing licence. If you don’t have a licence and would like to try out MQSCX then send a note to support@mqgem.com and a 1-month trial licence will be sent to you.

Creating a CCDT for any version

You may have read an earlier post where we described being able to determine what version of CCDT you had in your hand.

CCDT Version

How often have you had a CCDT file in your hand and wondered what version it was and whether you can give it to some of your known back-level client machines to use.

MQSCX can help you determine this. Open up your CCDT using the mqscx -n mode and then you can quite simply display the version number of all your client channels therein.

What you may not have realised from that post however, was that not only can MQSCX help to investigate what version number your CCDT is made for, it can also make a CCDT for the correct version as well. If you have back-level clients, it can be a real pain having to keep a queue manager of the same level around just to be able to create a CCDT that it will understand. Well, you can ditch that queue manager and use MQSCX instead. It’s really easy to do as well.

To use MQSCX to work with a CCDT, you need to use the -n parameter. This will then look for the CCDT file in the location specified by the MQCHLLIB and MQCHLTAB environment variables unless you provide the -t parameter to give it a specific file name. If one doesn’t exist, it will make a new one for you, and if one does exist it will read it and allow you to update it. In order to control the version of CCDT you are creating, you should additionally use the -V parameter which allows you to specify the version the CCDT file should be written as.

Here’s an example, run the MQSCX program like this:

mqscx -n -t C:\MQGem\CCDT\MQGEM.TAB -V7.0

And then you can use it to make DISPLAY, ALTER and DELETE commands.

MQSCX Extended MQSC Program – Version 8.0.0

CCDT commands directed to file ‘C:\MQGem\CCDT\MQGEM.TAB’

Licenced to Paul Clarke

Licence Location: Head Office

[12:02:10] DISPLAY CHANNEL(*) CONNAME VERSION

_________________________________________________

CHANNEL(MQG1.SVRCONN) CHLTYPE(CLNTCONN)

CONNAME(win12.mqgem.com(1602)) VERSION(8.0)

_________________________________________________

CHANNEL(MQG2.SVRCONN) CHLTYPE(CLNTCONN)

CONNAME(aix5.mqgem.com(4231)) VERSION(8.0)

_________________________________________________

CHANNEL(MQG3.SVRCONN) CHLTYPE(CLNTCONN)

CONNAME(mvs1.mqgem.com(1255)) VERSION(8.0)

_________________________________________________

Total display responses – Received:3

>

As you can see, at the moment all the channels in this CCDT are at V8.0 which means my V7.0 client won’t be able to read them. I need to make a change to each record to ensure MQSCX will write it out at version V7.0 as I have indicated on my start command. Helpfully, I can do that in one single command:-

ALTER CHANNEL(*)

This makes no actual change to the attributes of the channel definition, but does ‘touch’ each record to ensure that it gets the new version. Displaying the records again as above will show that the version number for each channel mentioned by the ALTER command (in this example all of them), now indicates it is at version V7.0, just what my back-level client application needs.

Exiting MQSCX and re-running it will show you that this earlier version of the CCDT has indeed been hardened.

Note that if you had been using some attributes introduced in later versions than V7.0, this information would be lost when altering the channel definition to be an earlier version.


If you’d like to try out MQSCX, please email support@mqgem.com to request a trial licence.