protected AMQQueue createQueue(
      final AMQShortString queueName,
      QueueDeclareBody body,
      VirtualHost virtualHost,
      final AMQProtocolSession session)
      throws AMQException {
    final QueueRegistry registry = virtualHost.getQueueRegistry();
    AMQShortString owner = body.getExclusive() ? session.getContextKey() : null;

    final AMQQueue queue =
        AMQQueueFactory.createAMQQueueImpl(
            queueName,
            body.getDurable(),
            owner,
            body.getAutoDelete(),
            body.getExclusive(),
            virtualHost,
            body.getArguments());

    if (body.getExclusive() && !body.getDurable()) {
      final AMQProtocolSession.Task deleteQueueTask =
          new AMQProtocolSession.Task() {
            public void doTask(AMQProtocolSession session) throws AMQException {
              if (registry.getQueue(queueName) == queue) {
                queue.delete();
              }
            }
          };

      session.addSessionCloseTask(deleteQueueTask);

      queue.addQueueDeleteTask(
          new AMQQueue.Task() {
            public void doTask(AMQQueue queue) {
              session.removeSessionCloseTask(deleteQueueTask);
            }
          });
    }

    return queue;
  }
  public void methodReceived(AMQStateManager stateManager, QueueDeclareBody body, int channelId)
      throws AMQException {
    final AMQProtocolSession protocolConnection = stateManager.getProtocolSession();
    final AMQSessionModel session = protocolConnection.getChannel(channelId);
    VirtualHost virtualHost = protocolConnection.getVirtualHost();
    ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
    QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
    DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();

    final AMQShortString queueName;

    // if we aren't given a queue name, we create one which we return to the client
    if ((body.getQueue() == null) || (body.getQueue().length() == 0)) {
      queueName = createName();
    } else {
      queueName = body.getQueue().intern();
    }

    AMQQueue queue;

    // TODO: do we need to check that the queue already exists with exactly the same
    // "configuration"?

    synchronized (queueRegistry) {
      queue = queueRegistry.getQueue(queueName);

      AMQSessionModel owningSession = null;

      if (queue != null) {
        owningSession = queue.getExclusiveOwningSession();
      }

      if (queue == null) {
        if (body.getPassive()) {
          String msg = "Queue: " + queueName + " not found on VirtualHost(" + virtualHost + ").";
          throw body.getChannelException(AMQConstant.NOT_FOUND, msg);
        } else {
          queue = createQueue(queueName, body, virtualHost, protocolConnection);
          queue.setAuthorizationHolder(protocolConnection);
          if (queue.isDurable() && !queue.isAutoDelete()) {
            store.createQueue(queue, body.getArguments());

            // Tell Andes kernel to create queue
            QpidAndesBridge.createQueue(queue);
          }
          if (body.getAutoDelete()) {
            queue.setDeleteOnNoConsumers(true);
          }
          queueRegistry.registerQueue(queue);
          if (body.getExclusive()) {
            queue.setExclusiveOwningSession(protocolConnection.getChannel(channelId));
            queue.setAuthorizationHolder(protocolConnection);

            if (!body.getDurable()) {
              final AMQQueue q = queue;
              final AMQProtocolSession.Task sessionCloseTask =
                  new AMQProtocolSession.Task() {
                    public void doTask(AMQProtocolSession session) throws AMQException {
                      q.setExclusiveOwningSession(null);
                    }
                  };
              protocolConnection.addSessionCloseTask(sessionCloseTask);
              queue.addQueueDeleteTask(
                  new AMQQueue.Task() {
                    public void doTask(AMQQueue queue) throws AMQException {
                      protocolConnection.removeSessionCloseTask(sessionCloseTask);
                    }
                  });
            }
          }
          if (autoRegister) {
            Exchange defaultExchange = exchangeRegistry.getDefaultExchange();

            virtualHost
                .getBindingFactory()
                .addBinding(
                    String.valueOf(queueName), queue, defaultExchange, Collections.EMPTY_MAP);
            _logger.info(
                "Queue "
                    + queueName
                    + " bound to default exchange("
                    + defaultExchange.getNameShortString()
                    + ")");
          }
        }
      } else if (queue.isExclusive()
          && !queue.isDurable()
          && (owningSession == null || owningSession.getConnectionModel() != protocolConnection)) {
        throw body.getConnectionException(
            AMQConstant.NOT_ALLOWED,
            "Queue "
                + queue.getNameShortString()
                + " is exclusive, but not created on this Connection.");
      } else if (!body.getPassive() && ((queue.isExclusive()) != body.getExclusive())) {

        throw body.getChannelException(
            AMQConstant.ALREADY_EXISTS,
            "Cannot re-declare queue '"
                + queue.getNameShortString()
                + "' with different exclusivity (was: "
                + queue.isExclusive()
                + " requested "
                + body.getExclusive()
                + ")");
      } else if (!body.getPassive()
          && body.getExclusive()
          && !(queue.isDurable()
              ? String.valueOf(queue.getOwner()).equals(session.getClientID())
              : (owningSession == null
                  || owningSession.getConnectionModel() == protocolConnection))) {
        throw body.getChannelException(
            AMQConstant.ALREADY_EXISTS,
            "Cannot declare queue('"
                + queueName
                + "'), "
                + "as exclusive queue with same name "
                + "declared on another client ID('"
                + queue.getOwner()
                + "') your clientID('"
                + session.getClientID()
                + "')");

      } else if (!body.getPassive() && queue.isAutoDelete() != body.getAutoDelete()) {
        throw body.getChannelException(
            AMQConstant.ALREADY_EXISTS,
            "Cannot re-declare queue '"
                + queue.getNameShortString()
                + "' with different auto-delete (was: "
                + queue.isAutoDelete()
                + " requested "
                + body.getAutoDelete()
                + ")");
      } else if (!body.getPassive() && queue.isDurable() != body.getDurable()) {
        throw body.getChannelException(
            AMQConstant.ALREADY_EXISTS,
            "Cannot re-declare queue '"
                + queue.getNameShortString()
                + "' with different durability (was: "
                + queue.isDurable()
                + " requested "
                + body.getDurable()
                + ")");
      }

      AMQChannel channel = protocolConnection.getChannel(channelId);

      if (channel == null) {
        throw body.getChannelNotFoundException(channelId);
      }

      // set this as the default queue on the channel:
      channel.setDefaultQueue(queue);
    }

    if (!body.getNowait()) {
      MethodRegistry methodRegistry = protocolConnection.getMethodRegistry();
      QueueDeclareOkBody responseBody =
          methodRegistry.createQueueDeclareOkBody(
              queueName, queue.getMessageCount(), queue.getConsumerCount());
      protocolConnection.writeFrame(responseBody.generateFrame(channelId));

      _logger.info("Queue " + queueName + " declared successfully");
    }
  }