Getting the IBM JMS samples working in batch on Ubuntu for people who cannot spell Java Massage Service.

Why these JMS blog posts?

I had a “quick” question from someone, “can I configure JMS to reduce CPU usage and improve performance?”. It was was wet Monday in Orkney (north of Scotland) and I thought I would spent an hour looking into it. A few weeks later, I am much wiser, and have some answers to the question. The Knowledge Centre has a lot of information, mostly is useful, mostly accurate, some information is missing and some assumes that you are very familiar with the product.

I also found that that the Java people tend to use different words for familiar concepts, so I had to struggle with this different language.

Below are the blog posts I wrote on getting JMS working on Ubuntu 18.04with MQ V9.

Basic background to JMS

JMS programs are written in Java (the clue is in the name)

They can run as a batch job, for example one program to put a message to a queue, and another program to get the message and send a reply back. You might have an application that connects to MQ, processes one message and ends, or a server application which connects and stays connected all day processing messages


You can run JMS applications in a Web Server

  1. Connect once and stay connected all day doing sends and receives
  2. Like a trigger monitor, a listener task gets a message from the queue and passes it to an Message Driven Bean(MDB) application which does all of the work, and sends the reply back to the requester.
  3. An application uses the web server and runs a transaction which invokes a program (MDB) to do the work. This is an URL usually something like http://localhost:9080/WMQ_IVT/ in your web browser.

JMS people speak a different language.

The JMS people (being Java people) speak with a different accent, which takes a bit of getting used to.

Puts vs send: MQ people speak of puts and gets, JMS people talk about send and receive.

Specifying queue names: C programmers often hard code names in their programs for example

#define SERVERQUEUE “PAYROLLSERVERQ”.

Change the common header file, and recompile it and it picks up the new defintions.

The JMS people have a better way of doing it. The mapping of  SERVERQUEUE to “PAYROLLSERVERQ” can be done outside of the program. You just change a configuration file, and do not need to rebuild your program. However some Java people write programs without the use of the external parameters, and define every thing in their Java program!

Connecting to a queue manager. In a similar way, to get a C program to talk to a queue manager as a client you need to set up an environment variable containing the channel name, IP address etc.

In JMS this is usually stored in a configuration file, so to change the queue manager, or where it is located, you change the configuration and restart the application.

  • In WAS Liberty the code to connect to MQ is called a connectionFactory. You pass parameters to this using data in XML in <jmsConnectionFactory …> tags. Personally, I would have called this <jmsConnectionFactoryInput… >. You just have to get used to these naming conventions.

The Russian doll of packaging java programs

If you open up a Russian Doll, you find another one inside. If you open this one, you find another one etc down to the smallest baby.

When working with Java you need to understand some of the packaging terms ( .jar, .war, .ear, MDB). At first with any new concept it sounds really hard, but you soon get used to it

  • You start with a source program myprog.java. This gets processed and produces a myprog.class file. For simple programs, this class file can be executed.
  • Normally your program needs other bits from libraries or other java programs for it to work. You package up your program and the java classes it needs into a .jar file. You can execute a name.jar file.
    • Why .jar? Well my guess is that there are tools which creates an “archive”, packaging files together using zip. So it is natural to call it Java Archive. Also jar sounds half the word “Ja-va” and calling it .jbntrp (Java Bits Needed To Run Program) is much harder than saying .jar.
  • If you want to run a Web application you need you need your .jar file or classes, and the webpages your application will use. Web pages are not java classes, so storing them in a .jar file feels wrong,  so we now have .war files or Web ARchive. This is all the .class files and web pages etc zipped up.
  • As well as a web application running from a URL, these applications often need to uses other components. Message Driven Beans (MDB) provide a service, they get called with data (the message), they do something, and return some data.
  • If you are running a big commercial application, or Enterprise Application, you break up your huge program into bits. You can have some bits running here, and other bits running over there. Just like with CICS you can have a File Owning Region, and a Application Owning region. For your big commercial application you have Enterprise Java Beans (EJBs) Which take the .war files, and the MDBs, and other into and create an Enterprise Archive – or an .ear file.

How do you look inside these are archives?

You can use the jar command as in

jar -tvf xxxx.yyy

For example to list what is inside it you need the -t option

jar –tvf new.ear

17972 Tue Nov 13 20:09:26 GMT 2018 WMQ_IVT.war
571 Mon Jul 09 11:40:24 BST 2018 META-INF/application.xml
10984 Tue Nov 06 09:20:42 GMT 2018 WMQ_IVT_MDB.jar
17972 Tue Nov 13 20:09:24 GMT 2018 CCP.war

To break up the archive file and eXtract files within it into the current directory, use

jar –xvf new.ear

once you have extracted it, you can then use jar on the files within it

jar -tvf WMQ_IVT.war

gives


WEB-INF/classes/IVT.class

which is what is executed!

You may also see .rar which are Resource Adapter ARchive files – ok – this should be .raar – but it is called .rar to keep it simple.

As I said it is like a Russian doll with, files within files, within files.

What’s in a bean?

You will hear a lot about Java Beans.
When you create an instance of a Java object you pass parameters, such as

new currentJob("Colin Paice","retired") or
new currentJob("Colin Paice", "retired","Orkney")

and there are methods which take the varying number of parameters and do things with the data.

A Bean is a java program, and instead of passing parameters into the object you invoke methods such as

job  = new currentJob();  // note no parameters are passed in
job.setName("Colin Paice");
job.setStatus("retired");
job.setAddress("Orkeny");

You can also issue

job.getName() .

to extract information.

Now comes the clever usage bit.
I can ask Java to tell me the methods a class has.  I will get back [“setName”,”setStatus”,”setAddress”,”getName”..]

So now I can select all the “get….” methods, and call them in turn.  This makes it great for systems management.   You can process my bean, and display all of the information in it.  I change the bean – and your program does not have to change – good eh?

A Message Driven Bean – is a bean with an additional method, “onMessage(…)” so we can now pass it data ( eg the content of an MQ message) to process.

Looking up parameters – JNDI

Java developers like to use an interface called JNDI get the configuration information.

This configuration could be in a database, or in the local file system – it depends on how you configure it.

As different applications can use the same repository, the JNDI uses a hierarchical naming standard. For example

application/Payroll/Server → PAYROLLONINPUT

application/LookupBalancel/Server → BALANCEINPUT

The application issues a query saying get me the queue name from “application/Payroll/Server”

there may also be

setup/configuation/constants

This means you can isolate the “application” and “setup” environments.

The Java people use the term initial context to identify the “application” or “setup” at the top of the naming ree.

Setting up the JNDI

It is good practice to set up your definitions once, and have every one use the same set. This takes time, and perhaps a database and server.

To save me time, (and help me understand the concepts) I used a directory tree on my laptop for “batch” programs”, and had the information stored within the Web Server configuration for the web server.

When using the file system as a JNDI repository, you point to a directory, and JNDI stores information within the directory.

Running the JMS “batch programs”

My system is Ubuntu 18.04 and I was running MQ V9.1.

I used the linux command find /opt/mqm -name Jms*.java to display all of the JMS sample programs.

This gave me

/opt/mqm/samp/jms/samples/JmsJndiProducer.java
/opt/mqm/samp/jms/samples/JmsBrowser.java
/opt/mqm/samp/jms/samples/JmsConsumer.java
/opt/mqm/samp/jms/samples/JmsJndiBrowser.java
/opt/mqm/samp/jms/samples/JmsProducer.java
/opt/mqm/samp/jms/samples/interactive/helper/JmsApp.java
/opt/mqm/samp/jms/samples/JmsJndiConsumer.java

I was interested in the JmsJndi* examples.

There are /opt/mqm/samp/jms/samples/JmsJndiProducer.class etc ready to run.

The syntax of the command is

JmsJndiProducer -i JNDI-Directory -c myQCF -d myQueue

Where the parameters summarised immediately below, and explained in more detail in the following text

  • -i JNDI-Directory is the directory where the JNDI data is stored (or the URL where the database is)
  • -c myQCF is the name of the connection factory (connection information object)
  • -d myQueue is the label which points to which queue to use

You define resources in the JNDI file using the JMSAdmin tool.

You need the ibmmq-java* package installed to get the JMS stuff.

First you need to define where your JNDI resources will be stored.

mkdir ~/JNDI-Directory

See Starting the administration tool

The JMSAdmin tool needs to be told where the JNDI repository is.

MQ provides a file /opt/mqm/java/bin/JMSAdmin.config. Read it, there are lots of comments.

You can use the command grep -v “#” /opt/mqm/java/bin/JMSAdmin.config to display just the non comment lines. This gave me

INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory
PROVIDER_URL=file:///home/colinpaice/JNDI-Directory
SECURITY_AUTHENTICATION=none

create a file JMSAdmin.config in your home directory and add the above statements to it.

INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory

says it is to read JNDI from a file in the file system.

Change PROVIDER_URL=file:///home/colinpaice/JNDI-Directory to match the directory you created above.

and make it writable

chmod 744 JMSAdmin.config

Objects required to run the sample programs

  1. The applications get passed a connectionFactory object, I’ll use ConnectionFactory CF1. This connection is to use bindings mode to queue manager QMA, and not use a client.
  2. Define a queue. The application will use JMSQ1, and this maps to queue Q1 on queue manager QMA.

Run the JMSAdmin tool to create the resources, using the above JMSAdmin configuration file.

See  Configuring JMS objects using the administration tool.  The syntax of the commands and the options is here.

/opt/mqm/java/bin/JMSAdmin -v -cfg JMSAdmin.config

def CF(CF1) QMGR(QMA) TRANSPORT(BIND)
# Define Queue Q1
InitCtx> DEF Q(JMSQ1) QMGR(QMA) QUEUE(Q1)

dis CTX gives

InitCtx> DIS CTX
JMSADM4089 InitCtx
.bindings java.io.File
a CF1 com.ibm.mq.jms.MQConnectionFactory
a JMSQ1 com.ibm.mq.jms.MQQueue
3 Object(s)
0 Context(s)
3 Binding(s), 2 Administered

end

You can use the command DIS CF(*) and DIS Q(*) to display  the objects

We have created a ConnectionFactory called CF1, and a queue object JMSQ1 which maps to queue Q1 on queue manager QMA.


To do things properly I should define a proper hierarchy

InitCtx> def ctx(Application)
InitCtx> change ctx(Application)
InitCtx/Application>def Q(APJMSQ1) QMGR(QMA) QUEUE(APPQ)
InitCtx/Application> change ctx(=UP)
InitCtx> dis ctx
.bindings java.io.File
a APJMSQ1 com.ibm.mq.jms.MQQueue
2 Object(s)
0 Context(s)
2 Binding(s), 1 Administered
end

In an application I would normally create the connectionFactory as Application/CF1 and the queue as Application/APJMSQ1

If you list the directory, you can see some of the elements

colinpaice@colinpaice:~$ ls -ltra JNDI-Directory
-rw-r--r-- 1 colinpaice colinpaice 15133 Oct 23 15:32 .bindings
drwxr-xr-x 57 colinpaice colinpaice 4096 Oct 26 08:31 ..
drwxr-xr-x 3 colinpaice colinpaice 4096 Oct 26 13:40 .
drwxr-xr-x 2 colinpaice colinpaice 4096 Oct 26 13:42 Application

Run the JMS sample program

The syntax is

JmsJndiProducer -i JNDI-Directory -c myQCF -d myQueue

so we have

The whole command is

java -cp /opt/mqm/samp/jms/samples:/opt/mqm/java/lib/com.ibm.mqjms.jar -Djava.library.path=/opt/mqm/java/lib64 JmsJndiProducer -i file:///home/colinpaice/JNDI-Directory -c CF1 -d JMSQ1

This produced

Initial context found!
Sent message:
JMSMessage class: jms_text
JMSType: null
JMSDeliveryMode: 2
JMSDeliveryDelay: 0
JMSDeliveryTime: 1540558478659
JMSExpiration: 0
JMSPriority: 4
JMSMessageID: ID:414d5120514d41202020202020202020cdb6d25b09202925
JMSTimestamp: 1540558478659
JMSCorrelationID: null
JMSDestination: queue://QMA/Q1
JMSReplyTo: null
JMSRedelivered: false
JMSXAppID: java
JMSXDeliveryCount: 0
JMSXUserID: colinpaice
JMS_IBM_PutApplType: 6
JMS_IBM_PutDate: 20181026
JMS_IBM_PutTime: 12543866
JmsJndiProducer: Your lucky number today is 641
SUCCESS

To read the message run the consumer JMS application

java -cp /opt/mqm/samp/jms/samples:/opt/mqm/java/lib/com.ibm.mqjms.jar -Djava.library.path=/opt/mqm/java/lib64 JmsJndiConsumer -i file:///home/colinpaice/JNDI-Directory -c CF1 -d JMSQ1

I have successfully managed to use a JMS program in batch to put and get a message!

Doing the above was relatively painless – the hardest part was understanding the concepts and strange language.

5 thoughts on “Getting the IBM JMS samples working in batch on Ubuntu for people who cannot spell Java Massage Service.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s