10 Replies Latest reply on Apr 13, 2005 4:22 PM by Adrian Brock

    Remote ConnectionFactory/Queue reconnection

    Gerald Quintana Newbie

      Hello,

      I am sending message from JBoss EJB Session to a remote JBoss Queue. I have declared the remote JBossMQ like this:

      <?xml version="1.0" encoding="UTF-8"?>
      <connection-factories>
       <mbean code="org.jboss.naming.ExternalContext" name="jboss.jndi:service=ExternalContext,jndiName=external/RemoteJBoss">
       <attribute name="JndiName">java:external/RemoteJBoss</attribute>
       <attribute name="CacheContext">true</attribute>
       <attribute name="Properties">
      java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
      java.naming.provider.url=jnp://remoteserver:1099
      java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
       <attribute name="InitialContext">javax.naming.InitialContext</attribute>
       </attribute>
       <attribute name="RemoteAccess">true</attribute>
       </mbean>
       <mbean code="org.jboss.jms.jndi.JMSProviderLoader" name="jboss.mq:service=JMSProviderLoader,name=JMSExploitationProvider">
       <attribute name="ProviderName">JMSExploitationProvider</attribute>
       <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute>
       <attribute name="FactoryRef">XAConnectionFactory</attribute>
       <attribute name="QueueFactoryRef">XAConnectionFactory</attribute>
       <attribute name="TopicFactoryRef">XAConnectionFactory</attribute>
       <attribute name="Properties">
      java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
      java.naming.provider.url=jnp://remoteserver:1099
      java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
       </attribute>
       </mbean>
       <tx-connection-factory>
       <jndi-name>JMSExploitationXA</jndi-name>
       <xa-transaction/>
       <rar-name>jms-ra.rar</rar-name>
       <connection-definition>org.jboss.resource.adapter.jms.JmsConnectionFactory</connection-definition>
       <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Topic</config-property>
       <config-property name="JmsProviderAdapterJNDI" type="java.lang.String">java:/JMSExploitationProvider</config-property>
       <max-pool-size>20</max-pool-size>
       </tx-connection-factory>
      </connection-factories>


      Sending a message from the local JBoss to the remote one basically works perfectly.

      Nonetheless, when I stop and restart the remote JBoss, the local JBoss doesn't find the new remote ConnectionFactory/Queue because they are not refreshed: is there a cache somewhere?.

      Then if use the local JBoss web console to invoke JNDIView.list, the external context is refreshed (is the cache refreshed by this operation?) and everything works back again.

      What can I do avoid this trick on the local JBoss each the remote JBoss is restarted and make the reconnection automatic?

      Thanks for your help,
      Gérald

        • 1. Re: Remote ConnectionFactory/Queue reconnection
          harm laat, de Newbie

          Simply catch the exception and reconnect?

          • 2. Re: Remote ConnectionFactory/Queue reconnection
            Gerald Quintana Newbie

            Thanks for your post razor_harm!

            I get my ConnectionFactory and my Queue from the JNDI. Should I do an initialContext.lookup(...) twice ?

            In theory, given that I declare a <tx-connection-factory>, JBoss should build a pool of JMS connections. I wonder whether JBoss keeps old Connections in his pool and how he replaces them with new ones once the remote server has restarted?

            Gérald

            • 3. Re: Remote ConnectionFactory/Queue reconnection
              harm laat, de Newbie

               


              I get my ConnectionFactory and my Queue from the JNDI. Should I do an initialContext.lookup(...) twice ?


              Yes. I guess you could implement the javax.jms.ExceptionListener interface. (Altough, i'm not 100% sure if this is the way to do it, if you use a session bean).

              You will have to implement the onException() method.

               /**
              
               * Handle asynchronous errors with the connection.
              
               */
              
               public void onException(javax.jms.JMSException jsme) {
              
               // Tries to reconnect
              
               }
              


              Also register this listerer:

              connection.setExceptionListener(
              
               (javax.jms.ExceptionListener) ExceptionListenerImpl);
              


              You can do your reconnecting in the onException method.



              • 4. Re: Remote ConnectionFactory/Queue reconnection
                Gerald Quintana Newbie

                I can not call connection.setExceptionListener() because the problem occurs before I get the connection. This what I do:

                Context context = new InitialContext();
                ConnectionFactory connectionFactory = context.lookup("java:/JMSExploitationXA");
                Queue queue = context.lookup("java:/external/RemoteJBoss/queue/MyQueue");
                Connection connection = connectionFactory.createConnection();
                


                I don't know exactly where an exception is raised (I will look at this ASAP):
                • In the context.lookup("...")
                • In the connectionFactory.createConnection()

                  The ExceptionListener is useful when you want watch what's happening when you send/receive a message but it is not my case.

                  By the way, I thank you very much,
                  Gérald


                • 5. Re: Remote ConnectionFactory/Queue reconnection
                  Adrian Brock Master

                  JBoss's JMS Resource Adapter already implements the ExecptionListener
                  for you.

                  But it does not work in some versions, because some developers
                  didn't understand how it interacts with the pool and broke the code.
                  There is now a comment in the code, to stop people breaking it:

                   // If we are destroying, check the connection is not in the pool
                   if (kill)
                   {
                   // Adrian Brock: A resource adapter can asynchronously notify us that
                   // a connection error occurred.
                   // This could happen while the connection is not checked out.
                   // e.g. JMS can do this via an ExceptionListener on the connection.
                   // I have twice had to reinstate this line of code, PLEASE DO NOT REMOVE IT!
                   cls.remove(cl);
                   }
                  


                  • 6. Re: Remote ConnectionFactory/Queue reconnection
                    Gerald Quintana Newbie

                    Thank you for you Adrian, I don't understand your answer in detail but I am going to have a look at this ExceptionListener.

                    Nonetheless, here is the scenario:


                    1. Local JBoss and Remote JBoss are started
                    2. Remote JBoss is stopped and then restarted
                    3. Local JBoss try to send JMS message to a Queue located on the Remote JBoss. This Queue is accessed through an ExternalContext MBean (see my first post)

                      And now here is the stack trace. The problem doesn't come from the ConnectionFactory but from the Queue I got from JNDI registry through the ExternalContext :
                      2005-03-14 08:23:08,898 ERROR [org.jboss.ejb.plugins.LogInterceptor] TransactionRolledbackLocalException in method: public abstract void com.mycompany.myproject.bean.MyServiceLocal.sendMessage(int,java.lang.String,java.lang.String) throws javax.jms.JMSException, causedBy:
                      com.mycompany.myproject.ServiceLocatorException: Objet not found in the JNDI registry: java:comp/env/jms/Queue
                       at com.mycompany.myproject.ServiceLocator.lookup(ServiceLocator.java:38)
                       at com.mycompany.myproject.ServiceLocator.getObject(ServiceLocator.java:26)
                       at com.mycompany.myproject.bean.MyServiceBean.getQueue(MyServiceBean.java:84)
                       at com.mycompany.myproject.bean.MyServiceBean.sendMessage(MyServiceBean.java:105)
                      (... cut here ...)
                      Caused by: javax.naming.NamingException: Could not dereference object [Root exception is javax.naming.CommunicationException [Root exception is java.rmi.NoSuchObjectException: no such object in table]]
                       at org.jnp.interfaces.NamingContext.resolveLink(NamingContext.java:999)
                       at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:629)
                       at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:658)
                       at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:520)
                       at javax.naming.InitialContext.lookup(InitialContext.java:347)
                       at com.mycompany.myproject.ServiceLocator.lookup(ServiceLocator.java:36)
                       ... 66 more
                      Caused by: javax.naming.CommunicationException [Root exception is java.rmi.NoSuchObjectException: no such object in table]
                       at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:663)
                       at javax.naming.InitialContext.lookup(InitialContext.java:351)
                       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                       at java.lang.reflect.Method.invoke(Method.java:324)
                       at org.jboss.naming.ExternalContext$CachedContext.invoke(ExternalContext.java:528)
                       at $Proxy41.lookup(Unknown Source)
                       at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:610)
                       at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:520)
                       at javax.naming.InitialContext.lookup(InitialContext.java:347)
                       at org.jnp.interfaces.NamingContext.resolveLink(NamingContext.java:993)
                       ... 71 more
                      Caused by: java.rmi.NoSuchObjectException: no such object in table
                       at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:247)
                       at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:223)
                       at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:133)
                       at org.jnp.server.NamingServer_Stub.lookup(Unknown Source)
                       at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:544)
                       ... 82 more
                      


                      Why do I get a NamingException given that the remote JBoss with the referenced Queue has restarted?

                      Again thanks for your help, it is very appreciated!
                      Gérald


                    • 7. Re: Remote ConnectionFactory/Queue reconnection
                      Adrian Brock Master

                       

                      Caused by: java.rmi.NoSuchObjectException:


                      Paraphrasing the RMI documentation:
                      You have a stale RMI connection to a server, probably because you rebooted it?

                      RMI or JNDI config is not a topic for this forum.

                      • 8. Re: Remote ConnectionFactory/Queue reconnection
                        Gerald Quintana Newbie

                        Ah alright, I apologize for having polluted this forum. Where can I post this question?

                        • 9. Re: Remote ConnectionFactory/Queue reconnection
                          Benson Fung Newbie

                          Hi Adrian,

                          I really don't understand your answer. You always say this is not a suitable place to develop JNDI things, if that is the case, where is the suitable place to discuss. We know that JBOSSMQ configuration is very closely related to JNDI configuration. If the setup of the JNDI is incorrect, the client never connect to the JBOSSMQ server. Therefore, I don't think this is not a suitable place to discuss the JBOSSMQ configuration.

                          Are you a JBOSS expert? Sorry for my question, I am just wondering your answer is to the question.

                          Thanks
                          Benson

                          • 10. Re: Remote ConnectionFactory/Queue reconnection
                            Adrian Brock Master

                            JNDI has two parts:

                            1) Deployment - binding jms admin objects into jndi - suitable for this forum
                            because JBossMQ does that work.

                            But nobody ever reports a problem on that side since JBossMQ knows what it is doing.
                            Except the infamous XAConnectionFactory not bound problem FAQ
                            (AKA I have broken my server configuration but can't read server logs properly).

                            2) Accessing JNDI - client code and/or network/jndi configuration problems -
                            not JMS code and not a topic for this forum.
                            http://www.jboss.org/index.html?module=bb&op=viewforum&f=214

                            This forum is full of type (2) just because the object being looked up is a jms destination
                            or connection factory. The object being looked up is entirely irrelvent to the problem.

                            (2) would be a problem for this forum if your naming context used jms as its transport :-)