From c221b394fb6f23d96a25f388aee00b19d6bb9b8b Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 26 Aug 2009 16:55:43 +0000 Subject: Hide internal message ID behind API git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@808121 13f79535-47bb-0310-9956-ffa450edef68 --- cpp/src/CMakeLists.txt | 2 + cpp/src/Makefile.am | 2 + cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp | 7 +- cpp/src/qpid/client/amqp0_10/SessionImpl.cpp | 12 +- cpp/src/qpid/messaging/Message.cpp | 257 +--------------------- cpp/src/qpid/messaging/MessageImpl.cpp | 192 ++++++++++++++++ cpp/src/qpid/messaging/MessageImpl.h | 132 +++++++++++ cpp/src/tests/MessagingSessionTests.cpp | 17 ++ 8 files changed, 353 insertions(+), 268 deletions(-) create mode 100644 cpp/src/qpid/messaging/MessageImpl.cpp create mode 100644 cpp/src/qpid/messaging/MessageImpl.h (limited to 'cpp/src') diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 7456401618..92b76b5e41 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -528,6 +528,8 @@ set (libqpidclient_SOURCES qpid/messaging/ConnectionImpl.h qpid/messaging/Filter.cpp qpid/messaging/Message.cpp + qpid/messaging/MessageImpl.h + qpid/messaging/MessageImpl.cpp qpid/messaging/Receiver.cpp qpid/messaging/ReceiverImpl.h qpid/messaging/Session.cpp diff --git a/cpp/src/Makefile.am b/cpp/src/Makefile.am index 05b5efc5b5..3bfd405416 100644 --- a/cpp/src/Makefile.am +++ b/cpp/src/Makefile.am @@ -686,6 +686,8 @@ libqpidclient_la_SOURCES = \ qpid/messaging/Connection.cpp \ qpid/messaging/Filter.cpp \ qpid/messaging/Message.cpp \ + qpid/messaging/MessageImpl.h \ + qpid/messaging/MessageImpl.cpp \ qpid/messaging/Sender.cpp \ qpid/messaging/Receiver.cpp \ qpid/messaging/Session.cpp \ diff --git a/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp b/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp index b69c1917e6..f9bd355a78 100644 --- a/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp +++ b/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp @@ -26,6 +26,7 @@ #include "qpid/log/Statement.h" #include "qpid/messaging/Address.h" #include "qpid/messaging/Message.h" +#include "qpid/messaging/MessageImpl.h" #include "qpid/messaging/Variant.h" #include "qpid/framing/DeliveryProperties.h" #include "qpid/framing/FrameSet.h" @@ -41,6 +42,7 @@ using namespace qpid::framing; using namespace qpid::framing::message; using qpid::sys::AbsTime; using qpid::sys::Duration; +using qpid::messaging::MessageImplAccess; using qpid::messaging::Variant; namespace { @@ -219,9 +221,8 @@ void populateHeaders(qpid::messaging::Message& message, const AMQHeaderBody* hea void populate(qpid::messaging::Message& message, FrameSet& command) { //need to be able to link the message back to the transfer it was delivered by - //e.g. for rejecting. TODO: hide this from API - uint32_t commandId = command.getId(); - message.setInternalId(reinterpret_cast(commandId)); + //e.g. for rejecting. + MessageImplAccess::get(message).setInternalId(command.getId()); command.getContent(message.getBytes()); diff --git a/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp b/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp index 9ea2a9f598..e069520e95 100644 --- a/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp +++ b/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp @@ -29,6 +29,7 @@ #include "qpid/messaging/Address.h" #include "qpid/messaging/Filter.h" #include "qpid/messaging/Message.h" +#include "qpid/messaging/MessageImpl.h" #include "qpid/messaging/MessageListener.h" #include "qpid/messaging/Sender.h" #include "qpid/messaging/Receiver.h" @@ -39,6 +40,7 @@ #include using qpid::messaging::Filter; +using qpid::messaging::MessageImplAccess; using qpid::messaging::Sender; using qpid::messaging::Receiver; using qpid::messaging::VariantMap; @@ -78,16 +80,8 @@ void SessionImpl::acknowledge() void SessionImpl::reject(qpid::messaging::Message& m) { qpid::sys::Mutex::ScopedLock l(lock); - //TODO: how do I get the id of the original transfer command? think this through some more... - - // [tross] The following hack was added to get this code to compile on a 64-bit machine. - // It should be functionally equivalent to the original on a 32-bit architecture - // but is almost certainly not what was intended by the author. - uint64_t rawId(reinterpret_cast(m.getInternalId())); - SequenceNumber id((uint32_t) ((rawId & 0xFFFFFFFF) ^ ((rawId >> 32) & 0xFFFFFFFF))); - SequenceSet set; - set.add(id); + set.add(MessageImplAccess::get(m).getInternalId()); session.messageReject(set); } diff --git a/cpp/src/qpid/messaging/Message.cpp b/cpp/src/qpid/messaging/Message.cpp index e95a05db17..1d844b3027 100644 --- a/cpp/src/qpid/messaging/Message.cpp +++ b/cpp/src/qpid/messaging/Message.cpp @@ -19,263 +19,11 @@ * */ #include "qpid/messaging/Message.h" -#include "qpid/messaging/Address.h" -#include "qpid/messaging/Codec.h" -#include "qpid/messaging/MessageContent.h" -#include "qpid/messaging/Variant.h" +#include "qpid/messaging/MessageImpl.h" namespace qpid { -namespace client { -} - namespace messaging { -namespace { -const std::string EMPTY_STRING = ""; -} - -struct MessageImpl : MessageContent -{ - Address replyTo; - std::string subject; - std::string contentType; - VariantMap headers; - - std::string bytes; - Variant content;//used only for LIST and MAP - VariantType type;//if LIST, MAP content holds the value; if VOID bytes holds the value - - void* internalId; - - MessageImpl(const std::string& c); - MessageImpl(const char* chars, size_t count); - - void setReplyTo(const Address& d); - const Address& getReplyTo() const; - - void setSubject(const std::string& s); - const std::string& getSubject() const; - - void setContentType(const std::string& s); - const std::string& getContentType() const; - - const VariantMap& getHeaders() const; - VariantMap& getHeaders(); - - void setBytes(const std::string& bytes); - void setBytes(const char* chars, size_t count); - const std::string& getBytes() const; - std::string& getBytes(); - - void setInternalId(void*); - void* getInternalId(); - - bool isVoid() const; - - const std::string& asString() const; - std::string& asString(); - - const char* asChars() const; - size_t size() const; - - const Variant::Map& asMap() const; - Variant::Map& asMap(); - bool isMap() const; - - const Variant::List& asList() const; - Variant::List& asList(); - bool isList() const; - - void clear(); - - void encode(Codec& codec); - void decode(Codec& codec); - - Variant& operator[](const std::string&); - - std::ostream& print(std::ostream& out) const; - - //operator<< for variety of types... - MessageContent& operator<<(const std::string&); - MessageContent& operator<<(const char*); - MessageContent& operator<<(bool); - MessageContent& operator<<(int8_t); - MessageContent& operator<<(int16_t); - MessageContent& operator<<(int32_t); - MessageContent& operator<<(int64_t); - MessageContent& operator<<(uint8_t); - MessageContent& operator<<(uint16_t); - MessageContent& operator<<(uint32_t); - MessageContent& operator<<(uint64_t); - MessageContent& operator<<(double); - MessageContent& operator<<(float); - - //assignment from string, map and list - MessageContent& operator=(const std::string&); - MessageContent& operator=(const char*); - MessageContent& operator=(const Variant::Map&); - MessageContent& operator=(const Variant::List&); - - template MessageContent& append(T& t); -}; - -MessageImpl::MessageImpl(const std::string& c) : bytes(c), type(VOID), internalId(0) {} -MessageImpl::MessageImpl(const char* chars, size_t count) : bytes(chars, count), type(VOID), internalId(0) {} - -void MessageImpl::setReplyTo(const Address& d) { replyTo = d; } -const Address& MessageImpl::getReplyTo() const { return replyTo; } - -void MessageImpl::setSubject(const std::string& s) { subject = s; } -const std::string& MessageImpl::getSubject() const { return subject; } - -void MessageImpl::setContentType(const std::string& s) { contentType = s; } -const std::string& MessageImpl::getContentType() const { return contentType; } - -const VariantMap& MessageImpl::getHeaders() const { return headers; } -VariantMap& MessageImpl::getHeaders() { return headers; } - -//should these methods be on MessageContent? -void MessageImpl::setBytes(const std::string& c) { clear(); bytes = c; } -void MessageImpl::setBytes(const char* chars, size_t count) { clear(); bytes.assign(chars, count); } -const std::string& MessageImpl::getBytes() const { return bytes; } -std::string& MessageImpl::getBytes() { return bytes; } - - -Variant& MessageImpl::operator[](const std::string& key) { return asMap()[key]; } - -std::ostream& MessageImpl::print(std::ostream& out) const -{ - if (type == MAP) { - return out << content.asMap(); - } else if (type == LIST) { - return out << content.asList(); - } else { - return out << bytes; - } -} - -template MessageContent& MessageImpl::append(T& t) -{ - if (type == VOID) { - //TODO: this is inefficient, probably want to hold on to the stream object - std::stringstream s; - s << bytes; - s << t; - bytes = s.str(); - } else if (type == LIST) { - content.asList().push_back(Variant(t)); - } else { - throw InvalidConversion("<< operator only valid on strings and lists"); - } - return *this; -} - -MessageContent& MessageImpl::operator<<(const std::string& v) { return append(v); } -MessageContent& MessageImpl::operator<<(const char* v) { return append(v); } -MessageContent& MessageImpl::operator<<(bool v) { return append(v); } -MessageContent& MessageImpl::operator<<(int8_t v) { return append(v); } -MessageContent& MessageImpl::operator<<(int16_t v) { return append(v); } -MessageContent& MessageImpl::operator<<(int32_t v) { return append(v); } -MessageContent& MessageImpl::operator<<(int64_t v) { return append(v); } -MessageContent& MessageImpl::operator<<(uint8_t v) { return append(v); } -MessageContent& MessageImpl::operator<<(uint16_t v) { return append(v); } -MessageContent& MessageImpl::operator<<(uint32_t v) { return append(v); } -MessageContent& MessageImpl::operator<<(uint64_t v) { return append(v); } -MessageContent& MessageImpl::operator<<(double v) { return append(v); } -MessageContent& MessageImpl::operator<<(float v) { return append(v); } -MessageContent& MessageImpl::operator=(const std::string& s) -{ - type = VOID; - bytes = s; - return *this; -} -MessageContent& MessageImpl::operator=(const char* c) -{ - type = VOID; - bytes = c; - return *this; -} -MessageContent& MessageImpl::operator=(const Variant::Map& m) -{ - type = MAP; - content = m; - return *this; -} - -MessageContent& MessageImpl::operator=(const Variant::List& l) -{ - type = LIST; - content = l; - return *this; -} - -void MessageImpl::encode(Codec& codec) -{ - if (content.getType() != VOID) { - bytes = EMPTY_STRING; - codec.encode(content, bytes); - } -} - -void MessageImpl::decode(Codec& codec) -{ - codec.decode(bytes, content); - if (content.getType() == MAP) type = MAP; - else if (content.getType() == LIST) type = LIST; - else type = VOID;//TODO: what if codec set some type other than map or list?? -} - -void MessageImpl::setInternalId(void* i) { internalId = i; } -void* MessageImpl::getInternalId() { return internalId; } - -bool MessageImpl::isVoid() const { return type == VOID; } - -const std::string& MessageImpl::asString() const -{ - if (isVoid()) return getBytes(); - else return content.getString();//will throw an error -} -std::string& MessageImpl::asString() -{ - if (isVoid()) return getBytes(); - else return content.getString();//will throw an error -} - -const char* MessageImpl::asChars() const -{ - if (!isVoid()) throw InvalidConversion("Content is of structured type."); - return bytes.data(); -} -size_t MessageImpl::size() const -{ - return bytes.size(); -} - -const Variant::Map& MessageImpl::asMap() const { return content.asMap(); } -Variant::Map& MessageImpl::asMap() -{ - if (isVoid()) { - content = Variant::Map(); - type = MAP; - } - return content.asMap(); -} -bool MessageImpl::isMap() const { return type == MAP; } - -const Variant::List& MessageImpl::asList() const { return content.asList(); } -Variant::List& MessageImpl::asList() -{ - if (isVoid()) { - content = Variant::List(); - type = LIST; - } - return content.asList(); -} -bool MessageImpl::isList() const { return type == LIST; } - -void MessageImpl::clear() { bytes = EMPTY_STRING; content.reset(); type = VOID; } - - Message::Message(const std::string& bytes) : impl(new MessageImpl(bytes)) {} Message::Message(const char* bytes, size_t count) : impl(new MessageImpl(bytes, count)) {} @@ -314,9 +62,6 @@ void Message::encode(Codec& codec) { impl->encode(codec); } void Message::decode(Codec& codec) { impl->decode(codec); } -void Message::setInternalId(void* i) { impl->setInternalId(i); } -void* Message::getInternalId() { return impl->getInternalId(); } - std::ostream& operator<<(std::ostream& out, const MessageContent& content) { return content.print(out); diff --git a/cpp/src/qpid/messaging/MessageImpl.cpp b/cpp/src/qpid/messaging/MessageImpl.cpp new file mode 100644 index 0000000000..3c7f4fa515 --- /dev/null +++ b/cpp/src/qpid/messaging/MessageImpl.cpp @@ -0,0 +1,192 @@ +/* + * + * 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. + * + */ +#include "MessageImpl.h" +#include "qpid/messaging/Message.h" + +namespace qpid { +namespace messaging { + +namespace { +const std::string EMPTY_STRING = ""; +} + +MessageImpl::MessageImpl(const std::string& c) : bytes(c), type(VOID), internalId(0) {} +MessageImpl::MessageImpl(const char* chars, size_t count) : bytes(chars, count), type(VOID), internalId(0) {} + +void MessageImpl::setReplyTo(const Address& d) { replyTo = d; } +const Address& MessageImpl::getReplyTo() const { return replyTo; } + +void MessageImpl::setSubject(const std::string& s) { subject = s; } +const std::string& MessageImpl::getSubject() const { return subject; } + +void MessageImpl::setContentType(const std::string& s) { contentType = s; } +const std::string& MessageImpl::getContentType() const { return contentType; } + +const VariantMap& MessageImpl::getHeaders() const { return headers; } +VariantMap& MessageImpl::getHeaders() { return headers; } + +//should these methods be on MessageContent? +void MessageImpl::setBytes(const std::string& c) { clear(); bytes = c; } +void MessageImpl::setBytes(const char* chars, size_t count) { clear(); bytes.assign(chars, count); } +const std::string& MessageImpl::getBytes() const { return bytes; } +std::string& MessageImpl::getBytes() { return bytes; } + + +Variant& MessageImpl::operator[](const std::string& key) { return asMap()[key]; } + +std::ostream& MessageImpl::print(std::ostream& out) const +{ + if (type == MAP) { + return out << content.asMap(); + } else if (type == LIST) { + return out << content.asList(); + } else { + return out << bytes; + } +} + +template MessageContent& MessageImpl::append(T& t) +{ + if (type == VOID) { + //TODO: this is inefficient, probably want to hold on to the stream object + std::stringstream s; + s << bytes; + s << t; + bytes = s.str(); + } else if (type == LIST) { + content.asList().push_back(Variant(t)); + } else { + throw InvalidConversion("<< operator only valid on strings and lists"); + } + return *this; +} + +MessageContent& MessageImpl::operator<<(const std::string& v) { return append(v); } +MessageContent& MessageImpl::operator<<(const char* v) { return append(v); } +MessageContent& MessageImpl::operator<<(bool v) { return append(v); } +MessageContent& MessageImpl::operator<<(int8_t v) { return append(v); } +MessageContent& MessageImpl::operator<<(int16_t v) { return append(v); } +MessageContent& MessageImpl::operator<<(int32_t v) { return append(v); } +MessageContent& MessageImpl::operator<<(int64_t v) { return append(v); } +MessageContent& MessageImpl::operator<<(uint8_t v) { return append(v); } +MessageContent& MessageImpl::operator<<(uint16_t v) { return append(v); } +MessageContent& MessageImpl::operator<<(uint32_t v) { return append(v); } +MessageContent& MessageImpl::operator<<(uint64_t v) { return append(v); } +MessageContent& MessageImpl::operator<<(double v) { return append(v); } +MessageContent& MessageImpl::operator<<(float v) { return append(v); } +MessageContent& MessageImpl::operator=(const std::string& s) +{ + type = VOID; + bytes = s; + return *this; +} +MessageContent& MessageImpl::operator=(const char* c) +{ + type = VOID; + bytes = c; + return *this; +} +MessageContent& MessageImpl::operator=(const Variant::Map& m) +{ + type = MAP; + content = m; + return *this; +} + +MessageContent& MessageImpl::operator=(const Variant::List& l) +{ + type = LIST; + content = l; + return *this; +} + +void MessageImpl::encode(Codec& codec) +{ + if (content.getType() != VOID) { + bytes = EMPTY_STRING; + codec.encode(content, bytes); + } +} + +void MessageImpl::decode(Codec& codec) +{ + codec.decode(bytes, content); + if (content.getType() == MAP) type = MAP; + else if (content.getType() == LIST) type = LIST; + else type = VOID;//TODO: what if codec set some type other than map or list?? +} + +void MessageImpl::setInternalId(qpid::framing::SequenceNumber i) { internalId = i; } +qpid::framing::SequenceNumber MessageImpl::getInternalId() { return internalId; } + +bool MessageImpl::isVoid() const { return type == VOID; } + +const std::string& MessageImpl::asString() const +{ + if (isVoid()) return getBytes(); + else return content.getString();//will throw an error +} +std::string& MessageImpl::asString() +{ + if (isVoid()) return getBytes(); + else return content.getString();//will throw an error +} + +const char* MessageImpl::asChars() const +{ + if (!isVoid()) throw InvalidConversion("Content is of structured type."); + return bytes.data(); +} +size_t MessageImpl::size() const +{ + return bytes.size(); +} + +const Variant::Map& MessageImpl::asMap() const { return content.asMap(); } +Variant::Map& MessageImpl::asMap() +{ + if (isVoid()) { + content = Variant::Map(); + type = MAP; + } + return content.asMap(); +} +bool MessageImpl::isMap() const { return type == MAP; } + +const Variant::List& MessageImpl::asList() const { return content.asList(); } +Variant::List& MessageImpl::asList() +{ + if (isVoid()) { + content = Variant::List(); + type = LIST; + } + return content.asList(); +} +bool MessageImpl::isList() const { return type == LIST; } + +void MessageImpl::clear() { bytes = EMPTY_STRING; content.reset(); type = VOID; } + +MessageImpl& MessageImplAccess::get(Message& msg) +{ + return *msg.impl; +} + +}} // namespace qpid::messaging diff --git a/cpp/src/qpid/messaging/MessageImpl.h b/cpp/src/qpid/messaging/MessageImpl.h new file mode 100644 index 0000000000..3b8f103688 --- /dev/null +++ b/cpp/src/qpid/messaging/MessageImpl.h @@ -0,0 +1,132 @@ +#ifndef QPID_MESSAGING_MESSAGEIMPL_H +#define QPID_MESSAGING_MESSAGEIMPL_H + +/* + * + * 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. + * + */ +#include "qpid/messaging/Address.h" +#include "qpid/messaging/Codec.h" +#include "qpid/messaging/MessageContent.h" +#include "qpid/messaging/Variant.h" +#include "qpid/framing/SequenceNumber.h" + +namespace qpid { +namespace messaging { + +struct MessageImpl : MessageContent +{ + Address replyTo; + std::string subject; + std::string contentType; + Variant::Map headers; + + std::string bytes; + Variant content;//used only for LIST and MAP + VariantType type;//if LIST, MAP content holds the value; if VOID bytes holds the value + + qpid::framing::SequenceNumber internalId; + + MessageImpl(const std::string& c); + MessageImpl(const char* chars, size_t count); + + void setReplyTo(const Address& d); + const Address& getReplyTo() const; + + void setSubject(const std::string& s); + const std::string& getSubject() const; + + void setContentType(const std::string& s); + const std::string& getContentType() const; + + const Variant::Map& getHeaders() const; + Variant::Map& getHeaders(); + + void setBytes(const std::string& bytes); + void setBytes(const char* chars, size_t count); + const std::string& getBytes() const; + std::string& getBytes(); + + void setInternalId(qpid::framing::SequenceNumber id); + qpid::framing::SequenceNumber getInternalId(); + + bool isVoid() const; + + const std::string& asString() const; + std::string& asString(); + + const char* asChars() const; + size_t size() const; + + const Variant::Map& asMap() const; + Variant::Map& asMap(); + bool isMap() const; + + const Variant::List& asList() const; + Variant::List& asList(); + bool isList() const; + + void clear(); + + void encode(Codec& codec); + void decode(Codec& codec); + + Variant& operator[](const std::string&); + + std::ostream& print(std::ostream& out) const; + + //operator<< for variety of types... + MessageContent& operator<<(const std::string&); + MessageContent& operator<<(const char*); + MessageContent& operator<<(bool); + MessageContent& operator<<(int8_t); + MessageContent& operator<<(int16_t); + MessageContent& operator<<(int32_t); + MessageContent& operator<<(int64_t); + MessageContent& operator<<(uint8_t); + MessageContent& operator<<(uint16_t); + MessageContent& operator<<(uint32_t); + MessageContent& operator<<(uint64_t); + MessageContent& operator<<(double); + MessageContent& operator<<(float); + + //assignment from string, map and list + MessageContent& operator=(const std::string&); + MessageContent& operator=(const char*); + MessageContent& operator=(const Variant::Map&); + MessageContent& operator=(const Variant::List&); + + template MessageContent& append(T& t); +}; + +class Message; + +/** + * Provides access to the internal MessageImpl for a message which is + * useful when accessing any message state not exposed directly + * through the public API. + */ +struct MessageImplAccess +{ + static MessageImpl& get(Message&); +}; + +}} // namespace qpid::messaging + +#endif /*!QPID_MESSAGING_MESSAGEIMPL_H*/ diff --git a/cpp/src/tests/MessagingSessionTests.cpp b/cpp/src/tests/MessagingSessionTests.cpp index 6eebf717bf..be0b6f42d0 100644 --- a/cpp/src/tests/MessagingSessionTests.cpp +++ b/cpp/src/tests/MessagingSessionTests.cpp @@ -322,4 +322,21 @@ QPID_AUTO_TEST_CASE(testListMessage) fix.session.acknowledge(); } +QPID_AUTO_TEST_CASE(testReject) +{ + QueueFixture fix; + Sender sender = fix.session.createSender(fix.queue); + Message m1("reject-me"); + sender.send(m1); + Message m2("accept-me"); + sender.send(m2); + Receiver receiver = fix.session.createReceiver(fix.queue); + Message in = receiver.fetch(5 * qpid::sys::TIME_SEC); + BOOST_CHECK_EQUAL(in.getBytes(), m1.getBytes()); + fix.session.reject(in); + in = receiver.fetch(5 * qpid::sys::TIME_SEC); + BOOST_CHECK_EQUAL(in.getBytes(), m2.getBytes()); + fix.session.acknowledge(); +} + QPID_AUTO_TEST_SUITE_END() -- cgit v1.2.1