10 Replies Latest reply on Oct 19, 2006 2:09 AM by Kurt Edegger

    Seam Remoting und JMS Topic subscription questions.

    Kurt Edegger Newbie

      I'm having a seam page, which should invoke an action, whenever a JMS message is published to a topic as described in the reference manual.
      I followed the examples and got the page to invoke a javascript callback method, whenever a message is published after the page has subscribed to the topic.

      Currently the subscribtion is done on page load. This leads to two issues:

      1) Whenever the page is re-rendered (e.g. after a button is clicked), the page subscribes to the topic again and more importantly as a new listener (new polling token).
      So when a message is sent to the topic in an action method of the same page the message is lost (and the callback method is never invoked).

      2) The subscribers are piling up on the topic as verifiable by invoking listSubscriptionsAsText() on the topic bean in the JMX console.

      So finally, I'd like to ask, if anyone has some ideas on how to solve this issues or could give me any pointers.
      How could a subscription be made page scoped and not request scoped?
      How could I unsubscribe from a topic whenever the page is closed?

      Additionally I've realized that the subscriptions are done in a non-durable fashion. Is it possible to subscribe as a durable listener?

      Thanks for any hints,

      Kurt

        • 1. Re: Seam Remoting und JMS Topic subscription questions.
          Shane Bryzak Master

          The code for dealing with stale subscriptions is a little messy at the moment. However to deal with your immediate issue, if you can somehow pass your subscription token to the next page (with a hidden field or something) then you can manually insert your subscription into the registry like this:

           Seam.Remoting.subscriptionRegistry.push({topic:topicName, callback:callback, token:token});
          


          Then simply call Seam.Remoting.poll() to kick off the polling process.

          • 2. Re: Seam Remoting und JMS Topic subscription questions.
            Kurt Edegger Newbie

            Hi, thanks for your reply!

            I've tried to follow your hint, but somehow it seems that I cannot access the token after subscription to be able to write it to an input field.

            The xhtml page is defined as following:

            <script type="text/javascript">
            //<![CDATA[
             Seam.Remoting.setDebug(true);
            
             function connect() {
             for (var i = 0; i < Seam.Remoting.subscriptionRegistry.length; i++){
             Seam.Remoting.log(Seam.Remoting.subscriptionRegistry.topic);
             }
             Seam.Remoting.subscribe("taskListTopic", channelMessageCallback);
             }
            
             Seam.Remoting.setPollTimeout(10);
             Seam.Remoting.setPollInterval(3);
             connect();
            
             function channelMessageCallback(message) {
             Seam.Remoting.log("msg.rcvd");
             window.location.href=window.location.href;
             }
             // ]]>
             </script>
             <!-- /Seam Remoting -->
            
             <f:view>
             <h2><h:outputText value="#{msgs['home.Title']}" /></h2>
             <!-- here follows the view [.. snipped .. ] -->
             </f:view>
            
             <script type="text/javascript">
             //<![CDATA[
             Seam.Remoting.log("Script at the bottom of page...");
            
             function fillTokenField(){
             Seam.Remoting.log("filling input field with token");
             var tokenField = document.getElementById('token');
             tokenField.value="somethg";
             Seam.Remoting.log(tokenField.value);
             for (var i = 0; i < Seam.Remoting.subscriptionRegistry.length; i++){
             Seam.Remoting.log(i+": "+Seam.Remoting.subscriptionRegistry.topic+": "+Seam.Remoting.subscriptionRegistry.token);
             }
             tokenField.value = Seam.Remoting.subscriptionRegistry[0].token;
             Seam.Remoting.log(tokenField.value);
             }
            
             fillTokenField();
             // ]]>
             </script>
            

            After the page has been called, Seam log shows the following content:

            Fri Oct 13 2006 08:09:54 GMT+0200: Request packet:
            <envelope><body><subscribe topic="taskListTopic"/></body></envelope>
            
            Fri Oct 13 2006 08:09:54 GMT+0200: Script at the bottom of page...
            
            Fri Oct 13 2006 08:09:54 GMT+0200: filling input field with token
            
            Fri Oct 13 2006 08:09:54 GMT+0200: somethg
            
            Fri Oct 13 2006 08:09:54 GMT+0200: 0: taskListTopic: undefined
            
            Fri Oct 13 2006 08:09:54 GMT+0200: undefined
            
            Fri Oct 13 2006 08:09:54 GMT+0200: Response packet:
            <envelope><body><subscription topic="taskListTopic" token="ba340565-eeba-483f-9d10-9171e8fac57d"/></body></envelope>
            
            Fri Oct 13 2006 08:09:54 GMT+0200: Request packet:
            <envelope><body><poll token="ba340565-eeba-483f-9d10-9171e8fac57d" timeout="10"/></body></envelope>
            


            The last two lines of the log are the first polling performed. But as seen, at the point where the subscription list is written to the log, the token for the current subscription is 'undefined'.

            When is the token initialized?
            Am I missing something obvious?

            And just to make sure, I got you right, after I've written the token to an input field, I need to make sure this token is pushed into the subscriptionRegistry again after the page has reloaded.
            After that I start the polling process with Seam.Remoting.poll(), right?

            Thank you again,

            Kurt




            • 3. Re: Seam Remoting und JMS Topic subscription questions.
              Shane Bryzak Master

              The token is passed back in the response to the subscribe request, and added to the subscription registry in Seam.Remoting.subscriptionCallback(). You should put the code for setting the token in your channelMessageCallback() method (only setting it if it hasn't already been set).

              • 4. Re: Seam Remoting und JMS Topic subscription questions.
                Kurt Edegger Newbie

                Hi, thanks for helping me on this topic!

                But I'm not sure, if your suggestion would realy help me out, because the channelMessageCallback() method is not always called _before_ the page is refreshed. Actually in my scenario it is never called before the first refresh.

                Imagine this timeline:
                1) The page is rendered and the subscription takes place
                2) The user hits a button on the page triggering some action method
                3) The page is re-rendered because of the action triggered in 2)
                4) A JMS message is published on the topic ....

                At point 3) a new subscription would have taken place ....

                But I've noticed this Monday morning, that the exact same code produced a valid subscription AND token in the script at the bottom of the page [see code of posting Fri Oct 13, 2006 02:33 AM](after subscription).

                So I thought about a racing condition. After calling Seam.Remoting.subscribe() at the top of the page, your code is generating the token and is putting it into the SubscriptionRegistry. Simultaneously the page is rendered and the script at the bottom of the page is executed. If the token ends up in the registry before that point, everythings fine. But most of the times it won't!
                I think I've confirmed the issue by delaying the script at the bottom of the page artificially.

                setTimeout('fillTokenField();', 1000);


                I'm not sure, if this is the best approach. Assumptions on "how long something usually takes" have a tendency to break code after a while. Is there another way of knowing, if the subscription is completely performed, hence the token is generated?

                Thank you again for sticking with me,

                Kurt

                • 5. Re: Seam Remoting und JMS Topic subscription questions.
                  Shane Bryzak Master

                  Seam.Remoting.subscribe() sends an asynchronous request to the server, which means you're not guaranteed to have a token in the subscription registry by the time your page gets to the script at the bottom of the page.

                  I suggested putting the code to set the token inside your callback method, because it is synchronous with the subscription request. However if your callback method isn't being called before the page is refreshed (because you haven't received any messages during that time) then you can override SeamRemote.subscriptionCallback() instead:

                   <script type="text/javascript">
                   var cb = SeamRemote.subscriptionCallback;
                   SeamRemote.subscriptionCallback = function(doc) {
                   cb(doc);
                   document.getElementById('token').value = Seam.Remoting.subscriptionRegistry[0].token;
                   }
                   </script>
                   }
                  


                  Using setTimeout() is definitely not the way to do it.


                  • 6. Re: Seam Remoting und JMS Topic subscription questions.
                    Kurt Edegger Newbie

                    Thanks Shane,

                    overriding the subscriptionCallback definitely did the trick. I never wanted to use the setTimeout() version in a production environment.
                    So finally I got the token in an input field and this is passed along the request until the page is rerenderd.
                    I followed your suggestion, pushed the token manually into the registry and after calling Seam.Remoting.poll() the polling starts with the same token!

                    But ;), the polling stops after the first (polling-)request times out because of an JavaScript Error

                    Seam.Remoting.loadingMsgDiv has no properties
                    .

                    It seems uthat there is more going on behind the scenes at subscription.
                    Sorry to bother you again, bt do you have any thoughts on that one?

                    Kurt

                    • 7. Re: Seam Remoting und JMS Topic subscription questions.
                      Shane Bryzak Master

                      Hmm, I'm not sure why you'd be getting that specific Javascript error in relation to messaging. The only place I can see it possibly happening is in the Seam.Remoting.hideLoadingMessage() method - just to be safe I've updated this method in CVS to check that Seam.Remoting.loadingMsgDiv is not null, so you might like to get the latest version from CVS and try that.

                      Alternatively, you can just add this code snippet to your page if you don't want to get the latest CVS version:

                      Seam.Remoting.hideLoadingMessage = function()
                      {
                       if (Seam.Remoting.loadingMsgDiv)
                       Seam.Remoting.loadingMsgDiv.style.visibility = 'hidden';
                      }
                      


                      • 8. Re: Seam Remoting und JMS Topic subscription questions.
                        Kurt Edegger Newbie

                        Hi,

                        that finally did the trick! Thank you again for your help.

                        By the way, I'm using JBossMessaging instead of JBossMQ and therefore needed to set the connection provider in the subscriptionRegistry.
                        Is there a reason why the property connectionProvider in org.jboss.seam.remoting.messaging.SubscriptionRegistry lacks a getter method and hence cannot be set by a parameter in seam.properties, components.xml or web.xml?

                        I know, it's only the the getter missing, but without that java.beans.PropertyDescriptor won't extract the bean interface properly and the property cannot be set in org.jboss.seam.Component.

                        I needed to set the connection provider since the default one only uses the hardcoded JDNI_Factory_Name "UIL2ConnectionFactory".

                        Regards, Kurt

                        • 9. Re: Seam Remoting und JMS Topic subscription questions.
                          Shane Bryzak Master

                           

                          "appendix" wrote:

                          Is there a reason why the property connectionProvider in org.jboss.seam.remoting.messaging.SubscriptionRegistry lacks a getter method and hence cannot be set by a parameter in seam.properties, components.xml or web.xml?


                          I'll add the getter method for you today.

                          • 10. Re: Seam Remoting und JMS Topic subscription questions.
                            Kurt Edegger Newbie

                            Thank you Shane, you've been really helpful!

                            The getter is not an immediate issue for me. I just wanted to point that out, that some other guy later on won't need to worry, why the provider cannot be set in components.xml :)

                            Again, I'd like to thank you for your great help!

                            Kurt