Announcement Announcement Module
Collapse
No announcement yet.
Synchronous jmsTemplate with topics Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Synchronous jmsTemplate with topics

    I am trying to get messages from a topic - using JMSTemplate.receive - no messages come back even though I see them by going to the activeMQ admin console? How would I do it if jmsTemplate is not working?

  • #2
    I just ran a test and it worked fine for me.

    Are you using a timeout? Is the receive() active when you publish? Messages in topics are only received by active consumers by default. Consider using a message listener container and a durable subscription (or use a queue).

    Comment


    • #3
      Originally posted by Gary Russell View Post
      I just ran a test and it worked fine for me.

      Are you using a timeout? Is the receive() active when you publish? Messages in topics are only received by active consumers by default. Consider using a message listener container and a durable subscription (or use a queue).
      using the MessageListener is not ideal fro my environment bec. I only want to get the messages when the user requests it - otherwise I don't need it - so that's wh I need it working synchronously.
      Do Topics work Synchronously in the Spring environment?

      Here is how I instantiate the jmsTemplate, sender & receiver in the applicationcontext.xml
      <bean id="activeMQConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFacto ry">
      <property name="brokerURL" value="tcp://localhost:61616" />
      </bean>



      <bean id="testTopic" class="org.apache.activemq.command.ActiveMQTopic">
      <constructor-arg value="testNotifications" />
      </bean>

      <bean id="jmsSender" class="com.myJmsSender">
      <property name="jmsTemplate">
      <ref bean="jmsTemplate" />
      </property>
      </bean>
      <bean id="jmsReceiver" class="com.myJmsReceiver">
      <property name="jmsTemplate">
      <ref bean="jmsTemplate" />
      </property>
      </bean>

      <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate" >
      <property name="connectionFactory">
      <ref bean="activeMQConnectionFactory" />
      </property>
      <property name="defaultDestination" ref="testTopic"></property>

      </bean>

      Comment


      • #4
        Do Topics work Synchronously in the Spring environment?
        Yes, like I said, I just tested it and it worked fine for me. I had a jmsTemplate (similar configuration to yours) with a thread blocked in its receive() method, published a message to the topic and the template.receive() returned the message.

        You can't publish the message and then call receive(); that's not how JMS topics work (regardless of Spring).

        Comment


        • #5
          Heres my jmsReceiver class, do I have to run it in a separate thread when I call JMSMessageReceiver .getMessages
          public class JMSMessageReceiver {

          protected final Log logger = LogFactory.getLog(JMSMessagePublisher.class);

          private JmsTemplate jmsTemplate;

          public JmsTemplate getjmsTemplate() {
          return jmsTemplate;
          }

          public void setjmsTemplate(JmsTemplate jmsTemplate) {
          this.jmsTemplate = jmsTemplate;
          }

          public List<String> getMessages() {
          List<String> messages = new ArrayList<String>();
          Message msg = null;
          while((msg = jmsTemplate.receive()) != null){
          try {
          TextMessage textMessage = (TextMessage) msg;
          if (msg != null) {
          messages.add(textMessage.getText());
          }
          } catch (Exception e) {
          e.printStackTrace();
          }
          }

          return messages;
          }

          Comment


          • #6
            Please use [ code ] ... [ / code] tags (no spaces inside the brackets) when posting code and config.

            Are you saying you get zero messages? I would expect you to get one, but there is definitely a window to lose messages this way (the consumer only lives during the receive() and, like I said, if you're not consuming during the publish you will lose messages.

            For this application, you should probably drop down to some of the lower-level JmsTemplate APIs, such as...

            Code:
            jmsTemplate.execute(new SessionCallback<Object>() {
            	public Object doInJms(Session session) throws JMSException {
            		MessageConsumer consumer = session.createConsumer(destination);
            		while (true) {
            			Message message = consumer.receive();
            			System.out.println(message);
            		}
            	}
            });

            Comment


            • #7
              Originally posted by Gary Russell View Post
              Please use [ code ] ... [ / code] tags (no spaces inside the brackets) when posting code and config.

              Are you saying you get zero messages? I would expect you to get one, but there is definitely a window to lose messages this way (the consumer only lives during the receive() and, like I said, if you're not consuming during the publish you will lose messages.

              For this application, you should probably drop down to some of the lower-level JmsTemplate APIs, such as...

              Code:
              jmsTemplate.execute(new SessionCallback<Object>() {
              	public Object doInJms(Session session) throws JMSException {
              		MessageConsumer consumer = session.createConsumer(destination);
              		while (true) {
              			Message message = consumer.receive();
              			System.out.println(message);
              		}
              	}
              });



              Thanks alot for your help - I see what happens when my application gets deployed my jmsReceiver is not actually added as a topic consumer to ActiveMQ - it only gets registered in activeMQ at the first call to jmsTemplate.recieve -is there a way I can make sure it gets registered as a consumer on the application startup & not at the first time that I call receive?

              Comment


              • #8
                You can use a durable subscription, BUT earlier you said you only wanted to receive Messages when a client asks for them. If that's not the case, registering a MessageListener container is definitely simpler.

                Comment


                • #9
                  Originally posted by Mark Fisher View Post
                  You can use a durable subscription, BUT earlier you said you only wanted to receive Messages when a client asks for them. If that's not the case, registering a MessageListener container is definitely simpler.
                  I ended up calling jmsTemplate.receive when the setJmsTemplate gets called on the JMSReceiver instantiation from the applicationContext.xml- this way it establishes a connection, so when messages do come in & when the client asks for it it will receive them - is that Ok?
                  On the MessageListener part how do I define a clientID on startup - when I set it to be durable?

                  I have seen posts which say do not use jmsTemplate.receive - is that true? if not how else should I be receiving messages synchronously?

                  Comment


                  • #10
                    As I said, receive() on a topic has issues, because the consumer only lives within its scope, when it returns there is no consumer; if someone publishes another message while you are processing the current one, you will miss it. Use execute() with the SessionCallback as I described above.

                    A Queue has no such issues. Is there some reason you need to use a topic rather than a queue for this? Do you have a requirement for multiple consumers to get a message?

                    The DefaultMessageListenerContainer has a clientId property - use setClientId().

                    Comment


                    • #11
                      Originally posted by Gary Russell View Post
                      As I said, receive() on a topic has issues, because the consumer only lives within its scope, when it returns there is no consumer; if someone publishes another message while you are processing the current one, you will miss it. Use execute() with the SessionCallback as I described above.

                      A Queue has no such issues. Is there some reason you need to use a topic rather than a queue for this? Do you have a requirement for multiple consumers to get a message?

                      The DefaultMessageListenerContainer has a clientId property - use setClientId().
                      I originally used queues & it worked fine but then I found out that there will be multiple consumers for this message so I have no choice but to use topics.
                      I will use the execute then - Do I call jmsTemplate.execute whenever I am ready to get messages?

                      I saw the setClientId - but how do I have that value when I am instantiating it from the applicationContext.xml? where does the client id get generated?

                      Comment


                      • #12
                        You should call execute() when your application needs to. You won't see any messages until you call it, and create the consumer.


                        The client id is simply a unique identifier for the client, so the broker can maintain state for it (such as durable subscription to a topic)



                        You can either set it on the connection factory (preferred) or on the listener container bean.

                        Comment


                        • #13
                          Thanks alot for all you help with this - since I am new to spring I appreciate it very much - I ended up going the MessageListenerContainer - works alot better & cleaner like you had advised earlier - Since I set the clientID on the connectionFactory it is now durable so the consumer is there on the start of my service. I just maintain a static class to hold all the messages for when the client wants it.

                          In regard to the synchronous way even when I called execute I got the following message:
                          WARNING: Received a message on a connection which is not yet started. Have you forgotten to call Connection.start()?
                          Was I supposed to set additional properties in the jmsTemplate for recieving data? Is there a way to set the subscription durable with synchronouse to have the consumer there on start of the application like the messageListener is?

                          Comment

                          Working...
                          X