Search code examples
rabbitmqjmsopen-liberty

Connect OpenLiberty to RabbitMQ over JMS


I'm writing a Java EE 8 application that I want to connect to a RabbitMQ bus. The application is deployed in OpenLiberty. Since the application uses Java EE 8, I want to use JMS for connecting to RabbitMQ. I have previously connected to RabbitMQ over JMS in Tomcat as a proof-of-concept, so I know it must be possible.

According to the documentation and blogs I found, I need a Resource Adapter to connect OpenLiberty to basically everything else than its internal JMS engine. I have found the AMQP 1.0 resource adapter and wanted to give it a try.

My server.xml:

<featureManager>
  <feature>beanValidation-2.0</feature>
  <feature>cdi-2.0</feature>
  <feature>jaxrs-2.1</feature>
  <feature>jsp-2.3</feature>
  <feature>servlet-4.0</feature>
  <feature>jms-2.0</feature>

  <feature>appSecurity-3.0</feature>
  <feature>socialLogin-1.0</feature>
</featureManager>

<!-- the resource-adapter-1.0.0.rar comes from the aforementioned GitHub project -->
<resourceAdapter id="amqp" location="${server.config.dir}/resource-adapter-1.0.0.rar">
  <classloader apiTypeVisibility="+third-party"/>
</resourceAdapter>

<jmsConnectionFactory jndiName="jms/JmsFactory">
  <!-- using .amqp as that is the ID for the resource adapter -->
  <properties.amqp ConnectionFactory=""
                   JndiParameters=""
                   DeleteTemporaryDestinations="true"
                   UserName=""
                   Password="" />
</jmsConnectionFactory>

Then, in my application code, I have

@Inject
@JMSConnectionFactory("jms/JmsFactory")
private JMSContext context;

As soon as I invoke context.createQueue("ExampleQueue") (or whatever method call), I get

javax.naming.NameNotFoundException: Intermediate context does not exist: jms/JmsFactory

I've also tried doing a manual lookup, like so:

final InitialContext context = new InitialContext();
final Context environment = (Context) context.lookup("java:comp/env");

final QueueConnectionFactory factory = (QueueConnectionFactory) environment.lookup("jms/JmsFactory");
final Queue queue = InitialContext.doLookup("jms/ExampleQueue");

That fails at the environment.lookup with javax.naming.NameNotFoundException: java:comp/env/jms/JmsFactory.

What am I doing wrong, or overseeing here?


Solution

  • There is a mismatch between how Liberty expects a JMS Resource Adapter to be defined and how this resource adapter defines itself. Liberty expects a JMS Resource Adapter to use JMS classes in the ra.xml as the interface definition, so javax.jms.ConnectionFactory. Instead this RA uses org.jboss.resource.adapter.jms.JmsConnectionFactory. At runtime this is a javax.jms.ConnectionFactory, but not in the ra.xml.

    There is a simple workaround, just use the JCA connectionFactory element. I found the following configuration works:

    <connectionFactory jndiName="jms/JmsFactory">
       <!-- using .amqp as that is the ID for the resource adapter -->
       <properties.amqp DeleteTemporaryDestinations="true"
           ConnectionFactory="factory1"
           JndiParameters="java.naming.factory.initial=org.apache.qpid.jms.jndi.JmsInitialContextFactory;connectionFactory.factory1=amqp://localhost:5672"              
           UserName=""
           Password="" />
    </connectionFactory>
    

    There is a bug in Liberty for this issue 12088, but I would suggest just using the JCA connectionFactory element to get going.