Package org.springframework.amqp.rabbit.core

Source Code of org.springframework.amqp.rabbit.core.RabbitTemplateIntegrationTests$PlannedException

/*
* Copyright 2010-2014 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.amqp.rabbit.core;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.commons.logging.Log;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Address;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.ReceiveAndReplyCallback;
import org.springframework.amqp.core.ReceiveAndReplyMessageCallback;
import org.springframework.amqp.core.ReplyToAddressCallback;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.SingleConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.support.DefaultMessagePropertiesConverter;
import org.springframework.amqp.rabbit.support.MessagePropertiesConverter;
import org.springframework.amqp.rabbit.test.BrokerRunning;
import org.springframework.amqp.rabbit.test.BrokerTestUtils;
import org.springframework.amqp.support.converter.SimpleMessageConverter;
import org.springframework.amqp.utils.SerializationUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;
import org.springframework.util.ReflectionUtils.FieldFilter;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.GetResponse;

/**
* @author Dave Syer
* @author Mark Fisher
* @author Tomas Lukosius
* @author Gary Russell
* @author Gunnar Hillert
* @author Artem Bilan
*/
public class RabbitTemplateIntegrationTests {

  private static final String ROUTE = "test.queue";

  private static final Queue REPLY_QUEUE = new Queue("test.reply.queue");

  private RabbitTemplate template;

  @Before
  public void create() {
    final CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
    connectionFactory.setHost("localhost");
    connectionFactory.setPort(BrokerTestUtils.getPort());
    template = new RabbitTemplate(connectionFactory);
    template.setSendConnectionFactorySelectorExpression(new LiteralExpression("foo"));
  }

  @After
  public void cleanup() throws Exception {
    ((DisposableBean) template.getConnectionFactory()).destroy();
  }

  @Rule
  public BrokerRunning brokerIsRunning = BrokerRunning.isRunningWithEmptyQueues(ROUTE, REPLY_QUEUE.getName());

  @Test
  public void testSendToNonExistentAndThenReceive() throws Exception {
    // If transacted then the commit fails on send, so we get a nice synchronous exception
    template.setChannelTransacted(true);
    try {
      template.convertAndSend("", "no.such.route", "message");
      // fail("Expected AmqpException");
    } catch (AmqpException e) {
      // e.printStackTrace();
    }
    // Now send the real message, and all should be well...
    template.convertAndSend(ROUTE, "message");
    String result = (String) template.receiveAndConvert(ROUTE);
    assertEquals("message", result);
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testSendAndReceiveWithPostProcessor() throws Exception {
    template.convertAndSend(ROUTE, (Object)"message", new MessagePostProcessor() {
      @Override
      public Message postProcessMessage(Message message) throws AmqpException {
        message.getMessageProperties().setContentType("text/other");
        // message.getMessageProperties().setUserId("foo");
        return message;
      }
    });
    String result = (String) template.receiveAndConvert(ROUTE);
    assertEquals("message", result);
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testSendAndReceive() throws Exception {
    template.convertAndSend(ROUTE, "message");
    String result = (String) template.receiveAndConvert(ROUTE);
    assertEquals("message", result);
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testSendAndReceiveTransacted() throws Exception {
    template.setChannelTransacted(true);
    template.convertAndSend(ROUTE, "message");
    String result = (String) template.receiveAndConvert(ROUTE);
    assertEquals("message", result);
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testSendAndReceiveTransactedWithUncachedConnection() throws Exception {
    final SingleConnectionFactory singleConnectionFactory = new SingleConnectionFactory("localhost");
    RabbitTemplate template = new RabbitTemplate(singleConnectionFactory);
    template.setChannelTransacted(true);
    template.convertAndSend(ROUTE, "message");
    String result = (String) template.receiveAndConvert(ROUTE);
    assertEquals("message", result);
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
    singleConnectionFactory.destroy();
  }

  @Test
  public void testSendAndReceiveTransactedWithImplicitRollback() throws Exception {
    template.setChannelTransacted(true);
    template.convertAndSend(ROUTE, "message");
    // Rollback of manual receive is implicit because the channel is
    // closed...
    try {
      template.execute(new ChannelCallback<String>() {
        @Override
        public String doInRabbit(Channel channel) throws Exception {
          // Switch off the auto-ack so the message is rolled back...
          channel.basicGet(ROUTE, false);
          // This is the way to rollback with a cached channel (it is
          // the way the ConnectionFactoryUtils
          // handles it via a synchronization):
          channel.basicRecover(true);
          throw new PlannedException();
        }
      });
      fail("Expected PlannedException");
    } catch (Exception e) {
      assertTrue(e.getCause() instanceof PlannedException);
    }
    String result = (String) template.receiveAndConvert(ROUTE);
    assertEquals("message", result);
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testSendAndReceiveInCallback() throws Exception {
    template.convertAndSend(ROUTE, "message");
    final MessagePropertiesConverter messagePropertiesConverter = new DefaultMessagePropertiesConverter();
    String result = template.execute(new ChannelCallback<String>() {

      @Override
      public String doInRabbit(Channel channel) throws Exception {
        // We need noAck=false here for the message to be expicitly
        // acked
        GetResponse response = channel.basicGet(ROUTE, false);
        MessageProperties messageProps = messagePropertiesConverter.toMessageProperties(
            response.getProps(), response.getEnvelope(), "UTF-8");
        // Explicit ack
        channel.basicAck(response.getEnvelope().getDeliveryTag(), false);
        return (String) new SimpleMessageConverter().fromMessage(new Message(response.getBody(), messageProps));
      }
    });
    assertEquals("message", result);
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testReceiveInExternalTransaction() throws Exception {
    template.convertAndSend(ROUTE, "message");
    template.setChannelTransacted(true);
    String result = new TransactionTemplate(new TestTransactionManager())
        .execute(new TransactionCallback<String>() {
          @Override
          public String doInTransaction(TransactionStatus status) {
            return (String) template.receiveAndConvert(ROUTE);
          }
        });
    assertEquals("message", result);
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testReceiveInExternalTransactionAutoAck() throws Exception {
    template.convertAndSend(ROUTE, "message");
    // Should just result in auto-ack (not synched with external tx)
    template.setChannelTransacted(true);
    String result = new TransactionTemplate(new TestTransactionManager())
        .execute(new TransactionCallback<String>() {
          @Override
          public String doInTransaction(TransactionStatus status) {
            return (String) template.receiveAndConvert(ROUTE);
          }
        });
    assertEquals("message", result);
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testReceiveInExternalTransactionWithRollback() throws Exception {
    // Makes receive (and send in principle) transactional
    template.setChannelTransacted(true);
    template.convertAndSend(ROUTE, "message");
    try {
      new TransactionTemplate(new TestTransactionManager()).execute(new TransactionCallback<String>() {
        @Override
        public String doInTransaction(TransactionStatus status) {
          template.receiveAndConvert(ROUTE);
          throw new PlannedException();
        }
      });
      fail("Expected PlannedException");
    } catch (PlannedException e) {
      // Expected
    }
    String result = (String) template.receiveAndConvert(ROUTE);
    assertEquals("message", result);
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testReceiveInExternalTransactionWithNoRollback() throws Exception {
    // Makes receive non-transactional
    template.setChannelTransacted(false);
    template.convertAndSend(ROUTE, "message");
    try {
      new TransactionTemplate(new TestTransactionManager()).execute(new TransactionCallback<String>() {
        @Override
        public String doInTransaction(TransactionStatus status) {
          template.receiveAndConvert(ROUTE);
          throw new PlannedException();
        }
      });
      fail("Expected PlannedException");
    } catch (PlannedException e) {
      // Expected
    }
    // No rollback
    String result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testSendInExternalTransaction() throws Exception {
    template.setChannelTransacted(true);
    new TransactionTemplate(new TestTransactionManager()).execute(new TransactionCallback<Void>() {
      @Override
      public Void doInTransaction(TransactionStatus status) {
        template.convertAndSend(ROUTE, "message");
        return null;
      }
    });
    String result = (String) template.receiveAndConvert(ROUTE);
    assertEquals("message", result);
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testSendInExternalTransactionWithRollback() throws Exception {
    template.setChannelTransacted(true);
    try {
      new TransactionTemplate(new TestTransactionManager()).execute(new TransactionCallback<Void>() {
        @Override
        public Void doInTransaction(TransactionStatus status) {
          template.convertAndSend(ROUTE, "message");
          throw new PlannedException();
        }
      });
      fail("Expected PlannedException");
    } catch (PlannedException e) {
      // Expected
    }
    String result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testAtomicSendAndReceive() throws Exception {
    final CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
    cachingConnectionFactory.setHost("localhost");
    final RabbitTemplate template = new RabbitTemplate(cachingConnectionFactory);
    template.setRoutingKey(ROUTE);
    template.setQueue(ROUTE);
    ExecutorService executor = Executors.newFixedThreadPool(1);
    // Set up a consumer to respond to our producer
    Future<Message> received = executor.submit(new Callable<Message>() {

      @Override
      public Message call() throws Exception {
        Message message = null;
        for (int i = 0; i < 10; i++) {
          message = template.receive();
          if (message != null) {
            break;
          }
          Thread.sleep(100L);
        }
        assertNotNull("No message received", message);
        template.send(message.getMessageProperties().getReplyTo(), message);
        return message;
      }

    });
    Message message = new Message("test-message".getBytes(), new MessageProperties());
    Message reply = template.sendAndReceive(message);
    assertEquals(new String(message.getBody()), new String(received.get(1000, TimeUnit.MILLISECONDS).getBody()));
    assertNotNull("Reply is expected", reply);
    assertEquals(new String(message.getBody()), new String(reply.getBody()));
    // Message was consumed so nothing left on queue
    reply = template.receive();
    assertEquals(null, reply);
    cachingConnectionFactory.destroy();
  }

  @Test
  public void testAtomicSendAndReceiveExternalExecutor() throws Exception {
    final CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
    connectionFactory.setHost("localhost");
    ThreadPoolTaskExecutor exec = new ThreadPoolTaskExecutor();
    final String execName = "make-sure-exec-passed-in";
    exec.setBeanName(execName);
    exec.afterPropertiesSet();
    connectionFactory.setExecutor(exec);
    final Field[] fields = new Field[1];
    ReflectionUtils.doWithFields(RabbitTemplate.class, new FieldCallback() {
      @Override
      public void doWith(Field field) throws IllegalArgumentException,
          IllegalAccessException {
        field.setAccessible(true);
        fields[0] = field;
      }
    }, new FieldFilter() {
      @Override
      public boolean matches(Field field) {
        return field.getName().equals("logger");
      }
    });
    Log logger = Mockito.mock(Log.class);
    when(logger.isTraceEnabled()).thenReturn(true);

    final AtomicBoolean execConfiguredOk = new AtomicBoolean();

    doAnswer(new Answer<Object>(){
      @Override
      public Object answer(InvocationOnMock invocation) throws Throwable {
        String log = (String) invocation.getArguments()[0];
        if (log.startsWith("Message received") &&
            Thread.currentThread().getName().startsWith(execName)) {
          execConfiguredOk.set(true);
        }
        return null;
      }
    }).when(logger).trace(Mockito.anyString());
    final RabbitTemplate template = new RabbitTemplate(connectionFactory);
    ReflectionUtils.setField(fields[0], template, logger);
    template.setRoutingKey(ROUTE);
    template.setQueue(ROUTE);
    ExecutorService executor = Executors.newFixedThreadPool(1);
    // Set up a consumer to respond to our producer
    Future<Message> received = executor.submit(new Callable<Message>() {

      @Override
      public Message call() throws Exception {
        Message message = null;
        for (int i = 0; i < 10; i++) {
          message = template.receive();
          if (message != null) {
            break;
          }
          Thread.sleep(100L);
        }
        assertNotNull("No message received", message);
        template.send(message.getMessageProperties().getReplyTo(), message);
        return message;
      }

    });
    Message message = new Message("test-message".getBytes(), new MessageProperties());
    Message reply = template.sendAndReceive(message);
    assertEquals(new String(message.getBody()), new String(received.get(1000, TimeUnit.MILLISECONDS).getBody()));
    assertNotNull("Reply is expected", reply);
    assertEquals(new String(message.getBody()), new String(reply.getBody()));
    // Message was consumed so nothing left on queue
    reply = template.receive();
    assertEquals(null, reply);

    assertTrue(execConfiguredOk.get());
    connectionFactory.destroy();
  }

  @Test
  public void testAtomicSendAndReceiveWithRoutingKey() throws Exception {
    final CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
    cachingConnectionFactory.setHost("localhost");
    final RabbitTemplate template = new RabbitTemplate(cachingConnectionFactory);
    ExecutorService executor = Executors.newFixedThreadPool(1);
    // Set up a consumer to respond to our producer
    Future<Message> received = executor.submit(new Callable<Message>() {

      @Override
      public Message call() throws Exception {
        Message message = null;
        for (int i = 0; i < 10; i++) {
          message = template.receive(ROUTE);
          if (message != null) {
            break;
          }
          Thread.sleep(100L);
        }
        assertNotNull("No message received", message);
        template.send(message.getMessageProperties().getReplyTo(), message);
        return message;
      }

    });
    Message message = new Message("test-message".getBytes(), new MessageProperties());
    Message reply = template.sendAndReceive(ROUTE, message);
    assertEquals(new String(message.getBody()), new String(received.get(1000, TimeUnit.MILLISECONDS).getBody()));
    assertNotNull("Reply is expected", reply);
    assertEquals(new String(message.getBody()), new String(reply.getBody()));
    // Message was consumed so nothing left on queue
    reply = template.receive(ROUTE);
    assertEquals(null, reply);
    cachingConnectionFactory.destroy();
  }

  @Test
  public void testAtomicSendAndReceiveWithExchangeAndRoutingKey() throws Exception {
    final CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
    cachingConnectionFactory.setHost("localhost");
    final RabbitTemplate template = new RabbitTemplate(cachingConnectionFactory);
    ExecutorService executor = Executors.newFixedThreadPool(1);
    // Set up a consumer to respond to our producer
    Future<Message> received = executor.submit(new Callable<Message>() {

      @Override
      public Message call() throws Exception {
        Message message = null;
        for (int i = 0; i < 10; i++) {
          message = template.receive(ROUTE);
          if (message != null) {
            break;
          }
          Thread.sleep(100L);
        }
        assertNotNull("No message received", message);
        template.send(message.getMessageProperties().getReplyTo(), message);
        return message;
      }

    });
    Message message = new Message("test-message".getBytes(), new MessageProperties());
    Message reply = template.sendAndReceive("", ROUTE, message);
    assertEquals(new String(message.getBody()), new String(received.get(1000, TimeUnit.MILLISECONDS).getBody()));
    assertNotNull("Reply is expected", reply);
    assertEquals(new String(message.getBody()), new String(reply.getBody()));
    // Message was consumed so nothing left on queue
    reply = template.receive(ROUTE);
    assertEquals(null, reply);
    cachingConnectionFactory.destroy();
  }

  @Test
  public void testAtomicSendAndReceiveWithConversion() throws Exception {
    final CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
    cachingConnectionFactory.setHost("localhost");
    final RabbitTemplate template = new RabbitTemplate(cachingConnectionFactory);
    template.setRoutingKey(ROUTE);
    template.setQueue(ROUTE);
    ExecutorService executor = Executors.newFixedThreadPool(1);
    // Set up a consumer to respond to our producer
    Future<String> received = executor.submit(new Callable<String>() {

      @Override
      public String call() throws Exception {
        Message message = null;
        for (int i = 0; i < 10; i++) {
          message = template.receive();
          if (message != null) {
            break;
          }
          Thread.sleep(100L);
        }
        assertNotNull("No message received", message);
        template.send(message.getMessageProperties().getReplyTo(), message);
        return (String) template.getMessageConverter().fromMessage(message);
      }

    });
    String result = (String) template.convertSendAndReceive("message");
    assertEquals("message", received.get(1000, TimeUnit.MILLISECONDS));
    assertEquals("message", result);
    // Message was consumed so nothing left on queue
    result = (String) template.receiveAndConvert();
    assertEquals(null, result);
    cachingConnectionFactory.destroy();
  }

  @Test
  public void testAtomicSendAndReceiveWithConversionUsingRoutingKey() throws Exception {
    ExecutorService executor = Executors.newFixedThreadPool(1);
    // Set up a consumer to respond to our producer
    Future<String> received = executor.submit(new Callable<String>() {

      @Override
      public String call() throws Exception {
        Message message = null;
        for (int i = 0; i < 10; i++) {
          message = template.receive(ROUTE);
          if (message != null) {
            break;
          }
          Thread.sleep(100L);
        }
        assertNotNull("No message received", message);
        template.send(message.getMessageProperties().getReplyTo(), message);
        return (String) template.getMessageConverter().fromMessage(message);
      }

    });
    String result = (String) template.convertSendAndReceive(ROUTE, "message");
    assertEquals("message", received.get(1000, TimeUnit.MILLISECONDS));
    assertEquals("message", result);
    // Message was consumed so nothing left on queue
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testAtomicSendAndReceiveWithConversionUsingExchangeAndRoutingKey() throws Exception {
    ExecutorService executor = Executors.newFixedThreadPool(1);
    // Set up a consumer to respond to our producer
    Future<String> received = executor.submit(new Callable<String>() {

      @Override
      public String call() throws Exception {
        Message message = null;
        for (int i = 0; i < 10; i++) {
          message = template.receive(ROUTE);
          if (message != null) {
            break;
          }
          Thread.sleep(100L);
        }
        assertNotNull("No message received", message);
        template.send(message.getMessageProperties().getReplyTo(), message);
        return (String) template.getMessageConverter().fromMessage(message);
      }

    });
    String result = (String) template.convertSendAndReceive("", ROUTE, "message");
    assertEquals("message", received.get(1000, TimeUnit.MILLISECONDS));
    assertEquals("message", result);
    // Message was consumed so nothing left on queue
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testAtomicSendAndReceiveWithConversionAndMessagePostProcessor() throws Exception {
    final CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
    cachingConnectionFactory.setHost("localhost");
    final RabbitTemplate template = new RabbitTemplate(cachingConnectionFactory);
    template.setRoutingKey(ROUTE);
    template.setQueue(ROUTE);
    ExecutorService executor = Executors.newFixedThreadPool(1);
    // Set up a consumer to respond to our producer
    Future<String> received = executor.submit(new Callable<String>() {

      @Override
      public String call() throws Exception {
        Message message = null;
        for (int i = 0; i < 10; i++) {
          message = template.receive();
          if (message != null) {
            break;
          }
          Thread.sleep(100L);
        }
        assertNotNull("No message received", message);
        template.send(message.getMessageProperties().getReplyTo(), message);
        return (String) template.getMessageConverter().fromMessage(message);
      }

    });
    String result = (String) template.convertSendAndReceive((Object) "message", new MessagePostProcessor() {
      @Override
      public Message postProcessMessage(Message message) throws AmqpException {
        try {
          byte[] newBody = new String(message.getBody(), "UTF-8").toUpperCase().getBytes("UTF-8");
          return new Message(newBody, message.getMessageProperties());
        }
        catch (Exception e) {
          throw new AmqpException("unexpected failure in test", e);
        }
      }
    });
    assertEquals("MESSAGE", received.get(1000, TimeUnit.MILLISECONDS));
    assertEquals("MESSAGE", result);
    // Message was consumed so nothing left on queue
    result = (String) template.receiveAndConvert();
    assertEquals(null, result);
    cachingConnectionFactory.destroy();
  }

  @Test
  public void testAtomicSendAndReceiveWithConversionAndMessagePostProcessorUsingRoutingKey() throws Exception {
    ExecutorService executor = Executors.newFixedThreadPool(1);
    // Set up a consumer to respond to our producer
    Future<String> received = executor.submit(new Callable<String>() {

      @Override
      public String call() throws Exception {
        Message message = null;
        for (int i = 0; i < 10; i++) {
          message = template.receive(ROUTE);
          if (message != null) {
            break;
          }
          Thread.sleep(100L);
        }
        assertNotNull("No message received", message);
        template.send(message.getMessageProperties().getReplyTo(), message);
        return (String) template.getMessageConverter().fromMessage(message);
      }

    });
    String result = (String) template.convertSendAndReceive(ROUTE, (Object) "message", new MessagePostProcessor() {
      @Override
      public Message postProcessMessage(Message message) throws AmqpException {
        try {
          byte[] newBody = new String(message.getBody(), "UTF-8").toUpperCase().getBytes("UTF-8");
          return new Message(newBody, message.getMessageProperties());
        }
        catch (Exception e) {
          throw new AmqpException("unexpected failure in test", e);
        }
      }
    });
    assertEquals("MESSAGE", received.get(1000, TimeUnit.MILLISECONDS));
    assertEquals("MESSAGE", result);
    // Message was consumed so nothing left on queue
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testAtomicSendAndReceiveWithConversionAndMessagePostProcessorUsingExchangeAndRoutingKey() throws Exception {
    ExecutorService executor = Executors.newFixedThreadPool(1);
    // Set up a consumer to respond to our producer
    Future<String> received = executor.submit(new Callable<String>() {

      @Override
      public String call() throws Exception {
        Message message = null;
        for (int i = 0; i < 10; i++) {
          message = template.receive(ROUTE);
          if (message != null) {
            break;
          }
          Thread.sleep(100L);
        }
        assertNotNull("No message received", message);
        template.send(message.getMessageProperties().getReplyTo(), message);
        return (String) template.getMessageConverter().fromMessage(message);
      }

    });
    String result = (String) template.convertSendAndReceive("", ROUTE, "message", new MessagePostProcessor() {

      @Override
      public Message postProcessMessage(Message message) throws AmqpException {
        try {
          byte[] newBody = new String(message.getBody(), "UTF-8").toUpperCase().getBytes("UTF-8");
          return new Message(newBody, message.getMessageProperties());
        }
        catch (Exception e) {
          throw new AmqpException("unexpected failure in test", e);
        }
      }
    });
    assertEquals("MESSAGE", received.get(1000, TimeUnit.MILLISECONDS));
    assertEquals("MESSAGE", result);
    // Message was consumed so nothing left on queue
    result = (String) template.receiveAndConvert(ROUTE);
    assertEquals(null, result);
  }

  @Test
  public void testReceiveAndReplyNonStandardCorrelationNotBytes() {
    this.template.setQueue(ROUTE);
    this.template.setRoutingKey(ROUTE);
    MessageProperties messageProperties = new MessageProperties();
    messageProperties.getHeaders().put("baz", "bar");
    Message message = new Message("foo".getBytes(), messageProperties);
    this.template.send(ROUTE, message);

    this.template.setCorrelationKey("baz");
    boolean received = this.template.receiveAndReply(new ReceiveAndReplyMessageCallback() {

      @Override
      public Message handle(Message message) {
        return new Message("fuz".getBytes(), new MessageProperties());
      }
    });
    assertTrue(received);
    message = this.template.receive();
    assertNotNull(message);
    assertEquals("bar", message.getMessageProperties().getHeaders().get("baz"));
  }

  @Test
  public void testReceiveAndReply() {
    this.template.setQueue(ROUTE);
    this.template.setRoutingKey(ROUTE);
    this.template.convertAndSend(ROUTE, "test");

    boolean received = this.template.receiveAndReply(new ReceiveAndReplyMessageCallback() {

      @Override
      public Message handle(Message message) {
        message.getMessageProperties().setHeader("foo", "bar");
        return message;
      }
    });
    assertTrue(received);

    Message receive = this.template.receive();
    assertEquals("bar", receive.getMessageProperties().getHeaders().get("foo"));

    this.template.convertAndSend(ROUTE, 1);

    received = this.template.receiveAndReply(ROUTE, new ReceiveAndReplyCallback<Integer, Integer>() {

      @Override
      public Integer handle(Integer payload) {
        return payload + 1;
      }
    });
    assertTrue(received);

    Object result = this.template.receiveAndConvert(ROUTE);
    assertTrue(result instanceof Integer);
    assertEquals(2, result);

    this.template.convertAndSend(ROUTE, 2);

    received = this.template.receiveAndReply(ROUTE, new ReceiveAndReplyCallback<Integer, Integer>() {

      @Override
      public Integer handle(Integer payload) {
        return payload * 2;
      }
    }, "", ROUTE);
    assertTrue(received);

    result = this.template.receiveAndConvert(ROUTE);
    assertTrue(result instanceof Integer);
    assertEquals(4, result);

    received = this.template.receiveAndReply(new ReceiveAndReplyMessageCallback() {

      @Override
      public Message handle(Message message) {
        return message;
      }
    });
    assertFalse(received);

    this.template.convertAndSend(ROUTE, "test");
    received = this.template.receiveAndReply(new ReceiveAndReplyMessageCallback() {

      @Override
      public Message handle(Message message) {
        return null;
      }
    });
    assertTrue(received);

    result = this.template.receive();
    assertNull(result);

    this.template.convertAndSend(ROUTE, "TEST");
    received = this.template.receiveAndReply(new ReceiveAndReplyMessageCallback() {

      @Override
      public Message handle(Message message) {
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setContentType(message.getMessageProperties().getContentType());
        messageProperties.setHeader("testReplyTo", new Address("", ROUTE));
        return new Message(message.getBody(), messageProperties);
      }

    }, new ReplyToAddressCallback<Message>() {

      @Override
      public Address getReplyToAddress(Message request, Message reply) {
        return (Address) reply.getMessageProperties().getHeaders().get("testReplyTo");
      }

    });
    assertTrue(received);
    result = this.template.receiveAndConvert(ROUTE);
    assertEquals("TEST", result);

    assertEquals(null, template.receive(ROUTE));

    template.setChannelTransacted(true);

    this.template.convertAndSend(ROUTE, "TEST");
    result = new TransactionTemplate(new TestTransactionManager())
        .execute(new TransactionCallback<String>() {
          @Override
          public String doInTransaction(TransactionStatus status) {
            final AtomicReference<String> payloadReference = new AtomicReference<String>();
            boolean received = template.receiveAndReply(new ReceiveAndReplyCallback<String, Void>() {

              @Override
              public Void handle(String payload) {
                payloadReference.set(payload);
                return null;
              }
            });
            assertTrue(received);
            return payloadReference.get();
          }
        });
    assertEquals("TEST", result);
    assertEquals(null, template.receive(ROUTE));

    this.template.convertAndSend(ROUTE, "TEST");
    try {
      new TransactionTemplate(new TestTransactionManager())
          .execute(new TransactionCallbackWithoutResult() {

            @Override
            public void doInTransactionWithoutResult(TransactionStatus status) {
              template.receiveAndReply(new ReceiveAndReplyMessageCallback() {

                             @Override
                             public Message handle(Message message) {
                               return message;
                             }
                           }, new ReplyToAddressCallback<Message>() {

                             @Override
                             public Address getReplyToAddress(Message request, Message reply) {
                               throw new PlannedException();
                             }
                           });
            }
          });
      fail("Expected PlannedException");
    }
    catch (Exception e) {
      assertTrue(e.getCause() instanceof PlannedException);
    }

    assertEquals("TEST", template.receiveAndConvert(ROUTE));
    assertEquals(null, template.receive(ROUTE));

    template.convertAndSend("test");

    try {
      this.template.receiveAndReply(new ReceiveAndReplyCallback<Double, Void>() {

        @Override
        public Void handle(Double message) {
          return null;
        }
      });
      fail("IllegalArgumentException expected");
    }
    catch (Exception e) {
      assertTrue(e.getCause() instanceof IllegalArgumentException);
      assertTrue(e.getCause().getCause() instanceof ClassCastException);
    }

  }

  @Test
  public void testSymmetricalReceiveAndReply() throws InterruptedException, UnsupportedEncodingException {
    this.template.setQueue(ROUTE);
    this.template.setRoutingKey(ROUTE);
    this.template.setReplyQueue(REPLY_QUEUE);
    this.template.setReplyTimeout(10000);

    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(this.template.getConnectionFactory());
    container.setQueues(REPLY_QUEUE);
    container.setMessageListener(this.template);
    container.start();

    int count = 10;

    final Map<Double, Object> results = new HashMap<Double, Object>();

    ExecutorService executor = Executors.newFixedThreadPool(10);

    this.template.setCorrelationKey("CorrelationKey");

    for (int i = 0; i < count; i++) {
      executor.execute(new Runnable() {

        @Override
        public void run() {
          Double request = Math.random() * 100;
          Object reply = template.convertSendAndReceive(request);
          results.put(request, reply);
        }
      });
    }

    for (int i = 0; i < count; i++) {
      executor.execute(new Runnable() {

        @Override
        public void run() {
          Double request = Math.random() * 100;
          MessageProperties messageProperties = new MessageProperties();
          messageProperties.setContentType(MessageProperties.CONTENT_TYPE_SERIALIZED_OBJECT);
          Message reply = template.sendAndReceive(new Message(SerializationUtils.serialize(request), messageProperties));
          results.put(request, SerializationUtils.deserialize(reply.getBody()));
        }
      });
    }

    final AtomicInteger receiveCount = new AtomicInteger();

    long start = System.currentTimeMillis();
    do {
      template.receiveAndReply(new ReceiveAndReplyCallback<Double, Double>() {

        @Override
        public Double handle(Double payload) {
          receiveCount.incrementAndGet();
          return payload * 3;
        }
      });
      if (System.currentTimeMillis() > start + 10000) {
        fail("Something wrong with RabbitMQ");
      }
    } while (receiveCount.get() < count * 2);


    executor.shutdown();
    assertTrue(executor.awaitTermination(10, TimeUnit.SECONDS));
    container.stop();

    assertEquals(count * 2, results.size());

    for (Map.Entry<Double, Object> entry : results.entrySet()) {
      assertEquals(entry.getKey() * 3, entry.getValue());
    }

    String messageId = UUID.randomUUID().toString();

    MessageProperties messageProperties = new MessageProperties();
    messageProperties.setMessageId(messageId);
    messageProperties.setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN);
    messageProperties.setReplyTo(REPLY_QUEUE.getName());

    template.send(new Message("test".getBytes(), messageProperties));

    template.receiveAndReply(new ReceiveAndReplyCallback<String, String>() {

      @Override
      public String handle(String payload) {
        return payload.toUpperCase();
      }
    });

    Message result = this.template.receive(REPLY_QUEUE.getName());
    assertEquals("TEST", new String(result.getBody()));
    assertEquals(messageId, new String(result.getMessageProperties().getCorrelationId()));
  }

  @SuppressWarnings("serial")
  private class PlannedException extends RuntimeException {
    public PlannedException() {
      super("Planned");
    }
  }

  @SuppressWarnings("serial")
  private class TestTransactionManager extends AbstractPlatformTransactionManager {

    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {
    }

    @Override
    protected void doCommit(DefaultTransactionStatus status) throws TransactionException {
    }

    @Override
    protected Object doGetTransaction() throws TransactionException {
      return new Object();
    }

    @Override
    protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
    }

  }

}
TOP

Related Classes of org.springframework.amqp.rabbit.core.RabbitTemplateIntegrationTests$PlannedException

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.