Merge pull request #27 from vrtsystems/state-machine-client
Add storage of Queues and Exchanges to QAmqpClient.
This commit is contained in:
commit
73d80de53a
|
|
@ -203,9 +203,17 @@ void QAmqpChannelPrivate::close(const QAmqpMethodFrame &frame)
|
||||||
QAmqpMethodFrame closeOkFrame(QAmqpFrame::Channel, miCloseOk);
|
QAmqpMethodFrame closeOkFrame(QAmqpFrame::Channel, miCloseOk);
|
||||||
closeOkFrame.setChannel(channelNumber);
|
closeOkFrame.setChannel(channelNumber);
|
||||||
sendFrame(closeOkFrame);
|
sendFrame(closeOkFrame);
|
||||||
|
|
||||||
|
// notify everyone that the channel was closed on us.
|
||||||
|
notifyClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAmqpChannelPrivate::closeOk(const QAmqpMethodFrame &)
|
void QAmqpChannelPrivate::closeOk(const QAmqpMethodFrame &)
|
||||||
|
{
|
||||||
|
notifyClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QAmqpChannelPrivate::notifyClosed()
|
||||||
{
|
{
|
||||||
Q_Q(QAmqpChannel);
|
Q_Q(QAmqpChannel);
|
||||||
Q_EMIT q->closed();
|
Q_EMIT q->closed();
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ public:
|
||||||
void flow(bool active);
|
void flow(bool active);
|
||||||
void flowOk();
|
void flowOk();
|
||||||
void close(int code, const QString &text, int classId, int methodId);
|
void close(int code, const QString &text, int classId, int methodId);
|
||||||
|
void notifyClosed();
|
||||||
|
|
||||||
// reimp MethodHandler
|
// reimp MethodHandler
|
||||||
virtual bool _q_method(const QAmqpMethodFrame &frame);
|
virtual bool _q_method(const QAmqpMethodFrame &frame);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2014 Alexey Shcherbakov
|
||||||
|
* Copyright (C) 2014-2015 Matt Broadstone
|
||||||
|
* Contact: https://github.com/mbroadst/qamqp
|
||||||
|
*
|
||||||
|
* This file is part of the QAMQP Library.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
#include "qamqpqueue.h"
|
||||||
|
#include "qamqpexchange.h"
|
||||||
|
#include "qamqpchannelhash_p.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Retrieve a pointer to the named channel.
|
||||||
|
*
|
||||||
|
* A NULL string is assumed to be equivalent to "" for the purpose
|
||||||
|
* of retrieving the nameless (default) exchange.
|
||||||
|
*
|
||||||
|
* \param[in] name The name of the channel to retrieve.
|
||||||
|
* \retval NULL Channel does not exist.
|
||||||
|
*/
|
||||||
|
QAmqpChannel* QAmqpChannelHash::get(const QString& name) const
|
||||||
|
{
|
||||||
|
if (name.isEmpty())
|
||||||
|
return channels.value(QString());
|
||||||
|
return channels.value(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Return true if the named channel exists.
|
||||||
|
*/
|
||||||
|
bool QAmqpChannelHash::contains(const QString& name) const
|
||||||
|
{
|
||||||
|
if (name.isEmpty())
|
||||||
|
return channels.contains(QString());
|
||||||
|
return channels.contains(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Store an exchange in the hash. The nameless exchange is stored under
|
||||||
|
* the name "".
|
||||||
|
*/
|
||||||
|
void QAmqpChannelHash::put(QAmqpExchange* exchange)
|
||||||
|
{
|
||||||
|
if (exchange->name().isEmpty())
|
||||||
|
put(QString(), exchange);
|
||||||
|
else
|
||||||
|
put(exchange->name(), exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Store a queue in the hash. If the queue is nameless, we hook its
|
||||||
|
* declared signal and store it when the queue receives a name from the
|
||||||
|
* broker, otherwise we store it under the name given.
|
||||||
|
*/
|
||||||
|
void QAmqpChannelHash::put(QAmqpQueue* queue)
|
||||||
|
{
|
||||||
|
if (queue->name().isEmpty())
|
||||||
|
connect(queue, SIGNAL(declared()), this, SLOT(queueDeclared()));
|
||||||
|
else
|
||||||
|
put(queue->name(), queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Handle destruction of a channel. Do a full garbage collection run.
|
||||||
|
*/
|
||||||
|
void QAmqpChannelHash::channelDestroyed(QObject* object)
|
||||||
|
{
|
||||||
|
QList<QString> names(channels.keys());
|
||||||
|
QList<QString>::iterator it;
|
||||||
|
for (it = names.begin(); it != names.end(); it++) {
|
||||||
|
if (channels.value(*it) == object)
|
||||||
|
channels.remove(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Handle a queue that has just been declared and given a new name. The
|
||||||
|
* caller is assumed to be a QAmqpQueue instance.
|
||||||
|
*/
|
||||||
|
void QAmqpChannelHash::queueDeclared()
|
||||||
|
{
|
||||||
|
QAmqpQueue *queue = qobject_cast<QAmqpQueue*>(sender());
|
||||||
|
if (queue)
|
||||||
|
put(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Store a channel in the hash. The channel is assumed
|
||||||
|
* to be named at the time of storage. This hooks the 'destroyed' signal
|
||||||
|
* so the channel can be removed from our list.
|
||||||
|
*/
|
||||||
|
void QAmqpChannelHash::put(const QString& name, QAmqpChannel* channel)
|
||||||
|
{
|
||||||
|
connect(channel, SIGNAL(destroyed(QObject*)), this, SLOT(channelDestroyed(QObject*)));
|
||||||
|
channels[name] = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_qamqpchannelhash_p.cpp"
|
||||||
|
/* vim: set ts=4 sw=4 et */
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2014 Alexey Shcherbakov
|
||||||
|
* Copyright (C) 2014-2015 Matt Broadstone
|
||||||
|
* Contact: https://github.com/mbroadst/qamqp
|
||||||
|
*
|
||||||
|
* This file is part of the QAMQP Library.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
#ifndef QAMQPCHANNELHASH_P_H
|
||||||
|
#define QAMQPCHANNELHASH_P_H
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QString>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
/* Forward declarations */
|
||||||
|
class QAmqpChannel;
|
||||||
|
class QAmqpQueue;
|
||||||
|
class QAmqpExchange;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* QAmqpChannelHash is a container for storing queues and exchanges for later
|
||||||
|
* retrieval. When the objects are destroyed, they are automatically removed
|
||||||
|
* from the container.
|
||||||
|
*/
|
||||||
|
class QAmqpChannelHash : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* Retrieve a pointer to the named channel.
|
||||||
|
*
|
||||||
|
* A NULL string is assumed to be equivalent to "" for the purpose
|
||||||
|
* of retrieving the nameless (default) exchange.
|
||||||
|
*
|
||||||
|
* \param[in] name The name of the channel to retrieve.
|
||||||
|
* \retval NULL Channel does not exist.
|
||||||
|
*/
|
||||||
|
QAmqpChannel* get(const QString& name) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Return true if the named channel exists.
|
||||||
|
*/
|
||||||
|
bool contains(const QString& name) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Store an exchange in the hash. The nameless exchange is stored under
|
||||||
|
* the name "".
|
||||||
|
*/
|
||||||
|
void put(QAmqpExchange* exchange);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Store a queue in the hash. If the queue is nameless, we hook its
|
||||||
|
* declared signal and store it when the queue receives a name from the
|
||||||
|
* broker, otherwise we store it under the name given.
|
||||||
|
*/
|
||||||
|
void put(QAmqpQueue* queue);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
/*!
|
||||||
|
* Handle destruction of a channel. Do a full garbage collection run.
|
||||||
|
*/
|
||||||
|
void channelDestroyed(QObject* object);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Handle a queue that has just been declared and given a new name. The
|
||||||
|
* caller is assumed to be a QAmqpQueue instance.
|
||||||
|
*/
|
||||||
|
void queueDeclared();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*!
|
||||||
|
* Store a channel in the hash. This hooks the 'destroyed' signal
|
||||||
|
* so the channel can be removed from our list.
|
||||||
|
*/
|
||||||
|
void put(const QString& name, QAmqpChannel* channel);
|
||||||
|
|
||||||
|
/*! A collection of channels. Key is the channel's "name". */
|
||||||
|
QHash<QString, QAmqpChannel*> channels;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* vim: set ts=4 sw=4 et */
|
||||||
|
#endif
|
||||||
|
|
@ -660,7 +660,14 @@ QAmqpExchange *QAmqpClient::createExchange(int channelNumber)
|
||||||
QAmqpExchange *QAmqpClient::createExchange(const QString &name, int channelNumber)
|
QAmqpExchange *QAmqpClient::createExchange(const QString &name, int channelNumber)
|
||||||
{
|
{
|
||||||
Q_D(QAmqpClient);
|
Q_D(QAmqpClient);
|
||||||
QAmqpExchange *exchange = new QAmqpExchange(channelNumber, this);
|
QAmqpExchange *exchange;
|
||||||
|
if (d->exchanges.contains(name)) {
|
||||||
|
exchange = qobject_cast<QAmqpExchange*>(d->exchanges.get(name));
|
||||||
|
if (exchange)
|
||||||
|
return exchange;
|
||||||
|
}
|
||||||
|
|
||||||
|
exchange = new QAmqpExchange(channelNumber, this);
|
||||||
d->methodHandlersByChannel[exchange->channelNumber()].append(exchange->d_func());
|
d->methodHandlersByChannel[exchange->channelNumber()].append(exchange->d_func());
|
||||||
connect(this, SIGNAL(connected()), exchange, SLOT(_q_open()));
|
connect(this, SIGNAL(connected()), exchange, SLOT(_q_open()));
|
||||||
connect(this, SIGNAL(disconnected()), exchange, SLOT(_q_disconnected()));
|
connect(this, SIGNAL(disconnected()), exchange, SLOT(_q_disconnected()));
|
||||||
|
|
@ -668,6 +675,7 @@ QAmqpExchange *QAmqpClient::createExchange(const QString &name, int channelNumbe
|
||||||
|
|
||||||
if (!name.isEmpty())
|
if (!name.isEmpty())
|
||||||
exchange->setName(name);
|
exchange->setName(name);
|
||||||
|
d->exchanges.put(exchange);
|
||||||
return exchange;
|
return exchange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -679,7 +687,14 @@ QAmqpQueue *QAmqpClient::createQueue(int channelNumber)
|
||||||
QAmqpQueue *QAmqpClient::createQueue(const QString &name, int channelNumber)
|
QAmqpQueue *QAmqpClient::createQueue(const QString &name, int channelNumber)
|
||||||
{
|
{
|
||||||
Q_D(QAmqpClient);
|
Q_D(QAmqpClient);
|
||||||
QAmqpQueue *queue = new QAmqpQueue(channelNumber, this);
|
QAmqpQueue *queue;
|
||||||
|
if (d->queues.contains(name)) {
|
||||||
|
queue = qobject_cast<QAmqpQueue*>(d->queues.get(name));
|
||||||
|
if (queue)
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
queue = new QAmqpQueue(channelNumber, this);
|
||||||
d->methodHandlersByChannel[queue->channelNumber()].append(queue->d_func());
|
d->methodHandlersByChannel[queue->channelNumber()].append(queue->d_func());
|
||||||
d->contentHandlerByChannel[queue->channelNumber()].append(queue->d_func());
|
d->contentHandlerByChannel[queue->channelNumber()].append(queue->d_func());
|
||||||
d->bodyHandlersByChannel[queue->channelNumber()].append(queue->d_func());
|
d->bodyHandlersByChannel[queue->channelNumber()].append(queue->d_func());
|
||||||
|
|
@ -689,6 +704,7 @@ QAmqpQueue *QAmqpClient::createQueue(const QString &name, int channelNumber)
|
||||||
|
|
||||||
if (!name.isEmpty())
|
if (!name.isEmpty())
|
||||||
queue->setName(name);
|
queue->setName(name);
|
||||||
|
d->queues.put(queue);
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include <QAbstractSocket>
|
#include <QAbstractSocket>
|
||||||
#include <QSslError>
|
#include <QSslError>
|
||||||
|
|
||||||
|
#include "qamqpchannelhash_p.h"
|
||||||
#include "qamqpglobal.h"
|
#include "qamqpglobal.h"
|
||||||
#include "qamqpauthenticator.h"
|
#include "qamqpauthenticator.h"
|
||||||
#include "qamqptable.h"
|
#include "qamqptable.h"
|
||||||
|
|
@ -100,6 +101,12 @@ public:
|
||||||
QAMQP::Error error;
|
QAMQP::Error error;
|
||||||
QString errorString;
|
QString errorString;
|
||||||
|
|
||||||
|
/*! Exchange objects */
|
||||||
|
QAmqpChannelHash exchanges;
|
||||||
|
|
||||||
|
/*! Named queue objects */
|
||||||
|
QAmqpChannelHash queues;
|
||||||
|
|
||||||
QAmqpClient * const q_ptr;
|
QAmqpClient * const q_ptr;
|
||||||
Q_DECLARE_PUBLIC(QAmqpClient)
|
Q_DECLARE_PUBLIC(QAmqpClient)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ greaterThan(NEED_GCOV_SUPPORT, 0) {
|
||||||
|
|
||||||
PRIVATE_HEADERS += \
|
PRIVATE_HEADERS += \
|
||||||
qamqpchannel_p.h \
|
qamqpchannel_p.h \
|
||||||
|
qamqpchannelhash_p.h \
|
||||||
qamqpclient_p.h \
|
qamqpclient_p.h \
|
||||||
qamqpexchange_p.h \
|
qamqpexchange_p.h \
|
||||||
qamqpframe_p.h \
|
qamqpframe_p.h \
|
||||||
|
|
@ -56,6 +57,7 @@ HEADERS += \
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
qamqpauthenticator.cpp \
|
qamqpauthenticator.cpp \
|
||||||
qamqpchannel.cpp \
|
qamqpchannel.cpp \
|
||||||
|
qamqpchannelhash.cpp \
|
||||||
qamqpclient.cpp \
|
qamqpclient.cpp \
|
||||||
qamqpexchange.cpp \
|
qamqpexchange.cpp \
|
||||||
qamqpframe.cpp \
|
qamqpframe.cpp \
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,12 @@ void tst_QAMQPExchange::invalidRedeclaration()
|
||||||
// this is for rabbitmq:
|
// this is for rabbitmq:
|
||||||
QCOMPARE(redeclared->error(), QAMQP::PreconditionFailedError);
|
QCOMPARE(redeclared->error(), QAMQP::PreconditionFailedError);
|
||||||
|
|
||||||
|
// Server has probably closed the channel on us, if so, re-open it.
|
||||||
|
if (!exchange->isOpen()) {
|
||||||
|
exchange->reopen();
|
||||||
|
QVERIFY(waitForSignal(exchange, SIGNAL(opened())));
|
||||||
|
}
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
exchange->remove();
|
exchange->remove();
|
||||||
QVERIFY(waitForSignal(exchange, SIGNAL(removed())));
|
QVERIFY(waitForSignal(exchange, SIGNAL(removed())));
|
||||||
|
|
@ -209,6 +215,7 @@ void tst_QAMQPExchange::cleanupOnDeletion()
|
||||||
QVERIFY(waitForSignal(exchange, SIGNAL(declared())));
|
QVERIFY(waitForSignal(exchange, SIGNAL(declared())));
|
||||||
exchange->close();
|
exchange->close();
|
||||||
exchange->deleteLater();
|
exchange->deleteLater();
|
||||||
|
QVERIFY(waitForSignal(exchange, SIGNAL(destroyed())));
|
||||||
|
|
||||||
// now create, declare, and close the right way
|
// now create, declare, and close the right way
|
||||||
exchange = client->createExchange("test-deletion");
|
exchange = client->createExchange("test-deletion");
|
||||||
|
|
|
||||||
|
|
@ -683,6 +683,7 @@ void tst_QAMQPQueue::cleanupOnDeletion()
|
||||||
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
|
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
|
||||||
queue->close();
|
queue->close();
|
||||||
queue->deleteLater();
|
queue->deleteLater();
|
||||||
|
QVERIFY(waitForSignal(queue, SIGNAL(destroyed())));
|
||||||
|
|
||||||
// now create, declare, and close the right way
|
// now create, declare, and close the right way
|
||||||
queue = client->createQueue("test-deletion");
|
queue = client->createQueue("test-deletion");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue