/* * 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.amqp.channel; import org.springframework.amqp.core.AmqpAdmin; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.amqp.core.AnonymousQueue; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.FanoutExchange; import org.springframework.amqp.core.Queue; import org.springframework.amqp.rabbit.connection.Connection; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionListener; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer; import org.springframework.integration.amqp.support.AmqpHeaderMapper; import org.springframework.integration.dispatcher.AbstractDispatcher; import org.springframework.integration.dispatcher.BroadcastingDispatcher; /** * @author Mark Fisher * @author Gary Russell * @since 2.1 */ public class PublishSubscribeAmqpChannel extends AbstractSubscribableAmqpChannel implements ConnectionListener { private volatile FanoutExchange exchange; private final Queue queue = new AnonymousQueue(); private volatile Binding binding; private volatile boolean initialized; /** * Construct an instance with the supplied name, container and template; default header * mappers will be used if the message is mapped. * @param channelName the channel name. * @param container the container. * @param amqpTemplate the template. * @see #setExtractPayload(boolean) */ public PublishSubscribeAmqpChannel(String channelName, AbstractMessageListenerContainer container, AmqpTemplate amqpTemplate) { super(channelName, container, amqpTemplate, true); } /** * Construct an instance with the supplied name, container and template; default header * mappers will be used if the message is mapped. * @param channelName the channel name. * @param container the container. * @param amqpTemplate the template * @param outboundMapper the outbound mapper. * @param inboundMapper the inbound mapper. * @see #setExtractPayload(boolean) * @since 4.3 */ public PublishSubscribeAmqpChannel(String channelName, AbstractMessageListenerContainer container, AmqpTemplate amqpTemplate, AmqpHeaderMapper outboundMapper, AmqpHeaderMapper inboundMapper) { super(channelName, container, amqpTemplate, true, outboundMapper, inboundMapper); } /** * Configure the FanoutExchange instance. If this is not provided, then a * FanoutExchange will be declared implicitly, and its name will be the same * as the channel name prefixed by "si.fanout.". In either case, an effectively * anonymous Queue will be declared automatically. * @param exchange The fanout exchange. */ public void setExchange(FanoutExchange exchange) { this.exchange = exchange; } @Override protected String obtainQueueName(AmqpAdmin admin, String channelName) { if (this.exchange == null) { String exchangeName = "si.fanout." + channelName; this.exchange = new FanoutExchange(exchangeName); } admin.declareExchange(this.exchange); admin.declareQueue(this.queue); this.binding = BindingBuilder.bind(this.queue).to(this.exchange); admin.declareBinding(this.binding); if (!this.initialized && this.getAmqpTemplate() instanceof RabbitTemplate) { ConnectionFactory connectionFactory = this.getConnectionFactory(); if (connectionFactory != null) { connectionFactory.addConnectionListener(this); } } this.initialized = true; return this.queue.getName(); } private void doDeclares() { if (this.isRunning()) { AmqpAdmin admin = this.getAdmin(); if (admin != null) { if (this.queue != null) { admin.declareQueue(this.queue); } if (this.binding != null) { admin.declareBinding(this.binding); } } } } @Override protected AbstractDispatcher createDispatcher() { BroadcastingDispatcher broadcastingDispatcher = new BroadcastingDispatcher(true); broadcastingDispatcher.setBeanFactory(this.getBeanFactory()); return broadcastingDispatcher; } @Override protected String getExchangeName() { return (this.exchange != null) ? this.exchange.getName() : ""; } @Override public void destroy() throws Exception { super.destroy(); if (this.getConnectionFactory() != null) { this.getConnectionFactory().removeConnectionListener(this); this.initialized = false; } } @Override public void start() { this.doDeclares(); // connection may have been lost while we were stopped super.start(); } @Override public void onCreate(Connection connection) { doDeclares(); } @Override public void onClose(Connection connection) { } }