简体   繁体   中英

Read without removing message from JMS queue

How to read a message from WebSphere MQ without deleting the original message from queue?

I have spring application which reads the message from the WebSphere MQ. After reading, I have a process method which will process the data retrieved from queue.

Step 1:

response = jmsTemplate.receive();
//Message automatically removed from queue.

Step 2:

process(response);

There are chances of throwing exceptions in process method. In case of exceptions, I need to retain the message in the queue.

Is it possible? Is their any way to delete the message only on user acknowledgement?

I tried adding the following:

jmsTemplate.setSessionAcknowledgeMode(javax.jms.Session.CLIENT_ACKNOWLEDGE);

...but still the message is getting deleted.

JmsTemplate creating code snippet:

JndiConnectionFactorySupport connectionFactoryBean = new JndiConnectionFactorySupport();
    connectionFactoryBean.setBindingsDir(this.bindingDir);


        connectionFactoryBean
                .setConnectionFactoryName(connectionFactoryName);
        connectionFactoryBean.afterPropertiesSet();
        jmsTemplate.setConnectionFactory(connectionFactoryBean.getObject());


    JndiDestinationResolver destinationResolver = new JndiDestinationResolver();
    destinationResolver.setJndiTemplate(connectionFactoryBean
            .getJndiTemplate());

    jmsTemplate.setDestinationResolver(destinationResolver);
    jmsTemplate.setReceiveTimeout(20000);
    jmsTemplate.setDefaultDestinationName(this.defaultDestinationName);

            

Tried the jmsTemplate.execute() method as below:

@SuppressWarnings({ "unused", "unchecked" })
        Message responseMessage = (Message) jmsTemplate.execute(
            new SessionCallback() { 
                public Object doInJms(Session session)
                        throws JMSException {
                    MessageConsumer consumer = session
                    .createConsumer(jmsTemplate.getDestinationResolver().resolveDestinationName(session, "QUEUE_NAME", false));
                    Message response = consumer.receive(1);
                    try {
                        testMethod();//this method will throw exception.
                        response.acknowledge();
                        consumer.close();
                    } catch(Exception e){
                        consumer.close();//control will come here.
                    }
                    
                    return response;
                }
        }, true);

You can't do that with receive() methods because the operation is complete (from the session perspective) when the receive method returns.

You need to run the code that might fail within the scope of the session; eg with a JmsTemplate.execute() with a SessionCallback - something like this...

this.jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
this.jmsTemplate.convertAndSend("foo", "bar");
try {
    String value = this.jmsTemplate.execute(session -> {
        MessageConsumer consumer = session.createConsumer(
                this.jmsTemplate.getDestinationResolver().resolveDestinationName(session, "foo", false));
        String result;
        try {
            Message received = consumer.receive(5000);
            result = (String) this.jmsTemplate.getMessageConverter().fromMessage(received);
            // Do some stuff that might throw an exception
            received.acknowledge();
        }
        finally {
            consumer.close();
        }
        return result;
    }, true);
    System.out.println(value);
}
catch (Exception e) {
    e.printStackTrace();
}

You can add transactional processing of JMS messages. See the example

Your listener should be "transacted" . Like this

<jms:listener-container connection-factory="connectionFactory" acknowledge="transacted">
    <jms:listener ref="notificationProcessor" destination="incoming.queue"/>
</jms:listener-container>

You have to browse the queue.

Example of real code that was executed making usage of Websphere MQ

public void browseMessagesAndJiraCreation(String jiraUserName, String jiraPassword) { int counterMessages = jmsTemplate.browse(destinationQueueName, new BrowserCallback<Integer>() { @Override public Integer doInJms(final Session session, final QueueBrowser queueBrowser) throws JMSException { Enumeration<TextMessage> enumeration = queueBrowser.getEnumeration(); int counterMessages = 0; while (enumeration.hasMoreElements()) { counterMessages += 1; TextMessage msg = enumeration.nextElement(); logger.info("Found : {}", msg.getText()); JiraId jiraId = jiraManager.createIssue(jiraUserName, jiraPassword); jiraManager.attachFileToJira(jiraId, msg.getText(), jiraUserName, jiraPassword); } return counterMessages; } }); logger.info("{}:messages were browsed and processed from queue:{}.", counterMessages, destinationQueueName); }

Explanations:

  • usage of the Spring Framework JmsTemplate
  • you pass the String gestinationQueueName (example destinationQueueName=QL.PREFCNTR.USER.REPLY)
  • Java enumeration of Text messages
  • counterMessages is the counter of messages that were processed
  • messages are NOT consumed!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM