Demian Tinkiel
Demian Tinkiel

Reputation: 17

Spring AmqpAdmin create exchange & queues in vHost

A similar question to Send message to arbitrary vhost / exchange with RabbitMQ / Spring AMQP but I'm trying to have the AmqpAdmin create an exchange under a specific vHost

I tried doing something like

SimpleResourceHolder.bind(((RabbitAdmin) amqpAdmin).getRabbitTemplate().getConnectionFactory(), vhost);
...
amqpAdmin.declareExchange(exchange);
...
amqpAdmin.declareQueue(queue);
amqpAdmin.declareBinding(BindingBuilder.bind(queue).to(exchange).with(routingKey));

SimpleResourceHolder.unbind(((RabbitAdmin) amqpAdmin).getRabbitTemplate().getConnectionFactory());

However AmqpAdmin keeps using "/"

is there a way to tell it to use a specific vHost programmatically at runtime?

update 1: based on @artem-bilan I've had (partial) success by doing:


    public void sendToTopic(String domain, String topic, String routingKey, Object payload) {
        bindToVirtualHost(template, domain);
        try {
            template.setUsePublisherConnection(true);
            template.convertAndSend(topic, routingKey, payload);
        } finally {
            unbindFromVirtualHost(template);
            template.setUsePublisherConnection(false);
        }
    }

    private void bindToVirtualHost(RabbitTemplate rabbitTemplate, String vHost) {
        AbstractConnectionFactory factory = (AbstractConnectionFactory) rabbitTemplate.getConnectionFactory();
        LOG.debug("binding {} to {}", factory, vHost);
        factory.setVirtualHost(vHost);
    }

    private void unbindFromVirtualHost(RabbitTemplate rabbitTemplate) {
        AbstractConnectionFactory factory = (AbstractConnectionFactory) rabbitTemplate.getConnectionFactory();
        LOG.debug("unbinding {} back to default {}", factory, DEFAULT_VHOST);
        factory.setVirtualHost(DEFAULT_VHOST);
    }

I say (partial) because if I do:

// pre :Manually create vHost foo

        sendToTopic("bar","myTopic","key","The payload"); // connection error; protocol method: #method<connection.close>(reply-code=530, reply-text=NOT_ALLOWED - vhost TNo not found, as expected
        sendToTopic("foo","myTopic","key","The payload2"); // success, as expected
        sendToTopic("bar","myTopic","key","The payload3"); // success, NOT EXPECTED!

and the message of payload3 goes to vHost foo

Upvotes: 1

Views: 1214

Answers (1)

Artem Bilan
Artem Bilan

Reputation: 121292

The RabbitAdmin cannot do more than its ConnectionFactory allows. So, the vHost is similar to the host/port and it cannot be managed from end-user perspectiv.

See:

/**
 * Create a new CachingConnectionFactory given a host name
 * and port.
 * @param hostNameArg the host name to connect to
 * @param port the port number
 */
public CachingConnectionFactory(@Nullable String hostNameArg, int port) {

and its:

public void setVirtualHost(String virtualHost) {

The RabbitAdmin, on its turn, is just like this:

/**
 * Construct an instance using the provided {@link ConnectionFactory}.
 * @param connectionFactory the connection factory - must not be null.
 */
public RabbitAdmin(ConnectionFactory connectionFactory) {

So, to deal with different vHost, you need to have its own ConnectionFactory and RabbitAdmin.

No, AmqpAdmin cannot create for you a vHost. This is not an AMQP protocol operation. See https://docs.spring.io/spring-amqp/docs/2.2.7.RELEASE/reference/html/#management-rest-api for more info.

Upvotes: 2

Related Questions