org.springframework.integration.jms.request_reply.RequestReplyScenariosWithTempReplyQueuesTests.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.integration.jms.request_reply.RequestReplyScenariosWithTempReplyQueuesTests.java

Source

/*
 * Copyright 2002-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.integration.jms.request_reply;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.TextMessage;

import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.command.ActiveMQDestination;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Rule;
import org.junit.Test;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.gateway.RequestReplyExchanger;
import org.springframework.integration.jms.ActiveMQMultiContextTests;
import org.springframework.integration.jms.config.ActiveMqTestUtils;
import org.springframework.integration.test.support.LongRunningIntegrationTest;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.jms.listener.SessionAwareMessageListener;
import org.springframework.jms.support.converter.SimpleMessageConverter;
import org.springframework.messaging.MessageDeliveryException;
import org.springframework.messaging.support.GenericMessage;

/**
 * @author Oleg Zhurakousky
 * @author Gary Russell
 */
public class RequestReplyScenariosWithTempReplyQueuesTests extends ActiveMQMultiContextTests {

    private final Log logger = LogFactory.getLog(getClass());

    private final SimpleMessageConverter converter = new SimpleMessageConverter();

    @Rule
    public LongRunningIntegrationTest longTests = new LongRunningIntegrationTest();

    @SuppressWarnings("resource")
    @Test
    public void messageCorrelationBasedOnRequestMessageId() throws Exception {
        ActiveMqTestUtils.prepare();

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "producer-temp-reply-consumers.xml", this.getClass());
        RequestReplyExchanger gateway = context.getBean(RequestReplyExchanger.class);
        CachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);
        final JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);

        final Destination requestDestination = context.getBean("siOutQueue", Destination.class);

        new Thread(() -> {
            final Message requestMessage = jmsTemplate.receive(requestDestination);
            Destination replyTo = null;
            try {
                replyTo = requestMessage.getJMSReplyTo();
            } catch (Exception e) {
                fail();
            }
            jmsTemplate.send(replyTo, (MessageCreator) session -> {
                try {
                    TextMessage message = session.createTextMessage();
                    message.setText("bar");
                    message.setJMSCorrelationID(requestMessage.getJMSMessageID());
                    return message;
                } catch (Exception e) {
                    // ignore
                }
                return null;
            });
        }).start();
        gateway.exchange(new GenericMessage<String>("foo"));
        context.close();
    }

    @Test
    public void messageCorrelationBasedOnRequestCorrelationIdTimedOutFirstReply() throws Exception {
        ActiveMqTestUtils.prepare();
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "producer-temp-reply-consumers.xml", this.getClass());
        RequestReplyExchanger gateway = context.getBean(RequestReplyExchanger.class);
        ConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);

        final Destination requestDestination = context.getBean("siOutQueue", Destination.class);

        DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
        dmlc.setConnectionFactory(connectionFactory);
        dmlc.setDestination(requestDestination);
        dmlc.setMessageListener((SessionAwareMessageListener<Message>) (message, session) -> {
            Destination replyTo = null;
            try {
                replyTo = message.getJMSReplyTo();
            } catch (Exception e1) {
                fail();
            }
            String requestPayload = (String) extractPayload(message);
            if (requestPayload.equals("foo")) {
                try {
                    Thread.sleep(6000);
                } catch (Exception e2) {
                    /*ignore*/ }
            }
            try {
                TextMessage replyMessage = session.createTextMessage();
                replyMessage.setText(requestPayload);
                replyMessage.setJMSCorrelationID(message.getJMSMessageID());
                MessageProducer producer = session.createProducer(replyTo);
                producer.send(replyMessage);
            } catch (Exception e3) {
                // ignore. the test will fail
            }
        });
        dmlc.afterPropertiesSet();
        dmlc.start();

        try {
            gateway.exchange(new GenericMessage<String>("foo"));
        } catch (Exception e) {
            // ignore
        }
        Thread.sleep(1000);
        try {
            assertEquals("bar", gateway.exchange(new GenericMessage<String>("bar")).getPayload());
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }
        context.close();
    }

    /**
     * Validates that JOG will recreate a temporary queue
     * once a failure detected and that the messages will still be properly correlated
     */
    @Test
    public void brokenBrokerTest() throws Exception {

        BrokerService broker = new BrokerService();
        broker.setPersistent(false);
        broker.setUseJmx(false);
        broker.setTransportConnectorURIs(new String[] { "tcp://localhost:61623" });
        broker.setDeleteAllMessagesOnStartup(true);
        broker.start();

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("broken-broker.xml",
                this.getClass());

        final RequestReplyExchanger gateway = context.getBean(RequestReplyExchanger.class);

        int replyCounter = 0;
        int timeoutCounter = 0;
        for (int i = 0; i < 50; i++) {
            try {
                assertEquals(i + "", gateway.exchange(new GenericMessage<String>(String.valueOf(i))).getPayload());
                replyCounter++;
            } catch (Exception e) {
                timeoutCounter++;
            }
            if (i == 0 || i == 20 || i == 40) {
                Object replyDestination = TestUtils.getPropertyValue(context.getBean("jog"),
                        "handler.replyDestination");
                if (replyDestination != null) {
                    broker.removeDestination((ActiveMQDestination) replyDestination);
                }
            }
        }
        assertEquals(50, replyCounter + timeoutCounter);
        context.close();
    }

    @Test
    public void testConcurrently() throws Exception {
        ActiveMqTestUtils.prepare();
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "mult-producer-and-consumers-temp-reply.xml", this.getClass());
        final RequestReplyExchanger gateway = context.getBean(RequestReplyExchanger.class);
        Executor executor = Executors.newFixedThreadPool(10);
        final int testNumbers = 100;
        final CountDownLatch latch = new CountDownLatch(testNumbers);
        final AtomicInteger failures = new AtomicInteger();
        final AtomicInteger timeouts = new AtomicInteger();
        final AtomicInteger missmatches = new AtomicInteger();
        for (int i = 0; i < testNumbers; i++) {
            final int y = i;
            executor.execute(() -> {
                try {

                    String reply = (String) gateway.exchange(new GenericMessage<String>(String.valueOf(y)))
                            .getPayload();
                    if (!String.valueOf(y).equals(reply)) {
                        missmatches.incrementAndGet();
                    }
                } catch (Exception e) {
                    if (e instanceof MessageDeliveryException) {
                        timeouts.incrementAndGet();
                    } else {
                        failures.incrementAndGet();
                    }
                }
                //               if (latch.getCount()%100 == 0){
                //                  long count = testNumbers-latch.getCount();
                //                  if (count > 0){
                //                     print(failures, timeouts, missmatches, testNumbers-latch.getCount());
                //                  }
                //               }
                latch.countDown();
            });
        }
        latch.await();
        print(failures, timeouts, missmatches, testNumbers);
        Thread.sleep(5000);
        assertEquals(0, missmatches.get());
        assertEquals(0, failures.get());
        assertEquals(0, timeouts.get());
        context.close();
    }

    private void print(AtomicInteger failures, AtomicInteger timeouts, AtomicInteger missmatches,
            long echangesProcessed) {
        logger.info("============================");
        logger.info(echangesProcessed + " exchanges processed");
        logger.info("Failures: " + failures.get());
        logger.info("Timeouts: " + timeouts.get());
        logger.info("Missmatches: " + missmatches.get());
        logger.info("============================");
    }

    public static class MyRandomlySlowService {
        Random random = new Random();
        List<Integer> list = new ArrayList<Integer>();

        public String secho(String value) throws Exception {
            int i = random.nextInt(2000);
            Thread.sleep(i);
            return value;
        }
    }

    private Object extractPayload(Message jmsMessage) {
        try {
            return converter.fromMessage(jmsMessage);
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }
        return null;
    }
}