12 Replies Latest reply on Dec 2, 2013 5:33 PM by Keith Carlton

    How can I set socket binding address at runtime for JMS?

    Keith Carlton Newbie

      I'm migrating our companies distributed web application from JBoss 4.0.0 to JBoss 7.1.1; in our the 4.0 version, we are sending messages from a central server to a remote messaging queue where the destination is determined at runtime based on the target location.  Here are the guts of our current way of sending the message to a remote JBoss server:

      targetIP = resultSet.get("ip_address");
      Properties properties = new Properties();
      properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
      properties.put(Context.PROVIDER_URL, "jnp://" + targetIP + "/");
      
      InitialContext iniCtx = new InitialContext(properties);
      Object tmp = iniCtx.lookup("XAConnectionFactory");
      QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
      conn = qcf.createQueueConnection();
      Queue que = (Queue) iniCtx.lookup("queue/POSStoreInboundQueue");
      session = conn.createQueueSession(true, 0);
      
      conn.start();
      send = session.createSender(que);
      ObjectMessage om = (ObjectMessage) message;
      ObjectMessage tm = session.createObjectMessage(om.getObject());
      tm.setStringProperty("msgType", om.getStringProperty("msgType"));
      tm.setLongProperty("creationTime", om.getLongProperty("creationTime"));
      
      send.send(tm);
      
      session.commit();
      


      I've used Lukasz Antoniak's blog post to get a sample working of sending to a remote queue working (thank you Lukasz).
      The limitation I've run into with his example is that the remote destination/hostname is set in the configuration file and not at runtime.  I could conceivably set up a connection factory and netty connector for each location, but that gets a bit unwieldy as we scale up to our 80+ locations.  Is there a way I can do this at runtime?

       

      Thanks for any help in advance!

       

      Keith

        • 1. Re: How can I set socket binding address at runtime for JMS?
          Justin Bertram Master

          I haven't specifically tested this, but I do think you should be able to change the "host" and/or "port" value of an outbound-socket-binding at runtime.  However, it would require you to use the management API (not a bad thing) and then issue a "reload" when you were done (something akin to a soft reboot of the server).  So it's not terribly simple, but I do think it's possible.

           

          Aside from that you can just use the same method you were using before (JNDI lookup from the remote server, etc.) rather than using the method described on that blog.

          • 2. Re: How can I set socket binding address at runtime for JMS?
            Keith Carlton Newbie

            Changing the host and/or port using the management API would not work for us... we can send out 100,000 messages per day distributed over the 80+ stores.

             

            I've tried the JNDI lookup from a remote server using a similar method as before, but with no luck.  I read through the JNDI documentation here and this works if I am running a standalone program outside of our JBoss container, but within a JBoss server I get the following error:

            13:43:41,221 ERROR [messaging_logger] (Thread-96) javax.naming.NamingException: JBAS011843: Failed instantiate InitialContextFactory org.jboss.naming.remote.client.InitialContextFactory from classloader ModuleClassLoader for Module "deployment.TestEAR.ear.as7sample2.war:main" from Service Module Loader: javax.naming.NamingException: JBAS011843: Failed instantiate InitialContextFactory org.jboss.naming.remote.client.InitialContextFactory from classloader ModuleClassLoader for Module "deployment.TestEAR.ear.as7sample2.war:main" from Service Module Loader
                 at org.jboss.as.naming.InitialContextFactoryBuilder.createInitialContextFactory(InitialContextFactoryBuilder.java:64)
                 at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:681) [rt.jar:1.7.0_02]
                 at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307) [rt.jar:1.7.0_02]
                 at javax.naming.InitialContext.init(InitialContext.java:242) [rt.jar:1.7.0_02]
                 at javax.naming.InitialContext.(InitialContext.java:216) [rt.jar:1.7.0_02]
                 at com.sample.common.util.JMSHelper.sendMessage(JMSHelper.java:53) [classes:]
                 at com.sample.dao.PropertyDAOImpl.put(PropertyDAOImpl.java:49) [classes:]
                 at com.sample.buslogic.PropertyManagerImpl.put(PropertyManagerImpl.java:17) [classes:]
                 at com.sample.common.util.TestThread.run(TestThread.java:35) [classes:]
            

             

            Is there a different name I should be using for the initial context factory besides "org.jboss.naming.remote.client.InitialContextFactory"?

            • 3. Re: How can I set socket binding address at runtime for JMS?
              Justin Bertram Master

              You're EAR needs to depend on "org.jboss.remote-naming" module so it can have access to that class.

              1 of 1 people found this helpful
              • 4. Re: Re: How can I set socket binding address at runtime for JMS?
                Keith Carlton Newbie

                Justin- thanks for the right way to do that... I just dropped the jboss-client.jar file into my lib folder, but your way was definitely the right way.

                 

                After doing that, I reworked the code a bit... here is my latest version of my simple sender:

                Properties jndiProps = new Properties();
                jndiProps.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
                logger.info("provider ip: " + ipAddress);
                jndiProps.put(Context.PROVIDER_URL,"remote://" + ipAddress + ":4447");
                
                Context ctx = new InitialContext(jndiProps);
                
                QueueConnectionFactory qcf = (QueueConnectionFactory)ctx.lookup("jms/RemoteConnectionFactory");
                qcon = qcf.createQueueConnection();
                qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
                String queueName = "jms/queue/AppsInboundQueue";
                logger.info("looking up " + queueName);
                Queue q = (Queue)ctx.lookup(queueName);
                
                QueueSender qsender = qsession.createSender(q);   // line 42
                qcon.start();
                
                TextMessage message = qsession.createTextMessage();
                message.setText(messageText);
                qsender.send(message);
                logger.info("message sent");
                
                qsender.close();
                qsession.close();
                qcon.close();
                

                 

                When this method gets called, I get the following log output:

                13:40:26,361 INFO  [messaging_logger] (Thread-95) provider ip: 10.1.1.128
                13:40:26,506 INFO  [messaging_logger] (Thread-95) looking up jms/queue/AppsInboundQueue
                13:40:26,514 ERROR [messaging_logger] (Thread-95) javax.jms.InvalidDestinationException: Destination AppsInboundQueue does not exist: javax.jms.InvalidDestinationException: Destination AppsInboundQueue does not exist
                     at org.hornetq.jms.client.HornetQSession.createProducer(HornetQSession.java:337) [hornetq-jms-2.2.13.Final.jar:]
                     at org.hornetq.jms.client.HornetQSession.createSender(HornetQSession.java:828) [hornetq-jms-2.2.13.Final.jar:]
                     at com.sample.common.util.JMSHelper.sendMessage(JMSHelper.java:42) [classes:]
                     at com.sample.dao.PropertyDAOImpl.put(PropertyDAOImpl.java:49) [classes:]
                     at com.sample.buslogic.PropertyManagerImpl.put(PropertyManagerImpl.java:17) [classes:]
                     at com.sample.common.util.TestThread.run(TestThread.java:35) [classes:]
                

                According to the startup output of the server set up to receive the messages

                11:34:46,574 INFO  [org.jboss.as.messaging] (MSC service thread 1-1) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/queue/AppsInboundQueue
                

                so it appears that the queue should exist.  Using Lukasz Antoniak's example, I was able to send messages to the receiver; do I need to change the configuration on the receiver side to make it visible for a JNDI lookup?   Attached is the standalone.xml I'm using for the receiver.

                • 5. Re: Re: How can I set socket binding address at runtime for JMS?
                  Justin Bertram Master

                  Based on the evidence I have seen everything looks fine.  I'm not sure why it's failing.

                   

                  Does this code work when it's running in a standalone Java app (i.e. not in the application server) connecting to the remote server?

                   

                  Also, based on the stack-trace it looks like you're starting your own thread here.  This is typically discouraged within the application server.

                  • 6. Re: How can I set socket binding address at runtime for JMS?
                    Keith Carlton Newbie

                    Justin- Yes, I am starting my own thread- it is to simulate what we have to do in our production environment.  We are picking up messages that were put into a database by another application to send out to our remote locations.

                     

                    As for getting this to work in a standalone app, I run into the same issue.  I am able to send messages to "localhost" using the same method, but not to a remote host.  I'm thinking I may have to configure a connection factory for each location and determine which connection factory to use at runtime instead of being able to specify the JNDI address at runtime.

                    • 7. Re: How can I set socket binding address at runtime for JMS?
                      Justin Bertram Master

                      Your code is simple and it should work.  Something fishy is going on somewhere.  Can you give provide me with steps to reproduce?

                      • 8. Re: How can I set socket binding address at runtime for JMS?
                        Keith Carlton Newbie

                        Sure... here's the receiver setup.  I'll provide a smaller sender setup on later tonight.

                        1. Install Sun Java(TM) SE Runtime Environment (build 1.7.0_45-b18)  with JDK on Linux server (I'll call this Receiver from now on).
                          • Red Hat Enterprise Linux Server release 6.5 (Santiago) as a VM
                        2. Setup/install JBoss 7.1.1 Final on Receiver
                        3. Place standalone.xml from post at Nov 26, 2013 1:54 PM in the $JBOSS_HOME/standalone/configuration directory on Receiver
                        4. Start JBoss on Receiver- you should see jms/queue/AppsInboundQueue get its JNDI binding in the startup information.
                        • 9. Re: How can I set socket binding address at runtime for JMS?
                          Keith Carlton Newbie

                          So here is the rest (the sender side).

                          I am on a Windows 7 machine using Eclipse Indigo for my IDE.  I am using Java 1.7.0_02.

                          1. Install/setup Jboss 7.1.1 Final.
                          2. Place the attached standalone.xml file in the %JBOSS_HOME%\standalone\configuration directory.
                          3. Unzip the attached zip file and import the projects into Eclipse.
                          4. Add the server to Eclipse.
                          5. Right click the server go to "Add and Remove".  Add the TestEAR project.
                          6. Start the server.

                          When the application deploys, it starts a thread that will wait 5 seconds before sending the first message.  Then it will attempt to send a message every 90 seconds.  In order to change the IP address that the message is being sent to, look at the TestThread.java file where JMSHelper.sendMessage is called.

                           

                          Thanks for taking a look at this.

                           

                          Keith

                           

                           

                          ****** I've put in a revised version of the messaging_test.zip ******** 2013-11-29

                          • 10. Re: How can I set socket binding address at runtime for JMS?
                            Keith Carlton Newbie

                            Justin-

                            In looking through other discussions, I found mention of how binding the listening server to 0.0.0.0 as the IP could be the cause of the problem for HornetQ versions < 2.2.19.  So on the receiver, I changed the binding to its IP address and the exception in the sender code goes away.  There is however still a problem- I don't see the message coming in to the receiver in the admin console or in a simple MDB for that queue.  Any ideas on what I can do to get the receiver to see the messages?

                            Additionally, I do see the connection to port 4447 when I look at the results from the netstat command on the receiver so I don't think I am running into a firewall issue.

                             

                            Keith

                            • 11. Re: How can I set socket binding address at runtime for JMS?
                              Justin Bertram Master

                              Looks like your sender is using a transacted session but never committing the session so the sender will execute but the message will never be sent.

                              • 12. Re: How can I set socket binding address at runtime for JMS?
                                Keith Carlton Newbie

                                Justin- That did it!  Thank you for the help!