Search code examples
jmsspring-jmsjmstemplate

How to use JmsTemplate.sendAndReceive


I want to get sync response from jmsTemplate.sendAndReceive:

    Message responseMessage = producer.produceAndReceive(gzip, mestype, uploadFile.getName(), uploadFile.getAbsolutePath());

It calls produceAndReceive in another class:

  @Override
  public Message produceAndReceive(final byte[] data, final String type, final String name, final String archivePath) {
    jmsTemplate.setReceiveTimeout(20000);
    return jmsTemplate.sendAndReceive(SAPPI_EXPORT_QUEUE, new MessageCreator() {
      @Override
      public Message createMessage(Session session) throws JMSException {
        String msgId = UUIDGen.getUUID();
        BytesMessage message = session.createBytesMessage();
        message.writeBytes(data);
        message.setStringProperty(ISapProducer.IDOC_TYPE, type);
        message.setStringProperty(ISapProducer.ORIGIN_FILE_NAME, name);
        message.setStringProperty(ISapProducer.MESSAGE_ID, msgId);
        message.setStringProperty(ISapProducer.ARCHIVE_PATH, archivePath);

        message.setJMSReplyTo(session.createTemporaryQueue());
        message.setJMSCorrelationID(msgId);
        return message;
      }
    });
  }

after it step I suppose that message already placed in queue. I have @JmsListener method, that 'listen to' this queue:

  @Override
  @JmsListener(destination = "myqueue.export")
  public void consume(final Message message) throws ServerException {
     // some logic here
         final HttpStatus httpStatus = client.send(gzip, idocType, documentFileName, messageId, archivePath);
        jmsTemplate.send(message.getJMSReplyTo(), new MessageCreator() {
          @Override
          public Message createMessage(Session session) throws JMSException {
            Message responseMsg = session.createTextMessage(httpStatus.toString());
            responseMsg.setJMSCorrelationID(message.getJMSCorrelationID());
            return responseMsg;
          }
        });
    // some logic here

  }

Here I send http-request to remote system and try to use httpStatus at response message for sendAndReceive() method. But in responseMessage always null. And it looks like it works asynchronously.

How I can fix it?


Solution

  • Works fine for me...

    @SpringBootApplication
    public class So53506177Application {
    
        public static void main(String[] args) {
            SpringApplication.run(So53506177Application.class, args);
        }
    
        private final SimpleMessageConverter converter = new SimpleMessageConverter();
    
        @Bean
        public ApplicationRunner runner(JmsTemplate jmsTemplate) {
            return args -> {
                jmsTemplate.setReceiveTimeout(20000);
                Message received = jmsTemplate.sendAndReceive("foo", new MessageCreator() {
    
                    @Override
                    public Message createMessage(Session session) throws JMSException {
                        String msgId = "foo";
                        TextMessage message = session.createTextMessage("foo");
                        message.setJMSCorrelationID(msgId);
                        return message;
                    }
                });
                System.out.println("Reply: " + this.converter.fromMessage(received));
            };
        }
    
        @Autowired
        private JmsTemplate jmsTemplate;
    
        @JmsListener(destination = "foo")
        public void consume(final Message message) throws Exception {
            System.out.println("Received: " + this.converter.fromMessage(message));
            jmsTemplate.send(message.getJMSReplyTo(), new MessageCreator() {
    
                @Override
                public Message createMessage(Session session) throws JMSException {
                    Message responseMsg = session.createTextMessage("bar");
                    responseMsg.setJMSCorrelationID(message.getJMSCorrelationID());
                    return responseMsg;
                }
            });
        }
    
    }
    

    and

    Received: foo
    Reply: bar
    

    However, while it doesn't affect the result, you shouldn't create your own replyTo - the template creates its own after the MessageCreator exits (and consumes from it). It also deletes it when done:

    @Nullable
    protected Message doSendAndReceive(Session session, Destination destination, MessageCreator messageCreator)
            throws JMSException {
    
        Assert.notNull(messageCreator, "MessageCreator must not be null");
        TemporaryQueue responseQueue = null;
        MessageProducer producer = null;
        MessageConsumer consumer = null;
        try {
            Message requestMessage = messageCreator.createMessage(session);
            responseQueue = session.createTemporaryQueue();
            producer = session.createProducer(destination);
            consumer = session.createConsumer(responseQueue);
            requestMessage.setJMSReplyTo(responseQueue);
            if (logger.isDebugEnabled()) {
                logger.debug("Sending created message: " + requestMessage);
            }
            doSend(producer, requestMessage);
            return receiveFromConsumer(consumer, getReceiveTimeout());
        }
        finally {
            JmsUtils.closeMessageConsumer(consumer);
            JmsUtils.closeMessageProducer(producer);
            if (responseQueue != null) {
                responseQueue.delete();
            }
        }
    }
    

    You can also simplify your listener:

    @JmsListener(destination = "foo")
    public String consume(final Message message) throws Exception {
        System.out.println("Received: " + this.converter.fromMessage(message));
        return "bar";
    }