Friday, June 01, 2007

Travails with JMS on IBM websphere 6 %$#@*&

When a programmer wants to check if his code/artifact would work across all containers, Websphere comes in to throw a spanner in the works. First you have to unlearn all that you have leached out from Websphere 5 (no good except for nostalgia). Second these are the problems you face during installation
1. Something new - Profiles. you can create as many profiles as you want. If you have used Firefox, you would know about profiles.
2. Then you do a host of updgrades - I guess if your server version shows 6.0.2.15, you do have a stable environment.
3. JMS configurations have become a nightmare. I have an app which uses about 15 messaging destinations and you know what - using the destination names for your validations or logic is on websphere 6. What code works on Glassfish, JBoss, Weblogic is not guaranteed to work on Websphere simply because of many things which are as follows.
  1. Java Connector architecture - Learn the specs carefully
  2. Buses - Start point for your JMS configuration
  3. Bus Members - Create A bus and Add bus member - which is your server profile instance
  4. When you create a Bus member a Messaging instance is created. Check that it is created and started. If the state is not started, a good idea is to restart web-sphere at this point. Even after restart if the engine is not started, then even God cannot help you. Delete the Bus. Stop websphere, go to the profiles_root/databases/com.ibm.ws.sib and delete the Something<> directory
  5. Start websphere and follow the process from 2 to 4 again till you get it right.
  6. Go to your Bus and configure your destinations -(see also the note at the end)
  7. It is a good idea to restart websphere if you are unlucky yet again
  8. Now go to the Resource\JMS and choose the particular messaging provider and configure your JNDI names for the destinations and connection factories.
  9. Do a test if are able to lookup the JNDI names properly. if the tests fail restart websphere (yes once again) and retest. This should work. If not start again from Step 2
  10. Hopefully by now, you must have got it.
Now for some more points which you should check for in your code or deployment.
  1. If your have a code like - qConnection.stop- it wont work on websphere 6. You cannot stop connections, though you can still close sessions. Why is this restriction? The plain answer is "I don't know"
  2. Second when you have created a connection and are creating a session, if you get a time out error, restart the messaging engine in the Bus and try again. it should work. It did for me
A BIG NOTE
  1. Destinations and JNDI names and destination names
If any where you have the following type of code-

Destination _dest = jmsMessage.getReplyTo();
if(_dest instanceof Queue){
((Queue)_dest).getQueueName();
}

((Queue)_dest).getQueueName(); will not return the name you entered for the JMS queue in the messaging providers' area; instead you will get the name of the destination registered under your Bus. so if you had given a name as MYQ in the destination under the Bus and MYQueue for the JNDI and name under messaging provider's area,

((Queue)_dest).getQueueName() will return MYQ and not MYQueue
Now why is this so. I too don't know. the J2EE specs also doesn't mention clearly what shoudl be returned by javax.jms.Queue#getQueueName()

2. JNDI registration vis-a-vis Bus Destinations


Take a look at the following configuration

1. Destination under the Bus - MyQ

2. JNDI under the Messaging Provider's area
Name : MyQueue1
JNDI
Name : MyQueue1
BUS: MYBUS
Queue: MyQ

Name : MyQueue2
JNDI
Name : MyQueue2
BUS: MYBUS
Queue: MyQ


If you notice we have the same Bus destination as the Queue for two JNDI destinations.


Queue q1 = (Queue)jndiContext.lookUp("
MyQueue1");
q1.send(someJMSMessage);
....some more steps
....Some more steps
(the above two steps finish in a very negligible processing machine time)
q1.recieveNoWait();


and in the mean time somewhere else you are using a message listener on the Queue MyQueue2


Who should recieve the message - the listener or the q1 instance - well really cannot say. My experience is that
q1.recieveNoWait(); gets the message. Now why is this so
Names under Messaging Providers' area are like logical handle to the the same physical location

some thing like this.

java.io.File one = new java.io.File("Some path");
java.io.File two = new java.io.File("Some path");

File objects one and two point to the same location.


So if you are having code like this, it is a good idea to configure different physical destination for each of the JNDI lookups.

Phew. writing this is as traumatic an experience as configuring JMS on Websphere.

Whats the point I am trying to make - as a app server provider, if you cannot make the life of a programmer easier (as a programmer expecting them to make it easier is foolhardy), do not make it more difficult than it is.

It is not good if I only criticize, When it comes to JMS performance, nobody can beat Websphere default messaging and if you couple your app with MQ, then it is the best in the world when it comes to JMS performance.


CIAO, Enjoy Websphere.

PS: I am yet to try Pramati. So judgement stands till I do so.