/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.camel.component.rabbitmq.reply; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.AMQP.Queue.DeclareOk; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.Envelope; import org.apache.camel.AsyncCallback; import org.apache.camel.CamelContext; import org.apache.camel.Exchange; /** * A {@link ReplyManager} when using temporary queues. * * @version */ public class TemporaryQueueReplyManager extends ReplyManagerSupport { private RabbitConsumer consumer; public TemporaryQueueReplyManager(CamelContext camelContext) { super(camelContext); } protected ReplyHandler createReplyHandler(ReplyManager replyManager, Exchange exchange, AsyncCallback callback, String originalCorrelationId, String correlationId, long requestTimeout) { return new TemporaryQueueReplyHandler(this, exchange, callback, originalCorrelationId, correlationId, requestTimeout); } public void updateCorrelationId(String correlationId, String newCorrelationId, long requestTimeout) { log.trace("Updated provisional correlationId [{}] to expected correlationId [{}]", correlationId, newCorrelationId); ReplyHandler handler = correlation.remove(correlationId); if (handler != null) { correlation.put(newCorrelationId, handler, requestTimeout); } } @Override protected void handleReplyMessage(String correlationID, AMQP.BasicProperties properties, byte[] message) { ReplyHandler handler = correlation.get(correlationID); if (handler == null && endpoint.isUseMessageIDAsCorrelationID()) { handler = waitForProvisionCorrelationToBeUpdated(correlationID, message); } if (handler != null) { correlation.remove(correlationID); handler.onReply(correlationID, properties, message); } else { // we could not correlate the received reply message to a matching request and therefore // we cannot continue routing the unknown message // log a warn and then ignore the message log.warn("Reply received for unknown correlationID [{}]. The message will be ignored: {}", correlationID, message); } } @Override protected Connection createListenerContainer() throws Exception { log.debug("Creating connection"); Connection conn = endpoint.connect(executorService); log.debug("Creating channel"); Channel channel = conn.createChannel(); // setup the basicQos if (endpoint.isPrefetchEnabled()) { channel.basicQos(endpoint.getPrefetchSize(), endpoint.getPrefetchCount(), endpoint.isPrefetchGlobal()); } //Let the server pick a random name for us DeclareOk result = channel.queueDeclare(); log.info("Using temporary queue name: {}", result.getQueue()); setReplyTo(result.getQueue()); //TODO check for the RabbitMQConstants.EXCHANGE_NAME header channel.queueBind(getReplyTo(), endpoint.getExchangeName(), getReplyTo()); consumer = new RabbitConsumer(this, channel); consumer.start(); return conn; } @Override protected void doStop() throws Exception { super.doStop(); consumer.stop(); } //TODO combine with class in RabbitMQConsumer class RabbitConsumer extends com.rabbitmq.client.DefaultConsumer { private final TemporaryQueueReplyManager consumer; private final Channel channel; private String tag; /** * Constructs a new instance and records its association to the * passed-in channel. * * @param channel the channel to which this consumer is attached */ RabbitConsumer(TemporaryQueueReplyManager consumer, Channel channel) { super(channel); this.consumer = consumer; this.channel = channel; } @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { consumer.onMessage(properties, body); } /** * Bind consumer to channel */ private void start() throws IOException { tag = channel.basicConsume(getReplyTo(), endpoint.isAutoAck(), this); } /** * Unbind consumer from channel */ private void stop() throws IOException, TimeoutException { if (channel.isOpen()) { if (tag != null) { channel.basicCancel(tag); } channel.close(); } } } }