@Test public void testWithMessageHistory() throws Exception { GemfireMessageStore store = new GemfireMessageStore(this.cache); store.afterPropertiesSet(); store.getMessageGroup(1); Message<?> message = new GenericMessage<String>("Hello"); DirectChannel fooChannel = new DirectChannel(); fooChannel.setBeanName("fooChannel"); DirectChannel barChannel = new DirectChannel(); barChannel.setBeanName("barChannel"); message = MessageHistory.write(message, fooChannel); message = MessageHistory.write(message, barChannel); store.addMessageToGroup(1, message); message = store.getMessageGroup(1).getMessages().iterator().next(); MessageHistory messageHistory = MessageHistory.read(message); assertNotNull(messageHistory); assertEquals(2, messageHistory.size()); Properties fooChannelHistory = messageHistory.get(0); assertEquals("fooChannel", fooChannelHistory.get("name")); assertEquals("channel", fooChannelHistory.get("type")); }
@Test public void testCompression() throws Exception { final String[] codecs = new String[] {null, "none", "gzip", "snappy"}; byte[] ratherBigPayload = new byte[2048]; Arrays.fill(ratherBigPayload, (byte) 65); Binder binder = getBinder(); for (String codec : codecs) { DirectChannel moduleOutputChannel = new DirectChannel(); QueueChannel moduleInputChannel = new QueueChannel(); Properties props = new Properties(); if (codec != null) { props.put(KafkaMessageChannelBinder.COMPRESSION_CODEC, codec); } binder.bindProducer("foo.0", moduleOutputChannel, props); binder.bindConsumer("foo.0", moduleInputChannel, null); Message<?> message = org.springframework.integration.support.MessageBuilder.withPayload(ratherBigPayload) .build(); // Let the consumer actually bind to the producer before sending a msg binderBindUnbindLatency(); moduleOutputChannel.send(message); Message<?> inbound = moduleInputChannel.receive(2000); assertNotNull(inbound); assertArrayEquals(ratherBigPayload, (byte[]) inbound.getPayload()); binder.unbindProducers("foo.0"); binder.unbindConsumers("foo.0"); } }
@Test public void testCustomPartitionCountOverridesPartitioningIfLarger() throws Exception { byte[] ratherBigPayload = new byte[2048]; Arrays.fill(ratherBigPayload, (byte) 65); KafkaTestBinder binder = (KafkaTestBinder) getBinder(); DirectChannel moduleOutputChannel = new DirectChannel(); QueueChannel moduleInputChannel = new QueueChannel(); Properties producerProperties = new Properties(); producerProperties.put(BinderProperties.MIN_PARTITION_COUNT, "5"); producerProperties.put(BinderProperties.NEXT_MODULE_COUNT, "3"); producerProperties.put(BinderProperties.PARTITION_KEY_EXPRESSION, "payload"); Properties consumerProperties = new Properties(); consumerProperties.put(BinderProperties.MIN_PARTITION_COUNT, "5"); long uniqueBindingId = System.currentTimeMillis(); binder.bindProducer("foo" + uniqueBindingId + ".0", moduleOutputChannel, producerProperties); binder.bindConsumer("foo" + uniqueBindingId + ".0", moduleInputChannel, consumerProperties); Message<?> message = org.springframework.integration.support.MessageBuilder.withPayload(ratherBigPayload) .build(); // Let the consumer actually bind to the producer before sending a msg binderBindUnbindLatency(); moduleOutputChannel.send(message); Message<?> inbound = moduleInputChannel.receive(2000); assertNotNull(inbound); assertArrayEquals(ratherBigPayload, (byte[]) inbound.getPayload()); Collection<Partition> partitions = binder.getCoreBinder().getConnectionFactory().getPartitions("foo" + uniqueBindingId + ".0"); assertThat(partitions, hasSize(5)); binder.unbindProducers("foo" + uniqueBindingId + ".0"); binder.unbindConsumers("foo" + uniqueBindingId + ".0"); }
@Test public void testXPathRouterNoChannelResolver() { // Build the route DirectChannel inputChannel = new DirectChannel(); inputChannel.setBeanName("input"); XPathRouter router = new XPathRouter("//subject/text()"); router.setEvaluateAsString(true); inputChannel.subscribe(router); // Create message Object correlationId = "123-ABC"; String xmlSource = "<xml><subject>test</subject></xml>"; Message<String> message = MessageBuilder.withPayload(xmlSource).setCorrelationId(correlationId).build(); // Send and receive message synchronously MessagingTemplate template = new MessagingTemplate(inputChannel); try { Message<?> reply = template.sendAndReceive(message); assertFalse("should fail", true); } catch (MessageHandlingException ex) { assertTrue(ex.getMessage().contains("error occurred in message handler")); assertTrue( ex.getCause() .getMessage() .contains("unable to resolve channel names, no ChannelResolver available")); } }
@Test public void testNonDurablePubSubWithAutoBindDLQ() throws Exception { RabbitAdmin admin = new RabbitAdmin(this.rabbitAvailableRule.getResource()); MessageBus bus = getMessageBus(); Properties properties = new Properties(); properties.put("prefix", "xdbustest."); properties.put("autoBindDLQ", "true"); properties.put("durableSubscription", "false"); properties.put("maxAttempts", "1"); // disable retry properties.put("requeue", "false"); DirectChannel moduleInputChannel = new DirectChannel(); moduleInputChannel.setBeanName("nondurabletest"); moduleInputChannel.subscribe( new MessageHandler() { @Override public void handleMessage(Message<?> message) throws MessagingException { throw new RuntimeException("foo"); } }); bus.bindPubSubConsumer( "teststream.tap:stream:nondurabletest.0", moduleInputChannel, properties); bus.unbindConsumer("teststream.tap:stream:nondurabletest.0", moduleInputChannel); assertNull(admin.getQueueProperties("xdbustest.teststream.tap:stream:nondurabletest.0.dlq")); admin.deleteQueue("xdbustest.teststream.tap:stream:nondurabletest.0"); admin.deleteExchange("xdbustest.topic.tap:stream:nondurabletest.0"); }
@Test public void testXPathRouter() { // route to a channel determined by outcome of the xpath expression // Build the route DirectChannel inputChannel = new DirectChannel(); inputChannel.setBeanName("input"); XPathRouter router = new XPathRouter("//subject/text()"); router.setEvaluateAsString(true); inputChannel.subscribe(router); QueueChannel testChannel = new QueueChannel(); GenericApplicationContext context = new GenericApplicationContext(); context.getBeanFactory().registerSingleton("testChannel", testChannel); router.setBeanFactory(context); context.refresh(); // Create message Object correlationId = "123-ABC"; String xmlSource = "<xml><subject>testChannel</subject></xml>"; Message<String> message = MessageBuilder.withPayload(xmlSource).setCorrelationId(correlationId).build(); // Send and receive message inputChannel.send(message); Message<?> reply = testChannel.receive(0); assertEquals(xmlSource, reply.getPayload()); }
@Test public void correlationIdCopiedFromMessageId() { Message<String> message = MessageBuilder.withPayload("test").build(); DirectChannel inputChannel = new DirectChannel(); QueueChannel outputChannel = new QueueChannel(1); DefaultMessageSplitter splitter = new DefaultMessageSplitter(); splitter.setOutputChannel(outputChannel); EventDrivenConsumer endpoint = new EventDrivenConsumer(inputChannel, splitter); endpoint.start(); assertTrue(inputChannel.send(message)); Message<?> reply = outputChannel.receive(0); assertEquals(message.getHeaders().getId(), reply.getHeaders().getCorrelationId()); }
@Test public void testAutoBindDLQwithRepublish() throws Exception { // pre-declare the queue with dead-lettering, users can also use a policy RabbitAdmin admin = new RabbitAdmin(this.rabbitAvailableRule.getResource()); Map<String, Object> args = new HashMap<String, Object>(); args.put("x-dead-letter-exchange", "xdbustest.DLX"); Queue queue = new Queue("xdbustest.dlqpubtest", true, false, false, args); admin.declareQueue(queue); MessageBus bus = getMessageBus(); Properties properties = new Properties(); properties.put("prefix", "xdbustest."); properties.put("autoBindDLQ", "true"); properties.put("republishToDLQ", "true"); properties.put("maxAttempts", "1"); // disable retry properties.put("requeue", "false"); DirectChannel moduleInputChannel = new DirectChannel(); moduleInputChannel.setBeanName("dlqPubTest"); moduleInputChannel.subscribe( new MessageHandler() { @Override public void handleMessage(Message<?> message) throws MessagingException { throw new RuntimeException("foo"); } }); bus.bindConsumer("dlqpubtest", moduleInputChannel, properties); RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource()); template.convertAndSend("", "xdbustest.dlqpubtest", "foo"); int n = 0; while (n++ < 100) { org.springframework.amqp.core.Message deadLetter = template.receive("xdbustest.dlqpubtest.dlq"); if (deadLetter != null) { assertEquals("foo", new String(deadLetter.getBody())); assertNotNull(deadLetter.getMessageProperties().getHeaders().get("x-exception-stacktrace")); break; } Thread.sleep(100); } assertTrue(n < 100); bus.unbindConsumer("dlqpubtest", moduleInputChannel); admin.deleteQueue("xdbustest.dlqpubtest.dlq"); admin.deleteQueue("xdbustest.dlqpubtest"); admin.deleteExchange("xdbustest.DLX"); }
@Test public void testSendingTwoWayMessage() throws Exception { MessageChannel requestChannel = (MessageChannel) applicationContext.getBean("channelB"); Message message = new GenericMessage(MESSAGE_BODY); // Need to subscribe the responseChannel first DirectChannel responseChannel = (DirectChannel) applicationContext.getBean("channelC"); responseChannel.subscribe( new MessageHandler() { public void handleMessage(Message<?> message) { String result = (String) message.getPayload(); assertEquals("Get the wrong result", MESSAGE_BODY + " is processed", result); } }); requestChannel.send(message); }
@Test public void testSendingTwoWayMessageWithMessageAddress() throws Exception { MessageChannel requestChannel = (MessageChannel) applicationContext.getBean("channelD"); DirectChannel responseChannel = (DirectChannel) applicationContext.getBean("channelC"); Map<String, Object> headers = new HashMap<String, Object>(); headers.put(MessageHeaders.REPLY_CHANNEL, responseChannel); GenericMessage<String> message = new GenericMessage<String>(MESSAGE_BODY, headers); responseChannel.subscribe( new MessageHandler() { public void handleMessage(Message<?> message) { String result = (String) message.getPayload(); assertEquals("Get the wrong result", MESSAGE_BODY + " is processed", result); } }); requestChannel.send(message); }
@Test public void testDurablePubSubWithAutoBindDLQ() throws Exception { RabbitAdmin admin = new RabbitAdmin(this.rabbitAvailableRule.getResource()); MessageBus bus = getMessageBus(); Properties properties = new Properties(); properties.put("prefix", "xdbustest."); properties.put("autoBindDLQ", "true"); properties.put("durableSubscription", "true"); properties.put("maxAttempts", "1"); // disable retry properties.put("requeue", "false"); DirectChannel moduleInputChannel = new DirectChannel(); moduleInputChannel.setBeanName("durableTest"); moduleInputChannel.subscribe( new MessageHandler() { @Override public void handleMessage(Message<?> message) throws MessagingException { throw new RuntimeException("foo"); } }); bus.bindPubSubConsumer("teststream.tap:stream:durabletest.0", moduleInputChannel, properties); RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource()); template.convertAndSend("xdbustest.topic.tap:stream:durabletest.0", "", "foo"); int n = 0; while (n++ < 100) { Object deadLetter = template.receiveAndConvert("xdbustest.teststream.tap:stream:durabletest.0.dlq"); if (deadLetter != null) { assertEquals("foo", deadLetter); break; } Thread.sleep(100); } assertTrue(n < 100); bus.unbindConsumer("teststream.tap:stream:durabletest.0", moduleInputChannel); assertNotNull(admin.getQueueProperties("xdbustest.teststream.tap:stream:durabletest.0.dlq")); admin.deleteQueue("xdbustest.teststream.tap:stream:durabletest.0.dlq"); admin.deleteQueue("xdbustest.teststream.tap:stream:durabletest.0"); admin.deleteExchange("xdbustest.topic.tap:stream:durabletest.0"); admin.deleteExchange("xdbustest.DLX"); }
public List<String> getMyTweets() { @SuppressWarnings("resource") ApplicationContext context = new ClassPathXmlApplicationContext("TwitterSearch-context.xml"); final List<String> myTweets = new ArrayList<String>(); DirectChannel twitterInputChannel = context.getBean("twitterOut", DirectChannel.class); twitterInputChannel.subscribe( new MessageHandler() { @Override public void handleMessage(Message<?> message) throws MessagingException { myTweets.add(message.getPayload().toString()); } }); // Waiting for tweets in publish-subscribe mode try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return myTweets; }
@Test public void testSendAndReceiveBad() throws Exception { MessageBus messageBus = getMessageBus(); DirectChannel moduleOutputChannel = new DirectChannel(); DirectChannel moduleInputChannel = new DirectChannel(); messageBus.bindProducer("bad.0", moduleOutputChannel, null); messageBus.bindConsumer("bad.0", moduleInputChannel, null); Message<?> message = MessageBuilder.withPayload("bad").setHeader(MessageHeaders.CONTENT_TYPE, "foo/bar").build(); final CountDownLatch latch = new CountDownLatch(3); moduleInputChannel.subscribe( new MessageHandler() { @Override public void handleMessage(Message<?> message) throws MessagingException { latch.countDown(); throw new RuntimeException("bad"); } }); moduleOutputChannel.send(message); assertTrue(latch.await(10, TimeUnit.SECONDS)); messageBus.unbindConsumers("bad.0"); messageBus.unbindProducers("bad.0"); }
@SuppressWarnings("unchecked") @Test public void testBatchingAndCompression() throws Exception { RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource()); MessageBus bus = getMessageBus(); Properties properties = new Properties(); properties.put("deliveryMode", "NON_PERSISTENT"); properties.put("batchingEnabled", "true"); properties.put("batchSize", "2"); properties.put("batchBufferLimit", "100000"); properties.put("batchTimeout", "30000"); properties.put("compress", "true"); DirectChannel output = new DirectChannel(); output.setBeanName("batchingProducer"); bus.bindProducer("batching.0", output, properties); while (template.receive("xdbus.batching.0") != null) {} Log logger = spy( TestUtils.getPropertyValue( bus, "messageBus.compressingPostProcessor.logger", Log.class)); new DirectFieldAccessor(TestUtils.getPropertyValue(bus, "messageBus.compressingPostProcessor")) .setPropertyValue("logger", logger); when(logger.isTraceEnabled()).thenReturn(true); assertEquals( Deflater.BEST_SPEED, TestUtils.getPropertyValue(bus, "messageBus.compressingPostProcessor.level")); output.send(new GenericMessage<>("foo".getBytes())); output.send(new GenericMessage<>("bar".getBytes())); Object out = spyOn("batching.0").receive(false); assertThat(out, instanceOf(byte[].class)); assertEquals( "\u0000\u0000\u0000\u0003foo\u0000\u0000\u0000\u0003bar", new String((byte[]) out)); ArgumentCaptor<Object> captor = ArgumentCaptor.forClass(Object.class); verify(logger).trace(captor.capture()); assertThat(captor.getValue().toString(), containsString("Compressed 14 to ")); QueueChannel input = new QueueChannel(); input.setBeanName("batchingConsumer"); bus.bindConsumer("batching.0", input, null); output.send(new GenericMessage<>("foo".getBytes())); output.send(new GenericMessage<>("bar".getBytes())); Message<byte[]> in = (Message<byte[]>) input.receive(10000); assertNotNull(in); assertEquals("foo", new String(in.getPayload())); in = (Message<byte[]>) input.receive(10000); assertNotNull(in); assertEquals("bar", new String(in.getPayload())); assertNull(in.getHeaders().get(AmqpHeaders.DELIVERY_MODE)); bus.unbindProducers("batching.0"); bus.unbindConsumers("batching.0"); }
@Test public void testAutoBindDLQPartioned() throws Exception { RabbitAdmin admin = new RabbitAdmin(this.rabbitAvailableRule.getResource()); MessageBus bus = getMessageBus(); Properties properties = new Properties(); properties.put("prefix", "xdbustest."); properties.put("autoBindDLQ", "true"); properties.put("maxAttempts", "1"); // disable retry properties.put("requeue", "false"); properties.put("partitionIndex", "0"); DirectChannel input0 = new DirectChannel(); input0.setBeanName("test.input0DLQ"); bus.bindConsumer("partDLQ.0", input0, properties); properties.put("partitionIndex", "1"); DirectChannel input1 = new DirectChannel(); input1.setBeanName("test.input1DLQ"); bus.bindConsumer("partDLQ.0", input1, properties); properties.clear(); properties.put("prefix", "xdbustest."); properties.put( "partitionKeyExtractorClass", "org.springframework.xd.dirt.integration.bus.PartitionTestSupport"); properties.put( "partitionSelectorClass", "org.springframework.xd.dirt.integration.bus.PartitionTestSupport"); properties.put(BusProperties.NEXT_MODULE_COUNT, "2"); DirectChannel output = new DirectChannel(); output.setBeanName("test.output"); bus.bindProducer("partDLQ.0", output, properties); final CountDownLatch latch0 = new CountDownLatch(1); input0.subscribe( new MessageHandler() { @Override public void handleMessage(Message<?> message) throws MessagingException { if (latch0.getCount() <= 0) { throw new RuntimeException("dlq"); } latch0.countDown(); } }); final CountDownLatch latch1 = new CountDownLatch(1); input1.subscribe( new MessageHandler() { @Override public void handleMessage(Message<?> message) throws MessagingException { if (latch1.getCount() <= 0) { throw new RuntimeException("dlq"); } latch1.countDown(); } }); output.send(new GenericMessage<Integer>(1)); assertTrue(latch1.await(10, TimeUnit.SECONDS)); output.send(new GenericMessage<Integer>(0)); assertTrue(latch0.await(10, TimeUnit.SECONDS)); output.send(new GenericMessage<Integer>(1)); RabbitTemplate template = new RabbitTemplate(this.rabbitAvailableRule.getResource()); template.setReceiveTimeout(10000); String streamDLQName = "xdbustest.partDLQ.0.dlq"; org.springframework.amqp.core.Message received = template.receive(streamDLQName); assertNotNull(received); assertEquals(1, received.getMessageProperties().getHeaders().get("partition")); output.send(new GenericMessage<Integer>(0)); received = template.receive(streamDLQName); assertNotNull(received); assertEquals(0, received.getMessageProperties().getHeaders().get("partition")); admin.deleteQueue(streamDLQName); admin.deleteQueue("xdbustest.partDLQ.0-0"); admin.deleteQueue("xdbustest.partDLQ.0-1"); admin.deleteExchange("xdbustest.DLX"); }
private void doRegisterConsumer( String name, MessageChannel moduleInputChannel, Queue queue, RabbitPropertiesAccessor properties, boolean isPubSub) { // Fix for XD-2503 // Temporarily overrides the thread context classloader with the one where the // SimpleMessageListenerContainer // is defined // This allows for the proxying that happens while initializing the // SimpleMessageListenerContainer to work // correctly ClassLoader originalClassloader = Thread.currentThread().getContextClassLoader(); try { ClassUtils.overrideThreadContextClassLoader( SimpleMessageListenerContainer.class.getClassLoader()); SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer(this.connectionFactory); listenerContainer.setAcknowledgeMode( properties.getAcknowledgeMode(this.defaultAcknowledgeMode)); listenerContainer.setChannelTransacted( properties.getTransacted(this.defaultChannelTransacted)); listenerContainer.setDefaultRequeueRejected( properties.getRequeueRejected(this.defaultDefaultRequeueRejected)); if (!isPubSub) { int concurrency = properties.getConcurrency(this.defaultConcurrency); concurrency = concurrency > 0 ? concurrency : 1; listenerContainer.setConcurrentConsumers(concurrency); int maxConcurrency = properties.getMaxConcurrency(this.defaultMaxConcurrency); if (maxConcurrency > concurrency) { listenerContainer.setMaxConcurrentConsumers(maxConcurrency); } } listenerContainer.setPrefetchCount(properties.getPrefetchCount(this.defaultPrefetchCount)); listenerContainer.setTxSize(properties.getTxSize(this.defaultTxSize)); listenerContainer.setTaskExecutor(new SimpleAsyncTaskExecutor(queue.getName() + "-")); listenerContainer.setQueues(queue); int maxAttempts = properties.getMaxAttempts(this.defaultMaxAttempts); if (maxAttempts > 1 || properties.getRepublishToDLQ(this.defaultRepublishToDLQ)) { RetryOperationsInterceptor retryInterceptor = RetryInterceptorBuilder.stateless() .maxAttempts(maxAttempts) .backOffOptions( properties.getBackOffInitialInterval(this.defaultBackOffInitialInterval), properties.getBackOffMultiplier(this.defaultBackOffMultiplier), properties.getBackOffMaxInterval(this.defaultBackOffMaxInterval)) .recoverer(determineRecoverer(name, properties)) .build(); listenerContainer.setAdviceChain(new Advice[] {retryInterceptor}); } listenerContainer.setAfterReceivePostProcessors(this.decompressingPostProcessor); listenerContainer.setMessagePropertiesConverter( RabbitMessageChannelBinder.inboundMessagePropertiesConverter); listenerContainer.afterPropertiesSet(); AmqpInboundChannelAdapter adapter = new AmqpInboundChannelAdapter(listenerContainer); adapter.setBeanFactory(this.getBeanFactory()); DirectChannel bridgeToModuleChannel = new DirectChannel(); bridgeToModuleChannel.setBeanFactory(this.getBeanFactory()); bridgeToModuleChannel.setBeanName(name + ".bridge"); adapter.setOutputChannel(bridgeToModuleChannel); adapter.setBeanName("inbound." + name); DefaultAmqpHeaderMapper mapper = new DefaultAmqpHeaderMapper(); mapper.setRequestHeaderNames( properties.getRequestHeaderPattens(this.defaultRequestHeaderPatterns)); mapper.setReplyHeaderNames(properties.getReplyHeaderPattens(this.defaultReplyHeaderPatterns)); adapter.setHeaderMapper(mapper); adapter.afterPropertiesSet(); Binding consumerBinding = Binding.forConsumer(name, adapter, moduleInputChannel, properties); addBinding(consumerBinding); ReceivingHandler convertingBridge = new ReceivingHandler(); convertingBridge.setOutputChannel(moduleInputChannel); convertingBridge.setBeanName(name + ".convert.bridge"); convertingBridge.afterPropertiesSet(); bridgeToModuleChannel.subscribe(convertingBridge); consumerBinding.start(); } finally { Thread.currentThread().setContextClassLoader(originalClassloader); } }