9 Replies Latest reply on Feb 8, 2018 10:58 AM by jasonglass

    Use a custom JMSConnectionFactory

    chschroe

      Hi all,

      I try to inject a custom JMSConnectionFactory in WildFly using annotations, but I always get the default HornetQ connection factory. This is my code (stripped down to be suitable as an example):

       

      package jmstest;
      
      import ...;
      
      @Singleton
      @Startup
      @JMSConnectionFactoryDefinition(
              className = "jmstest.MyConnectionFactory",
              name = "java:app/foo")
      public class TestBean {
      
          @Resource(lookup = "java:app/foo")
          private ConnectionFactory connectionFactory;
          
          @PostConstruct
          public void debug() {
              System.out.println(connectionFactory);
          }
      
      }
      


      The MyConnectionFactory class is defined in the same project and implements the javax.jms.ConnectionFactory interface. (All methods throw an UnsupportedOperationException, but that should not matter.)

      When I deploy the module, the output is (among other lines):

       

      13:55:06,214 INFO  [stdout] (ServerService Thread Pool -- 83) org.hornetq.ra.HornetQRAConnectionFactoryImpl@3545fe45

       

      So it seems that the HornetQRAConnectionFactory is instantiated instead of MyConnectionFactory. What am I doing wrong?

       

      Thanks a lot,

      Christian

        • 1. Re: Use a custom JMSConnectionFactory
          jmesnil

          className and resourceAdapter are ignored in WildFly 8.  @JMSConnectionFactoryDefinition will always create HornetQ-backed connection factories.

           

          We will change this behaviour in WildFly 9 to support at least resourceAdapter.

          • 2. Re: Use a custom JMSConnectionFactory
            chschroe

            Ah, that explains a lot. Thanks for your answer.

            Is there another way to specify which JMS ConnectionFactory should be used without using the annotation? I tried to add a deployment descriptor (ejb-jar.xml) with a "jms-connection-factory" element, but I get several error messages upon deployment, so this approach is probably wrong.

            • 3. Re: Use a custom JMSConnectionFactory
              jesper.pedersen

              Don't use @JMSConnectionFactoryDefinition - you won't get access to all the properties of the deployment that you will need. The new deployment annotations are foobar, as they aim as a minimum solution that all JCA containers will support.

               

              Define a proper <resource-adapter> definition in the :resource-adapters: subsystem, and use @Resource.

              1 of 1 people found this helpful
              • 4. Re: Use a custom JMSConnectionFactory
                chschroe

                To be honest, this was my first approach: The goal of all my experiments is to send JMS messages from an enterprise bean to an external ActiveMQ broker. I have already defined ActiveMQ as a resource adapter and also have been able to receive JMS messages from the ActiveMQ broker in an MDB, but I did not manage to send messages because the classes seem to be incompatible (if I understand the error messages correctly). I am not sure if it is a problem with ActiveMQ (so I should post in the ActiveMQ mailing lists) or a problem with my configuration, so I tried to create my own connection factory to understand what's going on behind the scenes. Unfortunately, this led to even more problems and finally resulted in this discussion.

                I now went several steps back and tried to follow your suggestion. I was able to declare a ConnectionFactory resource that uses the ActiveMQ connection factory declared in the resource adapter configuration. However, when I tried to get a JMSContext from this connection factory, I got an AbstractMethodError. This is not surprising since ActiveMQ does only implement the JMS 1.1 API. On the other hand, the same seems to be true for HornetQ. As far as I have understood, WildFly comes with a wrapper that should normally handle this case (at least when I inject a JMSContext into my bean). So I instead declared a JMSContext, added an "Inject" annotation and used a "JMSConnectionFactory" annotation to reference the ActiveMQ connection factory. This seemed to work, but when I tried to get a producer from the context, a ClassCastException occured: "org.apache.activemq.ra.ActiveMQConnectionFactory cannot be cast to javax.jms.XAConnectionFactory". Well, again this is no surprise. I simply do not understand why the connection factory is supposed to be an XAConnectionFactory. Has this anything to do with the transaction mode of the bean where the JMSContext is used? Or am I on a wrong track?

                Thanks again for your help!

                • 5. Re: Use a custom JMSConnectionFactory
                  jmesnil

                  If all you need is sending and receiving JMS messages from a standalone ActiveMQ broker, I just wrote a page about that yesterday: How to Use Out of Process ActiveMQ with WildFly

                  • 6. Re: Use a custom JMSConnectionFactory
                    chschroe

                    Wow, that's great! Is it by coincidence that you just wrote this article or is it a response to this thread?

                    Anyway ... From the article it seems that it is not possible to use the new JMS 2.0 features (e.g. JMSContext) together with ActiveMQ. On the other hand, HornetQ also seems to support only JMS 1.1. (The homepage of the project states: "HornetQ supports the JMS 1.1 API ") In this discussion: Using Weld to inject new JMS 2 API you mention that "it's not HornetQ job to support injection of JMSContext". So why is it not possible to use ActiveMQ the same way as HornetQ?

                    This maybe leads back to my question: Why is it required that the ActiveMQ connection factory (org.apache.activemq.ra.ActiveMQConnectionFactory) implements the javax.jms.XAConnectionFactory interface? Why is it not sufficient to implement the javax.jms.ConnectionFactory interface (which it already does implement)?

                    • 7. Re: Use a custom JMSConnectionFactory
                      jmesnil

                      Christian Schröder wrote:

                       

                      Wow, that's great! Is it by coincidence that you just wrote this article or is it a response to this thread?

                      Coincidence

                       

                      Christian Schröder wrote:

                       

                      On the other hand, HornetQ also seems to support only JMS 1.1. (The homepage of the project states: "HornetQ supports the JMS 1.1 API ") In this discussion: Using Weld to inject new JMS 2 API you mention that "it's not HornetQ job to support injection of JMSContext". So why is it not possible to use ActiveMQ the same way as HornetQ?

                      HornetQ does support JMS 2.0 (their home page is out of date). The JMS implementation must support JMSContext (HornetQ does, ActiveMQ don't) to be used like you want.

                      All WildFly does is to inject the JMSContext created using the JMS provider client library.

                      • 8. Re: Use a custom JMSConnectionFactory
                        chschroe

                        Ok, that makes sense. So I will have to decide if I go the old JMS 1.1 way or use HornetQ instead of ActiveMQ.

                        Thanks a lot for you help and for all the work you spend in making WildFly such a great software!

                        • 9. Re: Use a custom JMSConnectionFactory
                          jasonglass

                          While a little late to the game, I was able to use JMSContext @inject annotation and specify a destination queue with @resource in JBoss EAP 7, ActiveMQ - Artemis without any difficulties.  Id didnt need to specify a connection factory as the Simple JMS 2.0 handles it for you at least I believe if its an in-vm connection factory