1 2 Previous Next 20 Replies Latest reply on Mar 26, 2012 5:31 PM by romarcio

    JNDI lookup of QueueConnectionFactory and Queues from outside and within JBoss

    peterfry

      JBoss AS 7.1 Final supports looking up QueueConnectionFactory objects and Queue objects via JNDI.

       

      I understand that from a remote client the initial context factory should be

      org.jboss.naming.remote.client.InitialContextFactory

       

      Is this class by default accessible to any module in an EAR file?

       

      Or should I be using initial context factory described in

       

      https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+client+using+JNDI

       

      to lookup these objects from within JBoss.

       

      The latter worked fine in CR1b for looking up EJBs from within JBoss and from an external client.

       

       

        • 1. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
          jaikiran

          Peter Fry wrote:

           

           

          I understand that from a remote client the initial context factory should be

           

          org.jboss.naming.remote.client.InitialContextFactory

           

          If you are looking up from withing the server, you don't need that initialcontext factory. AS7 on the server side will use the correct org.jboss.as.naming.InitialContextFactory on the server side.

          • 2. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
            peterfry

            I have made some progress but when executing the following from the remote client:

             

             

            qcf = (QueueConnectionFactory) _jndi.lookup( "jms/RemoteConnectionFactory" );

             

             

            I get:

             

             

            javax.naming.NamingException: Failed to lookup [Root exception is java.io.NotSerializableException: org.hornetq.core.client.impl.ClientSessionFactoryImpl]
            at org.jboss.naming.remote.client.ClientUtil.namingException(ClientUtil.java:36)
            at org.jboss.naming.remote.protocol.v1.Protocol$1.execute(Protocol.java:101)
            at org.jboss.naming.remote.protocol.v1.RemoteNamingStoreV1.lookup(RemoteNamingStoreV1.java:76)
            at org.jboss.naming.remote.client.RemoteContext.lookup(RemoteContext.java:77)
            at org.jboss.naming.remote.client.RemoteContext.lookup(RemoteContext.java:81)
            at javax.naming.InitialContext.lookup(InitialContext.java:392)
            at uk.co.mycompany.business.jms.queue.MessageConnection.<init>(MessageConnection.java:95)
            at uk.co.mycompany.business.jms.queue.MessageConnection.getConnection(MessageConnection.java:161)
            at uk.co.mycompany.business.jms.queue.MessageBase.createConnection(MessageBase.java:52)
            at uk.co.mycompany.business.jms.queue.MessageReceiver.<init>(MessageReceiver.java:90)
            at uk.co.mycompany.business.jms.queue.MessageReceiver.receiveMessage(MessageReceiver.java:358)
            at uk.co.mycompany.business.jms.queue.QueueFactory.flushQueue(QueueFactory.java:98)
            at uk.co.mycompany.business.jcb.runner.JCBRunner.main(JCBRunner.java:117)
            Caused by: java.io.NotSerializableException: org.hornetq.core.client.impl.ClientSessionFactoryImpl
            at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:891)
            at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:585)
            at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1063)
            at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1019)
            at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:885)
            at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1063)
            at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1019)
            at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:998)
            at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:885)
            at org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:62)
            at org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:119)
            at org.jboss.naming.remote.protocol.v1.Protocol$1$2.write(Protocol.java:135)
            at org.jboss.naming.remote.protocol.v1.WriteUtil.write(WriteUtil.java:61)
            at org.jboss.naming.remote.protocol.v1.Protocol$1.handleServerMessage(Protocol.java:125)
            at org.jboss.naming.remote.protocol.v1.RemoteNamingServerV1$MessageReciever$1.run(RemoteNamingServerV1.java:70)
            at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
            at java.lang.Thread.run(Thread.java:619)
            Caused by: an exception which occurred:
            in field factories
            in field serverLocator
            in object org.hornetq.jms.client.HornetQJMSConnectionFactory@25044e

             

             

             

            In addition, since we share messaging framework code between code running within jboss and also outside of jboss I had to introduce

             

            if( withinJboss )
            {
                     qcf = (QueueConnectionFactory) _jndi.lookup( "java:jboss/exported/jms/RemoteConnectionFactory" );
            }

            else
            {
                     qcf = (QueueConnectionFactory) _jndi.lookup( "jms/RemoteConnectionFactory" );
            }

            • 3. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
              jbertram

              What exactly is your use-case?

               

              If you are within JBoss AS and you are sending messages to a local destination you don't need to use "java:jboss/exported/jms/RemoteConnectionFactory" since that is for remote clients (as indicated by the name).  You can simply use "java:/JmsXA".  Make sure to use an empty initial context as well.

               

              If you are within JBoss AS and you are sending messages to a remote destination then you need to create a new <pooled-connection-factory> in standalone*.xml like the one that exists for JmsXA but you will need to use a different <connector> (i.e. not "in-vm") that points to the remote server to which you're connecting.  Documentation for the <connector> is available here.  Make sure to use an empty inital context as well.

               

              If you are outside JBoss AS then you would connect to the JBoss instance using code like this:

               

                      final Properties env = new Properties();

                      env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");

                      env.put(Context.PROVIDER_URL, "remote://localhost:4447");

                      env.put(Context.SECURITY_PRINCIPAL, "guest");

                      env.put(Context.SECURITY_CREDENTIALS, "pass");

                      Context context = new InitialContext(env);

                      ConnectionFactory cf = (ConnectionFactory) context.lookup("jms/RemoteConnectionFactory");

                      Destination destination = (Destination) context.lookup("jms/queue/test");

                      context.close();

                      Connection connection = cf.createConnection("guest", "pass");

                      Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

              • 4. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
                peterfry

                The stack trace indicating that org.hornetq.core.client.impl.ClientSessionFactoryImpl is not serializable is for the third usecase i.e. remotely looking up the connection factory outside of jboss,

                 

                 

                 

                 

                • 5. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
                  jbertram

                  So you receive a "java.io.NotSerializableException: org.hornetq.core.client.impl.ClientSessionFactoryImpl" when using this code from outside JBoss AS?

                   

                          env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");

                          env.put(Context.PROVIDER_URL, "remote://localhost:4447");

                          env.put(Context.SECURITY_PRINCIPAL, "guest");

                          env.put(Context.SECURITY_CREDENTIALS, "pass");

                          Context context = new InitialContext(env);

                          ConnectionFactory cf = (ConnectionFactory) context.lookup("jms/RemoteConnectionFactory");

                          Destination destination = (Destination) context.lookup("jms/queue/test");

                          context.close();

                          Connection connection = cf.createConnection("guest", "pass");

                          Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

                   

                  I've used this code from a remote client connecting to AS 7.1.0.Final and it worked without issue.

                  • 6. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
                    peterfry

                    For CR1b I had to use Hornetq natively to get JMS stuff working i.e.

                     

                     

                     

                    QueueConnectionFactory qcf = (QueueConnectionFactory) HornetQJMSClient.createConnectionFactoryWithoutHA( JMSFactoryType.CF, transportConfiguration );

                     

                     

                     

                     

                    _delegate = qcf.createQueueConnection();

                     

                    Moving to FINAL this stopped working but I found that changing the second line to:

                     

                    _delegate = qcf.createQueueConnection(

                    SECURITY_PRINCIPAL ), EnvironmentalProperties.getProperty( Context.SECURITY_CREDENTIALS) );

                     

                    Fixed things.

                     

                    Trying to get the queue connection factory in the JNDI way was causing problems but I think that was because code sharing the creation of the initial context was being accessed from JBoss and a non-Jboss remote client.

                     

                    For the non-Jboss remote client when I changed to using the

                     

                    org.jboss.naming.remote.client.InitialContextFactory

                     

                    I found that remote ejb lookups started to have issues.

                     

                    In summary the cleanest set up that works for me comprises:

                     

                    1) Using native Hornetq code to get a jms queue connection factory both from outside and inside jboss.

                    2) Using (for remote/local ejb lookups) a blank initial context along with the ejb protocol:

                     

                      env.put( Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming" );

                     

                    A file jboss-ejb-client.properties also needs to be on the class path in the remote case (see https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+client+using+JNDI )

                     

                     

                     

                    • 7. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
                      rsinghal

                      @Peter we also had exactly same use case where messaging framework is shared between the code running within the JBoss and outside of JBoss and we were also facing the same problem. To workaround this, we changed JNDI lookup within JBoss to remote lookup i.e. passing Provider URL and Initial Context Factory while setting up Initial Context and it worked perfectly fine. In this case you don't need to have different code even if your JMS server is not collocated with Application Server.

                      • 8. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
                        peterfry

                        Interesting Ravi, I have been guided by

                         

                        https://docs.jboss.org/author/display/AS71/JNDI+Reference

                         

                        which if I understand it correctly strongly suggests using the ejb:// protocol to reduce network round trips and deserialization/serialization overheads.

                         

                        More time may have allowed me to investigate the issues more. At least I wasn't the only one encountering the issue!

                         

                        Cheers,

                         

                        Peter.

                        • 9. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
                          jbertram

                          Technically you can use the exact same code inside and outside JBoss AS to lookup and use JMS resources bound in JNDI.  However, doing so will inflict a significant performance penalty inside JBoss AS since you will lose all the benefit of in-vm optimization and things like pooling if you use a connection factory like, e.g. JmsXA (which you should).  I always advise using in-vm resources where possible.  Of course, many applications don't really care about performance in many areas because bottlenecks lie elsewhere and/or because load isn't very high, so take my advice in context.

                          • 10. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
                            bessen

                            It is strange that I get the same exception javax.naming.NamingException: Failed to lookup [Root exception is java.io.NotSerializableException: org.hornetq.core.client.impl.ClientSessionFactoryImpl] occasionally and when it happens, I have to restart JBoss in order to look up JMS resourcces successfully.

                            • 11. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
                              lgauthier.opnworks

                              Justin,

                               

                              Sorry to bump in but sicne you seem to be the expert on AS7.1 JMS, I thought you may be able to help with a problem I presume others may stumble upon and is related to this thread.  I am working on configuring the 2nd scenario: within container webapp connecting to a remote (standalone) HornetQ server.

                               

                              Working with AS7.1.1 and HornetQ 2.2.5, I get the following:

                              Client with version 122 and address /127.0.0.1:58717 is not compatible with server version 2.2.5.Final (HQ_2_2_5_FINAL_AS7, 121). Please ensure all clients and servers are upgraded to the same version for them to interoperate properly.

                               

                              The message is quite clear but this is rather annoying. Do I really have to have the same version of the HornetQ RA to talk to a HornetQ server? This somewhat defeats the purpose of a decoupled message broker doesn't it? Since the HornetQ RA is "embedded" in AS7.1, it does not seem to be so easy to replace it with another version. I tried deploying the HornetQ RA but that causes classloading problems. I do not really like the idea that I need to upgrade my standalone message broker each time I upgrade my JEE container. In an entreprise landscape this is not a desirable contraint. To make things even more complicated, AS7.1.1 comes with HornetQ 2.2.13 which does not seem to be available anywhere.

                              • 12. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
                                jbertram

                                Couple of points:

                                1. Setting up AS7 is just about as easy as setting up HornetQ standalone since the runtime is so light.  You could even strip it down further if you like (see attached example).  AS7 gives you the benefit of more flexible management (e.g. via CLI, HTTP, Web, etc.) as well as a compatible version of HornetQ.
                                2. The version of HornetQ in AS 7.1.0.Final (which is what I assume you're using) is 2.2.11 which has an "incrementingVersion" (which is kind of like the wire-format version) of 122.  HornetQ 2.2.5.Final will only accept clients with an "incrementingVersion" of 121 (as the error message indicates) because the 121 server is not compatible with a 122 client.  However, HornetQ 2.2.11 is compatible with clients using an incrementingVersion of 121 (notice the "hornetq.version.compatibleVersionList").  We try to preserve full compatibility whenever we can, but when we can't we try to keep the server compatible with older clients since it is typically the server which is upgraded rather than the clients.  So, as you can see, the wire-format that actually controls compatibility and not the overall version number of HornetQ.  I hope that puts to rest many of your general concerns about compatibility.
                                3. As for why a new version of HornetQ hasn't been released lately see this thread.
                                • 13. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
                                  lgauthier.opnworks

                                  Thanks Justin, very useful info and it put me on the right track. I guess embedding HornetQ inside AS71 has many advanatages but also a few drawbacks such as a hard coupling with the embedded HornetQ RA. The proposed solution is workable for us but in the future, not sure it is the best scenario. I would prefer to be able to install the RA version I need not have to use the one provided by the app server.

                                   

                                  One point:

                                  To get things working the way I want, I had to use the trick documented here: https://community.jboss.org/thread/196472

                                  • 14. Re: JNDI lookup of QueueConnectionFactory and Queues from within JBoss
                                    jbertram

                                    Do you need to use the local HornetQ broker?  If not, you can use a profile like standalone.xml which doesn't include HornetQ at all and then you should be able to deploy the HornetQ JCA RA from 2.2.5.Final and use it in your application.

                                    1 2 Previous Next