public AmqpInboundChannelAdapter(AbstractMessageListenerContainer listenerContainer) { Assert.notNull(listenerContainer, "listenerContainer must not be null"); Assert.isNull(listenerContainer.getMessageListener(), "The listenerContainer provided to an AMQP inbound Channel Adapter " + "must not have a MessageListener configured since the adapter " + "configure its own listener implementation."); this.messageListenerContainer = listenerContainer; this.messageListenerContainer.setAutoStartup(false); setErrorMessageStrategy(new AmqpMessageHeaderErrorMessageStrategy()); }
@Override public void onInit() { super.onInit(); this.dispatcher = this.createDispatcher(); if (this.maxSubscribers == null) { this.maxSubscribers = this.getIntegrationProperty(this.isPubSub ? IntegrationProperties.CHANNELS_MAX_BROADCAST_SUBSCRIBERS : IntegrationProperties.CHANNELS_MAX_UNICAST_SUBSCRIBERS, Integer.class); } setMaxSubscribers(this.maxSubscribers); String queue = obtainQueueName(this.channelName); this.container.setQueueNames(queue); MessageConverter converter = (this.getAmqpTemplate() instanceof RabbitTemplate) ? ((RabbitTemplate) this.getAmqpTemplate()).getMessageConverter() : new SimpleMessageConverter(); MessageListener listener = new DispatchingMessageListener(converter, this.dispatcher, this, this.isPubSub, getMessageBuilderFactory(), getInboundHeaderMapper()); this.container.setMessageListener(listener); if (!this.container.isActive()) { this.container.afterPropertiesSet(); } }
private org.springframework.messaging.Message<Object> createMessage(Message message, Channel channel) { Object payload = AmqpInboundChannelAdapter.this.messageConverter.fromMessage(message); Map<String, Object> headers = AmqpInboundChannelAdapter.this.headerMapper .toHeadersFromRequest(message.getMessageProperties()); if (AmqpInboundChannelAdapter.this.messageListenerContainer.getAcknowledgeMode() == AcknowledgeMode.MANUAL) { headers.put(AmqpHeaders.DELIVERY_TAG, message.getMessageProperties().getDeliveryTag()); headers.put(AmqpHeaders.CHANNEL, channel); } if (AmqpInboundChannelAdapter.this.retryTemplate != null) { headers.put(IntegrationMessageHeaderAccessor.DELIVERY_ATTEMPT, new AtomicInteger()); } final org.springframework.messaging.Message<Object> messagingMessage = getMessageBuilderFactory() .withPayload(payload) .copyHeaders(headers) .build(); return messagingMessage; }
@Override protected void onInit() { if (this.retryTemplate != null) { Assert.state(getErrorChannel() == null, "Cannot have an 'errorChannel' property when a 'RetryTemplate' is " + "provided; use an 'ErrorMessageSendingRecoverer' in the 'recoveryCallback' property to " + "send an error message when retries are exhausted"); } Listener messageListener = new Listener(); this.messageListenerContainer.setMessageListener(messageListener); this.messageListenerContainer.afterPropertiesSet(); super.onInit(); }
container.setAcknowledgeMode(this.acknowledgeMode); container.setAdviceChain(this.adviceChain); container.setAutoStartup(this.autoStartup); container.setChannelTransacted(this.channelTransacted); container.setConnectionFactory(this.connectionFactory); if (this.errorHandler != null) { container.setErrorHandler(this.errorHandler); container.setExposeListenerChannel(this.exposeListenerChannel); container.setMessagePropertiesConverter(this.messagePropertiesConverter); container.setPhase(this.phase); container.setPrefetchCount(this.prefetchCount); container.setRecoveryInterval(this.recoveryInterval); container.setShutdownTimeout(this.shutdownTimeout); container.setTaskExecutor(this.taskExecutor); container.setTransactionAttribute(this.transactionAttribute); container.setTransactionManager(this.transactionManager); container.setMissingQueuesFatal(this.missingQueuesFatal);
AbstractMessageListenerContainer container = createContainer(); if (this.applicationContext != null) { container.setApplicationContext(this.applicationContext); container.setBeanName(this.beanName); container.setApplicationEventPublisher(this.applicationEventPublisher); container.setChannelTransacted(this.channelTransacted); container.setAcknowledgeMode(this.acknowledgeMode); container.setQueueNames(this.queueNames); container.setQueues(this.queues); container.setExposeListenerChannel(this.exposeListenerChannel); container.setMessageListener(this.messageListener); container.setErrorHandler(this.errorHandler); container.setMessageConverter(this.messageConverter); container.setDeBatchingEnabled(this.deBatchingEnabled); container.setAdviceChain(this.adviceChain); container.setAfterReceivePostProcessors(this.afterReceivePostProcessors);
container.setMessageListener(message -> { latch.countDown(); throw new RuntimeException("force rollback"); }); container.setQueueNames("queue"); container.setChannelTransacted(true); container.setShutdownTimeout(100); container.afterPropertiesSet(); container.start(); assertTrue(consumerLatch.await(10, TimeUnit.SECONDS)); container.stop();
instance.setConnectionFactory(this.connectionFactory); instance.setErrorHandler(this.errorHandler); endpoint.setMessageConverter(this.messageConverter); if (endpoint.getMessageConverter() == null) { instance.setMessageConverter(this.messageConverter); instance.setMessageConverter(this.messageConverter); instance.setAcknowledgeMode(this.acknowledgeMode); instance.setChannelTransacted(this.channelTransacted); instance.setApplicationContext(this.applicationContext); instance.setTaskExecutor(this.taskExecutor); instance.setTransactionManager(this.transactionManager); instance.setPrefetchCount(this.prefetchCount); instance.setDefaultRequeueRejected(this.defaultRequeueRejected); instance.setAdviceChain(this.adviceChain); instance.setRecoveryBackOff(this.recoveryBackOff); instance.setMismatchedQueuesFatal(this.mismatchedQueuesFatal);
public void testUninterruptibleListener(AbstractMessageListenerContainer container) throws Exception { CachingConnectionFactory cf = new CachingConnectionFactory("localhost"); container.setConnectionFactory(cf); container.setShutdownTimeout(500); container.setQueueNames("test.shutdown"); final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch testEnded = new CountDownLatch(1); container.setMessageListener(m -> { try { latch.countDown(); container.setApplicationEventPublisher(e -> { if (e instanceof AsyncConsumerStartedEvent) { startLatch.countDown(); Map<?, ?> channels = TestUtils.getPropertyValue(connection, "target.delegate._channelManager._channelMap", Map.class); container.start(); try { assertTrue(startLatch.await(30, TimeUnit.SECONDS)); container.stop(); assertThat(channels.size(), equalTo(1));
@Bean public AbstractMessageListenerContainer container() { AbstractMessageListenerContainer container = new SimpleMessageListenerContainer(cf()); container.setQueues(queue1()); container.setMessageListener(m -> { message().set(m); latch1().countDown(); latch2().countDown(); }); container.setFailedDeclarationRetryInterval(100); container.setMissingQueuesFatal(false); container.setRecoveryInterval(100); container.setAutoStartup(false); return container; }
private void assertBasicConfig(AbstractMessageListenerContainer container) { DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(container); assertSame(connectionFactory, container.getConnectionFactory()); assertSame(errorHandler, fieldAccessor.getPropertyValue("errorHandler")); assertSame(messageConverter, fieldAccessor.getPropertyValue("messageListener.messageConverter")); assertEquals(AcknowledgeMode.MANUAL, container.getAcknowledgeMode()); assertEquals(true, container.isChannelTransacted()); assertEquals(false, container.isAutoStartup()); assertEquals(99, container.getPhase()); }
this.lifecycleMonitor.notifyAll(); initializeProxy(this.delegate); checkMissingQueuesFatalFromProperty(); checkPossibleAuthenticationFailureFatalFromProperty(); doInitialize(); if (!this.isExposeListenerChannel() && this.transactionManager != null) { logger.warn("exposeListenerChannel=false is ignored when using a TransactionManager"); if (!this.taskExecutorSet && StringUtils.hasText(this.getBeanName())) { this.taskExecutor = new SimpleAsyncTaskExecutor(this.getBeanName() + "-"); this.taskExecutorSet = true; if (this.transactionManager != null && !isChannelTransacted()) { logger.debug("The 'channelTransacted' is coerced to 'true', when 'transactionManager' is provided"); setChannelTransacted(true); throw convertRabbitAccessException(ex);
Object listener = getMessageListener(); if (listener instanceof ChannelAwareMessageListener) { doInvokeListener((ChannelAwareMessageListener) listener, channel, message); boolean bindChannel = isExposeListenerChannel() && isChannelLocallyTransacted(); if (bindChannel) { RabbitResourceHolder resourceHolder = new RabbitResourceHolder(channel, false); resourceHolder.setSynchronizedWithTransaction(true); TransactionSynchronizationManager.bindResource(this.getConnectionFactory(), resourceHolder); doInvokeListener((MessageListener) listener, message); TransactionSynchronizationManager.unbindResource(this.getConnectionFactory());
/** * Start this container. * @see #doStart */ @Override public void start() { if (isRunning()) { return; } if (!this.initialized) { synchronized (this.lifecycleMonitor) { if (!this.initialized) { afterPropertiesSet(); } } } try { if (logger.isDebugEnabled()) { logger.debug("Starting Rabbit listener container."); } configureAdminIfNeeded(); checkMismatchedQueues(); doStart(); } catch (Exception ex) { throw convertRabbitAccessException(ex); } }
this.template.setRoutingKey(routingKey); this.container = new SimpleMessageListenerContainer(connectionFactory); this.container.setQueueNames(replyQueue); this.container.setMessageListener(this); this.container.afterPropertiesSet(); this.directReplyToContainer = null; if (replyAddress == null) {
boolean boundHere = false; try { if (!isExposeListenerChannel()) { resourceHolder = getTransactionalResourceHolder(); channelToUse = resourceHolder.getChannel(); if (isChannelLocallyTransacted() && !TransactionSynchronizationManager.isActualTransactionActive()) { resourceHolder.setSynchronizedWithTransaction(true); TransactionSynchronizationManager.bindResource(this.getConnectionFactory(), resourceHolder); boundHere = true; if (isChannelLocallyTransacted()) { RabbitResourceHolder localResourceHolder = new RabbitResourceHolder(channelToUse, false); localResourceHolder.setSynchronizedWithTransaction(true); TransactionSynchronizationManager.bindResource(this.getConnectionFactory(), localResourceHolder); boundHere = true; throw wrapToListenerExecutionFailedExceptionIfNeeded(e, message); cleanUpAfterInvoke(resourceHolder, channelToUse, boundHere);
private BrokerEventListener(AbstractMessageListenerContainer container, boolean ownContainer, String... eventKeys) { Assert.notNull(container, "listener container cannot be null"); Assert.isTrue(!ObjectUtils.isEmpty(eventKeys), "At least one event key is required"); this.container = container; this.container.setQueues(this.eventQueue); this.container.setMessageListener(this); this.eventKeys = Arrays.copyOf(eventKeys, eventKeys.length); this.container.getConnectionFactory().addConnectionListener(this); this.admin = new RabbitAdmin(this.container.getConnectionFactory()); this.ownContainer = ownContainer; }
/** * Delegates to {@link #validateConfiguration()} and {@link #initialize()}. */ @Override public final void afterPropertiesSet() { super.afterPropertiesSet(); Assert.state( this.exposeListenerChannel || !getAcknowledgeMode().isManual(), "You cannot acknowledge messages manually if the channel is not exposed to the listener " + "(please check your configuration and set exposeListenerChannel=true or acknowledgeMode!=MANUAL)"); Assert.state( !(getAcknowledgeMode().isAutoAck() && isChannelTransacted()), "The acknowledgeMode is NONE (autoack in Rabbit terms) which is not consistent with having a " + "transactional channel. Either use a different AcknowledgeMode or make sure channelTransacted=false"); validateConfiguration(); initialize(); }
@Test public void testRetryWithinOnMessageGateway() throws Exception { ConnectionFactory connectionFactory = mock(ConnectionFactory.class); AbstractMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory); AmqpInboundGateway adapter = new AmqpInboundGateway(container); adapter.setRequestChannel(new DirectChannel()); adapter.setRetryTemplate(new RetryTemplate()); QueueChannel errors = new QueueChannel(); ErrorMessageSendingRecoverer recoveryCallback = new ErrorMessageSendingRecoverer(errors); recoveryCallback.setErrorMessageStrategy(new AmqpMessageHeaderErrorMessageStrategy()); adapter.setRecoveryCallback(recoveryCallback); adapter.afterPropertiesSet(); ChannelAwareMessageListener listener = (ChannelAwareMessageListener) container.getMessageListener(); listener.onMessage(org.springframework.amqp.core.MessageBuilder.withBody("foo".getBytes()) .andProperties(new MessageProperties()).build(), null); Message<?> errorMessage = errors.receive(0); assertNotNull(errorMessage); assertThat(errorMessage.getPayload(), instanceOf(MessagingException.class)); MessagingException payload = (MessagingException) errorMessage.getPayload(); assertThat(payload.getMessage(), containsString("Dispatcher has no")); assertThat(StaticMessageHeaderAccessor.getDeliveryAttempt(payload.getFailedMessage()).get(), equalTo(3)); org.springframework.amqp.core.Message amqpMessage = errorMessage.getHeaders() .get(AmqpMessageHeaderErrorMessageStrategy.AMQP_RAW_MESSAGE, org.springframework.amqp.core.Message.class); assertThat(amqpMessage, notNullValue()); assertNull(errors.receive(0)); }
private void cleanUpAfterInvoke(@Nullable RabbitResourceHolder resourceHolder, Channel channelToUse, boolean boundHere) { if (resourceHolder != null && boundHere) { // so the channel exposed (because exposeListenerChannel is false) will be closed resourceHolder.setSynchronizedWithTransaction(false); } ConnectionFactoryUtils.releaseResources(resourceHolder); // NOSONAR - null check in method if (boundHere) { // unbind if we bound TransactionSynchronizationManager.unbindResource(this.getConnectionFactory()); if (!isExposeListenerChannel() && isChannelLocallyTransacted()) { /* * commit the temporary channel we exposed; the consumer's channel * will be committed later. Note that when exposing a different channel * when there's no transaction manager, the exposed channel is committed * on each message, and not based on txSize. */ RabbitUtils.commitIfNecessary(channelToUse); } } }