An application that runs inside a J2EE container can use JMS without knowing anything about the underlying JMS implementation (e.g., if it was using Solace, you could use MQ instead, by changing only configuration). But what about a stand-alone application, i.e., one that doesn't run in a J2EE container? How can it be made independent of JMS provider? If that's impossible, how close can you get?
You can get a 100% portable standalone JMS application with essentially no extra work on your part if the JMS providers you're switching between also provide a JNDI implementation. The JMS specification doesn't require JNDI but it establishes the convention that JNDI be used to locate administered objects like connections factories and destinations so it is very common for JMS providers to also provide a JNDI implementation as well.
In short your application can simply use the JMS and JNDI APIs. JMS and JNDI implementation details can be isolated to a jndi.properties
file placed on the application's classpath. Switching between providers would be as simple as changing this properties file and changing the jars on the classpath.
If the JMS providers you're switching between don't provide JNDI implementations then you'll have to use implementation-specific code to create your connection factories and destinations. This will, of course, hurt portability, but you should be able to create your own API to isolate these details to classes which you can switch out for yourself.