summaryrefslogtreecommitdiff
path: root/cpp/lib
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/lib')
-rw-r--r--cpp/lib/Makefile.am1
-rw-r--r--cpp/lib/broker/AccumulatedAck.cpp57
-rw-r--r--cpp/lib/broker/AccumulatedAck.h57
-rw-r--r--cpp/lib/broker/AutoDelete.cpp86
-rw-r--r--cpp/lib/broker/AutoDelete.h55
-rw-r--r--cpp/lib/broker/Binding.h38
-rw-r--r--cpp/lib/broker/Broker.cpp118
-rw-r--r--cpp/lib/broker/Broker.h106
-rw-r--r--cpp/lib/broker/BrokerAdapter.cpp388
-rw-r--r--cpp/lib/broker/BrokerAdapter.h222
-rw-r--r--cpp/lib/broker/BrokerChannel.cpp346
-rw-r--r--cpp/lib/broker/BrokerChannel.h159
-rw-r--r--cpp/lib/broker/BrokerExchange.h51
-rw-r--r--cpp/lib/broker/BrokerMessage.cpp245
-rw-r--r--cpp/lib/broker/BrokerMessage.h137
-rw-r--r--cpp/lib/broker/BrokerMessageBase.h184
-rw-r--r--cpp/lib/broker/BrokerMessageMessage.cpp239
-rw-r--r--cpp/lib/broker/BrokerMessageMessage.h91
-rw-r--r--cpp/lib/broker/BrokerQueue.cpp258
-rw-r--r--cpp/lib/broker/BrokerQueue.h151
-rw-r--r--cpp/lib/broker/BrokerSingleton.cpp36
-rw-r--r--cpp/lib/broker/BrokerSingleton.h52
-rw-r--r--cpp/lib/broker/CompletionHandler.h39
-rw-r--r--cpp/lib/broker/Configuration.cpp252
-rw-r--r--cpp/lib/broker/Configuration.h171
-rw-r--r--cpp/lib/broker/Connection.cpp128
-rw-r--r--cpp/lib/broker/Connection.h108
-rw-r--r--cpp/lib/broker/ConnectionFactory.cpp43
-rw-r--r--cpp/lib/broker/ConnectionFactory.h47
-rw-r--r--cpp/lib/broker/ConnectionToken.h38
-rw-r--r--cpp/lib/broker/Consumer.h37
-rw-r--r--cpp/lib/broker/Content.h64
-rw-r--r--cpp/lib/broker/DeletingTxOp.cpp45
-rw-r--r--cpp/lib/broker/DeletingTxOp.h45
-rw-r--r--cpp/lib/broker/Deliverable.h37
-rw-r--r--cpp/lib/broker/DeliverableMessage.cpp33
-rw-r--r--cpp/lib/broker/DeliverableMessage.h41
-rw-r--r--cpp/lib/broker/DeliveryRecord.cpp91
-rw-r--r--cpp/lib/broker/DeliveryRecord.h64
-rw-r--r--cpp/lib/broker/DirectExchange.cpp73
-rw-r--r--cpp/lib/broker/DirectExchange.h57
-rw-r--r--cpp/lib/broker/ExchangeBinding.cpp35
-rw-r--r--cpp/lib/broker/ExchangeBinding.h48
-rw-r--r--cpp/lib/broker/ExchangeRegistry.cpp76
-rw-r--r--cpp/lib/broker/ExchangeRegistry.h47
-rw-r--r--cpp/lib/broker/FanOutExchange.cpp60
-rw-r--r--cpp/lib/broker/FanOutExchange.h60
-rw-r--r--cpp/lib/broker/HandlerImpl.h71
-rw-r--r--cpp/lib/broker/HeadersExchange.cpp121
-rw-r--r--cpp/lib/broker/HeadersExchange.h65
-rw-r--r--cpp/lib/broker/InMemoryContent.cpp73
-rw-r--r--cpp/lib/broker/InMemoryContent.h45
-rw-r--r--cpp/lib/broker/LazyLoadedContent.cpp68
-rw-r--r--cpp/lib/broker/LazyLoadedContent.h49
-rw-r--r--cpp/lib/broker/Makefile.am96
-rw-r--r--cpp/lib/broker/MessageBuilder.cpp74
-rw-r--r--cpp/lib/broker/MessageBuilder.h57
-rw-r--r--cpp/lib/broker/MessageHandlerImpl.cpp243
-rw-r--r--cpp/lib/broker/MessageHandlerImpl.h130
-rw-r--r--cpp/lib/broker/MessageStore.h140
-rw-r--r--cpp/lib/broker/MessageStoreModule.cpp104
-rw-r--r--cpp/lib/broker/MessageStoreModule.h60
-rw-r--r--cpp/lib/broker/NameGenerator.cpp32
-rw-r--r--cpp/lib/broker/NameGenerator.h39
-rw-r--r--cpp/lib/broker/NullMessageStore.cpp104
-rw-r--r--cpp/lib/broker/NullMessageStore.h59
-rw-r--r--cpp/lib/broker/Prefetch.h42
-rw-r--r--cpp/lib/broker/QueuePolicy.cpp69
-rw-r--r--cpp/lib/broker/QueuePolicy.h54
-rw-r--r--cpp/lib/broker/QueueRegistry.cpp78
-rw-r--r--cpp/lib/broker/QueueRegistry.h96
-rw-r--r--cpp/lib/broker/RecoveryManager.cpp46
-rw-r--r--cpp/lib/broker/RecoveryManager.h45
-rw-r--r--cpp/lib/broker/Reference.cpp54
-rw-r--r--cpp/lib/broker/Reference.h111
-rw-r--r--cpp/lib/broker/TopicExchange.cpp156
-rw-r--r--cpp/lib/broker/TopicExchange.h100
-rw-r--r--cpp/lib/broker/TransactionalStore.h47
-rw-r--r--cpp/lib/broker/TxAck.cpp54
-rw-r--r--cpp/lib/broker/TxAck.h58
-rw-r--r--cpp/lib/broker/TxBuffer.cpp55
-rw-r--r--cpp/lib/broker/TxBuffer.h107
-rw-r--r--cpp/lib/broker/TxOp.h39
-rw-r--r--cpp/lib/broker/TxPublish.cpp60
-rw-r--r--cpp/lib/broker/TxPublish.h80
-rw-r--r--cpp/lib/client/Basic.cpp255
-rw-r--r--cpp/lib/client/Basic.h195
-rw-r--r--cpp/lib/client/ClientAdapter.cpp70
-rw-r--r--cpp/lib/client/ClientAdapter.h66
-rw-r--r--cpp/lib/client/ClientChannel.cpp302
-rw-r--r--cpp/lib/client/ClientChannel.h250
-rw-r--r--cpp/lib/client/ClientExchange.cpp34
-rw-r--r--cpp/lib/client/ClientExchange.h106
-rw-r--r--cpp/lib/client/ClientMessage.cpp162
-rw-r--r--cpp/lib/client/ClientMessage.h125
-rw-r--r--cpp/lib/client/ClientQueue.cpp58
-rw-r--r--cpp/lib/client/ClientQueue.h103
-rw-r--r--cpp/lib/client/Connection.cpp156
-rw-r--r--cpp/lib/client/Connection.h194
-rw-r--r--cpp/lib/client/Connector.cpp188
-rw-r--r--cpp/lib/client/Connector.h98
-rw-r--r--cpp/lib/client/IncomingMessage.cpp172
-rw-r--r--cpp/lib/client/IncomingMessage.h118
-rw-r--r--cpp/lib/client/Makefile.am36
-rw-r--r--cpp/lib/client/MessageListener.cpp24
-rw-r--r--cpp/lib/client/MessageListener.h49
-rw-r--r--cpp/lib/client/MethodBodyInstances.h100
-rw-r--r--cpp/lib/client/ResponseHandler.cpp86
-rw-r--r--cpp/lib/client/ResponseHandler.h68
-rw-r--r--cpp/lib/client/ReturnedMessageHandler.cpp24
-rw-r--r--cpp/lib/client/ReturnedMessageHandler.h49
-rw-r--r--cpp/lib/common/Exception.cpp46
-rw-r--r--cpp/lib/common/Exception.h97
-rw-r--r--cpp/lib/common/ExceptionHolder.cpp32
-rw-r--r--cpp/lib/common/ExceptionHolder.h67
-rw-r--r--cpp/lib/common/Makefile.am142
-rw-r--r--cpp/lib/common/QpidError.cpp42
-rw-r--r--cpp/lib/common/QpidError.h78
-rw-r--r--cpp/lib/common/SharedObject.h55
-rw-r--r--cpp/lib/common/doxygen_mainpage.h45
-rw-r--r--cpp/lib/common/framing/AMQBody.cpp33
-rw-r--r--cpp/lib/common/framing/AMQBody.h59
-rw-r--r--cpp/lib/common/framing/AMQContentBody.cpp43
-rw-r--r--cpp/lib/common/framing/AMQContentBody.h53
-rw-r--r--cpp/lib/common/framing/AMQDataBlock.h42
-rw-r--r--cpp/lib/common/framing/AMQFrame.cpp139
-rw-r--r--cpp/lib/common/framing/AMQFrame.h78
-rw-r--r--cpp/lib/common/framing/AMQHeaderBody.cpp75
-rw-r--r--cpp/lib/common/framing/AMQHeaderBody.h60
-rw-r--r--cpp/lib/common/framing/AMQHeartbeatBody.cpp29
-rw-r--r--cpp/lib/common/framing/AMQHeartbeatBody.h47
-rw-r--r--cpp/lib/common/framing/AMQMethodBody.cpp59
-rw-r--r--cpp/lib/common/framing/AMQMethodBody.h84
-rw-r--r--cpp/lib/common/framing/AMQRequestBody.cpp66
-rw-r--r--cpp/lib/common/framing/AMQRequestBody.h78
-rw-r--r--cpp/lib/common/framing/AMQResponseBody.cpp65
-rw-r--r--cpp/lib/common/framing/AMQResponseBody.h85
-rw-r--r--cpp/lib/common/framing/BasicHeaderProperties.cpp103
-rw-r--r--cpp/lib/common/framing/BasicHeaderProperties.h97
-rw-r--r--cpp/lib/common/framing/BodyHandler.cpp60
-rw-r--r--cpp/lib/common/framing/BodyHandler.h61
-rw-r--r--cpp/lib/common/framing/Buffer.cpp183
-rw-r--r--cpp/lib/common/framing/Buffer.h86
-rw-r--r--cpp/lib/common/framing/ChannelAdapter.cpp99
-rw-r--r--cpp/lib/common/framing/ChannelAdapter.h105
-rw-r--r--cpp/lib/common/framing/FieldTable.cpp150
-rw-r--r--cpp/lib/common/framing/FieldTable.h90
-rw-r--r--cpp/lib/common/framing/FramingContent.cpp75
-rw-r--r--cpp/lib/common/framing/FramingContent.h40
-rw-r--r--cpp/lib/common/framing/HeaderProperties.h46
-rw-r--r--cpp/lib/common/framing/InitiationHandler.cpp24
-rw-r--r--cpp/lib/common/framing/InitiationHandler.h41
-rw-r--r--cpp/lib/common/framing/InputHandler.h39
-rw-r--r--cpp/lib/common/framing/MethodContext.cpp31
-rw-r--r--cpp/lib/common/framing/MethodContext.h80
-rw-r--r--cpp/lib/common/framing/OutputHandler.h39
-rw-r--r--cpp/lib/common/framing/ProtocolInitiation.cpp63
-rw-r--r--cpp/lib/common/framing/ProtocolInitiation.h54
-rw-r--r--cpp/lib/common/framing/ProtocolVersion.cpp44
-rw-r--r--cpp/lib/common/framing/ProtocolVersion.h57
-rw-r--r--cpp/lib/common/framing/ProtocolVersionException.cpp33
-rw-r--r--cpp/lib/common/framing/ProtocolVersionException.h56
-rw-r--r--cpp/lib/common/framing/Proxy.cpp32
-rw-r--r--cpp/lib/common/framing/Proxy.h51
-rw-r--r--cpp/lib/common/framing/Requester.cpp40
-rw-r--r--cpp/lib/common/framing/Requester.h67
-rw-r--r--cpp/lib/common/framing/Responder.cpp43
-rw-r--r--cpp/lib/common/framing/Responder.h61
-rw-r--r--cpp/lib/common/framing/Value.cpp122
-rw-r--r--cpp/lib/common/framing/Value.h171
-rw-r--r--cpp/lib/common/framing/amqp_framing.h36
-rw-r--r--cpp/lib/common/framing/amqp_types.h57
-rw-r--r--cpp/lib/common/framing/amqp_types_full.h36
-rw-r--r--cpp/lib/common/sys/Acceptor.h47
-rw-r--r--cpp/lib/common/sys/AtomicCount.h53
-rw-r--r--cpp/lib/common/sys/Condition.h128
-rw-r--r--cpp/lib/common/sys/ConnectionInputHandler.h45
-rw-r--r--cpp/lib/common/sys/ConnectionInputHandlerFactory.h46
-rw-r--r--cpp/lib/common/sys/ConnectionOutputHandler.h41
-rw-r--r--cpp/lib/common/sys/Module.h161
-rw-r--r--cpp/lib/common/sys/Monitor.h55
-rw-r--r--cpp/lib/common/sys/Mutex.h165
-rw-r--r--cpp/lib/common/sys/ProducerConsumer.cpp141
-rw-r--r--cpp/lib/common/sys/ProducerConsumer.h165
-rw-r--r--cpp/lib/common/sys/Runnable.cpp32
-rw-r--r--cpp/lib/common/sys/Runnable.h50
-rw-r--r--cpp/lib/common/sys/ScopedIncrement.h59
-rw-r--r--cpp/lib/common/sys/ShutdownHandler.h37
-rw-r--r--cpp/lib/common/sys/Socket.h88
-rw-r--r--cpp/lib/common/sys/Thread.h142
-rw-r--r--cpp/lib/common/sys/ThreadSafeQueue.h98
-rw-r--r--cpp/lib/common/sys/Time.cpp60
-rw-r--r--cpp/lib/common/sys/Time.h58
-rw-r--r--cpp/lib/common/sys/TimeoutHandler.h39
-rw-r--r--cpp/lib/common/sys/apr/APRAcceptor.cpp122
-rw-r--r--cpp/lib/common/sys/apr/APRBase.cpp90
-rw-r--r--cpp/lib/common/sys/apr/APRBase.h78
-rw-r--r--cpp/lib/common/sys/apr/APRPool.cpp41
-rw-r--r--cpp/lib/common/sys/apr/APRPool.h50
-rw-r--r--cpp/lib/common/sys/apr/APRSocket.cpp78
-rw-r--r--cpp/lib/common/sys/apr/APRSocket.h48
-rw-r--r--cpp/lib/common/sys/apr/LFProcessor.cpp179
-rw-r--r--cpp/lib/common/sys/apr/LFProcessor.h121
-rw-r--r--cpp/lib/common/sys/apr/LFSessionContext.cpp179
-rw-r--r--cpp/lib/common/sys/apr/LFSessionContext.h90
-rw-r--r--cpp/lib/common/sys/apr/Socket.cpp86
-rw-r--r--cpp/lib/common/sys/apr/Thread.cpp33
-rw-r--r--cpp/lib/common/sys/posix/EventChannel.cpp325
-rw-r--r--cpp/lib/common/sys/posix/EventChannel.h176
-rw-r--r--cpp/lib/common/sys/posix/EventChannelAcceptor.cpp149
-rw-r--r--cpp/lib/common/sys/posix/EventChannelConnection.cpp229
-rw-r--r--cpp/lib/common/sys/posix/EventChannelConnection.h102
-rw-r--r--cpp/lib/common/sys/posix/EventChannelThreads.cpp119
-rw-r--r--cpp/lib/common/sys/posix/EventChannelThreads.h92
-rw-r--r--cpp/lib/common/sys/posix/PosixAcceptor.cpp48
-rw-r--r--cpp/lib/common/sys/posix/Socket.cpp118
-rw-r--r--cpp/lib/common/sys/posix/Thread.cpp28
-rw-r--r--cpp/lib/common/sys/posix/check.cpp39
-rw-r--r--cpp/lib/common/sys/posix/check.h62
219 files changed, 19448 insertions, 0 deletions
diff --git a/cpp/lib/Makefile.am b/cpp/lib/Makefile.am
new file mode 100644
index 0000000000..09a689bc76
--- /dev/null
+++ b/cpp/lib/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = common broker client
diff --git a/cpp/lib/broker/AccumulatedAck.cpp b/cpp/lib/broker/AccumulatedAck.cpp
new file mode 100644
index 0000000000..ff471b0287
--- /dev/null
+++ b/cpp/lib/broker/AccumulatedAck.cpp
@@ -0,0 +1,57 @@
+/*
+ *
+ * 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 "AccumulatedAck.h"
+
+#include <assert.h>
+
+using std::less_equal;
+using std::bind2nd;
+using namespace qpid::broker;
+
+void AccumulatedAck::update(uint64_t firstTag, uint64_t lastTag){
+ assert(firstTag<=lastTag);
+ if (firstTag <= range + 1) {
+ if (lastTag > range) range = lastTag;
+ } else {
+ for (uint64_t tag = firstTag; tag<=lastTag; tag++)
+ individual.push_back(tag);
+ }
+}
+
+void AccumulatedAck::consolidate(){
+ individual.sort();
+ //remove any individual tags that are covered by range
+ individual.remove_if(bind2nd(less_equal<uint64_t>(), range));
+ //update range if possible (using <= allows for duplicates from overlapping ranges)
+ while (individual.front() <= range + 1) {
+ range = individual.front();
+ individual.pop_front();
+ }
+}
+
+void AccumulatedAck::clear(){
+ range = 0;
+ individual.clear();
+}
+
+bool AccumulatedAck::covers(uint64_t tag) const{
+ return tag <= range || find(individual.begin(), individual.end(), tag) != individual.end();
+}
diff --git a/cpp/lib/broker/AccumulatedAck.h b/cpp/lib/broker/AccumulatedAck.h
new file mode 100644
index 0000000000..c4a6e3b79b
--- /dev/null
+++ b/cpp/lib/broker/AccumulatedAck.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _AccumulatedAck_
+#define _AccumulatedAck_
+
+#include <algorithm>
+#include <functional>
+#include <list>
+
+namespace qpid {
+ namespace broker {
+ /**
+ * Keeps an accumulated record of acked messages (by delivery
+ * tag).
+ */
+ class AccumulatedAck {
+ public:
+ /**
+ * If not zero, then everything up to this value has been
+ * acked.
+ */
+ uint64_t range;
+ /**
+ * List of individually acked messages that are not
+ * included in the range marked by 'range'.
+ */
+ std::list<uint64_t> individual;
+
+ AccumulatedAck(uint64_t r) : range(r) {}
+ void update(uint64_t firstTag, uint64_t lastTag);
+ void consolidate();
+ void clear();
+ bool covers(uint64_t tag) const;
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/AutoDelete.cpp b/cpp/lib/broker/AutoDelete.cpp
new file mode 100644
index 0000000000..2037a9c71c
--- /dev/null
+++ b/cpp/lib/broker/AutoDelete.cpp
@@ -0,0 +1,86 @@
+/*
+ *
+ * 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 <AutoDelete.h>
+#include <sys/Time.h>
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+
+AutoDelete::AutoDelete(QueueRegistry* const _registry, uint32_t _period)
+ : registry(_registry), period(_period), stopped(true) { }
+
+void AutoDelete::add(Queue::shared_ptr const queue){
+ Mutex::ScopedLock l(lock);
+ queues.push(queue);
+}
+
+Queue::shared_ptr const AutoDelete::pop(){
+ Queue::shared_ptr next;
+ Mutex::ScopedLock l(lock);
+ if(!queues.empty()){
+ next = queues.front();
+ queues.pop();
+ }
+ return next;
+}
+
+void AutoDelete::process(){
+ Queue::shared_ptr seen;
+ for(Queue::shared_ptr q = pop(); q; q = pop()){
+ if(seen == q){
+ add(q);
+ break;
+ }else if(q->canAutoDelete()){
+ std::string name(q->getName());
+ registry->destroy(name);
+ std::cout << "INFO: Auto-deleted queue named " << name << std::endl;
+ }else{
+ add(q);
+ if(!seen) seen = q;
+ }
+ }
+}
+
+void AutoDelete::run(){
+ Monitor::ScopedLock l(monitor);
+ while(!stopped){
+ process();
+ monitor.wait(period*TIME_MSEC);
+ }
+}
+
+void AutoDelete::start(){
+ Monitor::ScopedLock l(monitor);
+ if(stopped){
+ stopped = false;
+ runner = Thread(this);
+ }
+}
+
+void AutoDelete::stop(){
+ {
+ Monitor::ScopedLock l(monitor);
+ if(stopped) return;
+ stopped = true;
+ }
+ monitor.notify();
+ runner.join();
+}
diff --git a/cpp/lib/broker/AutoDelete.h b/cpp/lib/broker/AutoDelete.h
new file mode 100644
index 0000000000..9034de1730
--- /dev/null
+++ b/cpp/lib/broker/AutoDelete.h
@@ -0,0 +1,55 @@
+#ifndef _AutoDelete_
+#define _AutoDelete_
+/*
+ *
+ * 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 <iostream>
+#include <queue>
+#include <sys/Monitor.h>
+#include <BrokerQueue.h>
+#include <QueueRegistry.h>
+#include <sys/Thread.h>
+
+namespace qpid {
+ namespace broker{
+ class AutoDelete : private qpid::sys::Runnable {
+ qpid::sys::Mutex lock;
+ qpid::sys::Monitor monitor;
+ std::queue<Queue::shared_ptr> queues;
+ QueueRegistry* const registry;
+ uint32_t period;
+ volatile bool stopped;
+ qpid::sys::Thread runner;
+
+ Queue::shared_ptr const pop();
+ void process();
+ virtual void run();
+
+ public:
+ AutoDelete(QueueRegistry* const registry, uint32_t period);
+ void add(Queue::shared_ptr const);
+ void start();
+ void stop();
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/Binding.h b/cpp/lib/broker/Binding.h
new file mode 100644
index 0000000000..16ca223208
--- /dev/null
+++ b/cpp/lib/broker/Binding.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Binding_
+#define _Binding_
+
+#include <FieldTable.h>
+
+namespace qpid {
+ namespace broker {
+ class Binding{
+ public:
+ virtual void cancel() = 0;
+ virtual ~Binding(){}
+ };
+ }
+}
+
+
+#endif
+
diff --git a/cpp/lib/broker/Broker.cpp b/cpp/lib/broker/Broker.cpp
new file mode 100644
index 0000000000..f650452e33
--- /dev/null
+++ b/cpp/lib/broker/Broker.cpp
@@ -0,0 +1,118 @@
+/*
+ *
+ * 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 <iostream>
+#include <memory>
+
+#include "AMQFrame.h"
+#include "DirectExchange.h"
+#include "TopicExchange.h"
+#include "FanOutExchange.h"
+#include "HeadersExchange.h"
+#include "MessageStoreModule.h"
+#include "NullMessageStore.h"
+#include "ProtocolInitiation.h"
+#include "Connection.h"
+#include "sys/ConnectionInputHandler.h"
+#include "sys/ConnectionInputHandlerFactory.h"
+#include "sys/TimeoutHandler.h"
+
+#include "Broker.h"
+
+namespace qpid {
+namespace broker {
+
+const std::string empty;
+const std::string amq_direct("amq.direct");
+const std::string amq_topic("amq.topic");
+const std::string amq_fanout("amq.fanout");
+const std::string amq_match("amq.match");
+
+Broker::Broker(const Configuration& conf) :
+ config(conf),
+ queues(store.get()),
+ timeout(30000),
+ stagingThreshold(0),
+ cleaner(&queues, timeout/10),
+ factory(*this)
+{
+ if (config.getStore().empty())
+ store.reset(new NullMessageStore(config.isTrace()));
+ else
+ store.reset(new MessageStoreModule(config.getStore()));
+
+ exchanges.declare(empty, DirectExchange::typeName); // Default exchange.
+ exchanges.declare(amq_direct, DirectExchange::typeName);
+ exchanges.declare(amq_topic, TopicExchange::typeName);
+ exchanges.declare(amq_fanout, FanOutExchange::typeName);
+ exchanges.declare(amq_match, HeadersExchange::typeName);
+
+ if(store.get()) {
+ RecoveryManager recoverer(queues, exchanges);
+ MessageStoreSettings storeSettings = { getStagingThreshold() };
+ store->recover(recoverer, &storeSettings);
+ }
+
+ cleaner.start();
+}
+
+
+Broker::shared_ptr Broker::create(int16_t port)
+{
+ Configuration config;
+ config.setPort(port);
+ return create(config);
+}
+
+Broker::shared_ptr Broker::create(const Configuration& config) {
+ return Broker::shared_ptr(new Broker(config));
+}
+
+void Broker::run() {
+ getAcceptor().run(&factory);
+}
+
+void Broker::shutdown() {
+ if (acceptor)
+ acceptor->shutdown();
+}
+
+Broker::~Broker() {
+ shutdown();
+}
+
+int16_t Broker::getPort() const { return getAcceptor().getPort(); }
+
+Acceptor& Broker::getAcceptor() const {
+ if (!acceptor)
+ const_cast<Acceptor::shared_ptr&>(acceptor) =
+ Acceptor::create(config.getPort(),
+ config.getConnectionBacklog(),
+ config.getWorkerThreads(),
+ config.isTrace());
+ return *acceptor;
+}
+
+
+const int16_t Broker::DEFAULT_PORT(5672);
+
+
+}} // namespace qpid::broker
+
diff --git a/cpp/lib/broker/Broker.h b/cpp/lib/broker/Broker.h
new file mode 100644
index 0000000000..7c21e90b18
--- /dev/null
+++ b/cpp/lib/broker/Broker.h
@@ -0,0 +1,106 @@
+#ifndef _Broker_
+#define _Broker_
+
+/*
+ *
+ * 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 <Configuration.h>
+#include <ConnectionFactory.h>
+#include <sys/Runnable.h>
+#include <sys/Acceptor.h>
+#include <SharedObject.h>
+#include <MessageStore.h>
+#include <AutoDelete.h>
+#include <ExchangeRegistry.h>
+#include <ConnectionToken.h>
+#include <DirectExchange.h>
+#include <OutputHandler.h>
+#include <ProtocolInitiation.h>
+#include <QueueRegistry.h>
+
+namespace qpid {
+namespace broker {
+/**
+ * A broker instance.
+ */
+class Broker : public sys::Runnable,
+ public SharedObject<Broker>
+{
+ public:
+ static const int16_t DEFAULT_PORT;
+
+ virtual ~Broker();
+
+ /**
+ * Create a broker.
+ * @param port Port to listen on or 0 to pick a port dynamically.
+ */
+ static shared_ptr create(int16_t port = DEFAULT_PORT);
+
+ /**
+ * Create a broker using a Configuration.
+ */
+ static shared_ptr create(const Configuration& config);
+
+ /**
+ * Return listening port. If called before bind this is
+ * the configured port. If called after it is the actual
+ * port, which will be different if the configured port is
+ * 0.
+ */
+ virtual int16_t getPort() const;
+
+ /**
+ * Run the broker. Implements Runnable::run() so the broker
+ * can be run in a separate thread.
+ */
+ virtual void run();
+
+ /** Shut down the broker */
+ virtual void shutdown();
+
+ MessageStore& getStore() { return *store; }
+ QueueRegistry& getQueues() { return queues; }
+ ExchangeRegistry& getExchanges() { return exchanges; }
+ uint32_t getTimeout() { return timeout; }
+ uint64_t getStagingThreshold() { return stagingThreshold; }
+ AutoDelete& getCleaner() { return cleaner; }
+
+ private:
+ Broker(const Configuration& config);
+ sys::Acceptor& getAcceptor() const;
+
+ Configuration config;
+ sys::Acceptor::shared_ptr acceptor;
+ std::auto_ptr<MessageStore> store;
+ QueueRegistry queues;
+ ExchangeRegistry exchanges;
+ uint32_t timeout;
+ uint64_t stagingThreshold;
+ AutoDelete cleaner;
+ ConnectionFactory factory;
+};
+
+}}
+
+
+
+#endif /*!_Broker_*/
diff --git a/cpp/lib/broker/BrokerAdapter.cpp b/cpp/lib/broker/BrokerAdapter.cpp
new file mode 100644
index 0000000000..981801c40e
--- /dev/null
+++ b/cpp/lib/broker/BrokerAdapter.cpp
@@ -0,0 +1,388 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <boost/format.hpp>
+
+#include "BrokerAdapter.h"
+#include "BrokerChannel.h"
+#include "Connection.h"
+#include "AMQMethodBody.h"
+#include "Exception.h"
+
+namespace qpid {
+namespace broker {
+
+using boost::format;
+using namespace qpid;
+using namespace qpid::framing;
+
+typedef std::vector<Queue::shared_ptr> QueueVector;
+
+
+BrokerAdapter::BrokerAdapter(Channel& ch, Connection& c, Broker& b) :
+ CoreRefs(ch, c, b),
+ connection(c),
+ basicHandler(*this),
+ channelHandler(*this),
+ connectionHandler(*this),
+ exchangeHandler(*this),
+ messageHandler(*this),
+ queueHandler(*this),
+ txHandler(*this)
+{}
+
+
+ProtocolVersion BrokerAdapter::getVersion() const {
+ return connection.getVersion();
+}
+
+void BrokerAdapter::ConnectionHandlerImpl::startOk(
+ const MethodContext&, const FieldTable& /*clientProperties*/,
+ const string& /*mechanism*/,
+ const string& /*response*/, const string& /*locale*/)
+{
+ client.tune(
+ 100, connection.getFrameMax(), connection.getHeartbeat());
+}
+
+void BrokerAdapter::ConnectionHandlerImpl::secureOk(
+ const MethodContext&, const string& /*response*/){}
+
+void BrokerAdapter::ConnectionHandlerImpl::tuneOk(
+ const MethodContext&, uint16_t /*channelmax*/,
+ uint32_t framemax, uint16_t heartbeat)
+{
+ connection.setFrameMax(framemax);
+ connection.setHeartbeat(heartbeat);
+}
+
+void BrokerAdapter::ConnectionHandlerImpl::open(
+ const MethodContext& context, const string& /*virtualHost*/,
+ const string& /*capabilities*/, bool /*insist*/)
+{
+ string knownhosts;
+ client.openOk(
+ knownhosts, context.getRequestId());
+}
+
+void BrokerAdapter::ConnectionHandlerImpl::close(
+ const MethodContext& context, uint16_t /*replyCode*/, const string& /*replyText*/,
+ uint16_t /*classId*/, uint16_t /*methodId*/)
+{
+ client.closeOk(context.getRequestId());
+ connection.getOutput().close();
+}
+
+void BrokerAdapter::ConnectionHandlerImpl::closeOk(const MethodContext&){
+ connection.getOutput().close();
+}
+
+void BrokerAdapter::ChannelHandlerImpl::open(
+ const MethodContext& context, const string& /*outOfBand*/){
+ channel.open();
+ // FIXME aconway 2007-01-04: provide valid ID as per ampq 0-9
+ client.openOk(
+ std::string()/* ID */, context.getRequestId());
+}
+
+void BrokerAdapter::ChannelHandlerImpl::flow(const MethodContext&, bool /*active*/){}
+void BrokerAdapter::ChannelHandlerImpl::flowOk(const MethodContext&, bool /*active*/){}
+
+void BrokerAdapter::ChannelHandlerImpl::close(
+ const MethodContext& context, uint16_t /*replyCode*/,
+ const string& /*replyText*/,
+ uint16_t /*classId*/, uint16_t /*methodId*/)
+{
+ client.closeOk(context.getRequestId());
+ // FIXME aconway 2007-01-18: Following line will "delete this". Ugly.
+ connection.closeChannel(channel.getId());
+}
+
+void BrokerAdapter::ChannelHandlerImpl::closeOk(const MethodContext&){}
+
+
+
+void BrokerAdapter::ExchangeHandlerImpl::declare(const MethodContext& context, uint16_t /*ticket*/, const string& exchange, const string& type,
+ bool passive, bool /*durable*/, bool /*autoDelete*/, bool /*internal*/, bool nowait,
+ const FieldTable& /*arguments*/){
+
+ if(passive){
+ if(!broker.getExchanges().get(exchange)) {
+ throw ChannelException(404, "Exchange not found: " + exchange);
+ }
+ }else{
+ try{
+ std::pair<Exchange::shared_ptr, bool> response = broker.getExchanges().declare(exchange, type);
+ if(!response.second && response.first->getType() != type){
+ throw ConnectionException(
+ 530,
+ "Exchange already declared to be of type "
+ + response.first->getType() + ", requested " + type);
+ }
+ }catch(UnknownExchangeTypeException& e){
+ throw ConnectionException(
+ 503, "Exchange type not implemented: " + type);
+ }
+ }
+ if(!nowait){
+ client.declareOk(context.getRequestId());
+ }
+}
+
+void BrokerAdapter::ExchangeHandlerImpl::delete_(const MethodContext& context, uint16_t /*ticket*/,
+ const string& exchange, bool /*ifUnused*/, bool nowait){
+
+ //TODO: implement unused
+ broker.getExchanges().destroy(exchange);
+ if(!nowait) client.deleteOk(context.getRequestId());
+}
+
+void BrokerAdapter::QueueHandlerImpl::declare(const MethodContext& context, uint16_t /*ticket*/, const string& name,
+ bool passive, bool durable, bool exclusive,
+ bool autoDelete, bool nowait, const qpid::framing::FieldTable& arguments){
+ Queue::shared_ptr queue;
+ if (passive && !name.empty()) {
+ queue = connection.getQueue(name, channel.getId());
+ } else {
+ std::pair<Queue::shared_ptr, bool> queue_created =
+ broker.getQueues().declare(
+ name, durable,
+ autoDelete ? connection.getTimeout() : 0,
+ exclusive ? &connection : 0);
+ queue = queue_created.first;
+ assert(queue);
+ if (queue_created.second) { // This is a new queue
+ channel.setDefaultQueue(queue);
+
+ //apply settings & create persistent record if required
+ queue_created.first->create(arguments);
+
+ //add default binding:
+ broker.getExchanges().getDefault()->bind(queue, name, 0);
+ if (exclusive) {
+ connection.exclusiveQueues.push_back(queue);
+ } else if(autoDelete){
+ broker.getCleaner().add(queue);
+ }
+ }
+ }
+ if (exclusive && !queue->isExclusiveOwner(&connection))
+ throw ChannelException(
+ 405,
+ format("Cannot grant exclusive access to queue '%s'")
+ % queue->getName());
+ if (!nowait) {
+ string queueName = queue->getName();
+ client.declareOk(
+ queueName, queue->getMessageCount(), queue->getConsumerCount(),
+ context.getRequestId());
+ }
+}
+
+void BrokerAdapter::QueueHandlerImpl::bind(const MethodContext& context, uint16_t /*ticket*/, const string& queueName,
+ const string& exchangeName, const string& routingKey, bool nowait,
+ const FieldTable& arguments){
+
+ Queue::shared_ptr queue = connection.getQueue(queueName, channel.getId());
+ Exchange::shared_ptr exchange = broker.getExchanges().get(exchangeName);
+ if(exchange){
+ string exchangeRoutingKey = routingKey.empty() && queueName.empty() ? queue->getName() : routingKey;
+ exchange->bind(queue, exchangeRoutingKey, &arguments);
+ if(!nowait) client.bindOk(context.getRequestId());
+ }else{
+ throw ChannelException(
+ 404, "Bind failed. No such exchange: " + exchangeName);
+ }
+}
+
+void
+BrokerAdapter::QueueHandlerImpl::unbind(
+ const MethodContext& context,
+ uint16_t /*ticket*/,
+ const string& queueName,
+ const string& exchangeName,
+ const string& routingKey,
+ const qpid::framing::FieldTable& arguments )
+{
+ Queue::shared_ptr queue = connection.getQueue(queueName, channel.getId());
+ if (!queue.get()) throw ChannelException(404, "Unbind failed. No such exchange: " + exchangeName);
+
+ Exchange::shared_ptr exchange = broker.getExchanges().get(exchangeName);
+ if (!exchange.get()) throw ChannelException(404, "Unbind failed. No such exchange: " + exchangeName);
+
+ exchange->unbind(queue, routingKey, &arguments);
+
+ client.unbindOk(context.getRequestId());
+}
+
+void BrokerAdapter::QueueHandlerImpl::purge(const MethodContext& context, uint16_t /*ticket*/, const string& queueName, bool nowait){
+
+ Queue::shared_ptr queue = connection.getQueue(queueName, channel.getId());
+ int count = queue->purge();
+ if(!nowait) client.purgeOk( count, context.getRequestId());
+}
+
+void BrokerAdapter::QueueHandlerImpl::delete_(const MethodContext& context, uint16_t /*ticket*/, const string& queue,
+ bool ifUnused, bool ifEmpty, bool nowait){
+ ChannelException error(0, "");
+ int count(0);
+ Queue::shared_ptr q = connection.getQueue(queue, channel.getId());
+ if(ifEmpty && q->getMessageCount() > 0){
+ throw ChannelException(406, "Queue not empty.");
+ }else if(ifUnused && q->getConsumerCount() > 0){
+ throw ChannelException(406, "Queue in use.");
+ }else{
+ //remove the queue from the list of exclusive queues if necessary
+ if(q->isExclusiveOwner(&connection)){
+ QueueVector::iterator i = find(connection.exclusiveQueues.begin(), connection.exclusiveQueues.end(), q);
+ if(i < connection.exclusiveQueues.end()) connection.exclusiveQueues.erase(i);
+ }
+ count = q->getMessageCount();
+ q->destroy();
+ broker.getQueues().destroy(queue);
+ }
+
+ if(!nowait)
+ client.deleteOk(count, context.getRequestId());
+}
+
+
+
+
+void BrokerAdapter::BasicHandlerImpl::qos(const MethodContext& context, uint32_t prefetchSize, uint16_t prefetchCount, bool /*global*/){
+ //TODO: handle global
+ channel.setPrefetchSize(prefetchSize);
+ channel.setPrefetchCount(prefetchCount);
+ client.qosOk(context.getRequestId());
+}
+
+void BrokerAdapter::BasicHandlerImpl::consume(
+ const MethodContext& context, uint16_t /*ticket*/,
+ const string& queueName, const string& consumerTag,
+ bool noLocal, bool noAck, bool exclusive,
+ bool nowait, const FieldTable& fields)
+{
+
+ Queue::shared_ptr queue = connection.getQueue(queueName, channel.getId());
+ if(!consumerTag.empty() && channel.exists(consumerTag)){
+ throw ConnectionException(530, "Consumer tags must be unique");
+ }
+
+ string newTag = consumerTag;
+ channel.consume(
+ newTag, queue, !noAck, exclusive, noLocal ? &connection : 0, &fields);
+
+ if(!nowait) client.consumeOk(newTag, context.getRequestId());
+
+ //allow messages to be dispatched if required as there is now a consumer:
+ queue->dispatch();
+}
+
+void BrokerAdapter::BasicHandlerImpl::cancel(const MethodContext& context, const string& consumerTag, bool nowait){
+ channel.cancel(consumerTag);
+
+ if(!nowait) client.cancelOk(consumerTag, context.getRequestId());
+}
+
+void BrokerAdapter::BasicHandlerImpl::publish(
+ const MethodContext& context, uint16_t /*ticket*/,
+ const string& exchangeName, const string& routingKey,
+ bool mandatory, bool immediate)
+{
+
+ Exchange::shared_ptr exchange = exchangeName.empty() ? broker.getExchanges().getDefault() : broker.getExchanges().get(exchangeName);
+ if(exchange){
+ BasicMessage* msg = new BasicMessage(
+ &connection, exchangeName, routingKey, mandatory, immediate,
+ context.methodBody);
+ channel.handlePublish(msg);
+ }else{
+ throw ChannelException(
+ 404, "Exchange not found '" + exchangeName + "'");
+ }
+}
+
+void BrokerAdapter::BasicHandlerImpl::get(const MethodContext& context, uint16_t /*ticket*/, const string& queueName, bool noAck){
+ Queue::shared_ptr queue = connection.getQueue(queueName, channel.getId());
+ if(!connection.getChannel(channel.getId()).get(queue, "", !noAck)){
+ string clusterId;//not used, part of an imatix hack
+
+ client.getEmpty(clusterId, context.getRequestId());
+ }
+}
+
+void BrokerAdapter::BasicHandlerImpl::ack(const MethodContext&, uint64_t deliveryTag, bool multiple){
+ channel.ack(deliveryTag, multiple);
+}
+
+void BrokerAdapter::BasicHandlerImpl::reject(const MethodContext&, uint64_t /*deliveryTag*/, bool /*requeue*/){}
+
+void BrokerAdapter::BasicHandlerImpl::recover(const MethodContext&, bool requeue){
+ channel.recover(requeue);
+}
+
+void BrokerAdapter::TxHandlerImpl::select(const MethodContext& context){
+ channel.begin();
+ client.selectOk(context.getRequestId());
+}
+
+void BrokerAdapter::TxHandlerImpl::commit(const MethodContext& context){
+ channel.commit();
+ client.commitOk(context.getRequestId());
+}
+
+void BrokerAdapter::TxHandlerImpl::rollback(const MethodContext& context){
+
+ channel.rollback();
+ client.rollbackOk(context.getRequestId());
+ channel.recover(false);
+}
+
+void
+BrokerAdapter::ChannelHandlerImpl::ok( const MethodContext& )
+{
+ //no specific action required, generic response handling should be sufficient
+}
+
+
+//
+// Message class method handlers
+//
+void
+BrokerAdapter::ChannelHandlerImpl::ping( const MethodContext& context)
+{
+ client.ok(context.getRequestId());
+ client.pong();
+}
+
+
+void
+BrokerAdapter::ChannelHandlerImpl::pong( const MethodContext& context)
+{
+ client.ok(context.getRequestId());
+}
+
+void
+BrokerAdapter::ChannelHandlerImpl::resume(
+ const MethodContext&,
+ const string& /*channel*/ )
+{
+ assert(0); // FIXME aconway 2007-01-04: 0-9 feature
+}
+
+}} // namespace qpid::broker
+
diff --git a/cpp/lib/broker/BrokerAdapter.h b/cpp/lib/broker/BrokerAdapter.h
new file mode 100644
index 0000000000..2fafbcc180
--- /dev/null
+++ b/cpp/lib/broker/BrokerAdapter.h
@@ -0,0 +1,222 @@
+#ifndef _broker_BrokerAdapter_h
+#define _broker_BrokerAdapter_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "AMQP_ServerOperations.h"
+#include "HandlerImpl.h"
+#include "MessageHandlerImpl.h"
+#include "Exception.h"
+
+namespace qpid {
+namespace broker {
+
+class Channel;
+class Connection;
+class Broker;
+class ChannelHandler;
+class ConnectionHandler;
+class BasicHandler;
+class ExchangeHandler;
+class QueueHandler;
+class TxHandler;
+class MessageHandler;
+class AccessHandler;
+class FileHandler;
+class StreamHandler;
+class DtxHandler;
+class TunnelHandler;
+class MessageHandlerImpl;
+
+/**
+ * Per-channel protocol adapter.
+ *
+ * A container for a collection of AMQP-class adapters that translate
+ * AMQP method bodies into calls on the core Channel, Connection and
+ * Broker objects. Each adapter class also provides a client proxy
+ * to send methods to the peer.
+ *
+ */
+class BrokerAdapter : public CoreRefs, public framing::AMQP_ServerOperations
+{
+ public:
+ BrokerAdapter(Channel& ch, Connection& c, Broker& b);
+
+ framing::ProtocolVersion getVersion() const;
+ ChannelHandler* getChannelHandler() { return &channelHandler; }
+ ConnectionHandler* getConnectionHandler() { return &connectionHandler; }
+ BasicHandler* getBasicHandler() { return &basicHandler; }
+ ExchangeHandler* getExchangeHandler() { return &exchangeHandler; }
+ QueueHandler* getQueueHandler() { return &queueHandler; }
+ TxHandler* getTxHandler() { return &txHandler; }
+ MessageHandler* getMessageHandler() { return &messageHandler; }
+ AccessHandler* getAccessHandler() {
+ throw ConnectionException(540, "Access class not implemented"); }
+ FileHandler* getFileHandler() {
+ throw ConnectionException(540, "File class not implemented"); }
+ StreamHandler* getStreamHandler() {
+ throw ConnectionException(540, "Stream class not implemented"); }
+ DtxHandler* getDtxHandler() {
+ throw ConnectionException(540, "Dtx class not implemented"); }
+ TunnelHandler* getTunnelHandler() {
+ throw ConnectionException(540, "Tunnel class not implemented"); }
+
+ framing::AMQP_ClientProxy& getProxy() { return proxy; }
+
+ private:
+
+ class ConnectionHandlerImpl :
+ public ConnectionHandler,
+ public HandlerImpl<framing::AMQP_ClientProxy::Connection>
+ {
+ public:
+ ConnectionHandlerImpl(BrokerAdapter& parent) : HandlerImplType(parent) {}
+
+ void startOk(const framing::MethodContext& context,
+ const qpid::framing::FieldTable& clientProperties,
+ const std::string& mechanism, const std::string& response,
+ const std::string& locale);
+ void secureOk(const framing::MethodContext& context,
+ const std::string& response);
+ void tuneOk(const framing::MethodContext& context,
+ uint16_t channelMax,
+ uint32_t frameMax, uint16_t heartbeat);
+ void open(const framing::MethodContext& context,
+ const std::string& virtualHost,
+ const std::string& capabilities, bool insist);
+ void close(const framing::MethodContext& context, uint16_t replyCode,
+ const std::string& replyText,
+ uint16_t classId, uint16_t methodId);
+ void closeOk(const framing::MethodContext& context);
+ };
+
+ class ChannelHandlerImpl :
+ public ChannelHandler,
+ public HandlerImpl<framing::AMQP_ClientProxy::Channel>
+ {
+ public:
+ ChannelHandlerImpl(BrokerAdapter& parent) : HandlerImplType(parent) {}
+
+ void open(const framing::MethodContext& context, const std::string& outOfBand);
+ void flow(const framing::MethodContext& context, bool active);
+ void flowOk(const framing::MethodContext& context, bool active);
+ void ok( const framing::MethodContext& context );
+ void ping( const framing::MethodContext& context );
+ void pong( const framing::MethodContext& context );
+ void resume( const framing::MethodContext& context, const std::string& channelId );
+ void close(const framing::MethodContext& context, uint16_t replyCode, const
+ std::string& replyText, uint16_t classId, uint16_t methodId);
+ void closeOk(const framing::MethodContext& context);
+ };
+
+ class ExchangeHandlerImpl :
+ public ExchangeHandler,
+ public HandlerImpl<framing::AMQP_ClientProxy::Exchange>
+ {
+ public:
+ ExchangeHandlerImpl(BrokerAdapter& parent) : HandlerImplType(parent) {}
+
+ void declare(const framing::MethodContext& context, uint16_t ticket,
+ const std::string& exchange, const std::string& type,
+ bool passive, bool durable, bool autoDelete,
+ bool internal, bool nowait,
+ const qpid::framing::FieldTable& arguments);
+ void delete_(const framing::MethodContext& context, uint16_t ticket,
+ const std::string& exchange, bool ifUnused, bool nowait);
+ };
+
+ class QueueHandlerImpl :
+ public QueueHandler,
+ public HandlerImpl<framing::AMQP_ClientProxy::Queue>
+ {
+ public:
+ QueueHandlerImpl(BrokerAdapter& parent) : HandlerImplType(parent) {}
+
+ void declare(const framing::MethodContext& context, uint16_t ticket, const std::string& queue,
+ bool passive, bool durable, bool exclusive,
+ bool autoDelete, bool nowait,
+ const qpid::framing::FieldTable& arguments);
+ void bind(const framing::MethodContext& context, uint16_t ticket, const std::string& queue,
+ const std::string& exchange, const std::string& routingKey,
+ bool nowait, const qpid::framing::FieldTable& arguments);
+ void unbind(const framing::MethodContext& context,
+ uint16_t ticket,
+ const std::string& queue,
+ const std::string& exchange,
+ const std::string& routingKey,
+ const qpid::framing::FieldTable& arguments );
+ void purge(const framing::MethodContext& context, uint16_t ticket, const std::string& queue,
+ bool nowait);
+ void delete_(const framing::MethodContext& context, uint16_t ticket, const std::string& queue,
+ bool ifUnused, bool ifEmpty,
+ bool nowait);
+ };
+
+ class BasicHandlerImpl :
+ public BasicHandler,
+ public HandlerImpl<framing::AMQP_ClientProxy::Basic>
+ {
+ public:
+ BasicHandlerImpl(BrokerAdapter& parent) : HandlerImplType(parent) {}
+
+ void qos(const framing::MethodContext& context, uint32_t prefetchSize,
+ uint16_t prefetchCount, bool global);
+ void consume(
+ const framing::MethodContext& context, uint16_t ticket, const std::string& queue,
+ const std::string& consumerTag, bool noLocal, bool noAck,
+ bool exclusive, bool nowait,
+ const qpid::framing::FieldTable& fields);
+ void cancel(const framing::MethodContext& context, const std::string& consumerTag,
+ bool nowait);
+ void publish(const framing::MethodContext& context, uint16_t ticket,
+ const std::string& exchange, const std::string& routingKey,
+ bool mandatory, bool immediate);
+ void get(const framing::MethodContext& context, uint16_t ticket, const std::string& queue,
+ bool noAck);
+ void ack(const framing::MethodContext& context, uint64_t deliveryTag, bool multiple);
+ void reject(const framing::MethodContext& context, uint64_t deliveryTag, bool requeue);
+ void recover(const framing::MethodContext& context, bool requeue);
+ };
+
+ class TxHandlerImpl :
+ public TxHandler,
+ public HandlerImpl<framing::AMQP_ClientProxy::Tx>
+ {
+ public:
+ TxHandlerImpl(BrokerAdapter& parent) : HandlerImplType(parent) {}
+
+ void select(const framing::MethodContext& context);
+ void commit(const framing::MethodContext& context);
+ void rollback(const framing::MethodContext& context);
+ };
+
+ Connection& connection;
+ BasicHandlerImpl basicHandler;
+ ChannelHandlerImpl channelHandler;
+ ConnectionHandlerImpl connectionHandler;
+ ExchangeHandlerImpl exchangeHandler;
+ MessageHandlerImpl messageHandler;
+ QueueHandlerImpl queueHandler;
+ TxHandlerImpl txHandler;
+
+};
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_BrokerAdapter_h*/
diff --git a/cpp/lib/broker/BrokerChannel.cpp b/cpp/lib/broker/BrokerChannel.cpp
new file mode 100644
index 0000000000..5673a2c42a
--- /dev/null
+++ b/cpp/lib/broker/BrokerChannel.cpp
@@ -0,0 +1,346 @@
+/*
+ *
+ * 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 <assert.h>
+
+#include <iostream>
+#include <sstream>
+#include <algorithm>
+#include <functional>
+
+#include <boost/bind.hpp>
+
+#include "BrokerChannel.h"
+#include "DeletingTxOp.h"
+#include "framing/ChannelAdapter.h"
+#include <QpidError.h>
+#include <DeliverableMessage.h>
+#include <BrokerQueue.h>
+#include <BrokerMessage.h>
+#include <MessageStore.h>
+#include <TxAck.h>
+#include <TxPublish.h>
+#include "BrokerAdapter.h"
+#include "Connection.h"
+
+using std::mem_fun_ref;
+using std::bind2nd;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+
+Channel::Channel(
+ Connection& con, ChannelId id,
+ uint32_t _framesize, MessageStore* const _store,
+ uint64_t _stagingThreshold
+) :
+ ChannelAdapter(id, &con.getOutput(), con.getVersion()),
+ connection(con),
+ currentDeliveryTag(1),
+ transactional(false),
+ prefetchSize(0),
+ prefetchCount(0),
+ framesize(_framesize),
+ tagGenerator("sgen"),
+ accumulatedAck(0),
+ store(_store),
+ messageBuilder(this, _store, _stagingThreshold),
+ opened(id == 0),//channel 0 is automatically open, other must be explicitly opened
+ adapter(new BrokerAdapter(*this, con, con.broker))
+{
+ outstanding.reset();
+}
+
+Channel::~Channel(){
+ close();
+}
+
+bool Channel::exists(const string& consumerTag){
+ return consumers.find(consumerTag) != consumers.end();
+}
+
+// TODO aconway 2007-02-12: Why is connection token passed in instead
+// of using the channel's parent connection?
+void Channel::consume(string& tagInOut, Queue::shared_ptr queue, bool acks,
+ bool exclusive, ConnectionToken* const connection,
+ const FieldTable*)
+{
+ if(tagInOut.empty())
+ tagInOut = tagGenerator.generate();
+ std::auto_ptr<ConsumerImpl> c(
+ new ConsumerImpl(this, tagInOut, queue, connection, acks));
+ queue->consume(c.get(), exclusive);//may throw exception
+ consumers.insert(tagInOut, c.release());
+}
+
+void Channel::cancel(const string& tag){
+ // consumers is a ptr_map so erase will delete the consumer
+ // which will call cancel.
+ ConsumerImplMap::iterator i = consumers.find(tag);
+ if (i != consumers.end())
+ consumers.erase(i);
+}
+
+void Channel::close(){
+ opened = false;
+ consumers.clear();
+ recover(true);
+}
+
+void Channel::begin(){
+ transactional = true;
+}
+
+void Channel::commit(){
+ TxAck txAck(accumulatedAck, unacked);
+ txBuffer.enlist(&txAck);
+ if(txBuffer.prepare(store)){
+ txBuffer.commit();
+ }
+ accumulatedAck.clear();
+}
+
+void Channel::rollback(){
+ txBuffer.rollback();
+ accumulatedAck.clear();
+}
+
+void Channel::deliver(
+ Message::shared_ptr& msg, const string& consumerTag,
+ Queue::shared_ptr& queue, bool ackExpected)
+{
+ Mutex::ScopedLock locker(deliveryLock);
+
+ // Key the delivered messages to the id of the request in which they're sent
+ uint64_t deliveryTag = getNextSendRequestId();
+
+ if(ackExpected){
+ unacked.push_back(DeliveryRecord(msg, queue, consumerTag, deliveryTag));
+ outstanding.size += msg->contentSize();
+ outstanding.count++;
+ }
+ //send deliver method, header and content(s)
+ msg->deliver(*this, consumerTag, deliveryTag, framesize);
+}
+
+bool Channel::checkPrefetch(Message::shared_ptr& msg){
+ Mutex::ScopedLock locker(deliveryLock);
+ bool countOk = !prefetchCount || prefetchCount > unacked.size();
+ bool sizeOk = !prefetchSize || prefetchSize > msg->contentSize() + outstanding.size || unacked.empty();
+ return countOk && sizeOk;
+}
+
+Channel::ConsumerImpl::ConsumerImpl(Channel* _parent, const string& _tag,
+ Queue::shared_ptr _queue,
+ ConnectionToken* const _connection, bool ack
+) : parent(_parent), tag(_tag), queue(_queue), connection(_connection),
+ ackExpected(ack), blocked(false) {}
+
+bool Channel::ConsumerImpl::deliver(Message::shared_ptr& msg){
+ if(!connection || connection != msg->getPublisher()){//check for no_local
+ if(ackExpected && !parent->checkPrefetch(msg)){
+ blocked = true;
+ }else{
+ blocked = false;
+ parent->deliver(msg, tag, queue, ackExpected);
+ return true;
+ }
+ }
+ return false;
+}
+
+Channel::ConsumerImpl::~ConsumerImpl() {
+ cancel();
+}
+
+void Channel::ConsumerImpl::cancel(){
+ if(queue)
+ queue->cancel(this);
+}
+
+void Channel::ConsumerImpl::requestDispatch(){
+ if(blocked)
+ queue->dispatch();
+}
+
+void Channel::handleInlineTransfer(Message::shared_ptr msg)
+{
+ Exchange::shared_ptr exchange =
+ connection.broker.getExchanges().get(msg->getExchange());
+ if(transactional){
+ TxPublish* deliverable = new TxPublish(msg);
+ exchange->route(
+ *deliverable, msg->getRoutingKey(),
+ &(msg->getApplicationHeaders()));
+ txBuffer.enlist(new DeletingTxOp(deliverable));
+ }else{
+ DeliverableMessage deliverable(msg);
+ exchange->route(
+ deliverable, msg->getRoutingKey(),
+ &(msg->getApplicationHeaders()));
+ }
+}
+
+void Channel::handlePublish(Message* _message){
+ Message::shared_ptr message(_message);
+ messageBuilder.initialise(message);
+}
+
+void Channel::handleHeader(AMQHeaderBody::shared_ptr header){
+ messageBuilder.setHeader(header);
+ //at this point, decide based on the size of the message whether we want
+ //to stage it by saving content directly to disk as it arrives
+}
+
+void Channel::handleContent(AMQContentBody::shared_ptr content){
+ messageBuilder.addContent(content);
+}
+
+void Channel::handleHeartbeat(boost::shared_ptr<AMQHeartbeatBody>) {
+ // TODO aconway 2007-01-17: Implement heartbeating.
+}
+
+void Channel::complete(Message::shared_ptr msg) {
+ Exchange::shared_ptr exchange =
+ connection.broker.getExchanges().get(msg->getExchange());
+ assert(exchange.get());
+ if(transactional) {
+ std::auto_ptr<TxPublish> deliverable(new TxPublish(msg));
+ exchange->route(*deliverable, msg->getRoutingKey(),
+ &(msg->getApplicationHeaders()));
+ txBuffer.enlist(new DeletingTxOp(deliverable.release()));
+ } else {
+ DeliverableMessage deliverable(msg);
+ exchange->route(deliverable, msg->getRoutingKey(),
+ &(msg->getApplicationHeaders()));
+ }
+}
+
+void Channel::ack(){
+ ack(getFirstAckRequest(), getLastAckRequest());
+}
+
+// Used by Basic
+void Channel::ack(uint64_t deliveryTag, bool multiple){
+ if (multiple)
+ ack(0, deliveryTag);
+ else
+ ack(deliveryTag, deliveryTag);
+}
+
+void Channel::ack(uint64_t firstTag, uint64_t lastTag){
+ if(transactional){
+ accumulatedAck.update(firstTag, lastTag);
+
+ //TODO: I think the outstanding prefetch size & count should be updated at this point...
+ //TODO: ...this may then necessitate dispatching to consumers
+ }else{
+ Mutex::ScopedLock locker(deliveryLock);//need to synchronize with possible concurrent delivery
+
+ ack_iterator i = find_if(unacked.begin(), unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::matches), lastTag));
+ ack_iterator j = (firstTag == 0) ?
+ unacked.begin() :
+ find_if(unacked.begin(), unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::matches), firstTag));
+
+ if(i == unacked.end()){
+ throw ConnectionException(530, "Received ack for unrecognised delivery tag");
+ }else if(i!=j){
+ ack_iterator end = ++i;
+ for_each(j, end, mem_fun_ref(&DeliveryRecord::discard));
+ unacked.erase(unacked.begin(), end);
+
+ //recalculate the prefetch:
+ outstanding.reset();
+ for_each(unacked.begin(), unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::addTo), &outstanding));
+ }else{
+ i->discard();
+ i->subtractFrom(&outstanding);
+ unacked.erase(i);
+ }
+
+ //if the prefetch limit had previously been reached, there may
+ //be messages that can be now be delivered
+ std::for_each(consumers.begin(), consumers.end(),
+ boost::bind(&ConsumerImpl::requestDispatch, _1));
+ }
+}
+
+void Channel::recover(bool requeue){
+ Mutex::ScopedLock locker(deliveryLock);//need to synchronize with possible concurrent delivery
+
+ if(requeue){
+ outstanding.reset();
+ std::list<DeliveryRecord> copy = unacked;
+ unacked.clear();
+ for_each(copy.begin(), copy.end(), mem_fun_ref(&DeliveryRecord::requeue));
+ }else{
+ for_each(unacked.begin(), unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::redeliver), this));
+ }
+}
+
+bool Channel::get(Queue::shared_ptr queue, const string& destination, bool ackExpected){
+ Message::shared_ptr msg = queue->dequeue();
+ if(msg){
+ Mutex::ScopedLock locker(deliveryLock);
+ uint64_t myDeliveryTag = getNextSendRequestId();
+ msg->sendGetOk(MethodContext(this, msg->getRespondTo()),
+ destination,
+ queue->getMessageCount() + 1, myDeliveryTag,
+ framesize);
+ if(ackExpected){
+ unacked.push_back(DeliveryRecord(msg, queue, myDeliveryTag));
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+void Channel::deliver(Message::shared_ptr& msg, const string& consumerTag,
+ uint64_t deliveryTag)
+{
+ msg->deliver(*this, consumerTag, deliveryTag, framesize);
+}
+
+void Channel::handleMethodInContext(
+ boost::shared_ptr<qpid::framing::AMQMethodBody> method,
+ const MethodContext& context
+)
+{
+ try{
+ if(getId() != 0 && !method->isA<ChannelOpenBody>() && !isOpen()) {
+ std::stringstream out;
+ out << "Attempt to use unopened channel: " << getId();
+ throw ConnectionException(504, out.str());
+ } else {
+ method->invoke(*adapter, context);
+ }
+ }catch(ChannelException& e){
+ adapter->getProxy().getChannel().close(
+ e.code, e.toString(),
+ method->amqpClassId(), method->amqpMethodId());
+ connection.closeChannel(getId());
+ }catch(ConnectionException& e){
+ connection.close(e.code, e.toString(), method->amqpClassId(), method->amqpMethodId());
+ }catch(std::exception& e){
+ connection.close(541/*internal error*/, e.what(), method->amqpClassId(), method->amqpMethodId());
+ }
+}
diff --git a/cpp/lib/broker/BrokerChannel.h b/cpp/lib/broker/BrokerChannel.h
new file mode 100644
index 0000000000..5085783685
--- /dev/null
+++ b/cpp/lib/broker/BrokerChannel.h
@@ -0,0 +1,159 @@
+#ifndef _broker_BrokerChannel_h
+#define _broker_BrokerChannel_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 <list>
+
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/ptr_container/ptr_map.hpp>
+
+#include <AccumulatedAck.h>
+#include <Consumer.h>
+#include <DeliveryRecord.h>
+#include <MessageBuilder.h>
+#include <NameGenerator.h>
+#include <Prefetch.h>
+#include <TxBuffer.h>
+#include "framing/ChannelAdapter.h"
+#include "ChannelOpenBody.h"
+#include "CompletionHandler.h"
+
+namespace qpid {
+namespace broker {
+
+class ConnectionToken;
+class Connection;
+class Queue;
+class BrokerAdapter;
+
+using framing::string;
+
+/**
+ * Maintains state for an AMQP channel. Handles incoming and
+ * outgoing messages for that channel.
+ */
+class Channel : public framing::ChannelAdapter,
+ public CompletionHandler
+{
+ class ConsumerImpl : public Consumer
+ {
+ Channel* parent;
+ const string tag;
+ Queue::shared_ptr queue;
+ ConnectionToken* const connection;
+ const bool ackExpected;
+ bool blocked;
+
+ public:
+ ConsumerImpl(Channel* parent, const string& tag,
+ Queue::shared_ptr queue,
+ ConnectionToken* const connection, bool ack);
+ ~ConsumerImpl();
+ virtual bool deliver(Message::shared_ptr& msg);
+ void cancel();
+ void requestDispatch();
+ };
+
+ typedef boost::ptr_map<string,ConsumerImpl> ConsumerImplMap;
+
+ Connection& connection;
+ uint64_t currentDeliveryTag;
+ Queue::shared_ptr defaultQueue;
+ bool transactional;
+ ConsumerImplMap consumers;
+ uint32_t prefetchSize;
+ uint16_t prefetchCount;
+ Prefetch outstanding;
+ uint32_t framesize;
+ NameGenerator tagGenerator;
+ std::list<DeliveryRecord> unacked;
+ sys::Mutex deliveryLock;
+ TxBuffer txBuffer;
+ AccumulatedAck accumulatedAck;
+ MessageStore* const store;
+ MessageBuilder messageBuilder;//builder for in-progress message
+ bool opened;
+ boost::scoped_ptr<BrokerAdapter> adapter;
+
+ // completion handler for MessageBuilder
+ void complete(Message::shared_ptr msg);
+
+ void deliver(Message::shared_ptr& msg, const string& tag,
+ Queue::shared_ptr& queue, bool ackExpected);
+ bool checkPrefetch(Message::shared_ptr& msg);
+
+ public:
+ Channel(Connection& parent,
+ framing::ChannelId id,
+ uint32_t framesize,
+ MessageStore* const _store = 0,
+ uint64_t stagingThreshold = 0);
+
+ ~Channel();
+
+ bool isOpen() const { return opened; }
+ BrokerAdapter& getAdatper() { return *adapter; }
+
+ void open() { opened = true; }
+ void setDefaultQueue(Queue::shared_ptr queue){ defaultQueue = queue; }
+ Queue::shared_ptr getDefaultQueue() const { return defaultQueue; }
+ uint32_t setPrefetchSize(uint32_t size){ return prefetchSize = size; }
+ uint16_t setPrefetchCount(uint16_t n){ return prefetchCount = n; }
+
+ bool exists(const string& consumerTag);
+
+ /**
+ *@param tagInOut - if empty it is updated with the generated token.
+ */
+ void consume(string& tagInOut, Queue::shared_ptr queue, bool acks,
+ bool exclusive, ConnectionToken* const connection = 0,
+ const framing::FieldTable* = 0);
+ void cancel(const string& tag);
+ bool get(Queue::shared_ptr queue, const std::string& destination, bool ackExpected);
+ void begin();
+ void close();
+ void commit();
+ void rollback();
+ void ack();
+ void ack(uint64_t deliveryTag, bool multiple);
+ void ack(uint64_t deliveryTag, uint64_t endTag);
+ void recover(bool requeue);
+ void deliver(Message::shared_ptr& msg, const string& consumerTag, uint64_t deliveryTag);
+ void handlePublish(Message* msg);
+ void handleHeader(boost::shared_ptr<framing::AMQHeaderBody>);
+ void handleContent(boost::shared_ptr<framing::AMQContentBody>);
+ void handleHeartbeat(boost::shared_ptr<framing::AMQHeartbeatBody>);
+
+ void handleInlineTransfer(Message::shared_ptr msg);
+
+ // For ChannelAdapter
+ void handleMethodInContext(
+ boost::shared_ptr<framing::AMQMethodBody> method,
+ const framing::MethodContext& context);
+};
+
+}} // namespace broker
+
+
+#endif /*!_broker_BrokerChannel_h*/
diff --git a/cpp/lib/broker/BrokerExchange.h b/cpp/lib/broker/BrokerExchange.h
new file mode 100644
index 0000000000..6f4e9e6671
--- /dev/null
+++ b/cpp/lib/broker/BrokerExchange.h
@@ -0,0 +1,51 @@
+#ifndef _broker_BrokerExchange_h
+#define _broker_BrokerExchange_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 <boost/shared_ptr.hpp>
+#include <Deliverable.h>
+#include <BrokerQueue.h>
+#include <FieldTable.h>
+
+namespace qpid {
+ namespace broker {
+ using std::string;
+
+ class Exchange{
+ const string name;
+ public:
+ typedef boost::shared_ptr<Exchange> shared_ptr;
+
+ explicit Exchange(const string& _name) : name(_name){}
+ virtual ~Exchange(){}
+ string getName() { return name; }
+ virtual string getType() = 0;
+ virtual void bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args) = 0;
+ virtual void unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args) = 0;
+ virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args) = 0;
+ };
+ }
+}
+
+
+#endif /*!_broker_BrokerExchange_h*/
diff --git a/cpp/lib/broker/BrokerMessage.cpp b/cpp/lib/broker/BrokerMessage.cpp
new file mode 100644
index 0000000000..91ba3dfec0
--- /dev/null
+++ b/cpp/lib/broker/BrokerMessage.cpp
@@ -0,0 +1,245 @@
+/*
+ *
+ * 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 <boost/cast.hpp>
+
+#include <BrokerMessage.h>
+#include <iostream>
+
+#include <InMemoryContent.h>
+#include <LazyLoadedContent.h>
+#include <MessageStore.h>
+#include <BasicDeliverBody.h>
+#include <BasicGetOkBody.h>
+#include <AMQContentBody.h>
+#include <AMQHeaderBody.h>
+#include "AMQMethodBody.h"
+#include "AMQFrame.h"
+#include "framing/ChannelAdapter.h"
+
+using namespace boost;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+BasicMessage::BasicMessage(
+ const ConnectionToken* const _publisher,
+ const string& _exchange, const string& _routingKey,
+ bool _mandatory, bool _immediate, framing::AMQMethodBody::shared_ptr respondTo
+) :
+ Message(_publisher, _exchange, _routingKey, _mandatory,
+ _immediate, respondTo),
+ size(0)
+{}
+
+// FIXME aconway 2007-02-01: remove.
+// BasicMessage::BasicMessage(Buffer& buffer, bool headersOnly, uint32_t contentChunkSize) :
+// publisher(0), size(0)
+// {
+
+// decode(buffer, headersOnly, contentChunkSize);
+// }
+
+// For tests only.
+BasicMessage::BasicMessage() : size(0)
+{}
+
+BasicMessage::~BasicMessage(){}
+
+void BasicMessage::setHeader(AMQHeaderBody::shared_ptr _header){
+ this->header = _header;
+}
+
+void BasicMessage::addContent(AMQContentBody::shared_ptr data){
+ if (!content.get()) {
+ content = std::auto_ptr<Content>(new InMemoryContent());
+ }
+ content->add(data);
+ size += data->size();
+}
+
+bool BasicMessage::isComplete(){
+ return header.get() && (header->getContentSize() == contentSize());
+}
+
+void BasicMessage::deliver(ChannelAdapter& channel,
+ const string& consumerTag, uint64_t deliveryTag,
+ uint32_t framesize)
+{
+ // CCT -- TODO - Update code generator to take pointer/ not
+ // instance to avoid extra contruction
+ channel.send(
+ new BasicDeliverBody(
+ channel.getVersion(), consumerTag, deliveryTag,
+ getRedelivered(), getExchange(), getRoutingKey()));
+ sendContent(channel, framesize);
+}
+
+void BasicMessage::sendGetOk(const MethodContext& context,
+ const std::string& /*destination*/,
+ uint32_t messageCount,
+ uint64_t deliveryTag,
+ uint32_t framesize)
+{
+ // CCT -- TODO - Update code generator to take pointer/ not
+ // instance to avoid extra contruction
+ context.channel->send(
+ new BasicGetOkBody(
+ context.channel->getVersion(),
+ context.methodBody->getRequestId(),
+ deliveryTag, getRedelivered(), getExchange(),
+ getRoutingKey(), messageCount));
+ sendContent(*context.channel, framesize);
+}
+
+void BasicMessage::sendContent(
+ ChannelAdapter& channel, uint32_t framesize)
+{
+ channel.send(header);
+ Mutex::ScopedLock locker(contentLock);
+ if (content.get())
+ content->send(channel, framesize);
+}
+
+BasicHeaderProperties* BasicMessage::getHeaderProperties(){
+ return boost::polymorphic_downcast<BasicHeaderProperties*>(
+ header->getProperties());
+}
+
+const FieldTable& BasicMessage::getApplicationHeaders(){
+ return getHeaderProperties()->getHeaders();
+}
+
+bool BasicMessage::isPersistent()
+{
+ if(!header) return false;
+ BasicHeaderProperties* props = getHeaderProperties();
+ return props && props->getDeliveryMode() == PERSISTENT;
+}
+
+void BasicMessage::decode(Buffer& buffer, bool headersOnly, uint32_t contentChunkSize)
+{
+ decodeHeader(buffer);
+ if (!headersOnly) decodeContent(buffer, contentChunkSize);
+}
+
+void BasicMessage::decodeHeader(Buffer& buffer)
+{
+ string exchange;
+ string routingKey;
+
+ buffer.getShortString(exchange);
+ buffer.getShortString(routingKey);
+ setRouting(exchange, routingKey);
+
+ uint32_t headerSize = buffer.getLong();
+ AMQHeaderBody::shared_ptr headerBody(new AMQHeaderBody());
+ headerBody->decode(buffer, headerSize);
+ setHeader(headerBody);
+}
+
+void BasicMessage::decodeContent(Buffer& buffer, uint32_t chunkSize)
+{
+ uint64_t expected = expectedContentSize();
+ if (expected != buffer.available()) {
+ std::cout << "WARN: Expected " << expectedContentSize() << " bytes, got " << buffer.available() << std::endl;
+ throw Exception("Cannot decode content, buffer not large enough.");
+ }
+
+ if (!chunkSize || chunkSize > expected) {
+ chunkSize = expected;
+ }
+
+ uint64_t total = 0;
+ while (total < expectedContentSize()) {
+ uint64_t remaining = expected - total;
+ AMQContentBody::shared_ptr contentBody(new AMQContentBody());
+ contentBody->decode(buffer, remaining < chunkSize ? remaining : chunkSize);
+ addContent(contentBody);
+ total += chunkSize;
+ }
+}
+
+void BasicMessage::encode(Buffer& buffer)
+{
+ encodeHeader(buffer);
+ encodeContent(buffer);
+}
+
+void BasicMessage::encodeHeader(Buffer& buffer)
+{
+ buffer.putShortString(getExchange());
+ buffer.putShortString(getRoutingKey());
+ buffer.putLong(header->size());
+ header->encode(buffer);
+}
+
+void BasicMessage::encodeContent(Buffer& buffer)
+{
+ Mutex::ScopedLock locker(contentLock);
+ if (content.get()) content->encode(buffer);
+}
+
+uint32_t BasicMessage::encodedSize()
+{
+ return encodedHeaderSize() + encodedContentSize();
+}
+
+uint32_t BasicMessage::encodedContentSize()
+{
+ Mutex::ScopedLock locker(contentLock);
+ return content.get() ? content->size() : 0;
+}
+
+uint32_t BasicMessage::encodedHeaderSize()
+{
+ return getExchange().size() + 1
+ + getRoutingKey().size() + 1
+ + header->size() + 4;//4 extra bytes for size
+}
+
+uint64_t BasicMessage::expectedContentSize()
+{
+ return header.get() ? header->getContentSize() : 0;
+}
+
+void BasicMessage::releaseContent(MessageStore* store)
+{
+ Mutex::ScopedLock locker(contentLock);
+ if (!isPersistent() && getPersistenceId() == 0) {
+ store->stage(this);
+ }
+ if (!content.get() || content->size() > 0) {
+ // FIXME aconway 2007-02-07: handle MessageMessage.
+ //set content to lazy loading mode (but only if there is stored content):
+
+ //Note: the LazyLoadedContent instance contains a raw pointer to the message, however it is
+ // then set as a member of that message so its lifetime is guaranteed to be no longer than
+ // that of the message itself
+ content = std::auto_ptr<Content>(
+ new LazyLoadedContent(store, this, expectedContentSize()));
+ }
+}
+
+void BasicMessage::setContent(std::auto_ptr<Content>& _content)
+{
+ Mutex::ScopedLock locker(contentLock);
+ content = _content;
+}
diff --git a/cpp/lib/broker/BrokerMessage.h b/cpp/lib/broker/BrokerMessage.h
new file mode 100644
index 0000000000..fcb104edbb
--- /dev/null
+++ b/cpp/lib/broker/BrokerMessage.h
@@ -0,0 +1,137 @@
+#ifndef _broker_BrokerMessage_h
+#define _broker_BrokerMessage_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 <memory>
+#include <boost/shared_ptr.hpp>
+
+#include <BrokerMessageBase.h>
+#include <BasicHeaderProperties.h>
+#include <ConnectionToken.h>
+#include <Content.h>
+#include <Mutex.h>
+#include <TxBuffer.h>
+
+namespace qpid {
+
+namespace framing {
+class MethodContext;
+class ChannelAdapter;
+class AMQHeaderBody;
+}
+
+namespace broker {
+
+class MessageStore;
+using framing::string;
+
+/**
+ * Represents an AMQP message, i.e. a header body, a list of
+ * content bodies and some details about the publication
+ * request.
+ */
+class BasicMessage : public Message {
+ boost::shared_ptr<framing::AMQHeaderBody> header;
+ std::auto_ptr<Content> content;
+ sys::Mutex contentLock;
+ uint64_t size;
+
+ void sendContent(framing::ChannelAdapter&, uint32_t framesize);
+
+ public:
+ typedef boost::shared_ptr<BasicMessage> shared_ptr;
+
+ BasicMessage(const ConnectionToken* const publisher,
+ const string& exchange, const string& routingKey,
+ bool mandatory, bool immediate,
+ boost::shared_ptr<framing::AMQMethodBody> respondTo);
+ BasicMessage();
+ ~BasicMessage();
+ void setHeader(boost::shared_ptr<framing::AMQHeaderBody> header);
+ void addContent(framing::AMQContentBody::shared_ptr data);
+ bool isComplete();
+
+ void deliver(framing::ChannelAdapter&,
+ const string& consumerTag,
+ uint64_t deliveryTag,
+ uint32_t framesize);
+
+ void sendGetOk(const framing::MethodContext&,
+ const std::string& destination,
+ uint32_t messageCount,
+ uint64_t deliveryTag,
+ uint32_t framesize);
+
+ framing::BasicHeaderProperties* getHeaderProperties();
+ const framing::FieldTable& getApplicationHeaders();
+ bool isPersistent();
+ uint64_t contentSize() const { return size; }
+
+ void decode(framing::Buffer& buffer, bool headersOnly = false,
+ uint32_t contentChunkSize = 0);
+ void decodeHeader(framing::Buffer& buffer);
+ void decodeContent(framing::Buffer& buffer, uint32_t contentChunkSize = 0);
+
+ void encode(framing::Buffer& buffer);
+ void encodeHeader(framing::Buffer& buffer);
+ void encodeContent(framing::Buffer& buffer);
+ /**
+ * @returns the size of the buffer needed to encode this
+ * message in its entirety
+ */
+ uint32_t encodedSize();
+ /**
+ * @returns the size of the buffer needed to encode the
+ * 'header' of this message (not just the header frame,
+ * but other meta data e.g.routing key and exchange)
+ */
+ uint32_t encodedHeaderSize();
+ /**
+ * @returns the size of the buffer needed to encode the
+ * (possibly partial) content held by this message
+ */
+ uint32_t encodedContentSize();
+ /**
+ * Releases the in-memory content data held by this
+ * message. Must pass in a store from which the data can
+ * be reloaded.
+ */
+ void releaseContent(MessageStore* store);
+ /**
+ * If headers have been received, returns the expected
+ * content size else returns 0.
+ */
+ uint64_t expectedContentSize();
+ /**
+ * Sets the 'content' implementation of this message (the
+ * message controls the lifecycle of the content instance
+ * it uses).
+ */
+ void setContent(std::auto_ptr<Content>& content);
+};
+
+}
+}
+
+
+#endif /*!_broker_BrokerMessage_h*/
diff --git a/cpp/lib/broker/BrokerMessageBase.h b/cpp/lib/broker/BrokerMessageBase.h
new file mode 100644
index 0000000000..709369ae2f
--- /dev/null
+++ b/cpp/lib/broker/BrokerMessageBase.h
@@ -0,0 +1,184 @@
+#ifndef _broker_BrokerMessageBase_h
+#define _broker_BrokerMessageBase_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 <string>
+#include <boost/shared_ptr.hpp>
+#include "Content.h"
+#include "framing/amqp_types.h"
+
+namespace qpid {
+
+namespace framing {
+class MethodContext;
+class ChannelAdapter;
+class BasicHeaderProperties;
+class FieldTable;
+class AMQMethodBody;
+class AMQContentBody;
+class AMQHeaderBody;
+}
+
+
+namespace broker {
+class ConnectionToken;
+class MessageStore;
+
+/**
+ * Base class for all types of internal broker messages
+ * abstracting away the operations
+ * TODO; AMS: for the moment this is mostly a placeholder
+ */
+class Message {
+ public:
+ typedef boost::shared_ptr<Message> shared_ptr;
+ typedef boost::shared_ptr<framing::AMQMethodBody> AMQMethodBodyPtr;
+
+
+ Message(const ConnectionToken* publisher_,
+ const std::string& _exchange,
+ const std::string& _routingKey,
+ bool _mandatory, bool _immediate,
+ AMQMethodBodyPtr respondTo_) :
+ publisher(publisher_),
+ exchange(_exchange),
+ routingKey(_routingKey),
+ mandatory(_mandatory),
+ immediate(_immediate),
+ persistenceId(0),
+ redelivered(false),
+ respondTo(respondTo_)
+ {}
+
+ Message() :
+ mandatory(false),
+ immediate(false),
+ persistenceId(0),
+ redelivered(false)
+ {}
+
+ virtual ~Message() {};
+
+ // Accessors
+ const std::string& getRoutingKey() const { return routingKey; }
+ const std::string& getExchange() const { return exchange; }
+ uint64_t getPersistenceId() const { return persistenceId; }
+ bool getRedelivered() const { return redelivered; }
+ AMQMethodBodyPtr getRespondTo() const { return respondTo; }
+
+ void setRouting(const std::string& _exchange, const std::string& _routingKey)
+ { exchange = _exchange; routingKey = _routingKey; }
+ void setPersistenceId(uint64_t _persistenceId) { persistenceId = _persistenceId; } // XXXX: Only used in tests?
+ void redeliver() { redelivered = true; }
+
+ /**
+ * Used to deliver the message from the queue
+ */
+ virtual void deliver(framing::ChannelAdapter& channel,
+ const std::string& consumerTag,
+ uint64_t deliveryTag,
+ uint32_t framesize) = 0;
+ /**
+ * Used to return a message in response to a get from a queue
+ */
+ virtual void sendGetOk(const framing::MethodContext& context,
+ const std::string& destination,
+ uint32_t messageCount,
+ uint64_t deliveryTag,
+ uint32_t framesize) = 0;
+
+ virtual bool isComplete() = 0;
+
+ virtual uint64_t contentSize() const = 0;
+ // FIXME aconway 2007-02-06: Get rid of BasicHeaderProperties
+ // at this level. Expose only generic properties available from both
+ // message types (e.g. getApplicationHeaders below).
+ //
+ virtual framing::BasicHeaderProperties* getHeaderProperties() = 0;
+ virtual const framing::FieldTable& getApplicationHeaders() = 0;
+ virtual bool isPersistent() = 0;
+ virtual const ConnectionToken* getPublisher() const {
+ return publisher;
+ }
+
+ virtual void encode(framing::Buffer& /*buffer*/) {}; // XXXX: Only used in tests?
+ virtual void encodeHeader(framing::Buffer& /*buffer*/) {}; // XXXX: Only used in tests?
+
+ /**
+ * @returns the size of the buffer needed to encode this
+ * message in its entirety
+ *
+ * XXXX: Only used in tests?
+ */
+ virtual uint32_t encodedSize() = 0;
+ /**
+ * @returns the size of the buffer needed to encode the
+ * 'header' of this message (not just the header frame,
+ * but other meta data e.g.routing key and exchange)
+ *
+ * XXXX: Only used in tests?
+ */
+ virtual uint32_t encodedHeaderSize() = 0;
+ /**
+ * @returns the size of the buffer needed to encode the
+ * (possibly partial) content held by this message
+ */
+ virtual uint32_t encodedContentSize() = 0;
+ /**
+ * If headers have been received, returns the expected
+ * content size else returns 0.
+ */
+ virtual uint64_t expectedContentSize() = 0;
+
+ // TODO: AMS 29/1/2007 Don't think these are really part of base class
+
+ /**
+ * Sets the 'content' implementation of this message (the
+ * message controls the lifecycle of the content instance
+ * it uses).
+ */
+ virtual void setContent(std::auto_ptr<Content>& /*content*/) {};
+ virtual void setHeader(boost::shared_ptr<framing::AMQHeaderBody>) {};
+ virtual void addContent(boost::shared_ptr<framing::AMQContentBody>) {};
+ /**
+ * Releases the in-memory content data held by this
+ * message. Must pass in a store from which the data can
+ * be reloaded.
+ */
+ virtual void releaseContent(MessageStore* /*store*/) {};
+
+ private:
+ const ConnectionToken* publisher;
+ std::string exchange;
+ std::string routingKey;
+ const bool mandatory;
+ const bool immediate;
+ uint64_t persistenceId;
+ bool redelivered;
+ AMQMethodBodyPtr respondTo;
+};
+
+}}
+
+
+#endif /*!_broker_BrokerMessage_h*/
diff --git a/cpp/lib/broker/BrokerMessageMessage.cpp b/cpp/lib/broker/BrokerMessageMessage.cpp
new file mode 100644
index 0000000000..3449078d70
--- /dev/null
+++ b/cpp/lib/broker/BrokerMessageMessage.cpp
@@ -0,0 +1,239 @@
+/*
+ *
+ * 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 "QpidError.h"
+#include "BrokerMessageMessage.h"
+#include "ChannelAdapter.h"
+#include "MessageTransferBody.h"
+#include "MessageOpenBody.h"
+#include "MessageCloseBody.h"
+#include "MessageAppendBody.h"
+#include "Reference.h"
+#include "framing/FieldTable.h"
+#include "framing/BasicHeaderProperties.h"
+
+#include <algorithm>
+
+using namespace std;
+using namespace qpid::framing;
+
+namespace qpid {
+namespace broker {
+
+MessageMessage::MessageMessage(
+ ConnectionToken* publisher, RequestId requestId_, TransferPtr transfer_
+) : Message(publisher, transfer_->getDestination(),
+ transfer_->getRoutingKey(),
+ transfer_->getMandatory(),
+ transfer_->getImmediate(),
+ transfer_),
+ requestId(requestId_),
+ transfer(transfer_)
+{}
+
+MessageMessage::MessageMessage(
+ ConnectionToken* publisher, RequestId requestId_, TransferPtr transfer_,
+ ReferencePtr reference_
+) : Message(publisher, transfer_->getDestination(),
+ transfer_->getRoutingKey(),
+ transfer_->getMandatory(),
+ transfer_->getImmediate(),
+ transfer_),
+ requestId(requestId_),
+ transfer(transfer_),
+ reference(reference_)
+{}
+
+// TODO: astitcher 1-Mar-2007: This code desperately needs better factoring
+void MessageMessage::transferMessage(
+ framing::ChannelAdapter& channel,
+ const std::string& consumerTag,
+ uint32_t framesize)
+{
+ const framing::Content& body = transfer->getBody();
+
+ // Send any reference data
+ if (!body.isInline()){
+ // Open
+ channel.send(new MessageOpenBody(channel.getVersion(), reference->getId()));
+ // Appends
+ for(Reference::Appends::const_iterator a = reference->getAppends().begin();
+ a != reference->getAppends().end();
+ ++a) {
+ uint32_t sizeleft = (*a)->size();
+ const string& content = (*a)->getBytes();
+ // Calculate overhead bytes
+ // Assume that the overhead is constant as the reference name doesn't change
+ uint32_t overhead = sizeleft - content.size();
+ string::size_type contentStart = 0;
+ while (sizeleft) {
+ string::size_type contentSize = sizeleft <= framesize ? sizeleft : framesize-overhead;
+ channel.send(new MessageAppendBody(channel.getVersion(), reference->getId(),
+ string(content, contentStart, contentSize)));
+ sizeleft -= contentSize;
+ contentStart += contentSize;
+ }
+ }
+ }
+
+ // The transfer
+ if ( transfer->size()<=framesize ) {
+ channel.send(
+ new MessageTransferBody(channel.getVersion(),
+ transfer->getTicket(),
+ consumerTag,
+ getRedelivered(),
+ transfer->getImmediate(),
+ transfer->getTtl(),
+ transfer->getPriority(),
+ transfer->getTimestamp(),
+ transfer->getDeliveryMode(),
+ transfer->getExpiration(),
+ getExchange(),
+ getRoutingKey(),
+ transfer->getMessageId(),
+ transfer->getCorrelationId(),
+ transfer->getReplyTo(),
+ transfer->getContentType(),
+ transfer->getContentEncoding(),
+ transfer->getUserId(),
+ transfer->getAppId(),
+ transfer->getTransactionId(),
+ transfer->getSecurityToken(),
+ transfer->getApplicationHeaders(),
+ body,
+ transfer->getMandatory()));
+ } else {
+ // Thing to do here is to construct a simple reference message then deliver that instead
+ // fragmentation will be taken care of in the delivery if necessary;
+ string content = body.getValue();
+ string refname = "dummy";
+ TransferPtr newTransfer(
+ new MessageTransferBody(channel.getVersion(),
+ transfer->getTicket(),
+ consumerTag,
+ getRedelivered(),
+ transfer->getImmediate(),
+ transfer->getTtl(),
+ transfer->getPriority(),
+ transfer->getTimestamp(),
+ transfer->getDeliveryMode(),
+ transfer->getExpiration(),
+ getExchange(),
+ getRoutingKey(),
+ transfer->getMessageId(),
+ transfer->getCorrelationId(),
+ transfer->getReplyTo(),
+ transfer->getContentType(),
+ transfer->getContentEncoding(),
+ transfer->getUserId(),
+ transfer->getAppId(),
+ transfer->getTransactionId(),
+ transfer->getSecurityToken(),
+ transfer->getApplicationHeaders(),
+ framing::Content(REFERENCE, refname),
+ transfer->getMandatory()));
+ ReferencePtr newRef(new Reference(refname));
+ Reference::AppendPtr newAppend(new MessageAppendBody(channel.getVersion(), refname, content));
+ newRef->append(newAppend);
+ MessageMessage newMsg(const_cast<ConnectionToken*>(getPublisher()), 0, newTransfer, newRef);
+ newMsg.transferMessage(channel, consumerTag, framesize);
+ return;
+ }
+ // Close any reference data
+ if (!body.isInline()){
+ // Close
+ channel.send(new MessageCloseBody(channel.getVersion(), reference->getId()));
+ }
+}
+
+void MessageMessage::deliver(
+ framing::ChannelAdapter& channel,
+ const std::string& consumerTag,
+ uint64_t /*deliveryTag*/,
+ uint32_t framesize)
+{
+ transferMessage(channel, consumerTag, framesize);
+}
+
+void MessageMessage::sendGetOk(
+ const framing::MethodContext& context,
+ const std::string& destination,
+ uint32_t /*messageCount*/,
+ uint64_t /*deliveryTag*/,
+ uint32_t framesize)
+{
+ framing::ChannelAdapter* channel = context.channel;
+ transferMessage(*channel, destination, framesize);
+}
+
+bool MessageMessage::isComplete()
+{
+ return true;
+}
+
+uint64_t MessageMessage::contentSize() const
+{
+ if (transfer->getBody().isInline())
+ return transfer->getBody().getValue().size();
+ else
+ return reference->getSize();
+}
+
+qpid::framing::BasicHeaderProperties* MessageMessage::getHeaderProperties()
+{
+ return 0; // FIXME aconway 2007-02-05:
+}
+
+const FieldTable& MessageMessage::getApplicationHeaders()
+{
+ return transfer->getApplicationHeaders();
+}
+bool MessageMessage::isPersistent()
+{
+ return transfer->getDeliveryMode() == PERSISTENT;
+}
+
+uint32_t MessageMessage::encodedSize()
+{
+ THROW_QPID_ERROR(INTERNAL_ERROR, "Unfinished");
+ return 0; // FIXME aconway 2007-02-05:
+}
+
+uint32_t MessageMessage::encodedHeaderSize()
+{
+ THROW_QPID_ERROR(INTERNAL_ERROR, "Unfinished");
+ return 0; // FIXME aconway 2007-02-05:
+}
+
+uint32_t MessageMessage::encodedContentSize()
+{
+ THROW_QPID_ERROR(INTERNAL_ERROR, "Unfinished");
+ return 0; // FIXME aconway 2007-02-05:
+}
+
+uint64_t MessageMessage::expectedContentSize()
+{
+ THROW_QPID_ERROR(INTERNAL_ERROR, "Unfinished");
+ return 0; // FIXME aconway 2007-02-05:
+}
+
+
+}} // namespace qpid::broker
diff --git a/cpp/lib/broker/BrokerMessageMessage.h b/cpp/lib/broker/BrokerMessageMessage.h
new file mode 100644
index 0000000000..8a2ff3a063
--- /dev/null
+++ b/cpp/lib/broker/BrokerMessageMessage.h
@@ -0,0 +1,91 @@
+#ifndef _broker_BrokerMessageMessage_h
+#define _broker_BrokerMessageMessage_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 "BrokerMessageBase.h"
+#include "MessageTransferBody.h"
+#include "amqp_types.h"
+
+#include <vector>
+
+namespace qpid {
+
+namespace framing {
+class MessageTransferBody;
+}
+
+namespace broker {
+class ConnectionToken;
+class Reference;
+
+class MessageMessage: public Message{
+ public:
+ typedef boost::shared_ptr<MessageMessage> shared_ptr;
+ typedef boost::shared_ptr<framing::MessageTransferBody> TransferPtr;
+ typedef boost::shared_ptr<Reference> ReferencePtr;
+
+ MessageMessage(ConnectionToken* publisher, framing::RequestId, TransferPtr transfer);
+ MessageMessage(ConnectionToken* publisher, framing::RequestId, TransferPtr transfer, ReferencePtr reference);
+
+ // Default destructor okay
+
+ framing::RequestId getRequestId() {return requestId; }
+ TransferPtr getTransfer() { return transfer; }
+ ReferencePtr getReference() { return reference; }
+
+ void deliver(framing::ChannelAdapter& channel,
+ const std::string& consumerTag,
+ uint64_t deliveryTag,
+ uint32_t framesize);
+
+ void sendGetOk(const framing::MethodContext& context,
+ const std::string& destination,
+ uint32_t messageCount,
+ uint64_t deliveryTag,
+ uint32_t framesize);
+
+ bool isComplete();
+
+ uint64_t contentSize() const;
+ framing::BasicHeaderProperties* getHeaderProperties();
+ const framing::FieldTable& getApplicationHeaders();
+ bool isPersistent();
+
+ uint32_t encodedSize();
+ uint32_t encodedHeaderSize();
+ uint32_t encodedContentSize();
+ uint64_t expectedContentSize();
+
+ private:
+ void transferMessage(framing::ChannelAdapter& channel,
+ const std::string& consumerTag,
+ uint32_t framesize);
+
+ framing::RequestId requestId;
+ const TransferPtr transfer;
+ const ReferencePtr reference;
+};
+
+}}
+
+
+#endif /*!_broker_BrokerMessage_h*/
diff --git a/cpp/lib/broker/BrokerQueue.cpp b/cpp/lib/broker/BrokerQueue.cpp
new file mode 100644
index 0000000000..31309bd6c5
--- /dev/null
+++ b/cpp/lib/broker/BrokerQueue.cpp
@@ -0,0 +1,258 @@
+/*
+ *
+ * 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 <boost/format.hpp>
+
+#include <BrokerQueue.h>
+#include <MessageStore.h>
+#include <sys/Monitor.h>
+#include <sys/Time.h>
+#include <iostream>
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+using namespace qpid::framing;
+using boost::format;
+
+Queue::Queue(const string& _name, uint32_t _autodelete,
+ MessageStore* const _store,
+ const ConnectionToken* const _owner) :
+
+ name(_name),
+ autodelete(_autodelete),
+ store(_store),
+ owner(_owner),
+ queueing(false),
+ dispatching(false),
+ next(0),
+ lastUsed(0),
+ exclusive(0),
+ persistenceId(0)
+{
+ if(autodelete) lastUsed = now()/TIME_MSEC;
+}
+
+Queue::~Queue(){
+ for(Binding* b = bindings.front(); !bindings.empty(); b = bindings.front()){
+ b->cancel();
+ bindings.pop();
+ }
+}
+
+void Queue::bound(Binding* b){
+ bindings.push(b);
+}
+
+void Queue::deliver(Message::shared_ptr& msg){
+ enqueue(0, msg, 0);
+ process(msg);
+}
+
+void Queue::recover(Message::shared_ptr& msg){
+ push(msg);
+ if (store && msg->expectedContentSize() != msg->encodedContentSize()) {
+ //content has not been loaded, need to ensure that lazy loading mode is set:
+ //TODO: find a nicer way to do this
+ msg->releaseContent(store);
+ }
+}
+
+void Queue::process(Message::shared_ptr& msg){
+ Mutex::ScopedLock locker(lock);
+ if(queueing || !dispatch(msg)){
+ push(msg);
+ }
+}
+
+bool Queue::dispatch(Message::shared_ptr& msg){
+ if(consumers.empty()){
+ return false;
+ }else if(exclusive){
+ if(!exclusive->deliver(msg)){
+ std::cout << "WARNING: Dropping undeliverable message from queue with exclusive consumer." << std::endl;
+ }
+ return true;
+ }else{
+ //deliver to next consumer
+ next = next % consumers.size();
+ Consumer* c = consumers[next];
+ int start = next;
+ while(c){
+ next++;
+ if(c->deliver(msg)) return true;
+
+ next = next % consumers.size();
+ c = next == start ? 0 : consumers[next];
+ }
+ return false;
+ }
+}
+
+bool Queue::startDispatching(){
+ Mutex::ScopedLock locker(lock);
+ if(queueing && !dispatching){
+ dispatching = true;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+void Queue::dispatch(){
+ bool proceed = startDispatching();
+ while(proceed){
+ Mutex::ScopedLock locker(lock);
+ if(!messages.empty() && dispatch(messages.front())){
+ pop();
+ }else{
+ dispatching = false;
+ proceed = false;
+ queueing = !messages.empty();
+ }
+ }
+}
+
+void Queue::consume(Consumer* c, bool requestExclusive){
+ Mutex::ScopedLock locker(lock);
+ if(exclusive)
+ throw ChannelException(
+ 403, format("Queue '%s' has an exclusive consumer."
+ " No more consumers allowed.") % getName());
+ if(requestExclusive) {
+ if(!consumers.empty())
+ throw ChannelException(
+ 403, format("Queue '%s' already has conumers."
+ "Exclusive access denied.") %getName());
+ exclusive = c;
+ }
+ if(autodelete && consumers.empty()) lastUsed = 0;
+ consumers.push_back(c);
+}
+
+void Queue::cancel(Consumer* c){
+ Mutex::ScopedLock locker(lock);
+ Consumers::iterator i = std::find(consumers.begin(), consumers.end(), c);
+ if (i != consumers.end())
+ consumers.erase(i);
+ if(autodelete && consumers.empty()) lastUsed = now()*TIME_MSEC;
+ if(exclusive == c) exclusive = 0;
+}
+
+Message::shared_ptr Queue::dequeue(){
+ Mutex::ScopedLock locker(lock);
+ Message::shared_ptr msg;
+ if(!messages.empty()){
+ msg = messages.front();
+ pop();
+ }
+ return msg;
+}
+
+uint32_t Queue::purge(){
+ Mutex::ScopedLock locker(lock);
+ int count = messages.size();
+ while(!messages.empty()) pop();
+ return count;
+}
+
+void Queue::pop(){
+ if (policy.get()) policy->dequeued(messages.front()->contentSize());
+ messages.pop();
+}
+
+void Queue::push(Message::shared_ptr& msg){
+ queueing = true;
+ messages.push(msg);
+ if (policy.get()) {
+ policy->enqueued(msg->contentSize());
+ if (policy->limitExceeded()) {
+ msg->releaseContent(store);
+ }
+ }
+}
+
+uint32_t Queue::getMessageCount() const{
+ Mutex::ScopedLock locker(lock);
+ return messages.size();
+}
+
+uint32_t Queue::getConsumerCount() const{
+ Mutex::ScopedLock locker(lock);
+ return consumers.size();
+}
+
+bool Queue::canAutoDelete() const{
+ Mutex::ScopedLock locker(lock);
+ return lastUsed && (now()*TIME_MSEC - lastUsed > autodelete);
+}
+
+void Queue::enqueue(TransactionContext* ctxt, Message::shared_ptr& msg, const string * const xid)
+{
+ if (msg->isPersistent() && store) {
+ store->enqueue(ctxt, msg.get(), *this, xid);
+ }
+}
+
+void Queue::dequeue(TransactionContext* ctxt, Message::shared_ptr& msg, const string * const xid)
+{
+ if (msg->isPersistent() && store) {
+ store->dequeue(ctxt, msg.get(), *this, xid);
+ }
+}
+
+namespace
+{
+ const std::string qpidMaxSize("qpid.max_size");
+ const std::string qpidMaxCount("qpid.max_count");
+}
+
+void Queue::create(const FieldTable& settings)
+{
+ if (store) {
+ store->create(*this, settings);
+ }
+ configure(settings);
+}
+
+void Queue::configure(const FieldTable& settings)
+{
+ QueuePolicy* _policy = new QueuePolicy(settings);
+ if (_policy->getMaxCount() || _policy->getMaxSize()) {
+ setPolicy(std::auto_ptr<QueuePolicy>(_policy));
+ }
+}
+
+void Queue::destroy()
+{
+ if (store) {
+ store->destroy(*this);
+ }
+}
+
+void Queue::setPolicy(std::auto_ptr<QueuePolicy> _policy)
+{
+ policy = _policy;
+}
+
+const QueuePolicy* const Queue::getPolicy()
+{
+ return policy.get();
+}
diff --git a/cpp/lib/broker/BrokerQueue.h b/cpp/lib/broker/BrokerQueue.h
new file mode 100644
index 0000000000..12f5815027
--- /dev/null
+++ b/cpp/lib/broker/BrokerQueue.h
@@ -0,0 +1,151 @@
+#ifndef _broker_BrokerQueue_h
+#define _broker_BrokerQueue_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 <vector>
+#include <memory>
+#include <queue>
+#include <boost/shared_ptr.hpp>
+#include <amqp_types.h>
+#include <Binding.h>
+#include <ConnectionToken.h>
+#include <Consumer.h>
+#include <BrokerMessage.h>
+#include <FieldTable.h>
+#include <sys/Monitor.h>
+#include <QueuePolicy.h>
+
+// TODO aconway 2007-02-06: Use auto_ptr and boost::ptr_vector to
+// enforce ownership of Consumers.
+
+namespace qpid {
+ namespace broker {
+ class MessageStore;
+
+ /**
+ * Thrown when exclusive access would be violated.
+ */
+ using std::string;
+
+ /**
+ * The brokers representation of an amqp queue. Messages are
+ * delivered to a queue from where they can be dispatched to
+ * registered consumers or be stored until dequeued or until one
+ * or more consumers registers.
+ */
+ class Queue{
+ typedef std::vector<Consumer*> Consumers;
+ typedef std::queue<Binding*> Bindings;
+ typedef std::queue<Message::shared_ptr> Messages;
+
+ const string name;
+ const uint32_t autodelete;
+ MessageStore* const store;
+ const ConnectionToken* const owner;
+ Consumers consumers;
+ Bindings bindings;
+ Messages messages;
+ bool queueing;
+ bool dispatching;
+ int next;
+ mutable qpid::sys::Mutex lock;
+ int64_t lastUsed;
+ Consumer* exclusive;
+ mutable uint64_t persistenceId;
+ std::auto_ptr<QueuePolicy> policy;
+
+ void pop();
+ void push(Message::shared_ptr& msg);
+ bool startDispatching();
+ bool dispatch(Message::shared_ptr& msg);
+ void setPolicy(std::auto_ptr<QueuePolicy> policy);
+
+ public:
+
+ typedef boost::shared_ptr<Queue> shared_ptr;
+
+ typedef std::vector<shared_ptr> vector;
+
+ Queue(const string& name, uint32_t autodelete = 0,
+ MessageStore* const store = 0,
+ const ConnectionToken* const owner = 0);
+ ~Queue();
+
+ void create(const qpid::framing::FieldTable& settings);
+ void configure(const qpid::framing::FieldTable& settings);
+ void destroy();
+ /**
+ * Informs the queue of a binding that should be cancelled on
+ * destruction of the queue.
+ */
+ void bound(Binding* b);
+ /**
+ * Delivers a message to the queue. Will record it as
+ * enqueued if persistent then process it.
+ */
+ void deliver(Message::shared_ptr& msg);
+ /**
+ * Dispatches the messages immediately to a consumer if
+ * one is available or stores it for later if not.
+ */
+ void process(Message::shared_ptr& msg);
+ /**
+ * Used during recovery to add stored messages back to the queue
+ */
+ void recover(Message::shared_ptr& msg);
+ /**
+ * Dispatch any queued messages providing there are
+ * consumers for them. Only one thread can be dispatching
+ * at any time, but this method (rather than the caller)
+ * is responsible for ensuring that.
+ */
+ void dispatch();
+ void consume(Consumer* c, bool exclusive = false);
+ void cancel(Consumer* c);
+ uint32_t purge();
+ uint32_t getMessageCount() const;
+ uint32_t getConsumerCount() const;
+ inline const string& getName() const { return name; }
+ inline const bool isExclusiveOwner(const ConnectionToken* const o) const { return o == owner; }
+ inline bool hasExclusiveConsumer() const { return exclusive; }
+ inline uint64_t getPersistenceId() const { return persistenceId; }
+ inline void setPersistenceId(uint64_t _persistenceId) const { persistenceId = _persistenceId; }
+
+ bool canAutoDelete() const;
+
+ void enqueue(TransactionContext* ctxt, Message::shared_ptr& msg, const string * const xid);
+ /**
+ * dequeue from store (only done once messages is acknowledged)
+ */
+ void dequeue(TransactionContext* ctxt, Message::shared_ptr& msg, const string * const xid);
+ /**
+ * dequeues from memory only
+ */
+ Message::shared_ptr dequeue();
+
+ const QueuePolicy* const getPolicy();
+ };
+ }
+}
+
+
+#endif /*!_broker_BrokerQueue_h*/
diff --git a/cpp/lib/broker/BrokerSingleton.cpp b/cpp/lib/broker/BrokerSingleton.cpp
new file mode 100644
index 0000000000..4571764850
--- /dev/null
+++ b/cpp/lib/broker/BrokerSingleton.cpp
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "BrokerSingleton.h"
+
+namespace qpid {
+namespace broker {
+
+BrokerSingleton::BrokerSingleton() {
+ if (broker.get() == 0)
+ broker = Broker::create();
+ Broker::shared_ptr::operator=(broker);
+}
+
+BrokerSingleton::~BrokerSingleton() {
+ broker->shutdown();
+}
+
+Broker::shared_ptr BrokerSingleton::broker;
+
+}} // namespace qpid::broker
diff --git a/cpp/lib/broker/BrokerSingleton.h b/cpp/lib/broker/BrokerSingleton.h
new file mode 100644
index 0000000000..139e02a5fd
--- /dev/null
+++ b/cpp/lib/broker/BrokerSingleton.h
@@ -0,0 +1,52 @@
+#ifndef _broker_BrokerSingleton_h
+#define _broker_BrokerSingleton_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "Broker.h"
+
+namespace qpid {
+namespace broker {
+
+/**
+ * BrokerSingleton is a smart pointer to a process-wide singleton broker
+ * started on an os-chosen port. The broker starts the first time
+ * an instance of BrokerSingleton is created and runs untill the process exits.
+ *
+ * Useful for unit tests that want to share a broker between multiple
+ * tests to reduce overhead of starting/stopping a broker for every test.
+ *
+ * Tests that need a new broker can call Broker::create directly.
+ *
+ * THREAD UNSAFE.
+ */
+class BrokerSingleton : public Broker::shared_ptr
+{
+ public:
+ BrokerSingleton();
+ ~BrokerSingleton();
+ private:
+ static Broker::shared_ptr broker;
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_BrokerSingleton_h*/
diff --git a/cpp/lib/broker/CompletionHandler.h b/cpp/lib/broker/CompletionHandler.h
new file mode 100644
index 0000000000..9d51656282
--- /dev/null
+++ b/cpp/lib/broker/CompletionHandler.h
@@ -0,0 +1,39 @@
+#ifndef _broker_CompletionHandler_h
+#define _broker_CompletionHandler_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.
+ *
+ */
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Callback interface to handle completion of a message.
+ */
+class CompletionHandler
+{
+ public:
+ virtual ~CompletionHandler(){}
+ virtual void complete(Message::shared_ptr) = 0;
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_CompletionHandler_h*/
diff --git a/cpp/lib/broker/Configuration.cpp b/cpp/lib/broker/Configuration.cpp
new file mode 100644
index 0000000000..e83c359f2d
--- /dev/null
+++ b/cpp/lib/broker/Configuration.cpp
@@ -0,0 +1,252 @@
+/*
+ *
+ * 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 <Configuration.h>
+#include <string.h>
+#include <config.h>
+
+using namespace qpid::broker;
+using namespace std;
+
+Configuration::Configuration() :
+ daemon('d', "daemon", "Run as system daemon, detached from terminal.", false),
+ trace('t', "trace", "Print incoming & outgoing frames to the console", false),
+ port('p', "port", "Set the port to listen on (default=5672)", 5672),
+ workerThreads("worker-threads", "Set the number of worker threads to use (default=5).", 5),
+ maxConnections("max-connections", "Set the maximum number of connections the broker can accept (default=500).", 500),
+ connectionBacklog("connection-backlog", "Set the connection backlog for the servers socket (default=10)", 10),
+ store('s', "store", "Set the message store module to use (default='' which implies no store)", ""),
+ stagingThreshold("staging-threshold", "Set the message size threshold above which messages will be written to disk as they arrive (default=5,000,000)", 5000000),
+ help("help", "Print usage information", false),
+ version("version", "Print version information", false)
+{
+ options.push_back(&daemon);
+ options.push_back(&trace);
+ options.push_back(&port);
+ options.push_back(&workerThreads);
+ options.push_back(&maxConnections);
+ options.push_back(&connectionBacklog);
+ options.push_back(&store);
+ options.push_back(&stagingThreshold);
+ options.push_back(&help);
+ options.push_back(&version);
+}
+
+Configuration::~Configuration(){}
+
+void Configuration::parse(char const *progName, int argc, char** argv){
+ programName = progName;
+ int position = 1;
+ while(position < argc){
+ bool matched(false);
+ for(op_iterator i = options.begin(); i < options.end() && !matched; i++){
+ matched = (*i)->parse(position, argv, argc);
+ }
+ if(!matched) {
+ throw BadOptionException(
+ std::string("Unrecognised option: ")+argv[position]);
+ }
+ }
+}
+
+void Configuration::usage(){
+ std::cout << "Usage: " << programName << " [OPTION]..." << std::endl
+ << "Start the Qpid AMQP broker daemon." << std::endl << std::endl
+ << "Options:" << std::endl;
+ for(op_iterator i = options.begin(); i < options.end(); i++){
+ (*i)->print(std::cout);
+ }
+
+ std::cout << std::endl << "Report bugs to <" << PACKAGE_BUGREPORT << ">."
+ << std::endl;
+}
+
+bool Configuration::isHelp() const {
+ return help.getValue();
+}
+
+bool Configuration::isVersion() const {
+ return version.getValue();
+}
+
+bool Configuration::isDaemon() const {
+ return daemon.getValue();
+}
+
+bool Configuration::isTrace() const {
+ return trace.getValue();
+}
+
+int Configuration::getPort() const {
+ return port.getValue();
+}
+
+int Configuration::getWorkerThreads() const {
+ return workerThreads.getValue();
+}
+
+int Configuration::getMaxConnections() const {
+ return maxConnections.getValue();
+}
+
+int Configuration::getConnectionBacklog() const {
+ return connectionBacklog.getValue();
+}
+
+const std::string& Configuration::getStore() const {
+ return store.getValue();
+}
+
+long Configuration::getStagingThreshold() const {
+ return stagingThreshold.getValue();
+}
+
+
+Configuration::Option::Option(const char _flag, const string& _name, const string& _desc) :
+ flag(string("-") + _flag), name("--" +_name), desc(_desc) {}
+
+Configuration::Option::Option(const string& _name, const string& _desc) :
+ flag(""), name("--" + _name), desc(_desc) {}
+
+Configuration::Option::~Option(){}
+
+bool Configuration::Option::match(const string& arg){
+ return flag == arg || name == arg;
+}
+
+bool Configuration::Option::parse(int& i, char** argv, int argc){
+ const string arg(argv[i]);
+ if(match(arg)){
+ if(needsValue()){
+ if(++i < argc) setValue(argv[i]);
+ else throw ParseException("Argument " + arg + " requires a value!");
+ }else{
+ setValue("");
+ }
+ i++;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+void Configuration::Option::print(ostream& out) const {
+ out << " ";
+ if(flag.length() > 0){
+ out << flag << ", ";
+ } else {
+ out << " ";
+ }
+ out << name;
+ if(needsValue()) out << " <value>";
+ out << std::endl;
+ out << " " << desc << std::endl;
+}
+
+
+// String Option:
+
+Configuration::StringOption::StringOption(const char _flag, const string& _name, const string& _desc, const string _value) :
+ Option(_flag,_name,_desc), defaultValue(_value), value(_value) {}
+
+Configuration::StringOption::StringOption(const string& _name, const string& _desc, const string _value) :
+ Option(_name,_desc), defaultValue(_value), value(_value) {}
+
+Configuration::StringOption::~StringOption(){}
+
+const string& Configuration::StringOption::getValue() const {
+ return value;
+}
+
+bool Configuration::StringOption::needsValue() const {
+ return true;
+}
+
+void Configuration::StringOption::setValue(const std::string& _value){
+ value = _value;
+}
+
+// Int Option:
+
+Configuration::IntOption::IntOption(const char _flag, const string& _name, const string& _desc, const int _value) :
+ Option(_flag,_name,_desc), defaultValue(_value), value(_value) {}
+
+Configuration::IntOption::IntOption(const string& _name, const string& _desc, const int _value) :
+ Option(_name,_desc), defaultValue(_value), value(_value) {}
+
+Configuration::IntOption::~IntOption(){}
+
+int Configuration::IntOption::getValue() const {
+ return value;
+}
+
+bool Configuration::IntOption::needsValue() const {
+ return true;
+}
+
+void Configuration::IntOption::setValue(const std::string& _value){
+ value = atoi(_value.c_str());
+}
+
+// Long Option:
+
+Configuration::LongOption::LongOption(const char _flag, const string& _name, const string& _desc, const long _value) :
+ Option(_flag,_name,_desc), defaultValue(_value), value(_value) {}
+
+Configuration::LongOption::LongOption(const string& _name, const string& _desc, const long _value) :
+ Option(_name,_desc), defaultValue(_value), value(_value) {}
+
+Configuration::LongOption::~LongOption(){}
+
+long Configuration::LongOption::getValue() const {
+ return value;
+}
+
+bool Configuration::LongOption::needsValue() const {
+ return true;
+}
+
+void Configuration::LongOption::setValue(const std::string& _value){
+ value = atol(_value.c_str());
+}
+
+// Bool Option:
+
+Configuration::BoolOption::BoolOption(const char _flag, const string& _name, const string& _desc, const bool _value) :
+ Option(_flag,_name,_desc), defaultValue(_value), value(_value) {}
+
+Configuration::BoolOption::BoolOption(const string& _name, const string& _desc, const bool _value) :
+ Option(_name,_desc), defaultValue(_value), value(_value) {}
+
+Configuration::BoolOption::~BoolOption(){}
+
+bool Configuration::BoolOption::getValue() const {
+ return value;
+}
+
+bool Configuration::BoolOption::needsValue() const {
+ return false;
+}
+
+void Configuration::BoolOption::setValue(const std::string& /*not required*/){
+ //BoolOptions have no value. The fact that the option is specified
+ //implies the value is true.
+ value = true;
+}
diff --git a/cpp/lib/broker/Configuration.h b/cpp/lib/broker/Configuration.h
new file mode 100644
index 0000000000..27c743c8f0
--- /dev/null
+++ b/cpp/lib/broker/Configuration.h
@@ -0,0 +1,171 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Configuration_
+#define _Configuration_
+
+#include <cstdlib>
+#include <iostream>
+#include <vector>
+#include <Exception.h>
+
+namespace qpid {
+namespace broker {
+class Configuration{
+
+ class Option {
+ const std::string flag;
+ const std::string name;
+ const std::string desc;
+
+ bool match(const std::string& arg);
+
+ protected:
+ virtual bool needsValue() const = 0;
+ virtual void setValue(const std::string& value) = 0;
+
+ public:
+ Option(const char flag, const std::string& name, const std::string& desc);
+ Option(const std::string& name, const std::string& desc);
+ virtual ~Option();
+
+ bool parse(int& i, char** argv, int argc);
+ void print(std::ostream& out) const;
+ };
+
+ class IntOption : public Option{
+ const int defaultValue;
+ int value;
+ public:
+ IntOption(char flag, const std::string& name, const std::string& desc, const int value = 0);
+ IntOption(const std::string& name, const std::string& desc, const int value = 0);
+ virtual ~IntOption();
+
+ int getValue() const;
+ virtual bool needsValue() const;
+ virtual void setValue(const std::string& value);
+ virtual void setValue(int _value) { value = _value; }
+ };
+
+ class LongOption : public Option{
+ const long defaultValue;
+ int value;
+ public:
+ LongOption(char flag, const std::string& name, const std::string& desc, const long value = 0);
+ LongOption(const std::string& name, const std::string& desc, const long value = 0);
+ virtual ~LongOption();
+
+ long getValue() const;
+ virtual bool needsValue() const;
+ virtual void setValue(const std::string& value);
+ virtual void setValue(int _value) { value = _value; }
+ };
+
+ class StringOption : public Option{
+ const std::string defaultValue;
+ std::string value;
+ public:
+ StringOption(char flag, const std::string& name, const std::string& desc, const std::string value = "");
+ StringOption(const std::string& name, const std::string& desc, const std::string value = "");
+ virtual ~StringOption();
+
+ const std::string& getValue() const;
+ virtual bool needsValue() const;
+ virtual void setValue(const std::string& value);
+ };
+
+ class BoolOption : public Option{
+ const bool defaultValue;
+ bool value;
+ public:
+ BoolOption(char flag, const std::string& name, const std::string& desc, const bool value = 0);
+ BoolOption(const std::string& name, const std::string& desc, const bool value = 0);
+ virtual ~BoolOption();
+
+ bool getValue() const;
+ virtual bool needsValue() const;
+ virtual void setValue(const std::string& value);
+ virtual void setValue(bool _value) { value = _value; }
+ };
+
+ BoolOption daemon;
+ BoolOption trace;
+ IntOption port;
+ IntOption workerThreads;
+ IntOption maxConnections;
+ IntOption connectionBacklog;
+ StringOption store;
+ LongOption stagingThreshold;
+ BoolOption help;
+ BoolOption version;
+ char const *programName;
+
+ typedef std::vector<Option*>::iterator op_iterator;
+ std::vector<Option*> options;
+
+ public:
+
+ struct BadOptionException : public Exception {
+ template<class T>
+ BadOptionException(const T& msg) : Exception(msg) {}
+ };
+
+
+ class ParseException : public Exception {
+ public:
+ template <class T>
+ ParseException(const T& msg) : Exception(msg) {}
+ };
+
+
+ Configuration();
+ ~Configuration();
+
+ void parse(char const*, int argc, char** argv);
+
+ bool isHelp() const;
+ bool isVersion() const;
+ bool isDaemon() const;
+ bool isTrace() const;
+ int getPort() const;
+ int getWorkerThreads() const;
+ int getMaxConnections() const;
+ int getConnectionBacklog() const;
+ const std::string& getStore() const;
+ long getStagingThreshold() const;
+
+ void setHelp(bool b) { help.setValue(b); }
+ void setVersion(bool b) { version.setValue(b); }
+ void setDaemon(bool b) { daemon.setValue(b); }
+ void setTrace(bool b) { trace.setValue(b); }
+ void setPort(int i) { port.setValue(i); }
+ void setWorkerThreads(int i) { workerThreads.setValue(i); }
+ void setMaxConnections(int i) { maxConnections.setValue(i); }
+ void setConnectionBacklog(int i) { connectionBacklog.setValue(i); }
+ void setStore(const std::string& s) { store.setValue(s); }
+ void setStagingThreshold(long l) { stagingThreshold.setValue(l); }
+
+ void usage();
+};
+}
+}
+
+
+#endif
diff --git a/cpp/lib/broker/Connection.cpp b/cpp/lib/broker/Connection.cpp
new file mode 100644
index 0000000000..ae0114cba9
--- /dev/null
+++ b/cpp/lib/broker/Connection.cpp
@@ -0,0 +1,128 @@
+/*
+ *
+ * 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 <iostream>
+#include <assert.h>
+
+#include "Connection.h"
+#include "BrokerChannel.h"
+#include "AMQP_ClientProxy.h"
+#include "BrokerAdapter.h"
+
+using namespace boost;
+using namespace qpid::sys;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+namespace qpid {
+namespace broker {
+
+Connection::Connection(ConnectionOutputHandler* out_, Broker& broker_) :
+ broker(broker_),
+ out(out_),
+ framemax(65536),
+ heartbeat(0),
+ client(0),
+ timeout(broker.getTimeout()),
+ stagingThreshold(broker.getStagingThreshold())
+{}
+
+
+Queue::shared_ptr Connection::getQueue(const string& name, uint16_t channel){
+ Queue::shared_ptr queue;
+ if (name.empty()) {
+ queue = getChannel(channel).getDefaultQueue();
+ if (!queue) throw ConnectionException( 530, "Queue must be specified or previously declared" );
+ } else {
+ queue = broker.getQueues().find(name);
+ if (queue == 0) {
+ throw ChannelException( 404, "Queue not found: " + name);
+ }
+ }
+ return queue;
+}
+
+
+Exchange::shared_ptr Connection::findExchange(const string& name){
+ return broker.getExchanges().get(name);
+}
+
+
+void Connection::received(framing::AMQFrame* frame){
+ getChannel(frame->getChannel()).handleBody(frame->getBody());
+}
+
+void Connection::close(
+ ReplyCode code, const string& text, ClassId classId, MethodId methodId)
+{
+ client->close(code, text, classId, methodId);
+ getOutput().close();
+}
+
+void Connection::initiated(framing::ProtocolInitiation* header) {
+ version = ProtocolVersion(header->getMajor(), header->getMinor());
+ FieldTable properties;
+ string mechanisms("PLAIN");
+ string locales("en_US");
+ getChannel(0).init(0, *out, getVersion());
+ client = &getChannel(0).getAdatper().getProxy().getConnection();
+ client->start(
+ header->getMajor(), header->getMinor(),
+ properties, mechanisms, locales);
+}
+
+void Connection::idleOut(){}
+
+void Connection::idleIn(){}
+
+void Connection::closed(){
+ try {
+ while (!exclusiveQueues.empty()) {
+ broker.getQueues().destroy(exclusiveQueues.front()->getName());
+ exclusiveQueues.erase(exclusiveQueues.begin());
+ }
+ } catch(std::exception& e) {
+ std::cout << "Caught unhandled exception while closing session: " <<
+ e.what() << std::endl;
+ assert(0);
+ }
+}
+
+void Connection::closeChannel(uint16_t id) {
+ ChannelMap::iterator i = channels.find(id);
+ if (i != channels.end())
+ i->close();
+}
+
+
+Channel& Connection::getChannel(ChannelId id) {
+ ChannelMap::iterator i = channels.find(id);
+ if (i == channels.end()) {
+ i = channels.insert(
+ id, new Channel(
+ *this, id, framemax, broker.getQueues().getStore(),
+ broker.getStagingThreshold())).first;
+ }
+ return *i;
+}
+
+
+}}
+
diff --git a/cpp/lib/broker/Connection.h b/cpp/lib/broker/Connection.h
new file mode 100644
index 0000000000..1314ccbd97
--- /dev/null
+++ b/cpp/lib/broker/Connection.h
@@ -0,0 +1,108 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Connection_
+#define _Connection_
+
+#include <sstream>
+#include <vector>
+
+#include <boost/ptr_container/ptr_map.hpp>
+
+#include <AMQFrame.h>
+#include <AMQP_ServerOperations.h>
+#include <AMQP_ClientProxy.h>
+#include <sys/ConnectionOutputHandler.h>
+#include <sys/ConnectionInputHandler.h>
+#include <sys/TimeoutHandler.h>
+#include "framing/ProtocolVersion.h"
+#include "Broker.h"
+#include "Exception.h"
+#include "BrokerChannel.h"
+
+namespace qpid {
+namespace broker {
+
+class Channel;
+
+class Connection : public sys::ConnectionInputHandler,
+ public ConnectionToken
+{
+ public:
+ Connection(sys::ConnectionOutputHandler* out, Broker& broker);
+
+ /** Get a channel. Create if it does not already exist */
+ Channel& getChannel(framing::ChannelId channel);
+
+ /** Close a channel */
+ void closeChannel(framing::ChannelId channel);
+
+ /** Close the connection */
+ void close(framing::ReplyCode code, const string& text, framing::ClassId classId, framing::MethodId methodId);
+
+ sys::ConnectionOutputHandler& getOutput() const { return *out; }
+ framing::ProtocolVersion getVersion() const { return version; }
+
+ uint32_t getFrameMax() const { return framemax; }
+ uint16_t getHeartbeat() const { return heartbeat; }
+ uint32_t getTimeout() const { return timeout; }
+ uint64_t getStagingThreshold() const { return stagingThreshold; }
+
+ void setFrameMax(uint32_t fm) { framemax = fm; }
+ void setHeartbeat(uint16_t hb) { heartbeat = hb; }
+
+ /**
+ * Get named queue, never returns 0.
+ * @return: named queue or default queue for channel if name=""
+ * @exception: ChannelException if no queue of that name is found.
+ * @exception: ConnectionException if name="" and channel has no default.
+ */
+ Queue::shared_ptr getQueue(const string& name, uint16_t channel);
+
+ Broker& broker;
+ std::vector<Queue::shared_ptr> exclusiveQueues;
+
+ // ConnectionInputHandler methods
+ void received(framing::AMQFrame* frame);
+ void initiated(framing::ProtocolInitiation* header);
+ void idleOut();
+ void idleIn();
+ void closed();
+
+ private:
+ typedef boost::ptr_map<framing::ChannelId, Channel> ChannelMap;
+
+ typedef std::vector<Queue::shared_ptr>::iterator queue_iterator;
+ Exchange::shared_ptr findExchange(const string& name);
+
+ framing::ProtocolVersion version;
+ ChannelMap channels;
+ sys::ConnectionOutputHandler* out;
+ uint32_t framemax;
+ uint16_t heartbeat;
+ framing::AMQP_ClientProxy::Connection* client;
+ const uint32_t timeout; //timeout for auto-deleted queues (in ms)
+ const uint64_t stagingThreshold;
+
+};
+
+}}
+
+#endif
diff --git a/cpp/lib/broker/ConnectionFactory.cpp b/cpp/lib/broker/ConnectionFactory.cpp
new file mode 100644
index 0000000000..20485dd0e1
--- /dev/null
+++ b/cpp/lib/broker/ConnectionFactory.cpp
@@ -0,0 +1,43 @@
+/*
+ *
+ * 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 <ConnectionFactory.h>
+#include <Connection.h>
+
+namespace qpid {
+namespace broker {
+
+
+ConnectionFactory::ConnectionFactory(Broker& b) : broker(b)
+{}
+
+
+ConnectionFactory::~ConnectionFactory()
+{
+ broker.getCleaner().stop();
+}
+
+qpid::sys::ConnectionInputHandler*
+ConnectionFactory::create(qpid::sys::ConnectionOutputHandler* out)
+{
+ return new Connection(out, broker);
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/lib/broker/ConnectionFactory.h b/cpp/lib/broker/ConnectionFactory.h
new file mode 100644
index 0000000000..9147384b2a
--- /dev/null
+++ b/cpp/lib/broker/ConnectionFactory.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ConnectionFactory_
+#define _ConnectionFactory_
+
+#include "ConnectionInputHandlerFactory.h"
+
+namespace qpid {
+namespace broker {
+class Broker;
+
+class ConnectionFactory : public qpid::sys::ConnectionInputHandlerFactory
+{
+ public:
+ ConnectionFactory(Broker& b);
+
+ virtual qpid::sys::ConnectionInputHandler* create(
+ qpid::sys::ConnectionOutputHandler* ctxt);
+
+ virtual ~ConnectionFactory();
+
+ private:
+ Broker& broker;
+};
+
+}}
+
+
+#endif
diff --git a/cpp/lib/broker/ConnectionToken.h b/cpp/lib/broker/ConnectionToken.h
new file mode 100644
index 0000000000..7e7f813d0e
--- /dev/null
+++ b/cpp/lib/broker/ConnectionToken.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ConnectionToken_
+#define _ConnectionToken_
+
+namespace qpid {
+ namespace broker {
+ /**
+ * An empty interface allowing opaque implementations of some
+ * form of token to identify a connection.
+ */
+ class ConnectionToken{
+ public:
+ virtual ~ConnectionToken(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/Consumer.h b/cpp/lib/broker/Consumer.h
new file mode 100644
index 0000000000..26deef4a26
--- /dev/null
+++ b/cpp/lib/broker/Consumer.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Consumer_
+#define _Consumer_
+
+#include <BrokerMessage.h>
+
+namespace qpid {
+ namespace broker {
+ class Consumer{
+ public:
+ virtual bool deliver(Message::shared_ptr& msg) = 0;
+ virtual ~Consumer(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/Content.h b/cpp/lib/broker/Content.h
new file mode 100644
index 0000000000..b65a454778
--- /dev/null
+++ b/cpp/lib/broker/Content.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Content_
+#define _Content_
+
+#include <boost/function.hpp>
+
+#include <AMQContentBody.h>
+#include <Buffer.h>
+#include <OutputHandler.h>
+
+namespace qpid {
+
+namespace framing {
+class ChannelAdapter;
+}
+
+namespace broker {
+class Content{
+ public:
+ typedef std::string DataBlock;
+ typedef boost::function1<void, const DataBlock&> SendFn;
+
+ virtual ~Content(){}
+
+ /** Add a block of data to the content */
+ virtual void add(framing::AMQContentBody::shared_ptr data) = 0;
+
+ /** Total size of content in bytes */
+ virtual uint32_t size() = 0;
+
+ /**
+ * Iterate over the content calling SendFn for each block.
+ * Subdivide blocks if necessary to ensure each block is
+ * <= framesize bytes long.
+ */
+ virtual void send(framing::ChannelAdapter& channel, uint32_t framesize) = 0;
+
+ //FIXME aconway 2007-02-07: This is inconsistently implemented
+ //find out what is needed.
+ virtual void encode(qpid::framing::Buffer& buffer) = 0;
+};
+}}
+
+
+#endif
diff --git a/cpp/lib/broker/DeletingTxOp.cpp b/cpp/lib/broker/DeletingTxOp.cpp
new file mode 100644
index 0000000000..25fe9c98db
--- /dev/null
+++ b/cpp/lib/broker/DeletingTxOp.cpp
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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 <DeletingTxOp.h>
+
+using namespace qpid::broker;
+
+DeletingTxOp::DeletingTxOp(TxOp* const _delegate) : delegate(_delegate){}
+
+bool DeletingTxOp::prepare(TransactionContext* ctxt) throw(){
+ return delegate && delegate->prepare(ctxt);
+}
+
+void DeletingTxOp::commit() throw(){
+ if(delegate){
+ delegate->commit();
+ delete delegate;
+ delegate = 0;
+ }
+}
+
+void DeletingTxOp::rollback() throw(){
+ if(delegate){
+ delegate->rollback();
+ delete delegate;
+ delegate = 0;
+ }
+}
diff --git a/cpp/lib/broker/DeletingTxOp.h b/cpp/lib/broker/DeletingTxOp.h
new file mode 100644
index 0000000000..3e026cd4ca
--- /dev/null
+++ b/cpp/lib/broker/DeletingTxOp.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _DeletingTxOp_
+#define _DeletingTxOp_
+
+#include <TxOp.h>
+
+namespace qpid {
+ namespace broker {
+ /**
+ * TxOp wrapper that will delegate calls & delete the object
+ * to which it delegates after completion of the transaction.
+ */
+ class DeletingTxOp : public virtual TxOp{
+ TxOp* delegate;
+ public:
+ DeletingTxOp(TxOp* const delegate);
+ virtual bool prepare(TransactionContext* ctxt) throw();
+ virtual void commit() throw();
+ virtual void rollback() throw();
+ virtual ~DeletingTxOp(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/Deliverable.h b/cpp/lib/broker/Deliverable.h
new file mode 100644
index 0000000000..e33443555d
--- /dev/null
+++ b/cpp/lib/broker/Deliverable.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Deliverable_
+#define _Deliverable_
+
+#include <BrokerQueue.h>
+
+namespace qpid {
+ namespace broker {
+ class Deliverable{
+ public:
+ virtual void deliverTo(Queue::shared_ptr& queue) = 0;
+ virtual ~Deliverable(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/DeliverableMessage.cpp b/cpp/lib/broker/DeliverableMessage.cpp
new file mode 100644
index 0000000000..b9c89da690
--- /dev/null
+++ b/cpp/lib/broker/DeliverableMessage.cpp
@@ -0,0 +1,33 @@
+/*
+ *
+ * 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 <DeliverableMessage.h>
+
+using namespace qpid::broker;
+
+DeliverableMessage::DeliverableMessage(Message::shared_ptr& _msg) : msg(_msg)
+{
+}
+
+void DeliverableMessage::deliverTo(Queue::shared_ptr& queue)
+{
+ queue->deliver(msg);
+}
+
diff --git a/cpp/lib/broker/DeliverableMessage.h b/cpp/lib/broker/DeliverableMessage.h
new file mode 100644
index 0000000000..962f0da640
--- /dev/null
+++ b/cpp/lib/broker/DeliverableMessage.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _DeliverableMessage_
+#define _DeliverableMessage_
+
+#include <Deliverable.h>
+#include <BrokerMessage.h>
+#include <BrokerQueue.h>
+
+namespace qpid {
+ namespace broker {
+ class DeliverableMessage : public Deliverable{
+ Message::shared_ptr msg;
+ public:
+ DeliverableMessage(Message::shared_ptr& msg);
+ virtual void deliverTo(Queue::shared_ptr& queue);
+ virtual ~DeliverableMessage(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/DeliveryRecord.cpp b/cpp/lib/broker/DeliveryRecord.cpp
new file mode 100644
index 0000000000..0d2e5325c5
--- /dev/null
+++ b/cpp/lib/broker/DeliveryRecord.cpp
@@ -0,0 +1,91 @@
+/*
+ *
+ * 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 <DeliveryRecord.h>
+#include <BrokerChannel.h>
+
+using namespace qpid::broker;
+using std::string;
+
+DeliveryRecord::DeliveryRecord(Message::shared_ptr _msg,
+ Queue::shared_ptr _queue,
+ const string _consumerTag,
+ const uint64_t _deliveryTag) : msg(_msg),
+ queue(_queue),
+ consumerTag(_consumerTag),
+ deliveryTag(_deliveryTag),
+ pull(false){}
+
+DeliveryRecord::DeliveryRecord(Message::shared_ptr _msg,
+ Queue::shared_ptr _queue,
+ const uint64_t _deliveryTag) : msg(_msg),
+ queue(_queue),
+ consumerTag(""),
+ deliveryTag(_deliveryTag),
+ pull(true){}
+
+
+void DeliveryRecord::discard(TransactionContext* ctxt, const std::string* const xid) const{
+ queue->dequeue(ctxt, msg, xid);
+}
+
+void DeliveryRecord::discard() const{
+ discard(0, 0);
+}
+
+bool DeliveryRecord::matches(uint64_t tag) const{
+ return deliveryTag == tag;
+}
+
+bool DeliveryRecord::coveredBy(const AccumulatedAck* const range) const{
+ return range->covers(deliveryTag);
+}
+
+void DeliveryRecord::redeliver(Channel* const channel) const{
+ if(pull){
+ //if message was originally sent as response to get, we must requeue it
+ requeue();
+ }else{
+ channel->deliver(msg, consumerTag, deliveryTag);
+ }
+}
+
+void DeliveryRecord::requeue() const{
+ msg->redeliver();
+ queue->process(msg);
+}
+
+void DeliveryRecord::addTo(Prefetch* const prefetch) const{
+ if(!pull){
+ //ignore 'pulled' messages (i.e. those that were sent in
+ //response to get) when calculating prefetch
+ prefetch->size += msg->contentSize();
+ prefetch->count++;
+ }
+}
+
+void DeliveryRecord::subtractFrom(Prefetch* const prefetch) const{
+ if(!pull){
+ //ignore 'pulled' messages (i.e. those that were sent in
+ //response to get) when calculating prefetch
+ prefetch->size -= msg->contentSize();
+ prefetch->count--;
+ }
+}
diff --git a/cpp/lib/broker/DeliveryRecord.h b/cpp/lib/broker/DeliveryRecord.h
new file mode 100644
index 0000000000..bda2c2ec90
--- /dev/null
+++ b/cpp/lib/broker/DeliveryRecord.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _DeliveryRecord_
+#define _DeliveryRecord_
+
+#include <algorithm>
+#include <list>
+#include <AccumulatedAck.h>
+#include <BrokerMessage.h>
+#include <Prefetch.h>
+#include <BrokerQueue.h>
+
+namespace qpid {
+ namespace broker {
+ class Channel;
+
+ /**
+ * Record of a delivery for which an ack is outstanding.
+ */
+ class DeliveryRecord{
+ mutable Message::shared_ptr msg;
+ mutable Queue::shared_ptr queue;
+ std::string consumerTag;
+ uint64_t deliveryTag;
+ bool pull;
+
+ public:
+ DeliveryRecord(Message::shared_ptr msg, Queue::shared_ptr queue, const std::string consumerTag, const uint64_t deliveryTag);
+ DeliveryRecord(Message::shared_ptr msg, Queue::shared_ptr queue, const uint64_t deliveryTag);
+
+ void discard() const;
+ void discard(TransactionContext* ctxt, const std::string* const xid) const;
+ bool matches(uint64_t tag) const;
+ bool coveredBy(const AccumulatedAck* const range) const;
+ void requeue() const;
+ void redeliver(Channel* const) const;
+ void addTo(Prefetch* const prefetch) const;
+ void subtractFrom(Prefetch* const prefetch) const;
+ };
+
+ typedef std::list<DeliveryRecord>::iterator ack_iterator;
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/DirectExchange.cpp b/cpp/lib/broker/DirectExchange.cpp
new file mode 100644
index 0000000000..c898ae8d7e
--- /dev/null
+++ b/cpp/lib/broker/DirectExchange.cpp
@@ -0,0 +1,73 @@
+/*
+ *
+ * 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 <DirectExchange.h>
+#include <ExchangeBinding.h>
+#include <iostream>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+DirectExchange::DirectExchange(const string& _name) : Exchange(_name) {
+
+}
+
+void DirectExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args){
+ Mutex::ScopedLock l(lock);
+ std::vector<Queue::shared_ptr>& queues(bindings[routingKey]);
+ std::vector<Queue::shared_ptr>::iterator i = find(queues.begin(), queues.end(), queue);
+ if(i == queues.end()){
+ bindings[routingKey].push_back(queue);
+ queue->bound(new ExchangeBinding(this, queue, routingKey, args));
+ }
+}
+
+void DirectExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/){
+ Mutex::ScopedLock l(lock);
+ std::vector<Queue::shared_ptr>& queues(bindings[routingKey]);
+
+ std::vector<Queue::shared_ptr>::iterator i = find(queues.begin(), queues.end(), queue);
+ if(i < queues.end()){
+ queues.erase(i);
+ if(queues.empty()){
+ bindings.erase(routingKey);
+ }
+ }
+}
+
+void DirectExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/){
+ Mutex::ScopedLock l(lock);
+ std::vector<Queue::shared_ptr>& queues(bindings[routingKey]);
+ int count(0);
+ for(std::vector<Queue::shared_ptr>::iterator i = queues.begin(); i != queues.end(); i++, count++){
+ msg.deliverTo(*i);
+ }
+ if(!count){
+ std::cout << "WARNING: DirectExchange " << getName() << " could not route message with key " << routingKey << std::endl;
+ }
+}
+
+DirectExchange::~DirectExchange(){
+
+}
+
+
+const std::string DirectExchange::typeName("direct");
diff --git a/cpp/lib/broker/DirectExchange.h b/cpp/lib/broker/DirectExchange.h
new file mode 100644
index 0000000000..a7ef5aca9e
--- /dev/null
+++ b/cpp/lib/broker/DirectExchange.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _DirectExchange_
+#define _DirectExchange_
+
+#include <map>
+#include <vector>
+#include <BrokerExchange.h>
+#include <FieldTable.h>
+#include <BrokerMessage.h>
+#include <sys/Monitor.h>
+#include <BrokerQueue.h>
+
+namespace qpid {
+namespace broker {
+ class DirectExchange : public virtual Exchange{
+ std::map<string, std::vector<Queue::shared_ptr> > bindings;
+ qpid::sys::Mutex lock;
+
+ public:
+ static const std::string typeName;
+
+ DirectExchange(const std::string& name);
+
+ virtual std::string getType(){ return typeName; }
+
+ virtual void bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual ~DirectExchange();
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/lib/broker/ExchangeBinding.cpp b/cpp/lib/broker/ExchangeBinding.cpp
new file mode 100644
index 0000000000..bf2102414d
--- /dev/null
+++ b/cpp/lib/broker/ExchangeBinding.cpp
@@ -0,0 +1,35 @@
+/*
+ *
+ * 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 <ExchangeBinding.h>
+#include <BrokerExchange.h>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+ExchangeBinding::ExchangeBinding(Exchange* _e, Queue::shared_ptr _q, const string& _key, const FieldTable* _args) : e(_e), q(_q), key(_key), args(_args){}
+
+void ExchangeBinding::cancel(){
+ e->unbind(q, key, args);
+ delete this;
+}
+
+ExchangeBinding::~ExchangeBinding(){
+}
diff --git a/cpp/lib/broker/ExchangeBinding.h b/cpp/lib/broker/ExchangeBinding.h
new file mode 100644
index 0000000000..2afaa89552
--- /dev/null
+++ b/cpp/lib/broker/ExchangeBinding.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ExchangeBinding_
+#define _ExchangeBinding_
+
+#include <Binding.h>
+#include <FieldTable.h>
+#include <BrokerQueue.h>
+
+namespace qpid {
+ namespace broker {
+ class Exchange;
+ class Queue;
+
+ class ExchangeBinding : public virtual Binding{
+ Exchange* e;
+ Queue::shared_ptr q;
+ const string key;
+ const qpid::framing::FieldTable* args;
+ public:
+ ExchangeBinding(Exchange* _e, Queue::shared_ptr _q, const string& _key, const qpid::framing::FieldTable* _args);
+ virtual void cancel();
+ virtual ~ExchangeBinding();
+ };
+ }
+}
+
+
+#endif
+
diff --git a/cpp/lib/broker/ExchangeRegistry.cpp b/cpp/lib/broker/ExchangeRegistry.cpp
new file mode 100644
index 0000000000..3e5ed89b54
--- /dev/null
+++ b/cpp/lib/broker/ExchangeRegistry.cpp
@@ -0,0 +1,76 @@
+/*
+ *
+ * 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 <ExchangeRegistry.h>
+#include <DirectExchange.h>
+#include <FanOutExchange.h>
+#include <HeadersExchange.h>
+#include <TopicExchange.h>
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+using std::pair;
+
+pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, const string& type) throw(UnknownExchangeTypeException){
+ Mutex::ScopedLock locker(lock);
+ ExchangeMap::iterator i = exchanges.find(name);
+ if (i == exchanges.end()) {
+ Exchange::shared_ptr exchange;
+
+ if(type == TopicExchange::typeName){
+ exchange = Exchange::shared_ptr(new TopicExchange(name));
+ }else if(type == DirectExchange::typeName){
+ exchange = Exchange::shared_ptr(new DirectExchange(name));
+ }else if(type == FanOutExchange::typeName){
+ exchange = Exchange::shared_ptr(new FanOutExchange(name));
+ }else if (type == HeadersExchange::typeName) {
+ exchange = Exchange::shared_ptr(new HeadersExchange(name));
+ }else{
+ throw UnknownExchangeTypeException();
+ }
+ exchanges[name] = exchange;
+ return std::pair<Exchange::shared_ptr, bool>(exchange, true);
+ } else {
+ return std::pair<Exchange::shared_ptr, bool>(i->second, false);
+ }
+}
+
+void ExchangeRegistry::destroy(const string& name){
+ Mutex::ScopedLock locker(lock);
+ exchanges.erase(name);
+}
+
+Exchange::shared_ptr ExchangeRegistry::get(const string& name){
+ Mutex::ScopedLock locker(lock);
+ Exchange::shared_ptr exchange =exchanges[name];
+ if (!exchange)
+ throw ChannelException(404, "Exchange not found:" + name);
+ return exchange;
+}
+
+namespace
+{
+const std::string empty;
+}
+
+Exchange::shared_ptr ExchangeRegistry::getDefault()
+{
+ return get(empty);
+}
diff --git a/cpp/lib/broker/ExchangeRegistry.h b/cpp/lib/broker/ExchangeRegistry.h
new file mode 100644
index 0000000000..aeb32753df
--- /dev/null
+++ b/cpp/lib/broker/ExchangeRegistry.h
@@ -0,0 +1,47 @@
+#ifndef _broker_ExchangeRegistry_h
+#define _broker_ExchangeRegistry_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 <map>
+#include <BrokerExchange.h>
+#include <sys/Monitor.h>
+
+namespace qpid {
+namespace broker {
+ struct UnknownExchangeTypeException{};
+
+ class ExchangeRegistry{
+ typedef std::map<std::string, Exchange::shared_ptr> ExchangeMap;
+ ExchangeMap exchanges;
+ qpid::sys::Mutex lock;
+ public:
+ std::pair<Exchange::shared_ptr, bool> declare(const std::string& name, const std::string& type) throw(UnknownExchangeTypeException);
+ void destroy(const std::string& name);
+ Exchange::shared_ptr get(const std::string& name);
+ Exchange::shared_ptr getDefault();
+ };
+}
+}
+
+
+#endif /*!_broker_ExchangeRegistry_h*/
diff --git a/cpp/lib/broker/FanOutExchange.cpp b/cpp/lib/broker/FanOutExchange.cpp
new file mode 100644
index 0000000000..48afcc20d5
--- /dev/null
+++ b/cpp/lib/broker/FanOutExchange.cpp
@@ -0,0 +1,60 @@
+/*
+ *
+ * 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 <FanOutExchange.h>
+#include <ExchangeBinding.h>
+#include <algorithm>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+FanOutExchange::FanOutExchange(const std::string& _name) : Exchange(_name) {}
+
+void FanOutExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args){
+ Mutex::ScopedLock locker(lock);
+ // Add if not already present.
+ Queue::vector::iterator i = std::find(bindings.begin(), bindings.end(), queue);
+ if (i == bindings.end()) {
+ bindings.push_back(queue);
+ queue->bound(new ExchangeBinding(this, queue, routingKey, args));
+ }
+}
+
+void FanOutExchange::unbind(Queue::shared_ptr queue, const string& /*routingKey*/, const FieldTable* /*args*/){
+ Mutex::ScopedLock locker(lock);
+ Queue::vector::iterator i = std::find(bindings.begin(), bindings.end(), queue);
+ if (i != bindings.end()) {
+ bindings.erase(i);
+ // TODO aconway 2006-09-14: What about the ExchangeBinding object?
+ // Don't we have to verify routingKey/args match?
+ }
+}
+
+void FanOutExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* /*args*/){
+ Mutex::ScopedLock locker(lock);
+ for(Queue::vector::iterator i = bindings.begin(); i != bindings.end(); ++i){
+ msg.deliverTo(*i);
+ }
+}
+
+FanOutExchange::~FanOutExchange() {}
+
+const std::string FanOutExchange::typeName("fanout");
diff --git a/cpp/lib/broker/FanOutExchange.h b/cpp/lib/broker/FanOutExchange.h
new file mode 100644
index 0000000000..6dc70e69bb
--- /dev/null
+++ b/cpp/lib/broker/FanOutExchange.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _FanOutExchange_
+#define _FanOutExchange_
+
+#include <map>
+#include <vector>
+#include <BrokerExchange.h>
+#include <FieldTable.h>
+#include <BrokerMessage.h>
+#include <sys/Monitor.h>
+#include <BrokerQueue.h>
+
+namespace qpid {
+namespace broker {
+
+class FanOutExchange : public virtual Exchange {
+ std::vector<Queue::shared_ptr> bindings;
+ qpid::sys::Mutex lock;
+
+ public:
+ static const std::string typeName;
+
+ FanOutExchange(const std::string& name);
+
+ virtual std::string getType(){ return typeName; }
+
+ virtual void bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual ~FanOutExchange();
+};
+
+}
+}
+
+
+
+#endif
diff --git a/cpp/lib/broker/HandlerImpl.h b/cpp/lib/broker/HandlerImpl.h
new file mode 100644
index 0000000000..c55a36da45
--- /dev/null
+++ b/cpp/lib/broker/HandlerImpl.h
@@ -0,0 +1,71 @@
+#ifndef _broker_HandlerImpl_h
+#define _broker_HandlerImpl_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "BrokerChannel.h"
+#include "AMQP_ClientProxy.h"
+
+namespace qpid {
+
+namespace framing {
+class AMQP_ClientProxy;
+}
+
+namespace broker {
+
+class Broker;
+class Channel;
+class Connection;
+
+/**
+ * A collection of references to the core objects required by an adapter,
+ * and a client proxy.
+ */
+struct CoreRefs
+{
+ CoreRefs(Channel& ch, Connection& c, Broker& b)
+ : channel(ch), connection(c), broker(b), proxy(ch) {}
+
+ Channel& channel;
+ Connection& connection;
+ Broker& broker;
+ framing::AMQP_ClientProxy proxy;
+};
+
+
+/**
+ * Base template for protocol handler implementations.
+ * Provides the core references and appropriate AMQP class proxy.
+ */
+template <class ProxyType>
+struct HandlerImpl : public CoreRefs {
+ typedef HandlerImpl<ProxyType> HandlerImplType;
+ HandlerImpl(CoreRefs& parent)
+ : CoreRefs(parent), client(ProxyType::get(proxy)) {}
+ ProxyType client;
+};
+
+
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_HandlerImpl_h*/
diff --git a/cpp/lib/broker/HeadersExchange.cpp b/cpp/lib/broker/HeadersExchange.cpp
new file mode 100644
index 0000000000..acd344725a
--- /dev/null
+++ b/cpp/lib/broker/HeadersExchange.cpp
@@ -0,0 +1,121 @@
+/*
+ *
+ * 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 <HeadersExchange.h>
+#include <ExchangeBinding.h>
+#include <Value.h>
+#include <QpidError.h>
+#include <algorithm>
+
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+// TODO aconway 2006-09-20: More efficient matching algorithm.
+// The current search algorithm really sucks.
+// Fieldtables are heavy, maybe use shared_ptr to do handle-body.
+
+using namespace qpid::broker;
+
+namespace {
+ const std::string all("all");
+ const std::string any("any");
+ const std::string x_match("x-match");
+}
+
+HeadersExchange::HeadersExchange(const string& _name) : Exchange(_name) { }
+
+void HeadersExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args){
+ Mutex::ScopedLock locker(lock);
+ std::string what = args->getString("x-match");
+ if (what != all && what != any) {
+ THROW_QPID_ERROR(PROTOCOL_ERROR, "Invalid x-match value binding to headers exchange.");
+ }
+ bindings.push_back(Binding(*args, queue));
+ queue->bound(new ExchangeBinding(this, queue, routingKey, args));
+}
+
+void HeadersExchange::unbind(Queue::shared_ptr queue, const string& /*routingKey*/, const FieldTable* args){
+ Mutex::ScopedLock locker(lock);
+ Bindings::iterator i =
+ std::find(bindings.begin(),bindings.end(), Binding(*args, queue));
+ if (i != bindings.end()) bindings.erase(i);
+}
+
+
+void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* args){
+ Mutex::ScopedLock locker(lock);;
+ for (Bindings::iterator i = bindings.begin(); i != bindings.end(); ++i) {
+ if (match(i->first, *args)) msg.deliverTo(i->second);
+ }
+}
+
+HeadersExchange::~HeadersExchange() {}
+
+const std::string HeadersExchange::typeName("headers");
+
+namespace
+{
+
+ bool match_values(const Value& bind, const Value& msg) {
+ return dynamic_cast<const EmptyValue*>(&bind) || bind == msg;
+ }
+
+}
+
+
+bool HeadersExchange::match(const FieldTable& bind, const FieldTable& msg) {
+ typedef FieldTable::ValueMap Map;
+ std::string what = bind.getString(x_match);
+ if (what == all) {
+ for (Map::const_iterator i = bind.getMap().begin();
+ i != bind.getMap().end();
+ ++i)
+ {
+ if (i->first != x_match)
+ {
+ Map::const_iterator j = msg.getMap().find(i->first);
+ if (j == msg.getMap().end()) return false;
+ if (!match_values(*(i->second), *(j->second))) return false;
+ }
+ }
+ return true;
+ } else if (what == any) {
+ for (Map::const_iterator i = bind.getMap().begin();
+ i != bind.getMap().end();
+ ++i)
+ {
+ if (i->first != x_match)
+ {
+ Map::const_iterator j = msg.getMap().find(i->first);
+ if (j != msg.getMap().end()) {
+ if (match_values(*(i->second), *(j->second))) return true;
+ }
+ }
+ }
+ return false;
+ } else {
+ return false;
+ }
+}
+
+
+
diff --git a/cpp/lib/broker/HeadersExchange.h b/cpp/lib/broker/HeadersExchange.h
new file mode 100644
index 0000000000..5e8da5ad85
--- /dev/null
+++ b/cpp/lib/broker/HeadersExchange.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _HeadersExchange_
+#define _HeadersExchange_
+
+#include <vector>
+#include <BrokerExchange.h>
+#include <FieldTable.h>
+#include <BrokerMessage.h>
+#include <sys/Monitor.h>
+#include <BrokerQueue.h>
+
+namespace qpid {
+namespace broker {
+
+
+class HeadersExchange : public virtual Exchange {
+ typedef std::pair<qpid::framing::FieldTable, Queue::shared_ptr> Binding;
+ typedef std::vector<Binding> Bindings;
+
+ Bindings bindings;
+ qpid::sys::Mutex lock;
+
+ public:
+ static const std::string typeName;
+
+ HeadersExchange(const string& name);
+
+ virtual std::string getType(){ return typeName; }
+
+ virtual void bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual ~HeadersExchange();
+
+ static bool match(const qpid::framing::FieldTable& bindArgs, const qpid::framing::FieldTable& msgArgs);
+};
+
+
+
+}
+}
+
+#endif
diff --git a/cpp/lib/broker/InMemoryContent.cpp b/cpp/lib/broker/InMemoryContent.cpp
new file mode 100644
index 0000000000..3e4ac29486
--- /dev/null
+++ b/cpp/lib/broker/InMemoryContent.cpp
@@ -0,0 +1,73 @@
+/*
+ *
+ * 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 <InMemoryContent.h>
+#include "AMQFrame.h"
+#include "framing/ChannelAdapter.h"
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using boost::static_pointer_cast;
+
+void InMemoryContent::add(AMQContentBody::shared_ptr data)
+{
+ content.push_back(data);
+}
+
+uint32_t InMemoryContent::size()
+{
+ int sum(0);
+ for (content_iterator i = content.begin(); i != content.end(); i++) {
+ sum += (*i)->size();
+ }
+ return sum;
+}
+
+// FIXME aconway 2007-02-01: Remove version parameter.
+void InMemoryContent::send(ChannelAdapter& channel, uint32_t framesize)
+{
+ for (content_iterator i = content.begin(); i != content.end(); i++) {
+ if ((*i)->size() > framesize) {
+ uint32_t offset = 0;
+ for (int chunk = (*i)->size() / framesize; chunk > 0; chunk--) {
+ string data = (*i)->getData().substr(offset, framesize);
+ channel.send(new AMQContentBody(data));
+ offset += framesize;
+ }
+ uint32_t remainder = (*i)->size() % framesize;
+ if (remainder) {
+ string data = (*i)->getData().substr(offset, remainder);
+ channel.send(new AMQContentBody(data));
+ }
+ } else {
+ AMQBody::shared_ptr contentBody =
+ static_pointer_cast<AMQBody, AMQContentBody>(*i);
+ channel.send(contentBody);
+ }
+ }
+}
+
+void InMemoryContent::encode(Buffer& buffer)
+{
+ for (content_iterator i = content.begin(); i != content.end(); i++) {
+ (*i)->encode(buffer);
+ }
+}
+
diff --git a/cpp/lib/broker/InMemoryContent.h b/cpp/lib/broker/InMemoryContent.h
new file mode 100644
index 0000000000..7a58ace3a7
--- /dev/null
+++ b/cpp/lib/broker/InMemoryContent.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _InMemoryContent_
+#define _InMemoryContent_
+
+#include <Content.h>
+#include <vector>
+
+
+namespace qpid {
+ namespace broker {
+ class InMemoryContent : public Content{
+ typedef std::vector<qpid::framing::AMQContentBody::shared_ptr> content_list;
+ typedef content_list::iterator content_iterator;
+
+ content_list content;
+ public:
+ void add(qpid::framing::AMQContentBody::shared_ptr data);
+ uint32_t size();
+ void send(framing::ChannelAdapter&, uint32_t framesize);
+ void encode(qpid::framing::Buffer& buffer);
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/LazyLoadedContent.cpp b/cpp/lib/broker/LazyLoadedContent.cpp
new file mode 100644
index 0000000000..131943b448
--- /dev/null
+++ b/cpp/lib/broker/LazyLoadedContent.cpp
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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 <LazyLoadedContent.h>
+#include "AMQFrame.h"
+#include "framing/ChannelAdapter.h"
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+LazyLoadedContent::~LazyLoadedContent()
+{
+ store->destroy(msg);
+}
+
+LazyLoadedContent::LazyLoadedContent(MessageStore* const _store, Message* const _msg, uint64_t _expectedSize) :
+ store(_store), msg(_msg), expectedSize(_expectedSize) {}
+
+void LazyLoadedContent::add(AMQContentBody::shared_ptr data)
+{
+ store->appendContent(msg, data->getData());
+}
+
+uint32_t LazyLoadedContent::size()
+{
+ return 0;//all content is written as soon as it is added
+}
+
+void LazyLoadedContent::send(ChannelAdapter& channel, uint32_t framesize)
+{
+ if (expectedSize > framesize) {
+ for (uint64_t offset = 0; offset < expectedSize; offset += framesize)
+ {
+ uint64_t remaining = expectedSize - offset;
+ string data;
+ store->loadContent(msg, data, offset,
+ remaining > framesize ? framesize : remaining);
+ channel.send(new AMQContentBody(data));
+ }
+ } else {
+ string data;
+ store->loadContent(msg, data, 0, expectedSize);
+ channel.send(new AMQContentBody(data));
+ }
+}
+
+void LazyLoadedContent::encode(Buffer&)
+{
+ //do nothing as all content is written as soon as it is added
+}
+
diff --git a/cpp/lib/broker/LazyLoadedContent.h b/cpp/lib/broker/LazyLoadedContent.h
new file mode 100644
index 0000000000..e000a4ef69
--- /dev/null
+++ b/cpp/lib/broker/LazyLoadedContent.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _LazyLoadedContent_
+#define _LazyLoadedContent_
+
+#include <Content.h>
+#include <MessageStore.h>
+
+namespace qpid {
+ namespace broker {
+ class LazyLoadedContent : public Content{
+ MessageStore* const store;
+ Message* const msg;
+ const uint64_t expectedSize;
+ public:
+ LazyLoadedContent(
+ MessageStore* const store, Message* const msg,
+ uint64_t expectedSize);
+ ~LazyLoadedContent();
+ void add(qpid::framing::AMQContentBody::shared_ptr data);
+ uint32_t size();
+ void send(
+ framing::ChannelAdapter&,
+ uint32_t framesize);
+ void encode(qpid::framing::Buffer& buffer);
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/Makefile.am b/cpp/lib/broker/Makefile.am
new file mode 100644
index 0000000000..68649c2b28
--- /dev/null
+++ b/cpp/lib/broker/Makefile.am
@@ -0,0 +1,96 @@
+AM_CXXFLAGS = $(WARNING_CFLAGS)
+INCLUDES = \
+ -I$(top_srcdir)/gen \
+ -I$(top_srcdir)/lib/common \
+ -I$(top_srcdir)/lib/common/sys \
+ -I$(top_srcdir)/lib/common/framing \
+ $(APR_CXXFLAGS)
+
+lib_LTLIBRARIES = libqpidbroker.la
+libqpidbroker_la_LIBADD = ../common/libqpidcommon.la
+libqpidbroker_la_LDFLAGS = -version-info $(LIBTOOL_VERSION_INFO_ARG)
+libqpidbroker_la_SOURCES = \
+ AccumulatedAck.cpp \
+ AccumulatedAck.h \
+ AutoDelete.cpp \
+ AutoDelete.h \
+ Binding.h \
+ Broker.cpp \
+ Broker.h \
+ BrokerSingleton.cpp \
+ BrokerSingleton.h \
+ BrokerChannel.cpp \
+ BrokerChannel.h \
+ BrokerExchange.h \
+ BrokerMessage.cpp \
+ BrokerMessage.h \
+ BrokerMessageMessage.cpp \
+ BrokerMessageMessage.h \
+ BrokerQueue.cpp \
+ BrokerQueue.h \
+ Configuration.cpp \
+ Configuration.h \
+ ConnectionToken.h \
+ Consumer.h \
+ Content.h \
+ DeletingTxOp.cpp \
+ DeletingTxOp.h \
+ Deliverable.h \
+ DeliverableMessage.cpp \
+ DeliverableMessage.h \
+ DeliveryRecord.cpp \
+ DeliveryRecord.h \
+ DirectExchange.cpp \
+ DirectExchange.h \
+ ExchangeBinding.cpp \
+ ExchangeBinding.h \
+ ExchangeRegistry.cpp \
+ ExchangeRegistry.h \
+ FanOutExchange.cpp \
+ FanOutExchange.h \
+ HeadersExchange.cpp \
+ HeadersExchange.h \
+ InMemoryContent.cpp \
+ InMemoryContent.h \
+ LazyLoadedContent.cpp \
+ LazyLoadedContent.h \
+ MessageBuilder.cpp \
+ MessageBuilder.h \
+ MessageStore.h \
+ MessageStoreModule.cpp \
+ MessageStoreModule.h \
+ NameGenerator.cpp \
+ NameGenerator.h \
+ NullMessageStore.cpp \
+ NullMessageStore.h \
+ Prefetch.h \
+ QueuePolicy.cpp \
+ QueuePolicy.h \
+ QueueRegistry.cpp \
+ QueueRegistry.h \
+ RecoveryManager.cpp \
+ RecoveryManager.h \
+ Reference.cpp \
+ Reference.h \
+ ConnectionFactory.cpp \
+ ConnectionFactory.h \
+ Connection.cpp \
+ Connection.h \
+ BrokerAdapter.cpp \
+ BrokerAdapter.h \
+ MessageHandlerImpl.cpp \
+ MessageHandlerImpl.h \
+ TopicExchange.cpp \
+ TopicExchange.h \
+ TransactionalStore.h \
+ TxAck.cpp \
+ TxAck.h \
+ TxBuffer.cpp \
+ TxBuffer.h \
+ TxOp.h \
+ TxPublish.cpp \
+ TxPublish.h
+
+
+# Force build during dist phase so help2man will work.
+dist-hook: $(lib_LTLIBRARIES)
diff --git a/cpp/lib/broker/MessageBuilder.cpp b/cpp/lib/broker/MessageBuilder.cpp
new file mode 100644
index 0000000000..8bffaef50f
--- /dev/null
+++ b/cpp/lib/broker/MessageBuilder.cpp
@@ -0,0 +1,74 @@
+/*
+ *
+ * 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 <MessageBuilder.h>
+
+#include <InMemoryContent.h>
+#include <LazyLoadedContent.h>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using std::auto_ptr;
+
+MessageBuilder::MessageBuilder(CompletionHandler* _handler,
+ MessageStore* const _store,
+ uint64_t _stagingThreshold
+) :
+ handler(_handler),
+ store(_store),
+ stagingThreshold(_stagingThreshold)
+{}
+
+void MessageBuilder::route(){
+ if (message->isComplete()) {
+ if (handler) handler->complete(message);
+ message.reset();
+ }
+}
+
+void MessageBuilder::initialise(Message::shared_ptr& msg){
+ if(message.get()){
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Invalid message sequence: got publish before previous content was completed.");
+ }
+ message = msg;
+}
+
+void MessageBuilder::setHeader(AMQHeaderBody::shared_ptr& header){
+ if(!message.get()){
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Invalid message sequence: got header before publish.");
+ }
+ message->setHeader(header);
+ if (stagingThreshold && header->getContentSize() >= stagingThreshold) {
+ store->stage(message.get());
+ message->releaseContent(store);
+ } else {
+ auto_ptr<Content> content(new InMemoryContent());
+ message->setContent(content);
+ }
+ route();
+}
+
+void MessageBuilder::addContent(AMQContentBody::shared_ptr& content){
+ if(!message.get()){
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Invalid message sequence: got content before publish.");
+ }
+ message->addContent(content);
+ route();
+}
diff --git a/cpp/lib/broker/MessageBuilder.h b/cpp/lib/broker/MessageBuilder.h
new file mode 100644
index 0000000000..30834e1075
--- /dev/null
+++ b/cpp/lib/broker/MessageBuilder.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _MessageBuilder_
+#define _MessageBuilder_
+
+#include <memory>
+#include <QpidError.h>
+#include <BrokerExchange.h>
+#include <BrokerMessage.h>
+#include <MessageStore.h>
+#include <AMQContentBody.h>
+#include <AMQHeaderBody.h>
+#include <BasicPublishBody.h>
+#include "CompletionHandler.h"
+
+namespace qpid {
+ namespace broker {
+ class MessageBuilder{
+ public:
+ MessageBuilder(CompletionHandler* _handler,
+ MessageStore* const store = 0,
+ uint64_t stagingThreshold = 0);
+ void initialise(Message::shared_ptr& msg);
+ void setHeader(framing::AMQHeaderBody::shared_ptr& header);
+ void addContent(framing::AMQContentBody::shared_ptr& content);
+ Message::shared_ptr getMessage() { return message; }
+ private:
+ Message::shared_ptr message;
+ CompletionHandler* handler;
+ MessageStore* const store;
+ const uint64_t stagingThreshold;
+
+ void route();
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/MessageHandlerImpl.cpp b/cpp/lib/broker/MessageHandlerImpl.cpp
new file mode 100644
index 0000000000..fa7c10f26c
--- /dev/null
+++ b/cpp/lib/broker/MessageHandlerImpl.cpp
@@ -0,0 +1,243 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "QpidError.h"
+#include "MessageHandlerImpl.h"
+#include "BrokerChannel.h"
+#include "FramingContent.h"
+#include "Connection.h"
+#include "Broker.h"
+#include "BrokerMessageMessage.h"
+#include "MessageAppendBody.h"
+#include "MessageTransferBody.h"
+#include "BrokerAdapter.h"
+
+namespace qpid {
+namespace broker {
+
+using namespace framing;
+
+MessageHandlerImpl::MessageHandlerImpl(CoreRefs& parent)
+ : HandlerImplType(parent) {}
+
+//
+// Message class method handlers
+//
+
+void
+MessageHandlerImpl::cancel(const MethodContext& context,
+ const string& destination )
+{
+ channel.cancel(destination);
+ client.ok(context.getRequestId());
+}
+
+void
+MessageHandlerImpl::open(const MethodContext& context,
+ const string& reference)
+{
+ references.open(reference);
+ client.ok(context.getRequestId());
+}
+
+void
+MessageHandlerImpl::append(const MethodContext& context,
+ const string& reference,
+ const string& /*bytes*/ )
+{
+ references.get(reference)->append(
+ boost::shared_polymorphic_downcast<MessageAppendBody>(
+ context.methodBody));
+ client.ok(context.getRequestId());
+}
+
+void
+MessageHandlerImpl::close(const MethodContext& context,
+ const string& reference)
+{
+ Reference::shared_ptr ref = references.get(reference);
+ client.ok(context.getRequestId());
+
+ // Send any transfer messages to their correct exchanges and okay them
+ const Reference::Messages& msgs = ref->getMessages();
+ for (Reference::Messages::const_iterator m = msgs.begin(); m != msgs.end(); ++m) {
+ channel.handleInlineTransfer(*m);
+ client.ok((*m)->getRequestId());
+ }
+ ref->close();
+}
+
+void
+MessageHandlerImpl::checkpoint(const MethodContext& context,
+ const string& /*reference*/,
+ const string& /*identifier*/ )
+{
+ // Initial implementation (which is conforming) is to do nothing here
+ // and return offset zero for the resume
+ client.ok(context.getRequestId());
+}
+
+void
+MessageHandlerImpl::resume(const MethodContext& context,
+ const string& reference,
+ const string& /*identifier*/ )
+{
+ // Initial (null) implementation
+ // open reference and return 0 offset
+ references.open(reference);
+ client.offset(0, context.getRequestId());
+}
+
+void
+MessageHandlerImpl::offset(const MethodContext&,
+ uint64_t /*value*/ )
+{
+ // Shouldn't ever receive this as it is reponse to resume
+ // which is never sent
+ // TODO astitcher 2007-02-16 What is the correct exception to throw here?
+ THROW_QPID_ERROR(INTERNAL_ERROR, "impossible");
+}
+
+void
+MessageHandlerImpl::consume(const MethodContext& context,
+ uint16_t /*ticket*/,
+ const string& queueName,
+ const string& destination,
+ bool noLocal,
+ bool noAck,
+ bool exclusive,
+ const framing::FieldTable& filter )
+{
+ Queue::shared_ptr queue = connection.getQueue(queueName, channel.getId());
+ if(!destination.empty() && channel.exists(destination))
+ throw ConnectionException(530, "Consumer tags must be unique");
+ string tag = destination;
+ channel.consume(
+ tag, queue, !noAck, exclusive,
+ noLocal ? &connection : 0, &filter);
+ client.ok(context.getRequestId());
+ // Dispatch messages as there is now a consumer.
+ queue->dispatch();
+}
+
+void
+MessageHandlerImpl::get( const MethodContext& context,
+ uint16_t /*ticket*/,
+ const string& queueName,
+ const string& destination,
+ bool noAck )
+{
+ Queue::shared_ptr queue =
+ connection.getQueue(queueName, context.channel->getId());
+
+ if(channel.get(queue, destination, !noAck))
+ client.ok(context.getRequestId());
+ else
+ client.empty(context.getRequestId());
+}
+
+void
+MessageHandlerImpl::empty( const MethodContext& )
+{
+ // Shouldn't ever receive this as it is a response to get
+ // which is never sent
+ // TODO astitcher 2007-02-09 What is the correct exception to throw here?
+ THROW_QPID_ERROR(INTERNAL_ERROR, "Impossible");
+}
+
+void
+MessageHandlerImpl::ok(const MethodContext& /*context*/)
+{
+ channel.ack();
+}
+
+void
+MessageHandlerImpl::qos(const MethodContext& context,
+ uint32_t prefetchSize,
+ uint16_t prefetchCount,
+ bool /*global*/ )
+{
+ //TODO: handle global
+ channel.setPrefetchSize(prefetchSize);
+ channel.setPrefetchCount(prefetchCount);
+ client.ok(context.getRequestId());
+}
+
+void
+MessageHandlerImpl::recover(const MethodContext& context,
+ bool requeue)
+{
+ channel.recover(requeue);
+ client.ok(context.getRequestId());
+}
+
+void
+MessageHandlerImpl::reject(const MethodContext& /*context*/,
+ uint16_t /*code*/,
+ const string& /*text*/ )
+{
+ channel.ack();
+ // channel.requeue();
+}
+
+void
+MessageHandlerImpl::transfer(const MethodContext& context,
+ uint16_t /*ticket*/,
+ const string& /* destination */,
+ bool /*redelivered*/,
+ bool /*immediate*/,
+ uint64_t /*ttl*/,
+ uint8_t /*priority*/,
+ uint64_t /*timestamp*/,
+ uint8_t /*deliveryMode*/,
+ uint64_t /*expiration*/,
+ const string& /*exchangeName*/,
+ const string& /*routingKey*/,
+ const string& /*messageId*/,
+ const string& /*correlationId*/,
+ const string& /*replyTo*/,
+ const string& /*contentType*/,
+ const string& /*contentEncoding*/,
+ const string& /*userId*/,
+ const string& /*appId*/,
+ const string& /*transactionId*/,
+ const string& /*securityToken*/,
+ const framing::FieldTable& /*applicationHeaders*/,
+ const framing::Content& body,
+ bool /*mandatory*/)
+{
+ MessageTransferBody::shared_ptr transfer(
+ boost::shared_polymorphic_downcast<MessageTransferBody>(
+ context.methodBody));
+ RequestId requestId = context.getRequestId();
+
+ if (body.isInline()) {
+ MessageMessage::shared_ptr message(
+ new MessageMessage(&connection, requestId, transfer));
+ channel.handleInlineTransfer(message);
+ client.ok(requestId);
+ } else {
+ Reference::shared_ptr ref(references.get(body.getValue()));
+ MessageMessage::shared_ptr message(
+ new MessageMessage(&connection, requestId, transfer, ref));
+ ref->addMessage(message);
+ }
+}
+
+
+}} // namespace qpid::broker
diff --git a/cpp/lib/broker/MessageHandlerImpl.h b/cpp/lib/broker/MessageHandlerImpl.h
new file mode 100644
index 0000000000..872d429d5c
--- /dev/null
+++ b/cpp/lib/broker/MessageHandlerImpl.h
@@ -0,0 +1,130 @@
+#ifndef _broker_MessageHandlerImpl_h
+#define _broker_MessageHandlerImpl_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <memory>
+
+#include "AMQP_ServerOperations.h"
+#include "AMQP_ClientProxy.h"
+#include "Reference.h"
+#include "HandlerImpl.h"
+
+namespace qpid {
+namespace broker {
+
+class Connection;
+class Broker;
+class MessageMessage;
+
+class MessageHandlerImpl :
+ public framing::AMQP_ServerOperations::MessageHandler,
+ public HandlerImpl<framing::AMQP_ClientProxy::Message>
+{
+ public:
+ MessageHandlerImpl(CoreRefs& parent);
+
+ void append(const framing::MethodContext&,
+ const std::string& reference,
+ const std::string& bytes );
+
+ void cancel(const framing::MethodContext&,
+ const std::string& destination );
+
+ void checkpoint(const framing::MethodContext&,
+ const std::string& reference,
+ const std::string& identifier );
+
+ void close(const framing::MethodContext&,
+ const std::string& reference );
+
+ void consume(const framing::MethodContext&,
+ uint16_t ticket,
+ const std::string& queue,
+ const std::string& destination,
+ bool noLocal,
+ bool noAck,
+ bool exclusive,
+ const framing::FieldTable& filter );
+
+ void empty( const framing::MethodContext& );
+
+ void get(const framing::MethodContext&,
+ uint16_t ticket,
+ const std::string& queue,
+ const std::string& destination,
+ bool noAck );
+
+ void offset(const framing::MethodContext&,
+ uint64_t value );
+
+ void ok( const framing::MethodContext& );
+
+ void open(const framing::MethodContext&,
+ const std::string& reference );
+
+ void qos(const framing::MethodContext&,
+ uint32_t prefetchSize,
+ uint16_t prefetchCount,
+ bool global );
+
+ void recover(const framing::MethodContext&,
+ bool requeue );
+
+ void reject(const framing::MethodContext&,
+ uint16_t code,
+ const std::string& text );
+
+ void resume(const framing::MethodContext&,
+ const std::string& reference,
+ const std::string& identifier );
+
+ void transfer(const framing::MethodContext&,
+ uint16_t ticket,
+ const std::string& destination,
+ bool redelivered,
+ bool immediate,
+ uint64_t ttl,
+ uint8_t priority,
+ uint64_t timestamp,
+ uint8_t deliveryMode,
+ uint64_t expiration,
+ const std::string& exchange,
+ const std::string& routingKey,
+ const std::string& messageId,
+ const std::string& correlationId,
+ const std::string& replyTo,
+ const std::string& contentType,
+ const std::string& contentEncoding,
+ const std::string& userId,
+ const std::string& appId,
+ const std::string& transactionId,
+ const std::string& securityToken,
+ const framing::FieldTable& applicationHeaders,
+ const framing::Content& body,
+ bool mandatory );
+ private:
+ ReferenceRegistry references;
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_MessageHandlerImpl_h*/
diff --git a/cpp/lib/broker/MessageStore.h b/cpp/lib/broker/MessageStore.h
new file mode 100644
index 0000000000..9e38408886
--- /dev/null
+++ b/cpp/lib/broker/MessageStore.h
@@ -0,0 +1,140 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _MessageStore_
+#define _MessageStore_
+
+#include <BrokerMessage.h>
+#include <FieldTable.h>
+#include <RecoveryManager.h>
+#include <TransactionalStore.h>
+
+namespace qpid {
+ namespace broker {
+ struct MessageStoreSettings
+ {
+ /**
+ * Messages whose content length is larger than this value
+ * will be staged (i.e. will have thier data written to
+ * disk as it arrives) and will load their data lazily. On
+ * recovery therefore, only the headers should be loaded.
+ */
+ uint64_t stagingThreshold;
+ };
+ /**
+ * An abstraction of the persistent storage for messages. (In
+ * all methods, any pointers/references to queues or messages
+ * are valid only for the duration of the call).
+ */
+ class MessageStore : public TransactionalStore{
+ public:
+ /**
+ * Record the existance of a durable queue
+ */
+ virtual void create(const Queue& queue, const qpid::framing::FieldTable& settings) = 0;
+ /**
+ * Destroy a durable queue
+ */
+ virtual void destroy(const Queue& queue) = 0;
+
+ /**
+ * Request recovery of queue and message state from store
+ */
+ virtual void recover(RecoveryManager& queues, const MessageStoreSettings* const settings = 0) = 0;
+
+ /**
+ * Stores a messages before it has been enqueued
+ * (enqueueing automatically stores the message so this is
+ * only required if storage is required prior to that
+ * point). If the message has not yet been stored it will
+ * store the headers as well as any content passed in. A
+ * persistence id will be set on the message which can be
+ * used to load the content or to append to it.
+ */
+ virtual void stage(Message* const msg) = 0;
+
+ /**
+ * Destroys a previously staged message. This only needs
+ * to be called if the message is never enqueued. (Once
+ * enqueued, deletion will be automatic when the message
+ * is dequeued from all queues it was enqueued onto).
+ */
+ virtual void destroy(Message* const msg) = 0;
+
+ /**
+ * Appends content to a previously staged message
+ */
+ virtual void appendContent(Message* const msg, const std::string& data) = 0;
+
+ /**
+ * Loads (a section) of content data for the specified
+ * message (previously stored through a call to stage or
+ * enqueue) into data. The offset refers to the content
+ * only (i.e. an offset of 0 implies that the start of the
+ * content should be loaded, not the headers or related
+ * meta-data).
+ */
+ virtual void loadContent(Message* const msg, std::string& data, uint64_t offset, uint32_t length) = 0;
+
+ /**
+ * Enqueues a message, storing the message if it has not
+ * been previously stored and recording that the given
+ * message is on the given queue.
+ *
+ * @param msg the message to enqueue
+ * @param queue the name of the queue onto which it is to be enqueued
+ * @param xid (a pointer to) an identifier of the
+ * distributed transaction in which the operation takes
+ * place or null for 'local' transactions
+ */
+ virtual void enqueue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const std::string * const xid) = 0;
+ /**
+ * Dequeues a message, recording that the given message is
+ * no longer on the given queue and deleting the message
+ * if it is no longer on any other queue.
+ *
+ * @param msg the message to dequeue
+ * @param queue the name of th queue from which it is to be dequeued
+ * @param xid (a pointer to) an identifier of the
+ * distributed transaction in which the operation takes
+ * place or null for 'local' transactions
+ */
+ virtual void dequeue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const std::string * const xid) = 0;
+
+ /**
+ * Treat all enqueue/dequeues where this xid was specified as being prepared.
+ */
+ virtual void prepared(const std::string * const xid) = 0;
+ /**
+ * Treat all enqueue/dequeues where this xid was specified as being committed.
+ */
+ virtual void committed(const std::string * const xid) = 0;
+ /**
+ * Treat all enqueue/dequeues where this xid was specified as being aborted.
+ */
+ virtual void aborted(const std::string * const xid) = 0;
+
+ virtual ~MessageStore(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/MessageStoreModule.cpp b/cpp/lib/broker/MessageStoreModule.cpp
new file mode 100644
index 0000000000..676e86f84a
--- /dev/null
+++ b/cpp/lib/broker/MessageStoreModule.cpp
@@ -0,0 +1,104 @@
+/*
+ *
+ * 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 <MessageStoreModule.h>
+#include <iostream>
+
+using namespace qpid::broker;
+
+MessageStoreModule::MessageStoreModule(const std::string& name) : store(name)
+{
+}
+
+void MessageStoreModule::create(const Queue& queue, const qpid::framing::FieldTable& settings)
+{
+ store->create(queue, settings);
+}
+
+void MessageStoreModule::destroy(const Queue& queue)
+{
+ store->destroy(queue);
+}
+
+void MessageStoreModule::recover(RecoveryManager& registry, const MessageStoreSettings* const settings)
+{
+ store->recover(registry, settings);
+}
+
+void MessageStoreModule::stage(Message* const msg)
+{
+ store->stage(msg);
+}
+
+void MessageStoreModule::destroy(Message* const msg)
+{
+ store->destroy(msg);
+}
+
+void MessageStoreModule::appendContent(Message* const msg, const std::string& data)
+{
+ store->appendContent(msg, data);
+}
+
+void MessageStoreModule::loadContent(Message* const msg, string& data, uint64_t offset, uint32_t length)
+{
+ store->loadContent(msg, data, offset, length);
+}
+
+void MessageStoreModule::enqueue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const string * const xid)
+{
+ store->enqueue(ctxt, msg, queue, xid);
+}
+
+void MessageStoreModule::dequeue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const string * const xid)
+{
+ store->dequeue(ctxt, msg, queue, xid);
+}
+
+void MessageStoreModule::prepared(const string * const xid)
+{
+ store->prepared(xid);
+}
+
+void MessageStoreModule::committed(const string * const xid)
+{
+ store->committed(xid);
+}
+
+void MessageStoreModule::aborted(const string * const xid)
+{
+ store->aborted(xid);
+}
+
+std::auto_ptr<TransactionContext> MessageStoreModule::begin()
+{
+ return store->begin();
+}
+
+void MessageStoreModule::commit(TransactionContext* ctxt)
+{
+ store->commit(ctxt);
+}
+
+void MessageStoreModule::abort(TransactionContext* ctxt)
+{
+ store->abort(ctxt);
+}
diff --git a/cpp/lib/broker/MessageStoreModule.h b/cpp/lib/broker/MessageStoreModule.h
new file mode 100644
index 0000000000..27fedbf635
--- /dev/null
+++ b/cpp/lib/broker/MessageStoreModule.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _MessageStoreModule_
+#define _MessageStoreModule_
+
+#include <BrokerMessage.h>
+#include <MessageStore.h>
+#include <BrokerQueue.h>
+#include <RecoveryManager.h>
+#include <sys/Module.h>
+
+namespace qpid {
+ namespace broker {
+ /**
+ * A null implementation of the MessageStore interface
+ */
+ class MessageStoreModule : public MessageStore{
+ qpid::sys::Module<MessageStore> store;
+ public:
+ MessageStoreModule(const std::string& name);
+ void create(const Queue& queue, const qpid::framing::FieldTable& settings);
+ void destroy(const Queue& queue);
+ void recover(RecoveryManager& queues, const MessageStoreSettings* const settings = 0);
+ void stage(Message* const msg);
+ void destroy(Message* const msg);
+ void appendContent(Message* const msg, const std::string& data);
+ void loadContent(Message* const msg, std::string& data, uint64_t offset, uint32_t length);
+ void enqueue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const string * const xid);
+ void dequeue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const string * const xid);
+ void prepared(const std::string * const xid);
+ void committed(const std::string * const xid);
+ void aborted(const std::string * const xid);
+ std::auto_ptr<TransactionContext> begin();
+ void commit(TransactionContext* ctxt);
+ void abort(TransactionContext* ctxt);
+ ~MessageStoreModule(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/NameGenerator.cpp b/cpp/lib/broker/NameGenerator.cpp
new file mode 100644
index 0000000000..3f281859fa
--- /dev/null
+++ b/cpp/lib/broker/NameGenerator.cpp
@@ -0,0 +1,32 @@
+/*
+ *
+ * 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 <NameGenerator.h>
+#include <sstream>
+
+using namespace qpid::broker;
+
+NameGenerator::NameGenerator(const std::string& _base) : base(_base), counter(1) {}
+
+std::string NameGenerator::generate(){
+ std::stringstream ss;
+ ss << base << counter++;
+ return ss.str();
+}
diff --git a/cpp/lib/broker/NameGenerator.h b/cpp/lib/broker/NameGenerator.h
new file mode 100644
index 0000000000..b2dbbdfb69
--- /dev/null
+++ b/cpp/lib/broker/NameGenerator.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _NameGenerator_
+#define _NameGenerator_
+
+#include <BrokerMessage.h>
+
+namespace qpid {
+ namespace broker {
+ class NameGenerator{
+ const std::string base;
+ unsigned int counter;
+ public:
+ NameGenerator(const std::string& base);
+ std::string generate();
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/NullMessageStore.cpp b/cpp/lib/broker/NullMessageStore.cpp
new file mode 100644
index 0000000000..bcb15c2ae0
--- /dev/null
+++ b/cpp/lib/broker/NullMessageStore.cpp
@@ -0,0 +1,104 @@
+/*
+ *
+ * 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 <NullMessageStore.h>
+
+#include <BrokerQueue.h>
+#include <RecoveryManager.h>
+
+#include <iostream>
+
+using namespace qpid::broker;
+
+NullMessageStore::NullMessageStore(bool _warn) : warn(_warn){}
+
+void NullMessageStore::create(const Queue& queue, const qpid::framing::FieldTable&)
+{
+ if (warn) std::cout << "WARNING: Can't create durable queue '" << queue.getName() << "'. Persistence not enabled." << std::endl;
+}
+
+void NullMessageStore::destroy(const Queue& queue)
+{
+ if (warn) std::cout << "WARNING: Can't destroy durable queue '" << queue.getName() << "'. Persistence not enabled." << std::endl;
+}
+
+void NullMessageStore::recover(RecoveryManager&, const MessageStoreSettings* const)
+{
+ if (warn) std::cout << "WARNING: Persistence not enabled, no recovery of queues or messages." << std::endl;
+}
+
+void NullMessageStore::stage(Message* const)
+{
+ if (warn) std::cout << "WARNING: Can't stage message. Persistence not enabled." << std::endl;
+}
+
+void NullMessageStore::destroy(Message* const)
+{
+ if (warn) std::cout << "WARNING: No need to destroy staged message. Persistence not enabled." << std::endl;
+}
+
+void NullMessageStore::appendContent(Message* const, const string&)
+{
+ if (warn) std::cout << "WARNING: Can't append content. Persistence not enabled." << std::endl;
+}
+
+void NullMessageStore::loadContent(Message* const, string&, uint64_t, uint32_t)
+{
+ if (warn) std::cout << "WARNING: Can't load content. Persistence not enabled." << std::endl;
+}
+
+void NullMessageStore::enqueue(TransactionContext*, Message* const, const Queue& queue, const string * const)
+{
+ if (warn) std::cout << "WARNING: Can't enqueue message onto '" << queue.getName() << "'. Persistence not enabled." << std::endl;
+}
+
+void NullMessageStore::dequeue(TransactionContext*, Message* const, const Queue& queue, const string * const)
+{
+ if (warn) std::cout << "WARNING: Can't dequeue message from '" << queue.getName() << "'. Persistence not enabled." << std::endl;
+}
+
+void NullMessageStore::prepared(const string * const)
+{
+ if (warn) std::cout << "WARNING: Persistence not enabled." << std::endl;
+}
+
+void NullMessageStore::committed(const string * const)
+{
+ if (warn) std::cout << "WARNING: Persistence not enabled." << std::endl;
+}
+
+void NullMessageStore::aborted(const string * const)
+{
+ if (warn) std::cout << "WARNING: Persistence not enabled." << std::endl;
+}
+
+std::auto_ptr<TransactionContext> NullMessageStore::begin()
+{
+ return std::auto_ptr<TransactionContext>();
+}
+
+void NullMessageStore::commit(TransactionContext*)
+{
+}
+
+void NullMessageStore::abort(TransactionContext*)
+{
+}
diff --git a/cpp/lib/broker/NullMessageStore.h b/cpp/lib/broker/NullMessageStore.h
new file mode 100644
index 0000000000..705f18ab43
--- /dev/null
+++ b/cpp/lib/broker/NullMessageStore.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _NullMessageStore_
+#define _NullMessageStore_
+
+#include <BrokerMessage.h>
+#include <MessageStore.h>
+#include <BrokerQueue.h>
+
+namespace qpid {
+ namespace broker {
+
+ /**
+ * A null implementation of the MessageStore interface
+ */
+ class NullMessageStore : public MessageStore{
+ const bool warn;
+ public:
+ NullMessageStore(bool warn = false);
+ virtual void create(const Queue& queue, const qpid::framing::FieldTable& settings);
+ virtual void destroy(const Queue& queue);
+ virtual void recover(RecoveryManager& queues, const MessageStoreSettings* const settings = 0);
+ virtual void stage(Message* const msg);
+ virtual void destroy(Message* const msg);
+ virtual void appendContent(Message* const msg, const std::string& data);
+ virtual void loadContent(Message* const msg, std::string& data, uint64_t offset, uint32_t length);
+ virtual void enqueue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const string * const xid);
+ virtual void dequeue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const string * const xid);
+ virtual void prepared(const std::string * const xid);
+ virtual void committed(const std::string * const xid);
+ virtual void aborted(const std::string * const xid);
+ virtual std::auto_ptr<TransactionContext> begin();
+ virtual void commit(TransactionContext* ctxt);
+ virtual void abort(TransactionContext* ctxt);
+ ~NullMessageStore(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/Prefetch.h b/cpp/lib/broker/Prefetch.h
new file mode 100644
index 0000000000..b6d4026c3f
--- /dev/null
+++ b/cpp/lib/broker/Prefetch.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Prefetch_
+#define _Prefetch_
+
+#include <amqp_types.h>
+
+namespace qpid {
+ namespace broker {
+ /**
+ * Count and total size of asynchronously delivered
+ * (i.e. pushed) messages that have acks outstanding.
+ */
+ struct Prefetch{
+ uint32_t size;
+ uint16_t count;
+
+ void reset() { size = 0; count = 0; }
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/QueuePolicy.cpp b/cpp/lib/broker/QueuePolicy.cpp
new file mode 100644
index 0000000000..94b86f2bbb
--- /dev/null
+++ b/cpp/lib/broker/QueuePolicy.cpp
@@ -0,0 +1,69 @@
+/*
+ *
+ * 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 <QueuePolicy.h>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+QueuePolicy::QueuePolicy(uint32_t _maxCount, uint64_t _maxSize) :
+ maxCount(_maxCount), maxSize(_maxSize), count(0), size(0) {}
+
+QueuePolicy::QueuePolicy(const FieldTable& settings) :
+ maxCount(getInt(settings, maxCountKey, 0)),
+ maxSize(getInt(settings, maxSizeKey, 0)), count(0), size(0) {}
+
+void QueuePolicy::enqueued(uint64_t _size)
+{
+ if (maxCount) count++;
+ if (maxSize) size += _size;
+}
+
+void QueuePolicy::dequeued(uint64_t _size)
+{
+ if (maxCount) count--;
+ if (maxSize) size -= _size;
+}
+
+bool QueuePolicy::limitExceeded()
+{
+ return (maxSize && size > maxSize) || (maxCount && count > maxCount);
+}
+
+void QueuePolicy::update(FieldTable& settings)
+{
+ if (maxCount) settings.setInt(maxCountKey, maxCount);
+ if (maxSize) settings.setInt(maxSizeKey, maxSize);
+}
+
+
+int QueuePolicy::getInt(const FieldTable& settings, const std::string& key, int defaultValue)
+{
+ //Note: currently field table only contain signed 32 bit ints, which
+ // restricts the values that can be set on the queue policy.
+ try {
+ return settings.getInt(key);
+ } catch (FieldNotFoundException& ignore) {
+ return defaultValue;
+ }
+}
+
+const std::string QueuePolicy::maxCountKey("qpid.max_count");
+const std::string QueuePolicy::maxSizeKey("qpid.max_size");
diff --git a/cpp/lib/broker/QueuePolicy.h b/cpp/lib/broker/QueuePolicy.h
new file mode 100644
index 0000000000..e7688f3e67
--- /dev/null
+++ b/cpp/lib/broker/QueuePolicy.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _QueuePolicy_
+#define _QueuePolicy_
+
+#include <FieldTable.h>
+
+namespace qpid {
+ namespace broker {
+ class QueuePolicy
+ {
+ static const std::string maxCountKey;
+ static const std::string maxSizeKey;
+
+ const uint32_t maxCount;
+ const uint64_t maxSize;
+ uint32_t count;
+ uint64_t size;
+
+ static int getInt(const qpid::framing::FieldTable& settings, const std::string& key, int defaultValue);
+
+ public:
+ QueuePolicy(uint32_t maxCount, uint64_t maxSize);
+ QueuePolicy(const qpid::framing::FieldTable& settings);
+ void enqueued(uint64_t size);
+ void dequeued(uint64_t size);
+ void update(qpid::framing::FieldTable& settings);
+ bool limitExceeded();
+ uint32_t getMaxCount() const { return maxCount; }
+ uint64_t getMaxSize() const { return maxSize; }
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/QueueRegistry.cpp b/cpp/lib/broker/QueueRegistry.cpp
new file mode 100644
index 0000000000..d33cd09840
--- /dev/null
+++ b/cpp/lib/broker/QueueRegistry.cpp
@@ -0,0 +1,78 @@
+/*
+ *
+ * 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 <QueueRegistry.h>
+#include <sstream>
+#include <assert.h>
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+
+QueueRegistry::QueueRegistry(MessageStore* const _store) : counter(1), store(_store){}
+
+QueueRegistry::~QueueRegistry(){}
+
+std::pair<Queue::shared_ptr, bool>
+QueueRegistry::declare(const string& declareName, bool durable,
+ uint32_t autoDelete, const ConnectionToken* owner)
+{
+ Mutex::ScopedLock locker(lock);
+ string name = declareName.empty() ? generateName() : declareName;
+ assert(!name.empty());
+ QueueMap::iterator i = queues.find(name);
+ if (i == queues.end()) {
+ Queue::shared_ptr queue(new Queue(name, autoDelete, durable ? store : 0, owner));
+ queues[name] = queue;
+ return std::pair<Queue::shared_ptr, bool>(queue, true);
+ } else {
+ return std::pair<Queue::shared_ptr, bool>(i->second, false);
+ }
+}
+
+void QueueRegistry::destroy(const string& name){
+ Mutex::ScopedLock locker(lock);
+ queues.erase(name);
+}
+
+Queue::shared_ptr QueueRegistry::find(const string& name){
+ Mutex::ScopedLock locker(lock);
+ QueueMap::iterator i = queues.find(name);
+ if (i == queues.end()) {
+ return Queue::shared_ptr();
+ } else {
+ return i->second;
+ }
+}
+
+string QueueRegistry::generateName(){
+ string name;
+ do {
+ std::stringstream ss;
+ ss << "tmp_" << counter++;
+ name = ss.str();
+ // Thread safety: Private function, only called with lock held
+ // so this is OK.
+ } while(queues.find(name) != queues.end());
+ return name;
+}
+
+MessageStore* const QueueRegistry::getStore() const {
+ return store;
+}
diff --git a/cpp/lib/broker/QueueRegistry.h b/cpp/lib/broker/QueueRegistry.h
new file mode 100644
index 0000000000..079034359e
--- /dev/null
+++ b/cpp/lib/broker/QueueRegistry.h
@@ -0,0 +1,96 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _QueueRegistry_
+#define _QueueRegistry_
+
+#include <map>
+#include <sys/Monitor.h>
+#include <BrokerQueue.h>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * A registry of queues indexed by queue name.
+ *
+ * Queues are reference counted using shared_ptr to ensure that they
+ * are deleted when and only when they are no longer in use.
+ *
+ */
+class QueueRegistry{
+
+ public:
+ QueueRegistry(MessageStore* const store = 0);
+ ~QueueRegistry();
+
+ /**
+ * Declare a queue.
+ *
+ * @return The queue and a boolean flag which is true if the queue
+ * was created by this declare call false if it already existed.
+ */
+ std::pair<Queue::shared_ptr, bool> declare(const string& name, bool durable = false, uint32_t autodelete = 0,
+ const ConnectionToken* const owner = 0);
+
+ /**
+ * Destroy the named queue.
+ *
+ * Note: if the queue is in use it is not actually destroyed until
+ * all shared_ptrs to it are destroyed. During that time it is
+ * possible that a new queue with the same name may be
+ * created. This should not create any problems as the new and
+ * old queues exist independently. The registry has
+ * forgotten the old queue so there can be no confusion for
+ * subsequent calls to find or declare with the same name.
+ *
+ */
+ void destroy(const string& name);
+
+ /**
+ * Find the named queue. Return 0 if not found.
+ */
+ Queue::shared_ptr find(const string& name);
+
+ /**
+ * Generate unique queue name.
+ */
+ string generateName();
+
+ /**
+ * Return the message store used.
+ */
+ MessageStore* const getStore() const;
+
+
+ private:
+ typedef std::map<string, Queue::shared_ptr> QueueMap;
+ QueueMap queues;
+ qpid::sys::Mutex lock;
+ int counter;
+ MessageStore* const store;
+};
+
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/broker/RecoveryManager.cpp b/cpp/lib/broker/RecoveryManager.cpp
new file mode 100644
index 0000000000..6548e6a24f
--- /dev/null
+++ b/cpp/lib/broker/RecoveryManager.cpp
@@ -0,0 +1,46 @@
+/*
+ *
+ * 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 <RecoveryManager.h>
+
+using namespace qpid::broker;
+
+RecoveryManager::RecoveryManager(QueueRegistry& _queues, ExchangeRegistry& _exchanges) : queues(_queues), exchanges(_exchanges) {}
+
+RecoveryManager::~RecoveryManager() {}
+
+Queue::shared_ptr RecoveryManager::recoverQueue(const string& name)
+{
+ std::pair<Queue::shared_ptr, bool> result = queues.declare(name, true);
+ try {
+ Exchange::shared_ptr exchange = exchanges.getDefault();
+ if (exchange) {
+ exchange->bind(result.first, result.first->getName(), 0);
+ }
+ } catch (ChannelException& e) {
+ //assume no default exchange has been declared
+ }
+ return result.first;
+}
+
+Exchange::shared_ptr RecoveryManager::recoverExchange(const string& name, const string& type)
+{
+ return exchanges.declare(name, type).first;
+}
diff --git a/cpp/lib/broker/RecoveryManager.h b/cpp/lib/broker/RecoveryManager.h
new file mode 100644
index 0000000000..d4e4cff3fd
--- /dev/null
+++ b/cpp/lib/broker/RecoveryManager.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _RecoveryManager_
+#define _RecoveryManager_
+
+#include <ExchangeRegistry.h>
+#include <QueueRegistry.h>
+
+namespace qpid {
+namespace broker {
+
+ class RecoveryManager{
+ QueueRegistry& queues;
+ ExchangeRegistry& exchanges;
+ public:
+ RecoveryManager(QueueRegistry& queues, ExchangeRegistry& exchanges);
+ ~RecoveryManager();
+ Queue::shared_ptr recoverQueue(const std::string& name);
+ Exchange::shared_ptr recoverExchange(const std::string& name, const std::string& type);
+ };
+
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/broker/Reference.cpp b/cpp/lib/broker/Reference.cpp
new file mode 100644
index 0000000000..c4c33e6363
--- /dev/null
+++ b/cpp/lib/broker/Reference.cpp
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <boost/bind.hpp>
+#include "Reference.h"
+#include "BrokerMessageMessage.h"
+#include "QpidError.h"
+#include "MessageAppendBody.h"
+#include "CompletionHandler.h"
+
+namespace qpid {
+namespace broker {
+
+Reference::shared_ptr ReferenceRegistry::open(const Reference::Id& id) {
+ ReferenceMap::iterator i = references.find(id);
+ // TODO aconway 2007-02-05: should we throw Channel or Connection
+ // exceptions here?
+ if (i != references.end())
+ throw ConnectionException(503, "Attempt to re-open reference " +id);
+ return references[id] = Reference::shared_ptr(new Reference(id, this));
+}
+
+Reference::shared_ptr ReferenceRegistry::get(const Reference::Id& id) {
+ ReferenceMap::iterator i = references.find(id);
+ if (i == references.end())
+ throw ConnectionException(503, "Attempt to use non-existent reference "+id);
+ return i->second;
+}
+
+void Reference::append(AppendPtr ptr) {
+ appends.push_back(ptr);
+ size += ptr->getBytes().length();
+}
+
+void Reference::close() {
+ registry->references.erase(getId());
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/lib/broker/Reference.h b/cpp/lib/broker/Reference.h
new file mode 100644
index 0000000000..e453645a54
--- /dev/null
+++ b/cpp/lib/broker/Reference.h
@@ -0,0 +1,111 @@
+#ifndef _broker_Reference_h
+#define _broker_Reference_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <string>
+#include <vector>
+#include <map>
+#include <boost/shared_ptr.hpp>
+#include <boost/range.hpp>
+
+namespace qpid {
+
+namespace framing {
+class MessageAppendBody;
+}
+
+namespace broker {
+
+class MessageMessage;
+class ReferenceRegistry;
+
+/**
+ * A reference is an accumulation point for data in a multi-frame
+ * message. A reference can be used by multiple transfer commands to
+ * create multiple messages, so the reference tracks which commands
+ * are using it. When the reference is closed, all the associated
+ * transfers are completed.
+ *
+ * THREAD UNSAFE: per-channel resource, access to channels is
+ * serialized.
+ */
+class Reference
+{
+ public:
+ typedef std::string Id;
+ typedef boost::shared_ptr<Reference> shared_ptr;
+ typedef boost::shared_ptr<MessageMessage> MessagePtr;
+ typedef std::vector<MessagePtr> Messages;
+ typedef boost::shared_ptr<framing::MessageAppendBody> AppendPtr;
+ typedef std::vector<AppendPtr> Appends;
+
+ Reference(const Id& id_=Id(), ReferenceRegistry* reg=0)
+ : id(id_), size(0), registry(reg) {}
+
+ const std::string& getId() const { return id; }
+ uint64_t getSize() const { return size; }
+
+ /** Add a message to be completed with this reference */
+ void addMessage(MessagePtr message) { messages.push_back(message); }
+
+ /** Append more data to the reference */
+ void append(AppendPtr ptr);
+
+ /** Close the reference, complete each associated message */
+ void close();
+
+ const Appends& getAppends() const { return appends; }
+ const Messages& getMessages() const { return messages; }
+
+ private:
+ Id id;
+ uint64_t size;
+ ReferenceRegistry* registry;
+ Messages messages;
+ Appends appends;
+};
+
+
+/**
+ * A registry/factory for references.
+ *
+ * THREAD UNSAFE: per-channel resource, access to channels is
+ * serialized.
+ */
+class ReferenceRegistry {
+ public:
+ ReferenceRegistry() {};
+ Reference::shared_ptr open(const Reference::Id& id);
+ Reference::shared_ptr get(const Reference::Id& id);
+
+ private:
+ typedef std::map<Reference::Id, Reference::shared_ptr> ReferenceMap;
+ ReferenceMap references;
+
+ // Reference calls references.erase().
+ friend class Reference;
+};
+
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_Reference_h*/
diff --git a/cpp/lib/broker/TopicExchange.cpp b/cpp/lib/broker/TopicExchange.cpp
new file mode 100644
index 0000000000..3ebb3c8c56
--- /dev/null
+++ b/cpp/lib/broker/TopicExchange.cpp
@@ -0,0 +1,156 @@
+/*
+ *
+ * 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 <TopicExchange.h>
+#include <ExchangeBinding.h>
+#include <algorithm>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+// TODO aconway 2006-09-20: More efficient matching algorithm.
+// Areas for improvement:
+// - excessive string copying: should be 0 copy, match from original buffer.
+// - match/lookup: use descision tree or other more efficient structure.
+
+Tokens& Tokens::operator=(const std::string& s) {
+ clear();
+ if (s.empty()) return *this;
+ std::string::const_iterator i = s.begin();
+ while (true) {
+ // Invariant: i is at the beginning of the next untokenized word.
+ std::string::const_iterator j = find(i, s.end(), '.');
+ push_back(std::string(i, j));
+ if (j == s.end()) return *this;
+ i = j + 1;
+ }
+ return *this;
+}
+
+TopicPattern& TopicPattern::operator=(const Tokens& tokens) {
+ Tokens::operator=(tokens);
+ normalize();
+ return *this;
+}
+
+namespace {
+const std::string hashmark("#");
+const std::string star("*");
+}
+
+void TopicPattern::normalize() {
+ std::string word;
+ Tokens::iterator i = begin();
+ while (i != end()) {
+ if (*i == hashmark) {
+ ++i;
+ while (i != end()) {
+ // Invariant: *(i-1)==#, [begin()..i-1] is normalized.
+ if (*i == star) { // Move * before #.
+ std::swap(*i, *(i-1));
+ ++i;
+ } else if (*i == hashmark) {
+ erase(i); // Remove extra #
+ } else {
+ break;
+ }
+ }
+ } else {
+ i ++;
+ }
+ }
+}
+
+
+namespace {
+// TODO aconway 2006-09-20: Ineficient to convert every routingKey to a string.
+// Need StringRef class that operates on a string in place witout copy.
+// Should be applied everywhere strings are extracted from frames.
+//
+bool do_match(Tokens::const_iterator pattern_begin, Tokens::const_iterator pattern_end, Tokens::const_iterator target_begin, Tokens::const_iterator target_end)
+{
+ // Invariant: [pattern_begin..p) matches [target_begin..t)
+ Tokens::const_iterator p = pattern_begin;
+ Tokens::const_iterator t = target_begin;
+ while (p != pattern_end && t != target_end)
+ {
+ if (*p == star || *p == *t) {
+ ++p, ++t;
+ } else if (*p == hashmark) {
+ ++p;
+ if (do_match(p, pattern_end, t, target_end)) return true;
+ while (t != target_end) {
+ ++t;
+ if (do_match(p, pattern_end, t, target_end)) return true;
+ }
+ return false;
+ } else {
+ return false;
+ }
+ }
+ while (p != pattern_end && *p == hashmark) ++p; // Ignore trailing #
+ return t == target_end && p == pattern_end;
+}
+}
+
+bool TopicPattern::match(const Tokens& target) const
+{
+ return do_match(begin(), end(), target.begin(), target.end());
+}
+
+TopicExchange::TopicExchange(const string& _name) : Exchange(_name) { }
+
+void TopicExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args){
+ Monitor::ScopedLock l(lock);
+ TopicPattern routingPattern(routingKey);
+ bindings[routingPattern].push_back(queue);
+ queue->bound(new ExchangeBinding(this, queue, routingKey, args));
+}
+
+void TopicExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/){
+ Monitor::ScopedLock l(lock);
+ BindingMap::iterator bi = bindings.find(TopicPattern(routingKey));
+ Queue::vector& qv(bi->second);
+ if (bi == bindings.end()) return;
+ Queue::vector::iterator q = find(qv.begin(), qv.end(), queue);
+ if(q == qv.end()) return;
+ qv.erase(q);
+ if(qv.empty()) bindings.erase(bi);
+}
+
+
+void TopicExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/){
+ Monitor::ScopedLock l(lock);
+ for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) {
+ if (i->first.match(routingKey)) {
+ Queue::vector& qv(i->second);
+ for(Queue::vector::iterator j = qv.begin(); j != qv.end(); j++){
+ msg.deliverTo(*j);
+ }
+ }
+ }
+}
+
+TopicExchange::~TopicExchange() {}
+
+const std::string TopicExchange::typeName("topic");
+
+
diff --git a/cpp/lib/broker/TopicExchange.h b/cpp/lib/broker/TopicExchange.h
new file mode 100644
index 0000000000..fa0c86863a
--- /dev/null
+++ b/cpp/lib/broker/TopicExchange.h
@@ -0,0 +1,100 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _TopicExchange_
+#define _TopicExchange_
+
+#include <map>
+#include <vector>
+#include <BrokerExchange.h>
+#include <FieldTable.h>
+#include <BrokerMessage.h>
+#include <sys/Monitor.h>
+#include <BrokerQueue.h>
+
+namespace qpid {
+namespace broker {
+
+/** A vector of string tokens */
+class Tokens : public std::vector<std::string> {
+ public:
+ Tokens() {};
+ // Default copy, assign, dtor are sufficient.
+
+ /** Tokenize s, provides automatic conversion of string to Tokens */
+ Tokens(const std::string& s) { operator=(s); }
+ /** Tokenizing assignment operator s */
+ Tokens & operator=(const std::string& s);
+
+ private:
+ size_t hash;
+};
+
+
+/**
+ * Tokens that have been normalized as a pattern and can be matched
+ * with topic Tokens. Normalized meands all sequences of mixed * and
+ * # are reduced to a series of * followed by at most one #.
+ */
+class TopicPattern : public Tokens
+{
+ public:
+ TopicPattern() {}
+ // Default copy, assign, dtor are sufficient.
+ TopicPattern(const Tokens& tokens) { operator=(tokens); }
+ TopicPattern(const std::string& str) { operator=(str); }
+ TopicPattern& operator=(const Tokens&);
+ TopicPattern& operator=(const std::string& str) { return operator=(Tokens(str)); }
+
+ /** Match a topic */
+ bool match(const std::string& topic) { return match(Tokens(topic)); }
+ bool match(const Tokens& topic) const;
+
+ private:
+ void normalize();
+};
+
+class TopicExchange : public virtual Exchange{
+ typedef std::map<TopicPattern, Queue::vector> BindingMap;
+ BindingMap bindings;
+ qpid::sys::Mutex lock;
+
+ public:
+ static const std::string typeName;
+
+ TopicExchange(const string& name);
+
+ virtual std::string getType(){ return typeName; }
+
+ virtual void bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args);
+
+ virtual ~TopicExchange();
+};
+
+
+
+}
+}
+
+#endif
diff --git a/cpp/lib/broker/TransactionalStore.h b/cpp/lib/broker/TransactionalStore.h
new file mode 100644
index 0000000000..17bca3878a
--- /dev/null
+++ b/cpp/lib/broker/TransactionalStore.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _TransactionalStore_
+#define _TransactionalStore_
+
+#include <memory>
+
+namespace qpid {
+ namespace broker {
+ struct InvalidTransactionContextException : public std::exception {};
+
+ class TransactionContext{
+ public:
+ virtual ~TransactionContext(){}
+ };
+
+ class TransactionalStore{
+ public:
+ virtual std::auto_ptr<TransactionContext> begin() = 0;
+ virtual void commit(TransactionContext*) = 0;
+ virtual void abort(TransactionContext*) = 0;
+
+ virtual ~TransactionalStore(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/TxAck.cpp b/cpp/lib/broker/TxAck.cpp
new file mode 100644
index 0000000000..b5211158f3
--- /dev/null
+++ b/cpp/lib/broker/TxAck.cpp
@@ -0,0 +1,54 @@
+/*
+ *
+ * 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 <TxAck.h>
+
+using std::bind1st;
+using std::bind2nd;
+using std::mem_fun_ref;
+using namespace qpid::broker;
+
+TxAck::TxAck(AccumulatedAck& _acked, std::list<DeliveryRecord>& _unacked, const std::string* const _xid) :
+ acked(_acked), unacked(_unacked), xid(_xid){
+
+}
+
+bool TxAck::prepare(TransactionContext* ctxt) throw(){
+ try{
+ //dequeue all acked messages from their queues
+ for (ack_iterator i = unacked.begin(); i != unacked.end(); i++) {
+ if (i->coveredBy(&acked)) {
+ i->discard(ctxt, xid);
+ }
+ }
+ return true;
+ }catch(...){
+ std::cout << "TxAck::prepare() - Failed to prepare" << std::endl;
+ return false;
+ }
+}
+
+void TxAck::commit() throw(){
+ //remove all acked records from the list
+ unacked.remove_if(bind2nd(mem_fun_ref(&DeliveryRecord::coveredBy), &acked));
+}
+
+void TxAck::rollback() throw(){
+}
diff --git a/cpp/lib/broker/TxAck.h b/cpp/lib/broker/TxAck.h
new file mode 100644
index 0000000000..88c321c445
--- /dev/null
+++ b/cpp/lib/broker/TxAck.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _TxAck_
+#define _TxAck_
+
+#include <algorithm>
+#include <functional>
+#include <list>
+#include <AccumulatedAck.h>
+#include <DeliveryRecord.h>
+#include <TxOp.h>
+
+namespace qpid {
+ namespace broker {
+ /**
+ * Defines the transactional behaviour for acks received by a
+ * transactional channel.
+ */
+ class TxAck : public TxOp{
+ AccumulatedAck& acked;
+ std::list<DeliveryRecord>& unacked;
+ const std::string* const xid;
+
+ public:
+ /**
+ * @param acked a representation of the accumulation of
+ * acks received
+ * @param unacked the record of delivered messages
+ */
+ TxAck(AccumulatedAck& acked, std::list<DeliveryRecord>& unacked, const std::string* const xid = 0);
+ virtual bool prepare(TransactionContext* ctxt) throw();
+ virtual void commit() throw();
+ virtual void rollback() throw();
+ virtual ~TxAck(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/TxBuffer.cpp b/cpp/lib/broker/TxBuffer.cpp
new file mode 100644
index 0000000000..acd3283bb7
--- /dev/null
+++ b/cpp/lib/broker/TxBuffer.cpp
@@ -0,0 +1,55 @@
+/*
+ *
+ * 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 <TxBuffer.h>
+
+using std::mem_fun;
+using namespace qpid::broker;
+
+bool TxBuffer::prepare(TransactionalStore* const store)
+{
+ std::auto_ptr<TransactionContext> ctxt;
+ if(store) ctxt = store->begin();
+ for(op_iterator i = ops.begin(); i < ops.end(); i++){
+ if(!(*i)->prepare(ctxt.get())){
+ if(store) store->abort(ctxt.get());
+ return false;
+ }
+ }
+ if(store) store->commit(ctxt.get());
+ return true;
+}
+
+void TxBuffer::commit()
+{
+ for_each(ops.begin(), ops.end(), mem_fun(&TxOp::commit));
+ ops.clear();
+}
+
+void TxBuffer::rollback()
+{
+ for_each(ops.begin(), ops.end(), mem_fun(&TxOp::rollback));
+ ops.clear();
+}
+
+void TxBuffer::enlist(TxOp* const op)
+{
+ ops.push_back(op);
+}
diff --git a/cpp/lib/broker/TxBuffer.h b/cpp/lib/broker/TxBuffer.h
new file mode 100644
index 0000000000..2d9a2a3679
--- /dev/null
+++ b/cpp/lib/broker/TxBuffer.h
@@ -0,0 +1,107 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _TxBuffer_
+#define _TxBuffer_
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include <TransactionalStore.h>
+#include <TxOp.h>
+
+/**
+ * Represents a single transaction. As such, an instance of this class
+ * will hold a list of operations representing the workload of the
+ * transaction. This work can be committed or rolled back. Committing
+ * is a two-stage process: first all the operations should be
+ * prepared, then if that succeeds they can be committed.
+ *
+ * In the 2pc case, a successful prepare may be followed by either a
+ * commit or a rollback.
+ *
+ * Atomicity of prepare is ensured by using a lower level
+ * transactional facility. This saves explicitly rolling back all the
+ * successfully prepared ops when one of them fails. i.e. we do not
+ * use 2pc internally, we instead ensure that prepare is atomic at a
+ * lower level. This makes individual prepare operations easier to
+ * code.
+ *
+ * Transactions on a messaging broker effect three types of 'action':
+ * (1) updates to persistent storage (2) updates to transient storage
+ * or cached data (3) network writes.
+ *
+ * Of these, (1) should always occur atomically during prepare to
+ * ensure that if the broker crashes while a transaction is being
+ * completed the persistent state (which is all that then remains) is
+ * consistent. (3) can only be done on commit, after a successful
+ * prepare. There is a little more flexibility with (2) but any
+ * changes made during prepare should be subject to the control of the
+ * TransactionalStore in use.
+ */
+namespace qpid {
+ namespace broker {
+ class TxBuffer{
+ typedef std::vector<TxOp*>::iterator op_iterator;
+ std::vector<TxOp*> ops;
+ public:
+ /**
+ * Requests that all ops are prepared. This should
+ * primarily involve making sure that a persistent record
+ * of the operations is stored where necessary.
+ *
+ * All ops will be prepared under a transaction on the
+ * specified store. If any operation fails on prepare,
+ * this transaction will be rolled back.
+ *
+ * Once prepared, a transaction can be committed (or in
+ * the 2pc case, rolled back).
+ *
+ * @returns true if all the operations prepared
+ * successfully, false if not.
+ */
+ bool prepare(TransactionalStore* const store);
+ /**
+ * Signals that the ops all prepared all completed
+ * successfully and can now commit, i.e. the operation can
+ * now be fully carried out.
+ *
+ * Should only be called after a call to prepare() returns
+ * true.
+ */
+ void commit();
+ /**
+ * Rolls back all the operations.
+ *
+ * Should only be called either after a call to prepare()
+ * returns true (2pc) or instead of a prepare call
+ * ('server-local')
+ */
+ void rollback();
+ /**
+ * Adds an operation to the transaction.
+ */
+ void enlist(TxOp* const op);
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/TxOp.h b/cpp/lib/broker/TxOp.h
new file mode 100644
index 0000000000..abba84a8e8
--- /dev/null
+++ b/cpp/lib/broker/TxOp.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _TxOp_
+#define _TxOp_
+
+#include <TransactionalStore.h>
+
+namespace qpid {
+ namespace broker {
+ class TxOp{
+ public:
+ virtual bool prepare(TransactionContext*) throw() = 0;
+ virtual void commit() throw() = 0;
+ virtual void rollback() throw() = 0;
+ virtual ~TxOp(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/broker/TxPublish.cpp b/cpp/lib/broker/TxPublish.cpp
new file mode 100644
index 0000000000..49dd8abd89
--- /dev/null
+++ b/cpp/lib/broker/TxPublish.cpp
@@ -0,0 +1,60 @@
+/*
+ *
+ * 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 <TxPublish.h>
+
+using namespace qpid::broker;
+
+TxPublish::TxPublish(Message::shared_ptr _msg, const std::string* const _xid) : msg(_msg), xid(_xid) {}
+
+bool TxPublish::prepare(TransactionContext* ctxt) throw(){
+ try{
+ for_each(queues.begin(), queues.end(), Prepare(ctxt, msg, xid));
+ return true;
+ }catch(...){
+ std::cout << "TxPublish::prepare() - Failed to prepare" << std::endl;
+ return false;
+ }
+}
+
+void TxPublish::commit() throw(){
+ for_each(queues.begin(), queues.end(), Commit(msg));
+}
+
+void TxPublish::rollback() throw(){
+}
+
+void TxPublish::deliverTo(Queue::shared_ptr& queue){
+ queues.push_back(queue);
+}
+
+TxPublish::Prepare::Prepare(TransactionContext* _ctxt, Message::shared_ptr& _msg, const string* const _xid)
+ : ctxt(_ctxt), msg(_msg), xid(_xid){}
+
+void TxPublish::Prepare::operator()(Queue::shared_ptr& queue){
+ queue->enqueue(ctxt, msg, xid);
+}
+
+TxPublish::Commit::Commit(Message::shared_ptr& _msg) : msg(_msg){}
+
+void TxPublish::Commit::operator()(Queue::shared_ptr& queue){
+ queue->process(msg);
+}
+
diff --git a/cpp/lib/broker/TxPublish.h b/cpp/lib/broker/TxPublish.h
new file mode 100644
index 0000000000..75f201257e
--- /dev/null
+++ b/cpp/lib/broker/TxPublish.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _TxPublish_
+#define _TxPublish_
+
+#include <algorithm>
+#include <functional>
+#include <list>
+#include <Deliverable.h>
+#include <BrokerMessage.h>
+#include <MessageStore.h>
+#include <BrokerQueue.h>
+#include <TxOp.h>
+
+namespace qpid {
+ namespace broker {
+ /**
+ * Defines the behaviour for publish operations on a
+ * transactional channel. Messages are routed through
+ * exchanges when received but are not at that stage delivered
+ * to the matching queues, rather the queues are held in an
+ * instance of this class. On prepare() the message is marked
+ * enqueued to the relevant queues in the MessagesStore. On
+ * commit() the messages will be passed to the queue for
+ * dispatch or to be added to the in-memory queue.
+ */
+ class TxPublish : public TxOp, public Deliverable{
+ class Prepare{
+ TransactionContext* ctxt;
+ Message::shared_ptr& msg;
+ const std::string* const xid;
+ public:
+ Prepare(TransactionContext* ctxt, Message::shared_ptr& msg, const std::string* const xid);
+ void operator()(Queue::shared_ptr& queue);
+ };
+
+ class Commit{
+ Message::shared_ptr& msg;
+ public:
+ Commit(Message::shared_ptr& msg);
+ void operator()(Queue::shared_ptr& queue);
+ };
+
+ Message::shared_ptr msg;
+ const std::string* const xid;
+ std::list<Queue::shared_ptr> queues;
+
+ public:
+ TxPublish(Message::shared_ptr msg, const std::string* const xid = 0);
+ virtual bool prepare(TransactionContext* ctxt) throw();
+ virtual void commit() throw();
+ virtual void rollback() throw();
+
+ virtual void deliverTo(Queue::shared_ptr& queue);
+
+ virtual ~TxPublish(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/client/Basic.cpp b/cpp/lib/client/Basic.cpp
new file mode 100644
index 0000000000..4a1cf249a8
--- /dev/null
+++ b/cpp/lib/client/Basic.cpp
@@ -0,0 +1,255 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <iostream>
+#include "Basic.h"
+#include "AMQMethodBody.h"
+#include "ClientChannel.h"
+#include "ReturnedMessageHandler.h"
+#include "MessageListener.h"
+#include "framing/FieldTable.h"
+#include "Connection.h"
+
+using namespace std;
+
+namespace qpid {
+namespace client {
+
+using namespace sys;
+using namespace framing;
+
+Basic::Basic(Channel& ch) : channel(ch), returnsHandler(0) {}
+
+void Basic::consume(
+ Queue& queue, std::string& tag, MessageListener* listener,
+ AckMode ackMode, bool noLocal, bool synch, const FieldTable* fields)
+{
+ channel.sendAndReceiveSync<BasicConsumeOkBody>(
+ synch,
+ new BasicConsumeBody(
+ channel.version, 0, queue.getName(), tag, noLocal,
+ ackMode == NO_ACK, false, !synch,
+ fields ? *fields : FieldTable()));
+ if (synch) {
+ BasicConsumeOkBody::shared_ptr response =
+ boost::shared_polymorphic_downcast<BasicConsumeOkBody>(
+ channel.responses.getResponse());
+ tag = response->getConsumerTag();
+ }
+ // FIXME aconway 2007-02-20: Race condition!
+ // We could receive the first message for the consumer
+ // before we create the consumer below.
+ // Move consumer creation to handler for BasicConsumeOkBody
+ {
+ Mutex::ScopedLock l(lock);
+ ConsumerMap::iterator i = consumers.find(tag);
+ if (i != consumers.end())
+ THROW_QPID_ERROR(CLIENT_ERROR,
+ "Consumer already exists with tag="+tag);
+ Consumer& c = consumers[tag];
+ c.listener = listener;
+ c.ackMode = ackMode;
+ c.lastDeliveryTag = 0;
+ }
+}
+
+
+void Basic::cancel(const std::string& tag, bool synch) {
+ Consumer c;
+ {
+ Mutex::ScopedLock l(lock);
+ ConsumerMap::iterator i = consumers.find(tag);
+ if (i == consumers.end())
+ return;
+ c = i->second;
+ consumers.erase(i);
+ }
+ if(c.ackMode == LAZY_ACK && c.lastDeliveryTag > 0)
+ channel.send(new BasicAckBody(channel.version, c.lastDeliveryTag, true));
+ channel.sendAndReceiveSync<BasicCancelOkBody>(
+ synch, new BasicCancelBody(channel.version, tag, !synch));
+}
+
+void Basic::cancelAll(){
+ ConsumerMap consumersCopy;
+ {
+ Mutex::ScopedLock l(lock);
+ consumersCopy = consumers;
+ consumers.clear();
+ }
+ for (ConsumerMap::iterator i=consumersCopy.begin();
+ i != consumersCopy.end(); ++i)
+ {
+ Consumer& c = i->second;
+ if ((c.ackMode == LAZY_ACK || c.ackMode == AUTO_ACK)
+ && c.lastDeliveryTag > 0)
+ {
+ channel.send(new BasicAckBody(channel.version, c.lastDeliveryTag, true));
+ }
+ }
+}
+
+
+
+bool Basic::get(Message& msg, const Queue& queue, AckMode ackMode) {
+ // Expect a message starting with a BasicGetOk
+ incoming.startGet();
+ channel.send(new BasicGetBody(channel.version, 0, queue.getName(), ackMode));
+ return incoming.waitGet(msg);
+}
+
+
+void Basic::publish(
+ const Message& msg, const Exchange& exchange,
+ const std::string& routingKey, bool mandatory, bool immediate)
+{
+ const string e = exchange.getName();
+ string key = routingKey;
+ channel.send(new BasicPublishBody(channel.version, 0, e, key, mandatory, immediate));
+ //break msg up into header frame and content frame(s) and send these
+ channel.send(msg.getHeader());
+ string data = msg.getData();
+ uint64_t data_length = data.length();
+ if(data_length > 0){
+ //frame itself uses 8 bytes
+ uint32_t frag_size = channel.connection->getMaxFrameSize() - 8;
+ if(data_length < frag_size){
+ channel.send(new AMQContentBody(data));
+ }else{
+ uint32_t offset = 0;
+ uint32_t remaining = data_length - offset;
+ while (remaining > 0) {
+ uint32_t length = remaining > frag_size ? frag_size : remaining;
+ string frag(data.substr(offset, length));
+ channel.send(new AMQContentBody(frag));
+
+ offset += length;
+ remaining = data_length - offset;
+ }
+ }
+ }
+}
+
+void Basic::handle(boost::shared_ptr<AMQMethodBody> method) {
+ assert(method->amqpClassId() ==BasicGetBody::CLASS_ID);
+ switch(method->amqpMethodId()) {
+ case BasicDeliverBody::METHOD_ID:
+ case BasicReturnBody::METHOD_ID:
+ case BasicGetOkBody::METHOD_ID:
+ case BasicGetEmptyBody::METHOD_ID:
+ incoming.add(method);
+ return;
+ }
+ throw Channel::UnknownMethod();
+}
+
+void Basic::deliver(Consumer& consumer, Message& msg){
+ //record delivery tag:
+ consumer.lastDeliveryTag = msg.getDeliveryTag();
+
+ //allow registered listener to handle the message
+ consumer.listener->received(msg);
+
+ if(channel.isOpen()){
+ bool multiple(false);
+ switch(consumer.ackMode){
+ case LAZY_ACK:
+ multiple = true;
+ if(++(consumer.count) < channel.getPrefetch())
+ break;
+ //else drop-through
+ case AUTO_ACK:
+ consumer.lastDeliveryTag = 0;
+ channel.send(
+ new BasicAckBody(
+ channel.version, msg.getDeliveryTag(), multiple));
+ case NO_ACK: // Nothing to do
+ case CLIENT_ACK: // User code must ack.
+ break;
+ // TODO aconway 2007-02-22: Provide a way for user
+ // to ack!
+ }
+ }
+
+ //as it stands, transactionality is entirely orthogonal to ack
+ //mode, though the acks will not be processed by the broker under
+ //a transaction until it commits.
+}
+
+
+void Basic::run() {
+ while(channel.isOpen()) {
+ try {
+ Message msg = incoming.waitDispatch();
+ if(msg.getMethod()->isA<BasicReturnBody>()) {
+ ReturnedMessageHandler* handler=0;
+ {
+ Mutex::ScopedLock l(lock);
+ handler=returnsHandler;
+ }
+ if(handler == 0) {
+ // TODO aconway 2007-02-20: proper logging.
+ cout << "Message returned: " << msg.getData() << endl;
+ }
+ else
+ handler->returned(msg);
+ }
+ else {
+ BasicDeliverBody::shared_ptr deliverBody =
+ boost::shared_polymorphic_downcast<BasicDeliverBody>(
+ msg.getMethod());
+ std::string tag = deliverBody->getConsumerTag();
+ Consumer consumer;
+ {
+ Mutex::ScopedLock l(lock);
+ ConsumerMap::iterator i = consumers.find(tag);
+ if(i == consumers.end())
+ THROW_QPID_ERROR(PROTOCOL_ERROR+504,
+ "Unknown consumer tag=" + tag);
+ consumer = i->second;
+ }
+ deliver(consumer, msg);
+ }
+ }
+ catch (const ShutdownException&) {
+ /* Orderly shutdown */
+ }
+ catch (const Exception& e) {
+ // FIXME aconway 2007-02-20: Report exception to user.
+ cout << "client::Basic::run() terminated by: " << e.toString()
+ << "(" << typeid(e).name() << ")" << endl;
+ }
+ }
+}
+
+void Basic::setReturnedMessageHandler(ReturnedMessageHandler* handler){
+ Mutex::ScopedLock l(lock);
+ returnsHandler = handler;
+}
+
+void Basic::setQos(){
+ channel.sendAndReceive<BasicQosOkBody>(
+ new BasicQosBody(channel.version, 0, channel.getPrefetch(), false));
+ if(channel.isTransactional())
+ channel.sendAndReceive<TxSelectOkBody>(new TxSelectBody(channel.version));
+}
+
+
+// TODO aconway 2007-02-22: NOTES:
+// Move incoming to BasicChannel - check for uses.
+
+}} // namespace qpid::client
diff --git a/cpp/lib/client/Basic.h b/cpp/lib/client/Basic.h
new file mode 100644
index 0000000000..f6ae633ab8
--- /dev/null
+++ b/cpp/lib/client/Basic.h
@@ -0,0 +1,195 @@
+#ifndef _client_Basic_h
+#define _client_Basic_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "IncomingMessage.h"
+#include "sys/Runnable.h"
+
+namespace qpid {
+
+namespace framing {
+class AMQMethodBody;
+class FieldTable;
+}
+
+namespace client {
+
+class Channel;
+class Message;
+class Queue;
+class Exchange;
+class MessageListener;
+class ReturnedMessageHandler;
+
+/**
+ * The available acknowledgements modes.
+ *
+ * \ingroup clientapi
+ */
+enum AckMode {
+ /** No acknowledgement will be sent, broker can
+ discard messages as soon as they are delivered
+ to a consumer using this mode. **/
+ NO_ACK = 0,
+ /** Each message will be automatically
+ acknowledged as soon as it is delivered to the
+ application **/
+ AUTO_ACK = 1,
+ /** Acknowledgements will be sent automatically,
+ but not for each message. **/
+ LAZY_ACK = 2,
+ /** The application is responsible for explicitly
+ acknowledging messages. **/
+ CLIENT_ACK = 3
+};
+
+
+/**
+ * Represents the AMQP Basic class for sending and receiving messages.
+ */
+class Basic : public sys::Runnable
+{
+ public:
+ Basic(Channel& parent);
+
+ /**
+ * Creates a 'consumer' for a queue. Messages in (or arriving
+ * at) that queue will be delivered to consumers
+ * asynchronously.
+ *
+ * @param queue a Queue instance representing the queue to
+ * consume from
+ *
+ * @param tag an identifier to associate with the consumer
+ * that can be used to cancel its subscription (if empty, this
+ * will be assigned by the broker)
+ *
+ * @param listener a pointer to an instance of an
+ * implementation of the MessageListener interface. Messages
+ * received from this queue for this consumer will result in
+ * invocation of the received() method on the listener, with
+ * the message itself passed in.
+ *
+ * @param ackMode the mode of acknowledgement that the broker
+ * should assume for this consumer. @see AckMode
+ *
+ * @param noLocal if true, this consumer will not be sent any
+ * message published by this connection
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void consume(
+ Queue& queue, std::string& tag, MessageListener* listener,
+ AckMode ackMode = NO_ACK, bool noLocal = false, bool synch = true,
+ const framing::FieldTable* fields = 0);
+
+ /**
+ * Cancels a subscription previously set up through a call to consume().
+ *
+ * @param tag the identifier used (or assigned) in the consume
+ * request that set up the subscription to be cancelled.
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void cancel(const std::string& tag, bool synch = true);
+ /**
+ * Synchronous pull of a message from a queue.
+ *
+ * @param msg a message object that will contain the message
+ * headers and content if the call completes.
+ *
+ * @param queue the queue to consume from
+ *
+ * @param ackMode the acknowledgement mode to use (@see
+ * AckMode)
+ *
+ * @return true if a message was succcessfully dequeued from
+ * the queue, false if the queue was empty.
+ */
+ bool get(Message& msg, const Queue& queue, AckMode ackMode = NO_ACK);
+
+ /**
+ * Publishes (i.e. sends a message to the broker).
+ *
+ * @param msg the message to publish
+ *
+ * @param exchange the exchange to publish the message to
+ *
+ * @param routingKey the routing key to publish with
+ *
+ * @param mandatory if true and the exchange to which this
+ * publish is directed has no matching bindings, the message
+ * will be returned (see setReturnedMessageHandler()).
+ *
+ * @param immediate if true and there is no consumer to
+ * receive this message on publication, the message will be
+ * returned (see setReturnedMessageHandler()).
+ */
+ void publish(const Message& msg, const Exchange& exchange,
+ const std::string& routingKey,
+ bool mandatory = false, bool immediate = false);
+
+ /**
+ * Set a handler for this channel that will process any
+ * returned messages
+ *
+ * @see publish()
+ */
+ void setReturnedMessageHandler(ReturnedMessageHandler* handler);
+
+ /**
+ * Deliver messages from the broker to the appropriate MessageListener.
+ */
+ void run();
+
+
+ private:
+
+ struct Consumer{
+ MessageListener* listener;
+ AckMode ackMode;
+ int count;
+ uint64_t lastDeliveryTag;
+ };
+
+ typedef std::map<std::string, Consumer> ConsumerMap;
+
+ void handle(boost::shared_ptr<framing::AMQMethodBody>);
+ void setQos();
+ void cancelAll();
+ void deliver(Consumer& consumer, Message& msg);
+
+ sys::Mutex lock;
+ Channel& channel;
+ IncomingMessage incoming;
+ ConsumerMap consumers;
+ ReturnedMessageHandler* returnsHandler;
+
+ // FIXME aconway 2007-02-22: Remove friendship.
+ friend class Channel;
+};
+
+}} // namespace qpid::client
+
+
+
+#endif /*!_client_Basic_h*/
diff --git a/cpp/lib/client/ClientAdapter.cpp b/cpp/lib/client/ClientAdapter.cpp
new file mode 100644
index 0000000000..c77f049c96
--- /dev/null
+++ b/cpp/lib/client/ClientAdapter.cpp
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "AMQP_ClientOperations.h"
+#include "ClientAdapter.h"
+#include "Connection.h"
+#include "Exception.h"
+#include "AMQMethodBody.h"
+
+namespace qpid {
+namespace client {
+
+using namespace qpid;
+using namespace qpid::framing;
+
+typedef std::vector<Queue::shared_ptr>::iterator queue_iterator;
+
+void ClientAdapter::handleMethodInContext(
+ boost::shared_ptr<qpid::framing::AMQMethodBody> method,
+ const MethodContext& context
+)
+{
+ try{
+ method->invoke(*clientOps, context);
+ }catch(ChannelException& e){
+ connection.client->getChannel().close(
+ context, e.code, e.toString(),
+ method->amqpClassId(), method->amqpMethodId());
+ connection.closeChannel(getId());
+ }catch(ConnectionException& e){
+ connection.client->getConnection().close(
+ context, e.code, e.toString(),
+ method->amqpClassId(), method->amqpMethodId());
+ }catch(std::exception& e){
+ connection.client->getConnection().close(
+ context, 541/*internal error*/, e.what(),
+ method->amqpClassId(), method->amqpMethodId());
+ }
+}
+
+void ClientAdapter::handleHeader(AMQHeaderBody::shared_ptr body) {
+ channel->handleHeader(body);
+}
+
+void ClientAdapter::handleContent(AMQContentBody::shared_ptr body) {
+ channel->handleContent(body);
+}
+
+void ClientAdapter::handleHeartbeat(AMQHeartbeatBody::shared_ptr) {
+ // TODO aconway 2007-01-17: Implement heartbeats.
+}
+
+
+
+}} // namespace qpid::client
+
diff --git a/cpp/lib/client/ClientAdapter.h b/cpp/lib/client/ClientAdapter.h
new file mode 100644
index 0000000000..d5e16fc6ad
--- /dev/null
+++ b/cpp/lib/client/ClientAdapter.h
@@ -0,0 +1,66 @@
+#ifndef _client_ClientAdapter_h
+#define _client_ClientAdapter_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "ChannelAdapter.h"
+#include "ClientChannel.h"
+
+namespace qpid {
+namespace client {
+
+class AMQMethodBody;
+class Connection;
+
+/**
+ * Per-channel protocol adapter.
+ *
+ * Translates protocol bodies into calls on the core Channel,
+ * Connection and Client objects.
+ *
+ * Owns a channel, has references to Connection and Client.
+ */
+class ClientAdapter : public framing::ChannelAdapter
+{
+ public:
+ ClientAdapter(std::auto_ptr<Channel> ch, Connection&, Client&);
+ Channel& getChannel() { return *channel; }
+
+ void handleHeader(boost::shared_ptr<qpid::framing::AMQHeaderBody>);
+ void handleContent(boost::shared_ptr<qpid::framing::AMQContentBody>);
+ void handleHeartbeat(boost::shared_ptr<qpid::framing::AMQHeartbeatBody>);
+
+ private:
+ void handleMethodInContext(
+ boost::shared_ptr<qpid::framing::AMQMethodBody> method,
+ const framing::MethodContext& context);
+
+ class ClientOps;
+
+ std::auto_ptr<Channel> channel;
+ Connection& connection;
+ Client& client;
+ boost::shared_ptr<ClientOps> clientOps;
+};
+
+}} // namespace qpid::client
+
+
+
+#endif /*!_client_ClientAdapter_h*/
diff --git a/cpp/lib/client/ClientChannel.cpp b/cpp/lib/client/ClientChannel.cpp
new file mode 100644
index 0000000000..84aa73e6bc
--- /dev/null
+++ b/cpp/lib/client/ClientChannel.cpp
@@ -0,0 +1,302 @@
+/*
+ *
+ * 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 <iostream>
+#include <ClientChannel.h>
+#include <sys/Monitor.h>
+#include <ClientMessage.h>
+#include <QpidError.h>
+#include <MethodBodyInstances.h>
+#include "Connection.h"
+
+// FIXME aconway 2007-01-26: Evaluate all throws, ensure consistent
+// handling of errors that should close the connection or the channel.
+// Make sure the user thread receives a connection in each case.
+//
+using namespace std;
+using namespace boost;
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+Channel::Channel(bool _transactional, uint16_t _prefetch) :
+ basic(*this),
+ connection(0),
+ prefetch(_prefetch),
+ transactional(_transactional)
+{ }
+
+Channel::~Channel(){
+ close();
+}
+
+void Channel::open(ChannelId id, Connection& con)
+{
+ if (isOpen())
+ THROW_QPID_ERROR(INTERNAL_ERROR, "Attempt to re-open channel "+id);
+ connection = &con;
+ init(id, con, con.getVersion()); // ChannelAdapter initialization.
+ string oob;
+ if (id != 0)
+ sendAndReceive<ChannelOpenOkBody>(new ChannelOpenBody(version, oob));
+}
+
+void Channel::protocolInit(
+ const std::string& uid, const std::string& pwd, const std::string& vhost) {
+ assert(connection);
+ responses.expect();
+ connection->connector->init(); // Send ProtocolInit block.
+ responses.receive<ConnectionStartBody>();
+
+ FieldTable props;
+ string mechanism("PLAIN");
+ string response = ((char)0) + uid + ((char)0) + pwd;
+ string locale("en_US");
+ ConnectionTuneBody::shared_ptr proposal =
+ sendAndReceive<ConnectionTuneBody>(
+ new ConnectionStartOkBody(
+ version, responses.getRequestId(), props, mechanism,
+ response, locale));
+
+ /**
+ * Assume for now that further challenges will not be required
+ //receive connection.secure
+ responses.receive(connection_secure));
+ //send connection.secure-ok
+ connection->send(new AMQFrame(0, new ConnectionSecureOkBody(response)));
+ **/
+
+ send(new ConnectionTuneOkBody(
+ version, responses.getRequestId(), proposal->getChannelMax(), connection->getMaxFrameSize(),
+ proposal->getHeartbeat()));
+
+ uint16_t heartbeat = proposal->getHeartbeat();
+ connection->connector->setReadTimeout(heartbeat * 2);
+ connection->connector->setWriteTimeout(heartbeat);
+
+ // Send connection open.
+ std::string capabilities;
+ responses.expect();
+ send(new ConnectionOpenBody(version, vhost, capabilities, true));
+ //receive connection.open-ok (or redirect, but ignore that for now
+ //esp. as using force=true).
+ responses.waitForResponse();
+ if(responses.validate<ConnectionOpenOkBody>()) {
+ //ok
+ }else if(responses.validate<ConnectionRedirectBody>()){
+ //ignore for now
+ ConnectionRedirectBody::shared_ptr redirect(
+ shared_polymorphic_downcast<ConnectionRedirectBody>(
+ responses.getResponse()));
+ cout << "Received redirection to " << redirect->getHost()
+ << endl;
+ } else {
+ THROW_QPID_ERROR(PROTOCOL_ERROR, "Bad response");
+ }
+}
+
+bool Channel::isOpen() const { return connection; }
+
+void Channel::setQos() {
+ basic.setQos();
+ // FIXME aconway 2007-02-22: message
+}
+
+void Channel::setPrefetch(uint16_t _prefetch){
+ prefetch = _prefetch;
+ setQos();
+}
+
+void Channel::declareExchange(Exchange& exchange, bool synch){
+ string name = exchange.getName();
+ string type = exchange.getType();
+ FieldTable args;
+ sendAndReceiveSync<ExchangeDeclareOkBody>(
+ synch,
+ new ExchangeDeclareBody(
+ version, 0, name, type, false, false, false, false, !synch, args));
+}
+
+void Channel::deleteExchange(Exchange& exchange, bool synch){
+ string name = exchange.getName();
+ sendAndReceiveSync<ExchangeDeleteOkBody>(
+ synch,
+ new ExchangeDeleteBody(version, 0, name, false, !synch));
+}
+
+void Channel::declareQueue(Queue& queue, bool synch){
+ string name = queue.getName();
+ FieldTable args;
+ sendAndReceiveSync<QueueDeclareOkBody>(
+ synch,
+ new QueueDeclareBody(
+ version, 0, name, false/*passive*/, queue.isDurable(),
+ queue.isExclusive(), queue.isAutoDelete(), !synch, args));
+ if(synch){
+ if(queue.getName().length() == 0){
+ QueueDeclareOkBody::shared_ptr response =
+ shared_polymorphic_downcast<QueueDeclareOkBody>(
+ responses.getResponse());
+ queue.setName(response->getQueue());
+ }
+ }
+}
+
+void Channel::deleteQueue(Queue& queue, bool ifunused, bool ifempty, bool synch){
+ //ticket, queue, ifunused, ifempty, nowait
+ string name = queue.getName();
+ sendAndReceiveSync<QueueDeleteOkBody>(
+ synch,
+ new QueueDeleteBody(version, 0, name, ifunused, ifempty, !synch));
+}
+
+void Channel::bind(const Exchange& exchange, const Queue& queue, const std::string& key, const FieldTable& args, bool synch){
+ string e = exchange.getName();
+ string q = queue.getName();
+ sendAndReceiveSync<QueueBindOkBody>(
+ synch,
+ new QueueBindBody(version, 0, q, e, key,!synch, args));
+}
+
+void Channel::commit(){
+ sendAndReceive<TxCommitOkBody>(new TxCommitBody(version));
+}
+
+void Channel::rollback(){
+ sendAndReceive<TxRollbackOkBody>(new TxRollbackBody(version));
+}
+
+void Channel::handleMethodInContext(
+ AMQMethodBody::shared_ptr method, const MethodContext&)
+{
+ if(responses.isWaiting()) {
+ responses.signalResponse(method);
+ return;
+ }
+ try {
+ switch (method->amqpClassId()) {
+ case BasicDeliverBody::CLASS_ID: basic.handle(method); break;
+ case ChannelCloseBody::CLASS_ID: handleChannel(method); break;
+ case ConnectionCloseBody::CLASS_ID: handleConnection(method); break;
+ default: throw UnknownMethod();
+ }
+ }
+ catch (const UnknownMethod&) {
+ connection->close(
+ 504, "Unknown method",
+ method->amqpClassId(), method->amqpMethodId());
+ }
+}
+
+void Channel::handleChannel(AMQMethodBody::shared_ptr method) {
+ switch (method->amqpMethodId()) {
+ case ChannelCloseBody::METHOD_ID:
+ peerClose(shared_polymorphic_downcast<ChannelCloseBody>(method));
+ return;
+ case ChannelFlowBody::METHOD_ID:
+ // FIXME aconway 2007-02-22: Not yet implemented.
+ return;
+ }
+ throw UnknownMethod();
+}
+
+void Channel::handleConnection(AMQMethodBody::shared_ptr method) {
+ if (method->amqpMethodId() == ConnectionCloseBody::METHOD_ID) {
+ connection->close();
+ return;
+ }
+ throw UnknownMethod();
+}
+
+void Channel::handleHeader(AMQHeaderBody::shared_ptr body){
+ basic.incoming.add(body);
+}
+
+void Channel::handleContent(AMQContentBody::shared_ptr body){
+ basic.incoming.add(body);
+}
+
+void Channel::handleHeartbeat(AMQHeartbeatBody::shared_ptr /*body*/){
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Channel received heartbeat");
+}
+
+void Channel::start(){
+ basicDispatcher = Thread(basic);
+}
+
+// Close called by local application.
+void Channel::close(
+ uint16_t code, const std::string& text,
+ ClassId classId, MethodId methodId)
+{
+ if (isOpen()) {
+ try {
+ if (getId() != 0) {
+ sendAndReceive<ChannelCloseOkBody>(
+ new ChannelCloseBody(
+ version, code, text, classId, methodId));
+ }
+ static_cast<ConnectionForChannel*>(connection)->erase(getId());
+ closeInternal();
+ } catch (...) {
+ static_cast<ConnectionForChannel*>(connection)->erase(getId());
+ closeInternal();
+ throw;
+ }
+ }
+}
+
+// Channel closed by peer.
+void Channel::peerClose(ChannelCloseBody::shared_ptr) {
+ assert(isOpen());
+ closeInternal();
+ // FIXME aconway 2007-01-26: How to throw the proper exception
+ // to the application thread?
+}
+
+void Channel::closeInternal() {
+ if (isOpen());
+ {
+ basic.cancelAll();
+ basic.incoming.shutdown();
+ connection = 0;
+ // A 0 response means we are closed.
+ responses.signalResponse(AMQMethodBody::shared_ptr());
+ }
+ basicDispatcher.join();
+}
+
+void Channel::sendAndReceive(AMQMethodBody* toSend, ClassId c, MethodId m)
+{
+ responses.expect();
+ send(toSend);
+ responses.receive(c, m);
+}
+
+void Channel::sendAndReceiveSync(
+ bool sync, AMQMethodBody* body, ClassId c, MethodId m)
+{
+ if(sync)
+ sendAndReceive(body, c, m);
+ else
+ send(body);
+}
+
+
diff --git a/cpp/lib/client/ClientChannel.h b/cpp/lib/client/ClientChannel.h
new file mode 100644
index 0000000000..3ecab05d0b
--- /dev/null
+++ b/cpp/lib/client/ClientChannel.h
@@ -0,0 +1,250 @@
+#ifndef _client_ClientChannel_h
+#define _client_ClientChannel_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 "sys/types.h"
+#include <framing/amqp_framing.h>
+#include <ClientExchange.h>
+#include <ClientMessage.h>
+#include <ClientQueue.h>
+#include <ResponseHandler.h>
+#include "ChannelAdapter.h"
+#include "Thread.h"
+#include "Basic.h"
+
+namespace qpid {
+
+namespace framing {
+class ChannelCloseBody;
+class AMQMethodBody;
+}
+
+namespace client {
+
+class Connection;
+
+
+/**
+ * Represents an AMQP channel, i.e. loosely a session of work. It
+ * is through a channel that most of the AMQP 'methods' are
+ * exposed.
+ *
+ * \ingroup clientapi
+ */
+class Channel : public framing::ChannelAdapter
+{
+ private:
+ // TODO aconway 2007-02-22: Remove friendship.
+ friend class Basic;
+ // FIXME aconway 2007-02-22: friend class Message;
+
+ struct UnknownMethod {};
+
+ sys::Mutex lock;
+ Basic basic;
+ Connection* connection;
+ sys::Thread basicDispatcher;
+ ResponseHandler responses;
+
+ uint16_t prefetch;
+ const bool transactional;
+ framing::ProtocolVersion version;
+
+ void handleHeader(framing::AMQHeaderBody::shared_ptr body);
+ void handleContent(framing::AMQContentBody::shared_ptr body);
+ void handleHeartbeat(framing::AMQHeartbeatBody::shared_ptr body);
+ void handleMethodInContext(
+ framing::AMQMethodBody::shared_ptr, const framing::MethodContext&);
+ void handleChannel(framing::AMQMethodBody::shared_ptr method);
+ void handleConnection(framing::AMQMethodBody::shared_ptr method);
+
+ void setQos();
+
+ void protocolInit(
+ const std::string& uid, const std::string& pwd,
+ const std::string& vhost);
+
+ void sendAndReceive(
+ framing::AMQMethodBody*, framing::ClassId, framing::MethodId);
+
+ void sendAndReceiveSync(
+ bool sync,
+ framing::AMQMethodBody*, framing::ClassId, framing::MethodId);
+
+ template <class BodyType>
+ boost::shared_ptr<BodyType> sendAndReceive(framing::AMQMethodBody* body) {
+ sendAndReceive(body, BodyType::CLASS_ID, BodyType::METHOD_ID);
+ return boost::shared_polymorphic_downcast<BodyType>(
+ responses.getResponse());
+ }
+
+ template <class BodyType> void sendAndReceiveSync(
+ bool sync, framing::AMQMethodBody* body) {
+ sendAndReceiveSync(
+ sync, body, BodyType::CLASS_ID, BodyType::METHOD_ID);
+ }
+
+ void open(framing::ChannelId, Connection&);
+ void closeInternal();
+ void peerClose(boost::shared_ptr<framing::ChannelCloseBody>);
+
+ friend class Connection;
+
+ public:
+
+ /**
+ * Creates a channel object.
+ *
+ * @param transactional if true, the publishing and acknowledgement
+ * of messages will be transactional and can be committed or
+ * aborted in atomic units (@see commit(), @see rollback())
+ *
+ * @param prefetch specifies the number of unacknowledged
+ * messages the channel is willing to have sent to it
+ * asynchronously
+ */
+ Channel(bool transactional = false, uint16_t prefetch = 500);
+ ~Channel();
+
+ /**
+ * Declares an exchange.
+ *
+ * In AMQP Exchanges are the destinations to which messages
+ * are published. They have Queues bound to them and route
+ * messages they receive to those queues. The routing rules
+ * depend on the type of the exchange.
+ *
+ * @param exchange an Exchange object representing the
+ * exchange to declare
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void declareExchange(Exchange& exchange, bool synch = true);
+ /**
+ * Deletes an exchange
+ *
+ * @param exchange an Exchange object representing the exchange to delete
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void deleteExchange(Exchange& exchange, bool synch = true);
+ /**
+ * Declares a Queue
+ *
+ * @param queue a Queue object representing the queue to declare
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void declareQueue(Queue& queue, bool synch = true);
+ /**
+ * Deletes a Queue
+ *
+ * @param queue a Queue object representing the queue to delete
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void deleteQueue(Queue& queue, bool ifunused = false, bool ifempty = false, bool synch = true);
+ /**
+ * Binds a queue to an exchange. The exact semantics of this
+ * (in particular how 'routing keys' and 'binding arguments'
+ * are used) depends on the type of the exchange.
+ *
+ * @param exchange an Exchange object representing the
+ * exchange to bind to
+ *
+ * @param queue a Queue object representing the queue to be
+ * bound
+ *
+ * @param key the 'routing key' for the binding
+ *
+ * @param args the 'binding arguments' for the binding
+ *
+ * @param synch if true this call will block until a response
+ * is received from the broker
+ */
+ void bind(const Exchange& exchange, const Queue& queue,
+ const std::string& key, const framing::FieldTable& args,
+ bool synch = true);
+
+ /**
+ * Get a Basic object which provides functions to send and
+ * receive messages using the AMQP 0-8 Basic class methods.
+ *@see Basic
+ */
+ Basic& getBasic() { return basic; }
+
+ /**
+ * For a transactional channel this will commit all
+ * publications and acknowledgements since the last commit (or
+ * the channel was opened if there has been no previous
+ * commit). This will cause published messages to become
+ * available to consumers and acknowledged messages to be
+ * consumed and removed from the queues they were dispatched
+ * from.
+ *
+ * Transactionailty of a channel is specified when the channel
+ * object is created (@see Channel()).
+ */
+ void commit();
+
+ /**
+ * For a transactional channel, this will rollback any
+ * publications or acknowledgements. It will be as if the
+ * ppblished messages were never sent and the acknowledged
+ * messages were never consumed.
+ */
+ void rollback();
+
+ /**
+ * Change the prefetch in use.
+ */
+ void setPrefetch(uint16_t prefetch);
+
+ uint16_t getPrefetch() { return prefetch; }
+
+ /**
+ * Start message dispatching on a new thread
+ */
+ void start();
+
+ /**
+ * Close the channel with optional error information.
+ * Closing a channel that is not open has no effect.
+ */
+ void close(
+ framing::ReplyCode = 200, const std::string& ="OK",
+ framing::ClassId = 0, framing::MethodId = 0);
+
+ /** True if the channel is transactional */
+ bool isTransactional() { return transactional; }
+
+ /** True if the channel is open */
+ bool isOpen() const;
+};
+
+}}
+
+#endif /*!_client_ClientChannel_h*/
diff --git a/cpp/lib/client/ClientExchange.cpp b/cpp/lib/client/ClientExchange.cpp
new file mode 100644
index 0000000000..5e5f3f14c6
--- /dev/null
+++ b/cpp/lib/client/ClientExchange.cpp
@@ -0,0 +1,34 @@
+/*
+ *
+ * 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 <ClientExchange.h>
+
+qpid::client::Exchange::Exchange(std::string _name, std::string _type) : name(_name), type(_type){}
+const std::string& qpid::client::Exchange::getName() const { return name; }
+const std::string& qpid::client::Exchange::getType() const { return type; }
+
+const std::string qpid::client::Exchange::DIRECT_EXCHANGE = "direct";
+const std::string qpid::client::Exchange::TOPIC_EXCHANGE = "topic";
+const std::string qpid::client::Exchange::HEADERS_EXCHANGE = "headers";
+
+const qpid::client::Exchange qpid::client::Exchange::DEFAULT_EXCHANGE("", DIRECT_EXCHANGE);
+const qpid::client::Exchange qpid::client::Exchange::STANDARD_DIRECT_EXCHANGE("amq.direct", DIRECT_EXCHANGE);
+const qpid::client::Exchange qpid::client::Exchange::STANDARD_TOPIC_EXCHANGE("amq.topic", TOPIC_EXCHANGE);
+const qpid::client::Exchange qpid::client::Exchange::STANDARD_HEADERS_EXCHANGE("amq.headers", HEADERS_EXCHANGE);
diff --git a/cpp/lib/client/ClientExchange.h b/cpp/lib/client/ClientExchange.h
new file mode 100644
index 0000000000..a8ac21fa9b
--- /dev/null
+++ b/cpp/lib/client/ClientExchange.h
@@ -0,0 +1,106 @@
+/*
+ *
+ * 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 <string>
+
+#ifndef _Exchange_
+#define _Exchange_
+
+namespace qpid {
+namespace client {
+
+ /**
+ * A 'handle' used to represent an AMQP exchange in the Channel
+ * methods. Exchanges are the destinations to which messages are
+ * published.
+ *
+ * There are different types of exchange (the standard types are
+ * available as static constants, see DIRECT_EXCHANGE,
+ * TOPIC_EXCHANGE and HEADERS_EXCHANGE). A Queue can be bound to
+ * an exchange using Channel::bind() and messages published to
+ * that exchange are then routed to the queue based on the details
+ * of the binding and the type of exchange.
+ *
+ * There are some standard exchange instances that are predeclared
+ * on all AMQP brokers. These are defined as static members
+ * STANDARD_DIRECT_EXCHANGE, STANDARD_TOPIC_EXCHANGE and
+ * STANDARD_HEADERS_EXCHANGE. There is also the 'default' exchange
+ * (member DEFAULT_EXCHANGE) which is nameless and of type
+ * 'direct' and has every declared queue bound to it by queue
+ * name.
+ *
+ * \ingroup clientapi
+ */
+ class Exchange{
+ const std::string name;
+ const std::string type;
+
+ public:
+ /**
+ * A direct exchange routes messages published with routing
+ * key X to any queue bound with key X (i.e. an exact match is
+ * used).
+ */
+ static const std::string DIRECT_EXCHANGE;
+ /**
+ * A topic exchange treat the key with which a queue is bound
+ * as a pattern and routes all messages whose routing keys
+ * match that pattern to the bound queue. The routing key for
+ * a message must consist of zero or more alpha-numeric words
+ * delimited by dots. The pattern is of a similar form but *
+ * can be used to match excatly one word and # can be used to
+ * match zero or more words.
+ */
+ static const std::string TOPIC_EXCHANGE;
+ /**
+ * The headers exchange routes messages based on whether their
+ * headers match the binding arguments specified when
+ * binding. (see the AMQP spec for more details).
+ */
+ static const std::string HEADERS_EXCHANGE;
+
+ /**
+ * The 'default' exchange, nameless and of type 'direct'. Has
+ * every declared queue bound to it by name.
+ */
+ static const Exchange DEFAULT_EXCHANGE;
+ /**
+ * The standard direct exchange, named amq.direct.
+ */
+ static const Exchange STANDARD_DIRECT_EXCHANGE;
+ /**
+ * The standard topic exchange, named amq.topic.
+ */
+ static const Exchange STANDARD_TOPIC_EXCHANGE;
+ /**
+ * The standard headers exchange, named amq.header.
+ */
+ static const Exchange STANDARD_HEADERS_EXCHANGE;
+
+ Exchange(std::string name, std::string type = DIRECT_EXCHANGE);
+ const std::string& getName() const;
+ const std::string& getType() const;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/client/ClientMessage.cpp b/cpp/lib/client/ClientMessage.cpp
new file mode 100644
index 0000000000..f55c4abfe6
--- /dev/null
+++ b/cpp/lib/client/ClientMessage.cpp
@@ -0,0 +1,162 @@
+/*
+ *
+ * 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 <ClientMessage.h>
+using namespace qpid::client;
+using namespace qpid::framing;
+
+Message::Message(const std::string& d)
+ : header(new AMQHeaderBody(BASIC))
+{
+ setData(d);
+}
+
+void Message::setData(const std::string& d) {
+ data = d;
+ header->setContentSize(d.size());
+}
+
+Message::Message(AMQHeaderBody::shared_ptr& _header) : header(_header){
+}
+
+Message::~Message(){
+}
+
+BasicHeaderProperties* Message::getHeaderProperties() const {
+ return dynamic_cast<BasicHeaderProperties*>(header->getProperties());
+}
+
+const std::string& Message::getContentType() const {
+ return getHeaderProperties()->getContentType();
+}
+
+const std::string& Message::getContentEncoding() const {
+ return getHeaderProperties()->getContentEncoding();
+}
+
+FieldTable& Message::getHeaders() const {
+ return getHeaderProperties()->getHeaders();
+}
+
+uint8_t Message::getDeliveryMode() const {
+ return getHeaderProperties()->getDeliveryMode();
+}
+
+uint8_t Message::getPriority() const {
+ return getHeaderProperties()->getPriority();
+}
+
+const std::string& Message::getCorrelationId() const {
+ return getHeaderProperties()->getCorrelationId();
+}
+
+const std::string& Message::getReplyTo() const {
+ return getHeaderProperties()->getReplyTo();
+}
+
+const std::string& Message::getExpiration() const {
+ return getHeaderProperties()->getExpiration();
+}
+
+const std::string& Message::getMessageId() const {
+ return getHeaderProperties()->getMessageId();
+}
+
+uint64_t Message::getTimestamp() const {
+ return getHeaderProperties()->getTimestamp();
+}
+
+const std::string& Message::getType() const {
+ return getHeaderProperties()->getType();
+}
+
+const std::string& Message::getUserId() const {
+ return getHeaderProperties()->getUserId();
+}
+
+const std::string& Message::getAppId() const {
+ return getHeaderProperties()->getAppId();
+}
+
+const std::string& Message::getClusterId() const {
+ return getHeaderProperties()->getClusterId();
+}
+
+void Message::setContentType(const std::string& type){
+ getHeaderProperties()->setContentType(type);
+}
+
+void Message::setContentEncoding(const std::string& encoding){
+ getHeaderProperties()->setContentEncoding(encoding);
+}
+
+void Message::setHeaders(const FieldTable& headers){
+ getHeaderProperties()->setHeaders(headers);
+}
+
+void Message::setDeliveryMode(uint8_t mode){
+ getHeaderProperties()->setDeliveryMode(mode);
+}
+
+void Message::setPriority(uint8_t priority){
+ getHeaderProperties()->setPriority(priority);
+}
+
+void Message::setCorrelationId(const std::string& correlationId){
+ getHeaderProperties()->setCorrelationId(correlationId);
+}
+
+void Message::setReplyTo(const std::string& replyTo){
+ getHeaderProperties()->setReplyTo(replyTo);
+}
+
+void Message::setExpiration(const std::string& expiration){
+ getHeaderProperties()->setExpiration(expiration);
+}
+
+void Message::setMessageId(const std::string& messageId){
+ getHeaderProperties()->setMessageId(messageId);
+}
+
+void Message::setTimestamp(uint64_t timestamp){
+ getHeaderProperties()->setTimestamp(timestamp);
+}
+
+void Message::setType(const std::string& type){
+ getHeaderProperties()->setType(type);
+}
+
+void Message::setUserId(const std::string& userId){
+ getHeaderProperties()->setUserId(userId);
+}
+
+void Message::setAppId(const std::string& appId){
+ getHeaderProperties()->setAppId(appId);
+}
+
+void Message::setClusterId(const std::string& clusterId){
+ getHeaderProperties()->setClusterId(clusterId);
+}
+
+
+uint64_t Message::getDeliveryTag() const {
+ BasicDeliverBody* deliver=dynamic_cast<BasicDeliverBody*>(method.get());
+ return deliver ? deliver->getDeliveryTag() : 0;
+}
diff --git a/cpp/lib/client/ClientMessage.h b/cpp/lib/client/ClientMessage.h
new file mode 100644
index 0000000000..cb239ed4d6
--- /dev/null
+++ b/cpp/lib/client/ClientMessage.h
@@ -0,0 +1,125 @@
+#ifndef _client_ClientMessage_h
+#define _client_ClientMessage_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 <string>
+#include <framing/amqp_framing.h>
+
+namespace qpid {
+
+namespace client {
+class IncomingMessage;
+
+/**
+ * A representation of messages for sent or recived through the
+ * client api.
+ *
+ * \ingroup clientapi
+ */
+class Message {
+ framing::AMQMethodBody::shared_ptr method;
+ framing::AMQHeaderBody::shared_ptr header;
+ std::string data;
+ bool redelivered;
+
+ // FIXME aconway 2007-02-20: const incorrect, needs const return type.
+ framing::BasicHeaderProperties* getHeaderProperties() const;
+ Message(qpid::framing::AMQHeaderBody::shared_ptr& header);
+
+ public:
+ Message(const std::string& data=std::string());
+ ~Message();
+
+ /**
+ * Allows the application to access the content of messages
+ * received.
+ *
+ * @return a string representing the data of the message
+ */
+ std::string getData() const { return data; }
+
+ /**
+ * Allows the application to set the content of messages to be
+ * sent.
+ *
+ * @param data a string representing the data of the message
+ */
+ void setData(const std::string& _data);
+
+ /**
+ * @return true if this message was delivered previously (to
+ * any consumer) but was not acknowledged.
+ */
+ bool isRedelivered(){ return redelivered; }
+ void setRedelivered(bool _redelivered){ redelivered = _redelivered; }
+
+ uint64_t getDeliveryTag() const;
+
+ const std::string& getContentType() const;
+ const std::string& getContentEncoding() const;
+ qpid::framing::FieldTable& getHeaders() const;
+ uint8_t getDeliveryMode() const;
+ uint8_t getPriority() const;
+ const std::string& getCorrelationId() const;
+ const std::string& getReplyTo() const;
+ const std::string& getExpiration() const;
+ const std::string& getMessageId() const;
+ uint64_t getTimestamp() const;
+ const std::string& getType() const;
+ const std::string& getUserId() const;
+ const std::string& getAppId() const;
+ const std::string& getClusterId() const;
+
+ void setContentType(const std::string& type);
+ void setContentEncoding(const std::string& encoding);
+ void setHeaders(const qpid::framing::FieldTable& headers);
+ /**
+ * Sets the delivery mode. 1 = non-durable, 2 = durable.
+ */
+ void setDeliveryMode(uint8_t mode);
+ void setPriority(uint8_t priority);
+ void setCorrelationId(const std::string& correlationId);
+ void setReplyTo(const std::string& replyTo);
+ void setExpiration(const std::string& expiration);
+ void setMessageId(const std::string& messageId);
+ void setTimestamp(uint64_t timestamp);
+ void setType(const std::string& type);
+ void setUserId(const std::string& userId);
+ void setAppId(const std::string& appId);
+ void setClusterId(const std::string& clusterId);
+
+ /** Get the method used to deliver this message */
+ boost::shared_ptr<framing::AMQMethodBody> getMethod() const
+ { return method; }
+
+ void setMethod(framing::AMQMethodBody::shared_ptr m) { method=m; }
+ boost::shared_ptr<framing::AMQHeaderBody> getHeader() const
+ { return header; }
+
+ // TODO aconway 2007-02-15: remove friendships.
+ friend class IncomingMessage;
+ friend class Channel;
+};
+
+}}
+
+#endif /*!_client_ClientMessage_h*/
diff --git a/cpp/lib/client/ClientQueue.cpp b/cpp/lib/client/ClientQueue.cpp
new file mode 100644
index 0000000000..773be504d8
--- /dev/null
+++ b/cpp/lib/client/ClientQueue.cpp
@@ -0,0 +1,58 @@
+/*
+ *
+ * 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 <ClientQueue.h>
+
+qpid::client::Queue::Queue() : name(""), autodelete(true), exclusive(true), durable(false){}
+
+qpid::client::Queue::Queue(std::string _name) : name(_name), autodelete(false), exclusive(false), durable(false){}
+
+qpid::client::Queue::Queue(std::string _name, bool temp) : name(_name), autodelete(temp), exclusive(temp), durable(false){}
+
+qpid::client::Queue::Queue(std::string _name, bool _autodelete, bool _exclusive, bool _durable)
+ : name(_name), autodelete(_autodelete), exclusive(_exclusive), durable(_durable){}
+
+const std::string& qpid::client::Queue::getName() const{
+ return name;
+}
+
+void qpid::client::Queue::setName(const std::string& _name){
+ name = _name;
+}
+
+bool qpid::client::Queue::isAutoDelete() const{
+ return autodelete;
+}
+
+bool qpid::client::Queue::isExclusive() const{
+ return exclusive;
+}
+
+bool qpid::client::Queue::isDurable() const{
+ return durable;
+}
+
+void qpid::client::Queue::setDurable(bool _durable){
+ durable = _durable;
+}
+
+
+
+
diff --git a/cpp/lib/client/ClientQueue.h b/cpp/lib/client/ClientQueue.h
new file mode 100644
index 0000000000..b37a44b004
--- /dev/null
+++ b/cpp/lib/client/ClientQueue.h
@@ -0,0 +1,103 @@
+#ifndef _client_ClientQueue_h
+#define _client_ClientQueue_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 <string>
+
+namespace qpid {
+namespace client {
+
+ /**
+ * A 'handle' used to represent an AMQP queue in the Channel
+ * methods. Creating an instance of this class does not cause the
+ * queue to be created on the broker. Rather, an instance of this
+ * class should be passed to Channel::declareQueue() to ensure
+ * that the queue exists or is created.
+ *
+ * Queues hold messages and allow clients to consume
+ * (see Channel::consume()) or get (see Channel::get()) those messags. A
+ * queue receives messages by being bound to one or more Exchange;
+ * messages published to that exchange may then be routed to the
+ * queue based on the details of the binding and the type of the
+ * exchange (see Channel::bind()).
+ *
+ * Queues are identified by a name. They can be exclusive (in which
+ * case they can only be used in the context of the connection
+ * over which they were declared, and are deleted when then
+ * connection closes), or they can be shared. Shared queues can be
+ * auto deleted when they have no consumers.
+ *
+ * We use the term 'temporary queue' to refer to an exclusive
+ * queue.
+ *
+ * \ingroup clientapi
+ */
+ class Queue{
+ std::string name;
+ const bool autodelete;
+ const bool exclusive;
+ bool durable;
+
+ public:
+
+ /**
+ * Creates an unnamed, non-durable, temporary queue. A name
+ * will be assigned to this queue instance by a call to
+ * Channel::declareQueue().
+ */
+ Queue();
+ /**
+ * Creates a shared, non-durable, queue with a given name,
+ * that will not be autodeleted.
+ *
+ * @param name the name of the queue
+ */
+ Queue(std::string name);
+ /**
+ * Creates a non-durable queue with a given name.
+ *
+ * @param name the name of the queue
+ *
+ * @param temp if true the queue will be a temporary queue, if
+ * false it will be shared and not autodeleted.
+ */
+ Queue(std::string name, bool temp);
+ /**
+ * This constructor allows the autodelete, exclusive and
+ * durable propeties to be explictly set. Note however that if
+ * exclusive is true, autodelete has no meaning as exclusive
+ * queues are always destroyed when the connection that
+ * created them is closed.
+ */
+ Queue(std::string name, bool autodelete, bool exclusive, bool durable);
+ const std::string& getName() const;
+ void setName(const std::string&);
+ bool isAutoDelete() const;
+ bool isExclusive() const;
+ bool isDurable() const;
+ void setDurable(bool durable);
+ };
+
+}
+}
+
+#endif /*!_client_ClientQueue_h*/
diff --git a/cpp/lib/client/Connection.cpp b/cpp/lib/client/Connection.cpp
new file mode 100644
index 0000000000..618f3cbc92
--- /dev/null
+++ b/cpp/lib/client/Connection.cpp
@@ -0,0 +1,156 @@
+/*
+ *
+ * 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 <algorithm>
+#include <boost/format.hpp>
+#include <boost/bind.hpp>
+
+#include <Connection.h>
+#include <ClientChannel.h>
+#include <ClientMessage.h>
+#include <QpidError.h>
+#include <iostream>
+#include <sstream>
+#include <MethodBodyInstances.h>
+#include <functional>
+
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+
+namespace qpid {
+namespace client {
+
+const std::string Connection::OK("OK");
+
+Connection::Connection(
+ bool _debug, uint32_t _max_frame_size,
+ framing::ProtocolVersion _version
+) : channelIdCounter(0), version(_version), max_frame_size(_max_frame_size),
+ defaultConnector(version, _debug, _max_frame_size),
+ isOpen(false), debug(_debug)
+{
+ setConnector(defaultConnector);
+}
+
+Connection::~Connection(){}
+
+void Connection::setConnector(Connector& con)
+{
+ connector = &con;
+ connector->setInputHandler(this);
+ connector->setTimeoutHandler(this);
+ connector->setShutdownHandler(this);
+ out = connector->getOutputHandler();
+}
+
+void Connection::open(
+ const std::string& host, int port,
+ const std::string& uid, const std::string& pwd, const std::string& vhost)
+{
+ if (isOpen)
+ THROW_QPID_ERROR(INTERNAL_ERROR, "Channel object is already open");
+ connector->connect(host, port);
+ channels[0] = &channel0;
+ channel0.open(0, *this);
+ channel0.protocolInit(uid, pwd, vhost);
+ isOpen = true;
+}
+
+void Connection::shutdown() {
+ close();
+}
+
+void Connection::close(
+ ReplyCode code, const string& msg, ClassId classId, MethodId methodId
+)
+{
+ if(isOpen) {
+ // TODO aconway 2007-01-29: Exception handling - could end up
+ // partly closed with threads left unjoined.
+ isOpen = false;
+ channel0.sendAndReceive<ConnectionCloseOkBody>(
+ new ConnectionCloseBody(
+ getVersion(), code, msg, classId, methodId));
+
+ using boost::bind;
+ for_each(channels.begin(), channels.end(),
+ bind(&Channel::closeInternal,
+ bind(&ChannelMap::value_type::second, _1)));
+ channels.clear();
+ connector->close();
+ }
+}
+
+void Connection::openChannel(Channel& channel) {
+ ChannelId id = ++channelIdCounter;
+ assert (channels.find(id) == channels.end());
+ assert(out);
+ channels[id] = &channel;
+ channel.open(id, *this);
+}
+
+void Connection::erase(ChannelId id) {
+ channels.erase(id);
+}
+
+void Connection::received(AMQFrame* frame){
+ // FIXME aconway 2007-01-25: Mutex
+ ChannelId id = frame->getChannel();
+ Channel* channel = channels[id];
+ // FIXME aconway 2007-01-26: Exception thrown here is hanging the
+ // client. Need to review use of exceptions.
+ if (channel == 0)
+ THROW_QPID_ERROR(
+ PROTOCOL_ERROR+504,
+ (boost::format("Invalid channel number %g") % id).str());
+ try{
+ channel->handleBody(frame->getBody());
+ }catch(const qpid::QpidError& e){
+ channelException(
+ *channel, dynamic_cast<AMQMethodBody*>(frame->getBody().get()), e);
+ }
+}
+
+void Connection::send(AMQFrame* frame) {
+ out->send(frame);
+}
+
+void Connection::channelException(
+ Channel& channel, AMQMethodBody* method, const QpidError& e)
+{
+ int code = (e.code >= PROTOCOL_ERROR) ? e.code - PROTOCOL_ERROR : 500;
+ string msg = e.msg;
+ if(method == 0)
+ channel.close(code, msg);
+ else
+ channel.close(
+ code, msg, method->amqpClassId(), method->amqpMethodId());
+}
+
+void Connection::idleIn(){
+ connector->close();
+}
+
+void Connection::idleOut(){
+ out->send(new AMQFrame(version, 0, new AMQHeartbeatBody()));
+}
+
+}} // namespace qpid::client
diff --git a/cpp/lib/client/Connection.h b/cpp/lib/client/Connection.h
new file mode 100644
index 0000000000..b4bd311511
--- /dev/null
+++ b/cpp/lib/client/Connection.h
@@ -0,0 +1,194 @@
+#ifndef _client_Connection_
+#define _client_Connection_
+
+/*
+ *
+ * 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 <map>
+#include <string>
+#include <boost/shared_ptr.hpp>
+
+#include "amqp_types.h"
+#include <QpidError.h>
+#include <Connector.h>
+#include <sys/ShutdownHandler.h>
+#include <sys/TimeoutHandler.h>
+
+
+#include "framing/amqp_types.h"
+#include <framing/amqp_framing.h>
+#include <ClientExchange.h>
+#include <IncomingMessage.h>
+#include <ClientMessage.h>
+#include <MessageListener.h>
+#include <ClientQueue.h>
+#include <ResponseHandler.h>
+#include <AMQP_HighestVersion.h>
+#include "ClientChannel.h"
+
+namespace qpid {
+
+/**
+ * The client namespace contains all classes that make up a client
+ * implementation of the AMQP protocol. The key classes that form
+ * the basis of the client API to be used by applications are
+ * Connection and Channel.
+ */
+namespace client {
+
+class Channel;
+
+/**
+ * \internal provide access to selected private channel functions
+ * for the Connection without making it a friend of the entire channel.
+ */
+class ConnectionForChannel :
+ public framing::InputHandler,
+ public framing::OutputHandler,
+ public sys::TimeoutHandler,
+ public sys::ShutdownHandler
+
+{
+ private:
+ friend class Channel;
+ virtual void erase(framing::ChannelId) = 0;
+};
+
+
+/**
+ * \defgroup clientapi Application API for an AMQP client
+ */
+
+/**
+ * Represents a connection to an AMQP broker. All communication is
+ * initiated by establishing a connection, then opening one or
+ * more Channels over that connection.
+ *
+ * \ingroup clientapi
+ */
+class Connection : public ConnectionForChannel
+{
+ typedef std::map<framing::ChannelId, Channel*> ChannelMap;
+
+ framing::ChannelId channelIdCounter;
+ static const std::string OK;
+
+ framing::ProtocolVersion version;
+ const uint32_t max_frame_size;
+ ChannelMap channels;
+ Connector defaultConnector;
+ Connector* connector;
+ framing::OutputHandler* out;
+ volatile bool isOpen;
+ Channel channel0;
+ bool debug;
+
+ void erase(framing::ChannelId);
+ void channelException(
+ Channel&, framing::AMQMethodBody*, const QpidError&);
+
+ // TODO aconway 2007-01-26: too many friendships, untagle these classes.
+ friend class Channel;
+
+ public:
+ /**
+ * Creates a connection object, but does not open the
+ * connection.
+ *
+ * @param _version the version of the protocol to connect with
+ *
+ * @param debug turns on tracing for the connection
+ * (i.e. prints details of the frames sent and received to std
+ * out). Optional and defaults to false.
+ *
+ * @param max_frame_size the maximum frame size that the
+ * client will accept. Optional and defaults to 65536.
+ */
+ Connection(bool debug = false, uint32_t max_frame_size = 65536,
+ framing::ProtocolVersion=framing::highestProtocolVersion);
+ ~Connection();
+
+ /**
+ * Opens a connection to a broker.
+ *
+ * @param host the host on which the broker is running
+ *
+ * @param port the port on the which the broker is listening
+ *
+ * @param uid the userid to connect with
+ *
+ * @param pwd the password to connect with (currently SASL
+ * PLAIN is the only authentication method supported so this
+ * is sent in clear text)
+ *
+ * @param virtualhost the AMQP virtual host to use (virtual
+ * hosts, where implemented(!), provide namespace partitioning
+ * within a single broker).
+ */
+ void open(const std::string& host, int port = 5672,
+ const std::string& uid = "guest",
+ const std::string& pwd = "guest",
+ const std::string& virtualhost = "/");
+
+ /**
+ * Close the connection with optional error information for the peer.
+ *
+ * Any further use of this connection (without reopening it) will
+ * not succeed.
+ */
+ void close(framing::ReplyCode=200, const std::string& msg=OK,
+ framing::ClassId = 0, framing::MethodId = 0);
+
+ /**
+ * Associate a Channel with this connection and open it for use.
+ *
+ * In AMQP channels are like multi-plexed 'sessions' of work over
+ * a connection. Almost all the interaction with AMQP is done over
+ * a channel.
+ *
+ * @param connection the connection object to be associated with
+ * the channel. Call Channel::close() to close the channel.
+ */
+ void openChannel(Channel&);
+
+
+ // TODO aconway 2007-01-26: can these be private?
+ void send(framing::AMQFrame*);
+ void received(framing::AMQFrame*);
+ void idleOut();
+ void idleIn();
+ void shutdown();
+
+ /**\internal used for testing */
+ void setConnector(Connector& connector);
+
+ /**
+ * @return the maximum frame size in use on this connection
+ */
+ inline uint32_t getMaxFrameSize(){ return max_frame_size; }
+
+ /** @return protocol version in use on this connection. */
+ framing::ProtocolVersion getVersion() const { return version; }
+};
+
+}} // namespace qpid::client
+
+
+#endif
diff --git a/cpp/lib/client/Connector.cpp b/cpp/lib/client/Connector.cpp
new file mode 100644
index 0000000000..7b73cc016a
--- /dev/null
+++ b/cpp/lib/client/Connector.cpp
@@ -0,0 +1,188 @@
+/*
+ *
+ * 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 <iostream>
+#include <QpidError.h>
+#include <sys/Time.h>
+#include "Connector.h"
+
+namespace qpid {
+namespace client {
+
+using namespace qpid::sys;
+using namespace qpid::framing;
+using qpid::QpidError;
+
+Connector::Connector(
+ ProtocolVersion ver, bool _debug, uint32_t buffer_size
+) : debug(_debug),
+ receive_buffer_size(buffer_size),
+ send_buffer_size(buffer_size),
+ version(ver),
+ closed(true),
+ lastIn(0), lastOut(0),
+ timeout(0),
+ idleIn(0), idleOut(0),
+ timeoutHandler(0),
+ shutdownHandler(0),
+ inbuf(receive_buffer_size),
+ outbuf(send_buffer_size)
+{ }
+
+Connector::~Connector(){ }
+
+void Connector::connect(const std::string& host, int port){
+ socket = Socket::createTcp();
+ socket.connect(host, port);
+ closed = false;
+ receiver = Thread(this);
+}
+
+void Connector::init(){
+ ProtocolInitiation init(version);
+ writeBlock(&init);
+}
+
+void Connector::close(){
+ closed = true;
+ socket.close();
+ receiver.join();
+}
+
+void Connector::setInputHandler(InputHandler* handler){
+ input = handler;
+}
+
+void Connector::setShutdownHandler(ShutdownHandler* handler){
+ shutdownHandler = handler;
+}
+
+OutputHandler* Connector::getOutputHandler(){
+ return this;
+}
+
+void Connector::send(AMQFrame* f){
+ std::auto_ptr<AMQFrame> frame(f);
+ AMQBody::shared_ptr body = frame->getBody();
+ writeBlock(frame.get());
+ if(debug) std::cout << "SENT: " << *frame << std::endl;
+}
+
+void Connector::writeBlock(AMQDataBlock* data){
+ Mutex::ScopedLock l(writeLock);
+ data->encode(outbuf);
+ //transfer data to wire
+ outbuf.flip();
+ writeToSocket(outbuf.start(), outbuf.available());
+ outbuf.clear();
+}
+
+void Connector::writeToSocket(char* data, size_t available){
+ size_t written = 0;
+ while(written < available && !closed){
+ ssize_t sent = socket.send(data + written, available-written);
+ if(sent > 0) {
+ lastOut = now() * TIME_MSEC;
+ written += sent;
+ }
+ }
+}
+
+void Connector::handleClosed(){
+ closed = true;
+ socket.close();
+ if(shutdownHandler) shutdownHandler->shutdown();
+}
+
+void Connector::checkIdle(ssize_t status){
+ if(timeoutHandler){
+ Time t = now() * TIME_MSEC;
+ if(status == Socket::SOCKET_TIMEOUT) {
+ if(idleIn && (t - lastIn > idleIn)){
+ timeoutHandler->idleIn();
+ }
+ }
+ else if(status == 0 || status == Socket::SOCKET_EOF) {
+ handleClosed();
+ }
+ else {
+ lastIn = t;
+ }
+ if(idleOut && (t - lastOut > idleOut)){
+ timeoutHandler->idleOut();
+ }
+ }
+}
+
+void Connector::setReadTimeout(uint16_t t){
+ idleIn = t * 1000;//t is in secs
+ if(idleIn && (!timeout || idleIn < timeout)){
+ timeout = idleIn;
+ setSocketTimeout();
+ }
+
+}
+
+void Connector::setWriteTimeout(uint16_t t){
+ idleOut = t * 1000;//t is in secs
+ if(idleOut && (!timeout || idleOut < timeout)){
+ timeout = idleOut;
+ setSocketTimeout();
+ }
+}
+
+void Connector::setSocketTimeout(){
+ socket.setTimeout(timeout*TIME_MSEC);
+}
+
+void Connector::setTimeoutHandler(TimeoutHandler* handler){
+ timeoutHandler = handler;
+}
+
+void Connector::run(){
+ try{
+ while(!closed){
+ ssize_t available = inbuf.available();
+ if(available < 1){
+ THROW_QPID_ERROR(INTERNAL_ERROR, "Frame exceeds buffer size.");
+ }
+ ssize_t received = socket.recv(inbuf.start(), available);
+ checkIdle(received);
+
+ if(!closed && received > 0){
+ inbuf.move(received);
+ inbuf.flip();//position = 0, limit = total data read
+
+ AMQFrame frame(version);
+ while(frame.decode(inbuf)){
+ if(debug) std::cout << "RECV: " << frame << std::endl;
+ input->received(&frame);
+ }
+ //need to compact buffer to preserve any 'extra' data
+ inbuf.compact();
+ }
+ }
+ } catch (const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ handleClosed();
+ }
+}
+
+}} // namespace qpid::client
diff --git a/cpp/lib/client/Connector.h b/cpp/lib/client/Connector.h
new file mode 100644
index 0000000000..91234d2321
--- /dev/null
+++ b/cpp/lib/client/Connector.h
@@ -0,0 +1,98 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Connector_
+#define _Connector_
+
+
+#include <framing/InputHandler.h>
+#include <framing/OutputHandler.h>
+#include <framing/InitiationHandler.h>
+#include <framing/ProtocolInitiation.h>
+#include <ProtocolVersion.h>
+#include <sys/ShutdownHandler.h>
+#include <sys/TimeoutHandler.h>
+#include <sys/Thread.h>
+#include <sys/Monitor.h>
+#include <sys/Socket.h>
+
+namespace qpid {
+
+namespace client {
+
+class Connector : public framing::OutputHandler,
+ private sys::Runnable
+{
+ const bool debug;
+ const int receive_buffer_size;
+ const int send_buffer_size;
+ framing::ProtocolVersion version;
+
+ bool closed;
+
+ int64_t lastIn;
+ int64_t lastOut;
+ int64_t timeout;
+ uint32_t idleIn;
+ uint32_t idleOut;
+
+ sys::TimeoutHandler* timeoutHandler;
+ sys::ShutdownHandler* shutdownHandler;
+ framing::InputHandler* input;
+ framing::InitiationHandler* initialiser;
+ framing::OutputHandler* output;
+
+ framing::Buffer inbuf;
+ framing::Buffer outbuf;
+
+ sys::Mutex writeLock;
+ sys::Thread receiver;
+
+ sys::Socket socket;
+
+ void checkIdle(ssize_t status);
+ void writeBlock(framing::AMQDataBlock* data);
+ void writeToSocket(char* data, size_t available);
+ void setSocketTimeout();
+
+ void run();
+ void handleClosed();
+
+ friend class Channel;
+ public:
+ Connector(framing::ProtocolVersion pVersion,
+ bool debug = false, uint32_t buffer_size = 1024);
+ virtual ~Connector();
+ virtual void connect(const std::string& host, int port);
+ virtual void init();
+ virtual void close();
+ virtual void setInputHandler(framing::InputHandler* handler);
+ virtual void setTimeoutHandler(sys::TimeoutHandler* handler);
+ virtual void setShutdownHandler(sys::ShutdownHandler* handler);
+ virtual framing::OutputHandler* getOutputHandler();
+ virtual void send(framing::AMQFrame* frame);
+ virtual void setReadTimeout(uint16_t timeout);
+ virtual void setWriteTimeout(uint16_t timeout);
+};
+
+}}
+
+
+#endif
diff --git a/cpp/lib/client/IncomingMessage.cpp b/cpp/lib/client/IncomingMessage.cpp
new file mode 100644
index 0000000000..07f94ceb64
--- /dev/null
+++ b/cpp/lib/client/IncomingMessage.cpp
@@ -0,0 +1,172 @@
+/*
+ *
+ * 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 <IncomingMessage.h>
+#include "framing/AMQHeaderBody.h"
+#include "framing/AMQContentBody.h"
+#include "BasicGetOkBody.h"
+#include "BasicReturnBody.h"
+#include "BasicDeliverBody.h"
+#include <QpidError.h>
+#include <iostream>
+
+namespace qpid {
+namespace client {
+
+using namespace sys;
+using namespace framing;
+
+struct IncomingMessage::Guard: public Mutex::ScopedLock {
+ Guard(IncomingMessage* im) : Mutex::ScopedLock(im->lock) {
+ im->shutdownError.throwIf();
+ }
+};
+
+IncomingMessage::IncomingMessage() { reset(); }
+
+void IncomingMessage::reset() {
+ state = &IncomingMessage::expectRequest;
+ endFn= &IncomingMessage::endRequest;
+ buildMessage = Message();
+}
+
+void IncomingMessage::startGet() {
+ Guard g(this);
+ if (state != &IncomingMessage::expectRequest) {
+ endGet(new QPID_ERROR(CLIENT_ERROR, "Message already in progress."));
+ }
+ else {
+ state = &IncomingMessage::expectGetOk;
+ endFn = &IncomingMessage::endGet;
+ getError.reset();
+ getState = GETTING;
+ }
+}
+
+bool IncomingMessage::waitGet(Message& msg) {
+ Guard g(this);
+ while (getState == GETTING && !shutdownError && !getError)
+ getReady.wait(lock);
+ shutdownError.throwIf();
+ getError.throwIf();
+ msg = getMessage;
+ return getState==GOT;
+}
+
+Message IncomingMessage::waitDispatch() {
+ Guard g(this);
+ while(dispatchQueue.empty() && !shutdownError)
+ dispatchReady.wait(lock);
+ shutdownError.throwIf();
+
+ Message msg(dispatchQueue.front());
+ dispatchQueue.pop();
+ return msg;
+}
+
+void IncomingMessage::add(BodyPtr body) {
+ Guard g(this);
+ shutdownError.throwIf();
+ // Call the current state function.
+ (this->*state)(body);
+}
+
+void IncomingMessage::shutdown() {
+ Mutex::ScopedLock l(lock);
+ shutdownError.reset(new ShutdownException());
+ getReady.notify();
+ dispatchReady.notify();
+}
+
+bool IncomingMessage::isShutdown() const {
+ Mutex::ScopedLock l(lock);
+ return shutdownError;
+}
+
+// Common check for all the expect functions. Called in network thread.
+template<class T>
+boost::shared_ptr<T> IncomingMessage::expectCheck(BodyPtr body) {
+ boost::shared_ptr<T> ptr = boost::dynamic_pointer_cast<T>(body);
+ if (!ptr)
+ throw QPID_ERROR(PROTOCOL_ERROR+504, "Unexpected frame type");
+ return ptr;
+}
+
+void IncomingMessage::expectGetOk(BodyPtr body) {
+ if (dynamic_cast<BasicGetOkBody*>(body.get()))
+ state = &IncomingMessage::expectHeader;
+ else if (dynamic_cast<BasicGetEmptyBody*>(body.get())) {
+ getState = EMPTY;
+ endGet();
+ }
+ else
+ throw QPID_ERROR(PROTOCOL_ERROR+504, "Unexpected frame type");
+}
+
+void IncomingMessage::expectHeader(BodyPtr body) {
+ AMQHeaderBody::shared_ptr header = expectCheck<AMQHeaderBody>(body);
+ buildMessage.header = header;
+ state = &IncomingMessage::expectContent;
+ checkComplete();
+}
+
+void IncomingMessage::expectContent(BodyPtr body) {
+ AMQContentBody::shared_ptr content = expectCheck<AMQContentBody>(body);
+ buildMessage.setData(buildMessage.getData() + content->getData());
+ checkComplete();
+}
+
+void IncomingMessage::checkComplete() {
+ size_t declaredSize = buildMessage.header->getContentSize();
+ size_t currentSize = buildMessage.getData().size();
+ if (declaredSize == currentSize)
+ (this->*endFn)(0);
+ else if (declaredSize < currentSize)
+ (this->*endFn)(new QPID_ERROR(
+ PROTOCOL_ERROR, "Message content exceeds declared size."));
+}
+
+void IncomingMessage::expectRequest(BodyPtr body) {
+ AMQMethodBody::shared_ptr method = expectCheck<AMQMethodBody>(body);
+ buildMessage.setMethod(method);
+ state = &IncomingMessage::expectHeader;
+}
+
+void IncomingMessage::endGet(Exception* ex) {
+ getError.reset(ex);
+ if (getState == GETTING) {
+ getMessage = buildMessage;
+ getState = GOT;
+ }
+ reset();
+ getReady.notify();
+}
+
+void IncomingMessage::endRequest(Exception* ex) {
+ ExceptionHolder eh(ex);
+ if (!eh) {
+ dispatchQueue.push(buildMessage);
+ reset();
+ dispatchReady.notify();
+ }
+ eh.throwIf();
+}
+
+}} // namespace qpid::client
diff --git a/cpp/lib/client/IncomingMessage.h b/cpp/lib/client/IncomingMessage.h
new file mode 100644
index 0000000000..2d7c8723c5
--- /dev/null
+++ b/cpp/lib/client/IncomingMessage.h
@@ -0,0 +1,118 @@
+#ifndef _IncomingMessage_
+#define _IncomingMessage_
+
+/*
+ *
+ * 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 <string>
+#include <queue>
+#include <framing/amqp_framing.h>
+#include "ExceptionHolder.h"
+#include "ClientMessage.h"
+#include "sys/Mutex.h"
+#include "sys/Condition.h"
+
+namespace qpid {
+
+namespace framing {
+class AMQBody;
+}
+
+namespace client {
+/**
+ * Accumulates incoming message frames into messages.
+ * Client-initiated messages (basic.get) are initiated and made
+ * available to the user thread one at a time.
+ *
+ * Broker initiated messages (basic.return, basic.deliver) are
+ * queued for handling by the user dispatch thread.
+ */
+class IncomingMessage {
+ public:
+ typedef boost::shared_ptr<framing::AMQBody> BodyPtr;
+ IncomingMessage();
+
+ /** Expect a new message starting with getOk. Called in user thread.*/
+ void startGet();
+
+ /** Wait for the message to complete, return the message.
+ * Called in user thread.
+ *@raises QpidError if there was an error.
+ */
+ bool waitGet(Message&);
+
+ /** Wait for the next broker-initiated message. */
+ Message waitDispatch();
+
+ /** Add a frame body to the message. Called in network thread. */
+ void add(BodyPtr);
+
+ /** Shut down: all further calls to any function throw ex. */
+ void shutdown();
+
+ /** Check if shutdown */
+ bool isShutdown() const;
+
+ private:
+
+ typedef void (IncomingMessage::* ExpectFn)(BodyPtr);
+ typedef void (IncomingMessage::* EndFn)(Exception*);
+ typedef std::queue<Message> MessageQueue;
+ struct Guard;
+ friend struct Guard;
+
+ void reset();
+ template <class T> boost::shared_ptr<T> expectCheck(BodyPtr);
+
+ // State functions - a state machine where each state is
+ // a member function that processes a frame body.
+ void expectGetOk(BodyPtr);
+ void expectHeader(BodyPtr);
+ void expectContent(BodyPtr);
+ void expectRequest(BodyPtr);
+
+ // End functions.
+ void endGet(Exception* ex = 0);
+ void endRequest(Exception* ex);
+
+ // Check for complete message.
+ void checkComplete();
+
+ mutable sys::Mutex lock;
+ ExpectFn state;
+ EndFn endFn;
+ Message buildMessage;
+ ExceptionHolder shutdownError;
+
+ // For basic.get messages.
+ sys::Condition getReady;
+ ExceptionHolder getError;
+ Message getMessage;
+ enum { GETTING, GOT, EMPTY } getState;
+
+ // For broker-initiated messages
+ sys::Condition dispatchReady;
+ MessageQueue dispatchQueue;
+};
+
+}}
+
+
+#endif
diff --git a/cpp/lib/client/Makefile.am b/cpp/lib/client/Makefile.am
new file mode 100644
index 0000000000..1e10a2a244
--- /dev/null
+++ b/cpp/lib/client/Makefile.am
@@ -0,0 +1,36 @@
+AM_CXXFLAGS = $(WARNING_CFLAGS)
+INCLUDES = \
+ -I$(top_srcdir)/gen \
+ -I$(top_srcdir)/lib/common \
+ -I$(top_srcdir)/lib/common/sys \
+ -I$(top_srcdir)/lib/common/framing \
+ $(APR_CXXFLAGS)
+
+lib_LTLIBRARIES = libqpidclient.la
+libqpidclient_la_LIBADD = ../common/libqpidcommon.la
+libqpidclient_la_LDFLAGS = -version-info $(LIBTOOL_VERSION_INFO_ARG)
+libqpidclient_la_SOURCES = \
+ ClientChannel.cpp \
+ ClientExchange.cpp \
+ ClientMessage.cpp \
+ ClientQueue.cpp \
+ Basic.cpp \
+ Connection.cpp \
+ Connector.cpp \
+ IncomingMessage.cpp \
+ MessageListener.cpp \
+ ResponseHandler.cpp \
+ ReturnedMessageHandler.cpp
+pkginclude_HEADERS = \
+ ClientChannel.h \
+ ClientExchange.h \
+ ClientMessage.h \
+ ClientQueue.h \
+ Basic.h \
+ Connection.h \
+ Connector.h \
+ IncomingMessage.h \
+ MessageListener.h \
+ MethodBodyInstances.h \
+ ResponseHandler.h \
+ ReturnedMessageHandler.h
diff --git a/cpp/lib/client/MessageListener.cpp b/cpp/lib/client/MessageListener.cpp
new file mode 100644
index 0000000000..70d44e7040
--- /dev/null
+++ b/cpp/lib/client/MessageListener.cpp
@@ -0,0 +1,24 @@
+/*
+ *
+ * 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 <MessageListener.h>
+
+qpid::client::MessageListener::~MessageListener() {}
diff --git a/cpp/lib/client/MessageListener.h b/cpp/lib/client/MessageListener.h
new file mode 100644
index 0000000000..cfb917b4f8
--- /dev/null
+++ b/cpp/lib/client/MessageListener.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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 <string>
+
+#ifndef _MessageListener_
+#define _MessageListener_
+
+#include <ClientMessage.h>
+
+namespace qpid {
+namespace client {
+
+ /**
+ * An interface through which asynchronously delivered messages
+ * can be received by an application.
+ *
+ * @see Channel::consume()
+ *
+ * \ingroup clientapi
+ */
+ class MessageListener{
+ public:
+ virtual ~MessageListener();
+ virtual void received(Message& msg) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/client/MethodBodyInstances.h b/cpp/lib/client/MethodBodyInstances.h
new file mode 100644
index 0000000000..acbeeb1158
--- /dev/null
+++ b/cpp/lib/client/MethodBodyInstances.h
@@ -0,0 +1,100 @@
+/*
+ *
+ * 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 <framing/amqp_framing.h>
+
+#ifndef _MethodBodyInstances_h_
+#define _MethodBodyInstances_h_
+
+namespace qpid {
+namespace client {
+
+/**
+ * A list of method body instances that can be used to compare against
+ * incoming bodies.
+ */
+class MethodBodyInstances
+{
+private:
+ qpid::framing::ProtocolVersion version;
+public:
+ const qpid::framing::BasicCancelOkBody basic_cancel_ok;
+ const qpid::framing::BasicConsumeOkBody basic_consume_ok;
+ const qpid::framing::BasicDeliverBody basic_deliver;
+ const qpid::framing::BasicGetEmptyBody basic_get_empty;
+ const qpid::framing::BasicGetOkBody basic_get_ok;
+ const qpid::framing::BasicQosOkBody basic_qos_ok;
+ const qpid::framing::BasicReturnBody basic_return;
+ const qpid::framing::ChannelCloseBody channel_close;
+ const qpid::framing::ChannelCloseOkBody channel_close_ok;
+ const qpid::framing::ChannelFlowBody channel_flow;
+ const qpid::framing::ChannelOpenOkBody channel_open_ok;
+ const qpid::framing::ConnectionCloseBody connection_close;
+ const qpid::framing::ConnectionCloseOkBody connection_close_ok;
+ const qpid::framing::ConnectionOpenOkBody connection_open_ok;
+ const qpid::framing::ConnectionRedirectBody connection_redirect;
+ const qpid::framing::ConnectionStartBody connection_start;
+ const qpid::framing::ConnectionTuneBody connection_tune;
+ const qpid::framing::ExchangeDeclareOkBody exchange_declare_ok;
+ const qpid::framing::ExchangeDeleteOkBody exchange_delete_ok;
+ const qpid::framing::QueueDeclareOkBody queue_declare_ok;
+ const qpid::framing::QueueDeleteOkBody queue_delete_ok;
+ const qpid::framing::QueueBindOkBody queue_bind_ok;
+ const qpid::framing::TxCommitOkBody tx_commit_ok;
+ const qpid::framing::TxRollbackOkBody tx_rollback_ok;
+ const qpid::framing::TxSelectOkBody tx_select_ok;
+
+ MethodBodyInstances(uint8_t major, uint8_t minor) :
+ version(major, minor),
+ basic_cancel_ok(version),
+ basic_consume_ok(version),
+ basic_deliver(version),
+ basic_get_empty(version),
+ basic_get_ok(version),
+ basic_qos_ok(version),
+ basic_return(version),
+ channel_close(version),
+ channel_close_ok(version),
+ channel_flow(version),
+ channel_open_ok(version),
+ connection_close(version),
+ connection_close_ok(version),
+ connection_open_ok(version),
+ connection_redirect(version),
+ connection_start(version),
+ connection_tune(version),
+ exchange_declare_ok(version),
+ exchange_delete_ok(version),
+ queue_declare_ok(version),
+ queue_delete_ok(version),
+ queue_bind_ok(version),
+ tx_commit_ok(version),
+ tx_rollback_ok(version),
+ tx_select_ok(version)
+ {}
+
+};
+
+static MethodBodyInstances method_bodies(8, 0);
+
+} // namespace client
+} // namespace qpid
+
+#endif
diff --git a/cpp/lib/client/ResponseHandler.cpp b/cpp/lib/client/ResponseHandler.cpp
new file mode 100644
index 0000000000..4498de41ae
--- /dev/null
+++ b/cpp/lib/client/ResponseHandler.cpp
@@ -0,0 +1,86 @@
+/*
+ *
+ * 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 <boost/format.hpp>
+
+#include <ResponseHandler.h>
+#include <sys/Monitor.h>
+#include <QpidError.h>
+#include "amqp_types.h"
+
+using namespace qpid::sys;
+using namespace qpid::framing;
+
+namespace qpid {
+namespace client {
+
+ResponseHandler::ResponseHandler() : waiting(false){}
+
+ResponseHandler::~ResponseHandler(){}
+
+bool ResponseHandler::validate(ClassId c, MethodId m) {
+ return response != 0 &&
+ response->amqpClassId() ==c && response->amqpMethodId() == m;
+}
+
+void ResponseHandler::waitForResponse(){
+ Monitor::ScopedLock l(monitor);
+ while (waiting)
+ monitor.wait();
+}
+
+void ResponseHandler::signalResponse(
+ qpid::framing::AMQMethodBody::shared_ptr _response)
+{
+ Monitor::ScopedLock l(monitor);
+ response = _response;
+ waiting = false;
+ monitor.notify();
+}
+
+void ResponseHandler::receive(ClassId c, MethodId m) {
+ Monitor::ScopedLock l(monitor);
+ while (waiting)
+ monitor.wait();
+ getResponse(); // Check for closed.
+ if(!validate(response->amqpClassId(), response->amqpMethodId())) {
+ THROW_QPID_ERROR(
+ PROTOCOL_ERROR,
+ boost::format("Expected class:method %d:%d, got %d:%d")
+ % c % m % response->amqpClassId() % response->amqpMethodId());
+ }
+}
+
+framing::AMQMethodBody::shared_ptr ResponseHandler::getResponse() {
+ if (!response)
+ THROW_QPID_ERROR(
+ PROTOCOL_ERROR, "Channel closed unexpectedly.");
+ return response;
+}
+
+RequestId ResponseHandler::getRequestId() {
+ assert(response->getRequestId());
+ return response->getRequestId();
+}
+void ResponseHandler::expect(){
+ waiting = true;
+}
+
+}} // namespace qpid::client
diff --git a/cpp/lib/client/ResponseHandler.h b/cpp/lib/client/ResponseHandler.h
new file mode 100644
index 0000000000..d28048c3d3
--- /dev/null
+++ b/cpp/lib/client/ResponseHandler.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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 <string>
+
+#include <framing/amqp_framing.h> // FIXME aconway 2007-02-01: #include cleanup.
+#include <sys/Monitor.h>
+
+#ifndef _ResponseHandler_
+#define _ResponseHandler_
+
+namespace qpid {
+namespace client {
+
+/**
+ * Holds a response from the broker peer for the client.
+ */
+class ResponseHandler{
+ bool waiting;
+ qpid::framing::AMQMethodBody::shared_ptr response;
+ qpid::sys::Monitor monitor;
+
+ public:
+ ResponseHandler();
+ ~ResponseHandler();
+
+ bool isWaiting(){ return waiting; }
+ framing::AMQMethodBody::shared_ptr getResponse();
+ void waitForResponse();
+
+ void signalResponse(framing::AMQMethodBody::shared_ptr response);
+
+ void expect();//must be called before calling receive
+ bool validate(framing::ClassId, framing::MethodId);
+ void receive(framing::ClassId, framing::MethodId);
+
+ framing::RequestId getRequestId();
+
+ template <class BodyType> bool validate() {
+ return validate(BodyType::CLASS_ID, BodyType::METHOD_ID);
+ }
+ template <class BodyType> void receive() {
+ receive(BodyType::CLASS_ID, BodyType::METHOD_ID);
+ }
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/client/ReturnedMessageHandler.cpp b/cpp/lib/client/ReturnedMessageHandler.cpp
new file mode 100644
index 0000000000..ee9f7462ef
--- /dev/null
+++ b/cpp/lib/client/ReturnedMessageHandler.cpp
@@ -0,0 +1,24 @@
+/*
+ *
+ * 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 <ReturnedMessageHandler.h>
+
+qpid::client::ReturnedMessageHandler::~ReturnedMessageHandler() {}
diff --git a/cpp/lib/client/ReturnedMessageHandler.h b/cpp/lib/client/ReturnedMessageHandler.h
new file mode 100644
index 0000000000..137f0b2e17
--- /dev/null
+++ b/cpp/lib/client/ReturnedMessageHandler.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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 <string>
+
+#ifndef _ReturnedMessageHandler_
+#define _ReturnedMessageHandler_
+
+#include <ClientMessage.h>
+
+namespace qpid {
+namespace client {
+
+ /**
+ * An interface through which returned messages can be received by
+ * an application.
+ *
+ * @see Channel::setReturnedMessageHandler()
+ *
+ * \ingroup clientapi
+ */
+ class ReturnedMessageHandler{
+ public:
+ virtual ~ReturnedMessageHandler();
+ virtual void returned(Message& msg) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/Exception.cpp b/cpp/lib/common/Exception.cpp
new file mode 100644
index 0000000000..f7d91498e0
--- /dev/null
+++ b/cpp/lib/common/Exception.cpp
@@ -0,0 +1,46 @@
+/*
+ *
+ * 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 <Exception.h>
+
+namespace qpid {
+
+Exception::Exception() throw() {}
+
+Exception::Exception(const std::string& str) throw() : whatStr(str) {}
+
+Exception::Exception(const char* str) throw() : whatStr(str) {}
+
+Exception::~Exception() throw() {}
+
+const char* Exception::what() const throw() { return whatStr.c_str(); }
+
+std::string Exception::toString() const throw() { return whatStr; }
+
+Exception* Exception::clone() const throw() { return new Exception(*this); }
+
+void Exception::throwSelf() const { throw *this; }
+
+ShutdownException::ShutdownException() : Exception("Shut down.") {}
+
+EmptyException::EmptyException() : Exception("Empty.") {}
+
+} // namespace qpid
diff --git a/cpp/lib/common/Exception.h b/cpp/lib/common/Exception.h
new file mode 100644
index 0000000000..b8cd68cf8c
--- /dev/null
+++ b/cpp/lib/common/Exception.h
@@ -0,0 +1,97 @@
+#ifndef _Exception_
+#define _Exception_
+
+/*
+ *
+ * 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 <exception>
+#include <string>
+#include <memory>
+#include <boost/shared_ptr.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "amqp_types.h"
+
+namespace qpid
+{
+/**
+ * Exception base class for all Qpid exceptions.
+ */
+class Exception : public std::exception
+{
+ protected:
+ std::string whatStr;
+
+ public:
+ Exception() throw();
+ Exception(const std::string& str) throw();
+ Exception(const char* str) throw();
+ Exception(const std::exception&) throw();
+
+ /** Allow any type that has ostream operator<< to act as message */
+ template <class T>
+ Exception(const T& message)
+ : whatStr(boost::lexical_cast<std::string>(message)) {}
+
+ virtual ~Exception() throw();
+
+ virtual const char* what() const throw();
+ virtual std::string toString() const throw();
+
+ virtual Exception* clone() const throw();
+ virtual void throwSelf() const;
+
+ typedef boost::shared_ptr<Exception> shared_ptr;
+};
+
+struct ChannelException : public Exception {
+ framing::ReplyCode code;
+ template <class T>
+ ChannelException(framing::ReplyCode code_, const T& message)
+ : Exception(message), code(code_) {}
+ void throwSelf() const { throw *this; }
+};
+
+struct ConnectionException : public Exception {
+ framing::ReplyCode code;
+ template <class T>
+ ConnectionException(framing::ReplyCode code_, const T& message)
+ : Exception(message), code(code_) {}
+ void throwSelf() const { throw *this; }
+};
+
+/**
+ * Exception used to indicate that a thread should shut down.
+ * Does not indicate an error that should be signalled to the user.
+ */
+struct ShutdownException : public Exception {
+ ShutdownException();
+ void throwSelf() const { throw *this; }
+};
+
+/** Exception to indicate empty queue or other empty state */
+struct EmptyException : public Exception {
+ EmptyException();
+ void throwSelf() const { throw *this; }
+};
+
+}
+
+#endif /*!_Exception_*/
diff --git a/cpp/lib/common/ExceptionHolder.cpp b/cpp/lib/common/ExceptionHolder.cpp
new file mode 100644
index 0000000000..de8d7b2487
--- /dev/null
+++ b/cpp/lib/common/ExceptionHolder.cpp
@@ -0,0 +1,32 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "ExceptionHolder.h"
+
+namespace qpid {
+
+ExceptionHolder::ExceptionHolder(const std::exception& e) {
+ const Exception* ex = dynamic_cast<const Exception*>(&e);
+ if (ex) {
+ reset(ex->clone());
+ } else {
+ reset(new Exception(e.what()));
+ }
+}
+
+}
diff --git a/cpp/lib/common/ExceptionHolder.h b/cpp/lib/common/ExceptionHolder.h
new file mode 100644
index 0000000000..2769455aba
--- /dev/null
+++ b/cpp/lib/common/ExceptionHolder.h
@@ -0,0 +1,67 @@
+#ifndef _qpid_ExceptionHolder_h
+#define _qpid_ExceptionHolder_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <assert.h>
+#include <Exception.h>
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+
+// FIXME aconway 2007-02-20: Not necessary, a simple
+// Exception::shared_ptr will do the job. Remove
+//
+/**
+ * Holder for a heap-allocated exc eption that can be stack allocated
+ * and thrown safely.
+ *
+ * Basically this is a shared_ptr with the Exception functions added
+ * so the catcher need not be aware that it is a pointer rather than a
+ * reference.
+ *
+ * shared_ptr is chosen over auto_ptr because it has normal
+ * copy semantics.
+ */
+class ExceptionHolder : public Exception, public boost::shared_ptr<Exception>
+{
+ public:
+ typedef boost::shared_ptr<Exception> shared_ptr;
+
+ ExceptionHolder() throw() {}
+ ExceptionHolder(Exception* p) throw() : shared_ptr(p) {}
+ ExceptionHolder(shared_ptr p) throw() : shared_ptr(p) {}
+
+ ExceptionHolder(const Exception& e) throw() : shared_ptr(e.clone()) {}
+ ExceptionHolder(const std::exception& e);
+
+ ~ExceptionHolder() throw() {}
+
+ const char* what() const throw() { return get()->what(); }
+ std::string toString() const throw() { return get()->toString(); }
+ Exception* clone() const throw() { return get()->clone(); }
+ void throwIf() const { if (get()) get()->throwSelf(); }
+ void throwSelf() const { assert(get()); get()->throwSelf(); }
+};
+
+} // namespace qpid
+
+
+
+#endif /*!_qpid_ExceptionHolder_h*/
diff --git a/cpp/lib/common/Makefile.am b/cpp/lib/common/Makefile.am
new file mode 100644
index 0000000000..d70adf1186
--- /dev/null
+++ b/cpp/lib/common/Makefile.am
@@ -0,0 +1,142 @@
+AM_CXXFLAGS = $(WARNING_CFLAGS)
+
+INCLUDES = \
+ -I$(top_srcdir)/gen \
+ -I$(top_srcdir)/lib/common/sys \
+ -I$(top_srcdir)/lib/common/framing \
+ $(APR_CXXFLAGS)
+
+apr = sys/apr
+apr_src = \
+ $(apr)/APRAcceptor.cpp \
+ $(apr)/APRBase.cpp \
+ $(apr)/APRPool.cpp \
+ $(apr)/APRSocket.cpp \
+ $(apr)/LFProcessor.cpp \
+ $(apr)/LFSessionContext.cpp \
+ $(apr)/Socket.cpp \
+ $(apr)/Thread.cpp
+apr_hdr = \
+ $(apr)/APRBase.h \
+ $(apr)/APRPool.h \
+ $(apr)/APRSocket.h \
+ $(apr)/LFProcessor.h \
+ $(apr)/LFSessionContext.h
+
+posix = sys/posix
+posix_src = \
+ $(posix)/PosixAcceptor.cpp \
+ $(posix)/Socket.cpp \
+ $(posix)/Thread.cpp \
+ $(posix)/check.cpp \
+ $(posix)/EventChannel.cpp \
+ $(posix)/EventChannelThreads.cpp
+posix_hdr = \
+ $(posix)/check.h \
+ $(posix)/EventChannel.h \
+ $(posix)/EventChannelThreads.h
+
+EXTRA_DIST=$(posix_src) $(posix_hdr)
+platform_src = $(apr_src)
+platform_hdr = $(apr_hdr)
+
+framing = framing
+gen = $(srcdir)/../../gen
+
+lib_LTLIBRARIES = libqpidcommon.la
+libqpidcommon_la_LIBADD = \
+ $(APR_LIBS) \
+ $(LIB_DLOPEN) \
+ $(LIB_CLOCK_GETTIME)
+
+libqpidcommon_la_LDFLAGS = \
+ -version-info \
+ $(LIBTOOL_VERSION_INFO_ARG)
+
+libqpidcommon_la_SOURCES = \
+ $(platform_src) \
+ $(framing)/AMQBody.cpp \
+ $(framing)/AMQRequestBody.cpp \
+ $(framing)/AMQResponseBody.cpp \
+ $(framing)/AMQContentBody.cpp \
+ $(framing)/AMQFrame.cpp \
+ $(framing)/AMQHeaderBody.cpp \
+ $(framing)/AMQHeartbeatBody.cpp \
+ $(framing)/AMQMethodBody.cpp \
+ $(framing)/MethodContext.cpp \
+ $(framing)/BasicHeaderProperties.cpp \
+ $(framing)/BodyHandler.cpp \
+ $(framing)/ChannelAdapter.cpp \
+ $(framing)/Buffer.cpp \
+ $(framing)/FieldTable.cpp \
+ $(framing)/FramingContent.cpp \
+ $(framing)/InitiationHandler.cpp \
+ $(framing)/ProtocolInitiation.cpp \
+ $(framing)/ProtocolVersion.cpp \
+ $(framing)/ProtocolVersionException.cpp \
+ $(framing)/Requester.cpp \
+ $(framing)/Responder.cpp \
+ $(framing)/Value.cpp \
+ $(framing)/Proxy.cpp \
+ $(gen)/AMQP_ClientProxy.cpp \
+ $(gen)/AMQP_HighestVersion.h \
+ $(gen)/AMQP_MethodVersionMap.cpp \
+ $(gen)/AMQP_ServerProxy.cpp \
+ Exception.cpp \
+ ExceptionHolder.cpp \
+ QpidError.cpp \
+ sys/Runnable.cpp \
+ sys/Time.cpp \
+ sys/ProducerConsumer.cpp
+
+nobase_pkginclude_HEADERS = \
+ $(gen)/AMQP_HighestVersion.h \
+ $(platform_hdr) \
+ $(framing)/AMQBody.h \
+ $(framing)/AMQContentBody.h \
+ $(framing)/AMQDataBlock.h \
+ $(framing)/AMQFrame.h \
+ $(framing)/AMQHeaderBody.h \
+ $(framing)/AMQHeartbeatBody.h \
+ $(framing)/AMQMethodBody.h \
+ $(framing)/MethodContext.h \
+ $(framing)/BasicHeaderProperties.h \
+ $(framing)/BodyHandler.h \
+ $(framing)/ChannelAdapter.h \
+ $(framing)/Buffer.h \
+ $(framing)/FieldTable.h \
+ $(framing)/FramingContent.h \
+ $(framing)/HeaderProperties.h \
+ $(framing)/InitiationHandler.h \
+ $(framing)/InputHandler.h \
+ $(framing)/OutputHandler.h \
+ $(framing)/ProtocolInitiation.h \
+ $(framing)/ProtocolVersion.h \
+ $(framing)/ProtocolVersionException.h \
+ $(framing)/Value.h \
+ $(framing)/amqp_framing.h \
+ $(framing)/amqp_types.h \
+ $(framing)/Proxy.h \
+ Exception.h \
+ ExceptionHolder.h \
+ QpidError.h \
+ SharedObject.h \
+ sys/Acceptor.h \
+ sys/AtomicCount.h \
+ sys/Module.h \
+ sys/Monitor.h \
+ sys/Mutex.h \
+ sys/Runnable.h \
+ sys/ConnectionOutputHandler.h \
+ sys/ConnectionInputHandler.h \
+ sys/ConnectionInputHandlerFactory.h \
+ sys/ShutdownHandler.h \
+ sys/Socket.h \
+ sys/Thread.h \
+ sys/Time.h \
+ sys/TimeoutHandler.h \
+ sys/ProducerConsumer.h
+
+
+# Force build during dist phase so help2man will work.
+dist-hook: $(lib_LTLIBRARIES)
diff --git a/cpp/lib/common/QpidError.cpp b/cpp/lib/common/QpidError.cpp
new file mode 100644
index 0000000000..9cd3051d1e
--- /dev/null
+++ b/cpp/lib/common/QpidError.cpp
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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 <boost/format.hpp>
+
+#include <QpidError.h>
+#include <sstream>
+
+using namespace qpid;
+
+QpidError::QpidError() : code(0) {}
+
+QpidError::~QpidError() throw() {}
+
+Exception* QpidError::clone() const throw() { return new QpidError(*this); }
+
+void QpidError::throwSelf() const { throw *this; }
+
+void QpidError::init() {
+ whatStr = boost::str(boost::format("Error [%d] %s (%s:%d)")
+ % code % msg % loc.file % loc.line);
+}
+
+
diff --git a/cpp/lib/common/QpidError.h b/cpp/lib/common/QpidError.h
new file mode 100644
index 0000000000..2a0395ab79
--- /dev/null
+++ b/cpp/lib/common/QpidError.h
@@ -0,0 +1,78 @@
+#ifndef __QpidError__
+#define __QpidError__
+/*
+ *
+ * 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 <string>
+#include <memory>
+#include <ostream>
+
+#include <Exception.h>
+
+namespace qpid {
+
+struct SrcLine {
+ public:
+ SrcLine(const std::string& file_="", int line_=0) :
+ file(file_), line(line_) {}
+
+ std::string file;
+ int line;
+};
+
+class QpidError : public Exception
+{
+ public:
+ const int code;
+ SrcLine loc;
+ std::string msg;
+
+ QpidError();
+
+ template <class T>
+ QpidError(int code_, const T& msg_, const SrcLine& loc_) throw()
+ : code(code_), loc(loc_), msg(boost::lexical_cast<std::string>(msg_))
+ { init(); }
+
+ ~QpidError() throw();
+ Exception* clone() const throw();
+ void throwSelf() const;
+
+ private:
+
+ void init();
+};
+
+
+} // namespace qpid
+
+#define SRCLINE ::qpid::SrcLine(__FILE__, __LINE__)
+
+#define QPID_ERROR(CODE, MESSAGE) ::qpid::QpidError((CODE), (MESSAGE), SRCLINE)
+
+#define THROW_QPID_ERROR(CODE, MESSAGE) throw QPID_ERROR(CODE,MESSAGE)
+
+const int PROTOCOL_ERROR = 10000;
+const int APR_ERROR = 20000;
+const int FRAMING_ERROR = 30000;
+const int CLIENT_ERROR = 40000;
+const int INTERNAL_ERROR = 50000;
+
+#endif
diff --git a/cpp/lib/common/SharedObject.h b/cpp/lib/common/SharedObject.h
new file mode 100644
index 0000000000..852a036ab9
--- /dev/null
+++ b/cpp/lib/common/SharedObject.h
@@ -0,0 +1,55 @@
+#ifndef _SharedObject_
+#define _SharedObject_
+
+/*
+ *
+ * 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 <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+ /**
+ * Template to enforce shared object conventions.
+ * Shared object classes should inherit : public qpid::SharedObject
+ * That ensures Foo:
+ * - has typedef boost::shared_ptr<T> shared_ptr
+ * - has virtual destructor
+ * - is boost::noncopyable (no default copy or assign)
+ * - has a protected default constructor.
+ *
+ * Shared objects should not have public constructors.
+ * Make constructors protected and provide public statc create()
+ * functions that return a shared_ptr.
+ */
+ template <class T>
+ class SharedObject : private boost::noncopyable
+ {
+ public:
+ typedef boost::shared_ptr<T> shared_ptr;
+
+ virtual ~SharedObject() {};
+
+ protected:
+ SharedObject() {}
+ };
+}
+
+#endif /*!_SharedObject_*/
diff --git a/cpp/lib/common/doxygen_mainpage.h b/cpp/lib/common/doxygen_mainpage.h
new file mode 100644
index 0000000000..b354238cd0
--- /dev/null
+++ b/cpp/lib/common/doxygen_mainpage.h
@@ -0,0 +1,45 @@
+// This header file is just for doxygen documentation purposes.
+
+/*!\mainpage Qpid C++ Developer Kit.
+ *
+ *\section intro_sec Introduction
+ *
+ * The <a href=http://incubator.apache.org/qpid/index.html>Qpid project</a> provides implementations of the <a href="http://amqp.org/">AMQP messaging specification</a> in several programming language.
+ *
+ * Qpidc provides APIs and libraries to implement AMQP
+ * clients in C++. Qpidc clients can interact with any compliant AMQP
+ * message broker. The Qpid project also provides an AMQP broker
+ * daemon called qpidd that you can use with your qpidc clients.
+ *
+ *\section install_sec Installation
+ *
+ * If you are installing from the source distribution
+ <pre>
+ > ./configure && make
+ > make install </pre>
+ * This will build and install the client development kit and the broker
+ * in standard places. Use
+ * <code>./configure --help</code> for more options.
+ *
+ * You can also install from RPMs with the <code>rpm -i</code> command.
+ * You will need
+ * - <code>qpidc</code> for core libraries.
+ * - <code>qpidc-devel</code> for header files and developer documentation.
+ * - <code>qpidd</code> for the broker daemon.
+ *
+ *\section getstart_sec Getting Started
+ *
+ * If you have installed in the standard places you should use
+ * these compile flags:
+ *
+ *<code> -I/usr/include/qpidc -I/usr/include/qpidc/framing -I/usr/include/qpidc/sys</code>
+ *
+ * and these link flags:
+ *
+ *<code> -lqpidcommon -lqpidclient</code>
+ *
+ * If you have installed somewhere else you should modify the flags
+ * appropriately.
+ *
+ * See the \ref clientapi "client API module" for more on the client API.
+ */
diff --git a/cpp/lib/common/framing/AMQBody.cpp b/cpp/lib/common/framing/AMQBody.cpp
new file mode 100644
index 0000000000..c7c253beda
--- /dev/null
+++ b/cpp/lib/common/framing/AMQBody.cpp
@@ -0,0 +1,33 @@
+/*
+ *
+ * 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 <AMQBody.h>
+#include <iostream>
+
+std::ostream& qpid::framing::operator<<(std::ostream& out, const qpid::framing::AMQBody& body)
+{
+ body.print(out);
+ return out;
+}
+
+qpid::framing::AMQBody::~AMQBody() {}
+
+
diff --git a/cpp/lib/common/framing/AMQBody.h b/cpp/lib/common/framing/AMQBody.h
new file mode 100644
index 0000000000..26076956ca
--- /dev/null
+++ b/cpp/lib/common/framing/AMQBody.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * 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 <boost/shared_ptr.hpp>
+#include <amqp_types.h>
+#include <Buffer.h>
+
+#ifndef _AMQBody_
+#define _AMQBody_
+
+namespace qpid {
+ namespace framing {
+
+ class AMQBody
+ {
+ public:
+ typedef boost::shared_ptr<AMQBody> shared_ptr;
+
+ virtual ~AMQBody();
+ virtual uint32_t size() const = 0;
+ virtual uint8_t type() const = 0;
+ virtual void encode(Buffer& buffer) const = 0;
+ virtual void decode(Buffer& buffer, uint32_t size) = 0;
+
+ virtual void print(std::ostream& out) const = 0;
+ };
+
+ std::ostream& operator<<(std::ostream& out, const AMQBody& body) ;
+
+ enum BodyTypes {
+ METHOD_BODY = 1,
+ HEADER_BODY = 2,
+ CONTENT_BODY = 3,
+ HEARTBEAT_BODY = 8,
+ REQUEST_BODY = 9,
+ RESPONSE_BODY = 10
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/lib/common/framing/AMQContentBody.cpp b/cpp/lib/common/framing/AMQContentBody.cpp
new file mode 100644
index 0000000000..573c17dade
--- /dev/null
+++ b/cpp/lib/common/framing/AMQContentBody.cpp
@@ -0,0 +1,43 @@
+/*
+ *
+ * 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 <AMQContentBody.h>
+#include <iostream>
+
+qpid::framing::AMQContentBody::AMQContentBody(){
+}
+
+qpid::framing::AMQContentBody::AMQContentBody(const string& _data) : data(_data){
+}
+
+uint32_t qpid::framing::AMQContentBody::size() const{
+ return data.size();
+}
+void qpid::framing::AMQContentBody::encode(Buffer& buffer) const{
+ buffer.putRawData(data);
+}
+void qpid::framing::AMQContentBody::decode(Buffer& buffer, uint32_t _size){
+ buffer.getRawData(data, _size);
+}
+
+void qpid::framing::AMQContentBody::print(std::ostream& out) const
+{
+ out << "content (" << size() << " bytes)";
+}
diff --git a/cpp/lib/common/framing/AMQContentBody.h b/cpp/lib/common/framing/AMQContentBody.h
new file mode 100644
index 0000000000..c9fa7cde5c
--- /dev/null
+++ b/cpp/lib/common/framing/AMQContentBody.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * 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 <amqp_types.h>
+#include <AMQBody.h>
+#include <Buffer.h>
+
+#ifndef _AMQContentBody_
+#define _AMQContentBody_
+
+namespace qpid {
+namespace framing {
+
+class AMQContentBody : public AMQBody
+{
+ string data;
+
+public:
+ typedef boost::shared_ptr<AMQContentBody> shared_ptr;
+
+ AMQContentBody();
+ AMQContentBody(const string& data);
+ inline virtual ~AMQContentBody(){}
+ inline uint8_t type() const { return CONTENT_BODY; };
+ inline string& getData(){ return data; }
+ uint32_t size() const;
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer, uint32_t size);
+ void print(std::ostream& out) const;
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/framing/AMQDataBlock.h b/cpp/lib/common/framing/AMQDataBlock.h
new file mode 100644
index 0000000000..2a6f843f1e
--- /dev/null
+++ b/cpp/lib/common/framing/AMQDataBlock.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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 <Buffer.h>
+
+#ifndef _AMQDataBlock_
+#define _AMQDataBlock_
+
+namespace qpid {
+namespace framing {
+
+class AMQDataBlock
+{
+public:
+ virtual ~AMQDataBlock() {}
+ virtual void encode(Buffer& buffer) = 0;
+ virtual bool decode(Buffer& buffer) = 0;
+ virtual uint32_t size() const = 0;
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/framing/AMQFrame.cpp b/cpp/lib/common/framing/AMQFrame.cpp
new file mode 100644
index 0000000000..bc9061b169
--- /dev/null
+++ b/cpp/lib/common/framing/AMQFrame.cpp
@@ -0,0 +1,139 @@
+
+/*
+ *
+ * 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 <boost/format.hpp>
+
+#include <AMQFrame.h>
+#include <QpidError.h>
+#include "AMQRequestBody.h"
+#include "AMQResponseBody.h"
+
+
+namespace qpid {
+namespace framing {
+
+
+AMQP_MethodVersionMap AMQFrame::versionMap;
+
+AMQFrame::AMQFrame(ProtocolVersion _version):
+version(_version)
+ {
+ assert(version != ProtocolVersion(0,0));
+ }
+
+AMQFrame::AMQFrame(ProtocolVersion _version, uint16_t _channel, AMQBody* _body) :
+version(_version), channel(_channel), body(_body)
+{}
+
+AMQFrame::AMQFrame(ProtocolVersion _version, uint16_t _channel, const AMQBody::shared_ptr& _body) :
+version(_version), channel(_channel), body(_body)
+{}
+
+AMQFrame::~AMQFrame() {}
+
+uint16_t AMQFrame::getChannel(){
+ return channel;
+}
+
+AMQBody::shared_ptr AMQFrame::getBody(){
+ return body;
+}
+
+void AMQFrame::encode(Buffer& buffer)
+{
+ buffer.putOctet(body->type());
+ buffer.putShort(channel);
+ buffer.putLong(body->size());
+ body->encode(buffer);
+ buffer.putOctet(0xCE);
+}
+
+uint32_t AMQFrame::size() const{
+ assert(body.get());
+ return 1/*type*/ + 2/*channel*/ + 4/*body size*/ + body->size()
+ + 1/*0xCE*/;
+}
+
+bool AMQFrame::decode(Buffer& buffer)
+{
+ if(buffer.available() < 7)
+ return false;
+ buffer.record();
+ uint32_t frameSize = decodeHead(buffer);
+ if(buffer.available() < frameSize + 1){
+ buffer.restore();
+ return false;
+ }
+ decodeBody(buffer, frameSize);
+ uint8_t end = buffer.getOctet();
+ if(end != 0xCE) THROW_QPID_ERROR(FRAMING_ERROR, "Frame end not found");
+ return true;
+}
+
+uint32_t AMQFrame::decodeHead(Buffer& buffer){
+ type = buffer.getOctet();
+ channel = buffer.getShort();
+ return buffer.getLong();
+}
+
+void AMQFrame::decodeBody(Buffer& buffer, uint32_t size)
+{
+ switch(type)
+ {
+ case METHOD_BODY:
+ body = AMQMethodBody::create(versionMap, version, buffer);
+ break;
+ case REQUEST_BODY:
+ body = AMQRequestBody::create(versionMap, version, buffer);
+ break;
+ case RESPONSE_BODY:
+ body = AMQResponseBody::create(versionMap, version, buffer);
+ break;
+ case HEADER_BODY:
+ body = AMQBody::shared_ptr(new AMQHeaderBody());
+ break;
+ case CONTENT_BODY:
+ body = AMQBody::shared_ptr(new AMQContentBody());
+ break;
+ case HEARTBEAT_BODY:
+ body = AMQBody::shared_ptr(new AMQHeartbeatBody());
+ break;
+ default:
+ THROW_QPID_ERROR(
+ FRAMING_ERROR,
+ boost::format("Unknown frame type %d") % type);
+ }
+ body->decode(buffer, size);
+}
+
+std::ostream& operator<<(std::ostream& out, const AMQFrame& t)
+{
+ out << "Frame[channel=" << t.channel << "; ";
+ if (t.body.get() == 0)
+ out << "empty";
+ else
+ out << *t.body;
+ out << "]";
+ return out;
+}
+
+
+}} // namespace qpid::framing
diff --git a/cpp/lib/common/framing/AMQFrame.h b/cpp/lib/common/framing/AMQFrame.h
new file mode 100644
index 0000000000..0c18e0c2a5
--- /dev/null
+++ b/cpp/lib/common/framing/AMQFrame.h
@@ -0,0 +1,78 @@
+#ifndef _AMQFrame_
+#define _AMQFrame_
+
+/*
+ *
+ * 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 <boost/cast.hpp>
+
+#include <amqp_types.h>
+#include <AMQBody.h>
+#include <AMQDataBlock.h>
+#include <AMQMethodBody.h>
+#include <AMQHeaderBody.h>
+#include <AMQContentBody.h>
+#include <AMQHeartbeatBody.h>
+#include <AMQP_MethodVersionMap.h>
+#include <AMQP_HighestVersion.h>
+#include <Buffer.h>
+
+namespace qpid {
+namespace framing {
+
+
+class AMQFrame : public AMQDataBlock
+{
+ public:
+ AMQFrame(ProtocolVersion _version = highestProtocolVersion);
+ AMQFrame(ProtocolVersion _version, uint16_t channel, AMQBody* body);
+ AMQFrame(ProtocolVersion _version, uint16_t channel, const AMQBody::shared_ptr& body);
+ virtual ~AMQFrame();
+ virtual void encode(Buffer& buffer);
+ virtual bool decode(Buffer& buffer);
+ virtual uint32_t size() const;
+ uint16_t getChannel();
+ AMQBody::shared_ptr getBody();
+
+ /** Convenience template to cast the body to an expected type */
+ template <class T> boost::shared_ptr<T> castBody() {
+ assert(dynamic_cast<T*>(getBody().get()));
+ boost::static_pointer_cast<T>(getBody());
+ }
+
+ uint32_t decodeHead(Buffer& buffer);
+ void decodeBody(Buffer& buffer, uint32_t size);
+
+ private:
+ static AMQP_MethodVersionMap versionMap;
+ ProtocolVersion version;
+
+ uint16_t channel;
+ uint8_t type;
+ AMQBody::shared_ptr body;
+
+
+ friend std::ostream& operator<<(std::ostream& out, const AMQFrame& body);
+};
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/cpp/lib/common/framing/AMQHeaderBody.cpp b/cpp/lib/common/framing/AMQHeaderBody.cpp
new file mode 100644
index 0000000000..3ddae4eebf
--- /dev/null
+++ b/cpp/lib/common/framing/AMQHeaderBody.cpp
@@ -0,0 +1,75 @@
+/*
+ *
+ * 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 <AMQHeaderBody.h>
+#include <QpidError.h>
+#include <BasicHeaderProperties.h>
+
+qpid::framing::AMQHeaderBody::AMQHeaderBody(int classId) : weight(0), contentSize(0){
+ createProperties(classId);
+}
+
+qpid::framing::AMQHeaderBody::AMQHeaderBody() : properties(0), weight(0), contentSize(0){
+}
+
+qpid::framing::AMQHeaderBody::~AMQHeaderBody(){
+ delete properties;
+}
+
+uint32_t qpid::framing::AMQHeaderBody::size() const{
+ return 12 + properties->size();
+}
+
+void qpid::framing::AMQHeaderBody::encode(Buffer& buffer) const {
+ buffer.putShort(properties->classId());
+ buffer.putShort(weight);
+ buffer.putLongLong(contentSize);
+ properties->encode(buffer);
+}
+
+void qpid::framing::AMQHeaderBody::decode(Buffer& buffer, uint32_t bufSize){
+ uint16_t classId = buffer.getShort();
+ weight = buffer.getShort();
+ contentSize = buffer.getLongLong();
+ createProperties(classId);
+ properties->decode(buffer, bufSize - 12);
+}
+
+void qpid::framing::AMQHeaderBody::createProperties(int classId){
+ switch(classId){
+ case BASIC:
+ properties = new qpid::framing::BasicHeaderProperties();
+ break;
+ default:
+ THROW_QPID_ERROR(FRAMING_ERROR, "Unknown header class");
+ }
+}
+
+void qpid::framing::AMQHeaderBody::print(std::ostream& out) const
+{
+ out << "header (" << size() << " bytes)" << " content_size=" << getContentSize();
+ const BasicHeaderProperties* props =
+ dynamic_cast<const BasicHeaderProperties*>(getProperties());
+ if (props) {
+ out << ", message_id=" << props->getMessageId();
+ out << ", delivery_mode=" << (int) props->getDeliveryMode();
+ out << ", headers=" << const_cast<BasicHeaderProperties*>(props)->getHeaders();
+ }
+}
diff --git a/cpp/lib/common/framing/AMQHeaderBody.h b/cpp/lib/common/framing/AMQHeaderBody.h
new file mode 100644
index 0000000000..d57f93aacd
--- /dev/null
+++ b/cpp/lib/common/framing/AMQHeaderBody.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * 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 <amqp_types.h>
+#include <AMQBody.h>
+#include <Buffer.h>
+#include <HeaderProperties.h>
+
+#ifndef _AMQHeaderBody_
+#define _AMQHeaderBody_
+
+namespace qpid {
+namespace framing {
+
+class AMQHeaderBody : public AMQBody
+{
+ HeaderProperties* properties;
+ uint16_t weight;
+ uint64_t contentSize;
+
+ void createProperties(int classId);
+public:
+ typedef boost::shared_ptr<AMQHeaderBody> shared_ptr;
+
+ AMQHeaderBody(int classId);
+ AMQHeaderBody();
+ inline uint8_t type() const { return HEADER_BODY; }
+ HeaderProperties* getProperties(){ return properties; }
+ const HeaderProperties* getProperties() const { return properties; }
+ inline uint64_t getContentSize() const { return contentSize; }
+ inline void setContentSize(uint64_t _size) { contentSize = _size; }
+ virtual ~AMQHeaderBody();
+ virtual uint32_t size() const;
+ virtual void encode(Buffer& buffer) const;
+ virtual void decode(Buffer& buffer, uint32_t size);
+ virtual void print(std::ostream& out) const;
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/framing/AMQHeartbeatBody.cpp b/cpp/lib/common/framing/AMQHeartbeatBody.cpp
new file mode 100644
index 0000000000..63f83a3d29
--- /dev/null
+++ b/cpp/lib/common/framing/AMQHeartbeatBody.cpp
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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 <AMQHeartbeatBody.h>
+#include <iostream>
+
+qpid::framing::AMQHeartbeatBody::~AMQHeartbeatBody() {}
+
+void qpid::framing::AMQHeartbeatBody::print(std::ostream& out) const {
+ out << "heartbeat";
+}
diff --git a/cpp/lib/common/framing/AMQHeartbeatBody.h b/cpp/lib/common/framing/AMQHeartbeatBody.h
new file mode 100644
index 0000000000..a3e9d823f1
--- /dev/null
+++ b/cpp/lib/common/framing/AMQHeartbeatBody.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * 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 <amqp_types.h>
+#include <AMQBody.h>
+#include <Buffer.h>
+
+#ifndef _AMQHeartbeatBody_
+#define _AMQHeartbeatBody_
+
+namespace qpid {
+namespace framing {
+
+class AMQHeartbeatBody : public AMQBody
+{
+public:
+ typedef boost::shared_ptr<AMQHeartbeatBody> shared_ptr;
+
+ virtual ~AMQHeartbeatBody();
+ inline uint32_t size() const { return 0; }
+ inline uint8_t type() const { return HEARTBEAT_BODY; }
+ inline void encode(Buffer& ) const {}
+ inline void decode(Buffer& , uint32_t /*size*/) {}
+ virtual void print(std::ostream& out) const;
+};
+
+}
+}
+
+#endif
diff --git a/cpp/lib/common/framing/AMQMethodBody.cpp b/cpp/lib/common/framing/AMQMethodBody.cpp
new file mode 100644
index 0000000000..23502068f5
--- /dev/null
+++ b/cpp/lib/common/framing/AMQMethodBody.cpp
@@ -0,0 +1,59 @@
+/*
+ *
+ * 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 <AMQFrame.h>
+#include <AMQMethodBody.h>
+#include <QpidError.h>
+#include "AMQP_MethodVersionMap.h"
+
+namespace qpid {
+namespace framing {
+
+void AMQMethodBody::encodeId(Buffer& buffer) const{
+ buffer.putShort(amqpClassId());
+ buffer.putShort(amqpMethodId());
+}
+
+void AMQMethodBody::invoke(AMQP_ServerOperations&, const MethodContext&){
+ assert(0);
+ THROW_QPID_ERROR(PROTOCOL_ERROR, "Method not supported by AMQP Server.");
+}
+
+AMQMethodBody::shared_ptr AMQMethodBody::create(
+ AMQP_MethodVersionMap& versionMap, ProtocolVersion version,
+ Buffer& buffer)
+{
+ ClassMethodId id;
+ id.decode(buffer);
+ return AMQMethodBody::shared_ptr(
+ versionMap.createMethodBody(
+ id.classId, id.methodId, version.getMajor(), version.getMinor()));
+}
+
+void AMQMethodBody::ClassMethodId::decode(Buffer& buffer) {
+ classId = buffer.getShort();
+ methodId = buffer.getShort();
+}
+
+void AMQMethodBody::decode(Buffer& buffer, uint32_t /*size*/) {
+ decodeContent(buffer);
+}
+
+}} // namespace qpid::framing
diff --git a/cpp/lib/common/framing/AMQMethodBody.h b/cpp/lib/common/framing/AMQMethodBody.h
new file mode 100644
index 0000000000..c2b00c2169
--- /dev/null
+++ b/cpp/lib/common/framing/AMQMethodBody.h
@@ -0,0 +1,84 @@
+#ifndef _AMQMethodBody_
+#define _AMQMethodBody_
+
+/*
+ *
+ * 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 <iostream>
+#include <amqp_types.h>
+#include <AMQBody.h>
+#include <Buffer.h>
+#include <AMQP_ServerOperations.h>
+#include <MethodContext.h>
+
+namespace qpid {
+namespace framing {
+
+class AMQP_MethodVersionMap;
+
+class AMQMethodBody : public AMQBody
+{
+ public:
+ typedef boost::shared_ptr<AMQMethodBody> shared_ptr;
+
+ static shared_ptr create(
+ AMQP_MethodVersionMap& map, ProtocolVersion version, Buffer& buf);
+
+ ProtocolVersion version;
+ uint8_t type() const { return METHOD_BODY; }
+ AMQMethodBody(uint8_t major, uint8_t minor) : version(major, minor) {}
+ AMQMethodBody(ProtocolVersion ver) : version(ver) {}
+ virtual ~AMQMethodBody() {}
+ void decode(Buffer&, uint32_t);
+
+ virtual MethodId amqpMethodId() const = 0;
+ virtual ClassId amqpClassId() const = 0;
+
+ virtual void invoke(AMQP_ServerOperations&, const MethodContext&);
+
+ template <class T> bool isA() {
+ return amqpClassId()==T::CLASS_ID && amqpMethodId()==T::METHOD_ID;
+ }
+
+ /** Return request ID or response correlationID */
+ virtual RequestId getRequestId() const { return 0; }
+
+ virtual bool isRequest() const { return false; }
+ virtual bool isResponse() const { return false; }
+
+ protected:
+ static uint32_t baseSize() { return 4; }
+
+ struct ClassMethodId {
+ uint16_t classId;
+ uint16_t methodId;
+ void decode(Buffer& b);
+ };
+
+ void encodeId(Buffer& buffer) const;
+ virtual void encodeContent(Buffer& buffer) const = 0;
+ virtual void decodeContent(Buffer& buffer) = 0;
+};
+
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/cpp/lib/common/framing/AMQRequestBody.cpp b/cpp/lib/common/framing/AMQRequestBody.cpp
new file mode 100644
index 0000000000..54e1c11863
--- /dev/null
+++ b/cpp/lib/common/framing/AMQRequestBody.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "AMQRequestBody.h"
+#include "AMQP_MethodVersionMap.h"
+
+namespace qpid {
+namespace framing {
+
+void AMQRequestBody::Data::encode(Buffer& buffer) const {
+ buffer.putLongLong(requestId);
+ buffer.putLongLong(responseMark);
+ buffer.putLong(0); // Reserved long in spec.
+}
+
+void AMQRequestBody::Data::decode(Buffer& buffer) {
+ requestId = buffer.getLongLong();
+ responseMark = buffer.getLongLong();
+ buffer.getLong(); // Ignore reserved long.
+}
+
+void AMQRequestBody::encode(Buffer& buffer) const {
+ data.encode(buffer);
+ encodeId(buffer);
+ encodeContent(buffer);
+}
+
+AMQRequestBody::shared_ptr
+AMQRequestBody::create(
+ AMQP_MethodVersionMap& versionMap, ProtocolVersion version,
+ Buffer& buffer)
+{
+ ClassMethodId id;
+ Data data;
+ data.decode(buffer);
+ id.decode(buffer);
+ AMQRequestBody* body = dynamic_cast<AMQRequestBody*>(
+ versionMap.createMethodBody(
+ id.classId, id.methodId, version.getMajor(), version.getMinor()));
+ assert(body);
+ body->data = data;
+ return AMQRequestBody::shared_ptr(body);
+}
+
+void AMQRequestBody::printPrefix(std::ostream& out) const {
+ out << "request(id=" << data.requestId << ",mark="
+ << data.responseMark << "): ";
+}
+
+}} // namespace qpid::framing
+
diff --git a/cpp/lib/common/framing/AMQRequestBody.h b/cpp/lib/common/framing/AMQRequestBody.h
new file mode 100644
index 0000000000..e184fff1d6
--- /dev/null
+++ b/cpp/lib/common/framing/AMQRequestBody.h
@@ -0,0 +1,78 @@
+#ifndef _framing_AMQRequestBody_h
+#define _framing_AMQRequestBody_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "AMQMethodBody.h"
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Body of a request method frame.
+ */
+class AMQRequestBody : public AMQMethodBody
+{
+ public:
+ typedef boost::shared_ptr<AMQRequestBody> shared_ptr;
+
+ struct Data {
+ Data(RequestId id=0, ResponseId mark=0)
+ : requestId(id), responseMark(mark) {}
+ void encode(Buffer&) const;
+ void decode(Buffer&);
+
+ RequestId requestId;
+ ResponseId responseMark;
+ };
+
+ static Data& getData(const AMQBody::shared_ptr& body) {
+ return boost::dynamic_pointer_cast<AMQRequestBody>(body)->getData();
+ }
+
+ static shared_ptr create(
+ AMQP_MethodVersionMap& versionMap, ProtocolVersion version,
+ Buffer& buffer);
+
+ AMQRequestBody(ProtocolVersion v, RequestId id=0, ResponseId mark=0)
+ : AMQMethodBody(v), data(id, mark) {}
+
+ uint8_t type() const { return REQUEST_BODY; }
+ void encode(Buffer& buffer) const;
+
+ Data& getData() { return data; }
+ RequestId getRequestId() const { return data.requestId; }
+ ResponseId getResponseMark() const { return data.responseMark; }
+ void setRequestId(RequestId id) { data.requestId=id; }
+ void setResponseMark(ResponseId mark) { data.responseMark=mark; }
+
+ bool isRequest()const { return true; }
+ protected:
+ static const uint32_t baseSize() { return AMQMethodBody::baseSize()+20; }
+ void printPrefix(std::ostream& out) const;
+
+ private:
+ Data data;
+};
+
+}} // namespace qpid::framing
+
+
+
+#endif /*!_framing_AMQRequestBody_h*/
diff --git a/cpp/lib/common/framing/AMQResponseBody.cpp b/cpp/lib/common/framing/AMQResponseBody.cpp
new file mode 100644
index 0000000000..7da71a5d25
--- /dev/null
+++ b/cpp/lib/common/framing/AMQResponseBody.cpp
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "AMQFrame.h"
+#include "AMQResponseBody.h"
+#include "AMQP_MethodVersionMap.h"
+
+namespace qpid {
+namespace framing {
+
+void AMQResponseBody::Data::encode(Buffer& buffer) const {
+ buffer.putLongLong(responseId);
+ buffer.putLongLong(requestId);
+ buffer.putLong(batchOffset);
+}
+
+void AMQResponseBody::Data::decode(Buffer& buffer) {
+ responseId = buffer.getLongLong();
+ requestId = buffer.getLongLong();
+ batchOffset = buffer.getLong();
+}
+
+void AMQResponseBody::encode(Buffer& buffer) const {
+ data.encode(buffer);
+ encodeId(buffer);
+ encodeContent(buffer);
+}
+
+AMQResponseBody::shared_ptr AMQResponseBody::create(
+ AMQP_MethodVersionMap& versionMap, ProtocolVersion version,
+ Buffer& buffer)
+{
+ ClassMethodId id;
+ Data data;
+ data.decode(buffer);
+ id.decode(buffer);
+ AMQResponseBody* body = dynamic_cast<AMQResponseBody*>(
+ versionMap.createMethodBody(
+ id.classId, id.methodId, version.getMajor(), version.getMinor()));
+ assert(body);
+ body->data = data;
+ return AMQResponseBody::shared_ptr(body);
+}
+
+void AMQResponseBody::printPrefix(std::ostream& out) const {
+ out << "response(id=" << data.responseId << ",request=" << data.requestId
+ << ",batch=" << data.batchOffset << "): ";
+}
+
+}} // namespace qpid::framing
diff --git a/cpp/lib/common/framing/AMQResponseBody.h b/cpp/lib/common/framing/AMQResponseBody.h
new file mode 100644
index 0000000000..fa381baddd
--- /dev/null
+++ b/cpp/lib/common/framing/AMQResponseBody.h
@@ -0,0 +1,85 @@
+#ifndef _framing_AMQResponseBody_h
+#define _framing_AMQResponseBody_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "AMQMethodBody.h"
+
+namespace qpid {
+namespace framing {
+
+class AMQP_MethodVersionMap;
+
+/**
+ * Body of a response method frame.
+ */
+class AMQResponseBody : public AMQMethodBody
+{
+
+ public:
+ typedef boost::shared_ptr<AMQResponseBody> shared_ptr;
+
+ struct Data {
+ Data(ResponseId id=0, RequestId req=0, BatchOffset off=0)
+ : responseId(id), requestId(req), batchOffset(off) {}
+ void encode(Buffer&) const;
+ void decode(Buffer&);
+
+ uint64_t responseId;
+ uint64_t requestId;
+ uint32_t batchOffset;
+ };
+
+ static Data& getData(const AMQBody::shared_ptr& body) {
+ return boost::dynamic_pointer_cast<AMQResponseBody>(body)->getData();
+ }
+
+ static shared_ptr create(
+ AMQP_MethodVersionMap& versionMap, ProtocolVersion version,
+ Buffer& buffer);
+
+ AMQResponseBody(
+ ProtocolVersion v, ResponseId id=0, RequestId req=0, BatchOffset off=0)
+ : AMQMethodBody(v), data(id, req, off) {}
+
+ uint8_t type() const { return RESPONSE_BODY; }
+ void encode(Buffer& buffer) const;
+
+ Data& getData() { return data; }
+ ResponseId getResponseId() const { return data.responseId; }
+ RequestId getRequestId() const { return data.requestId; }
+ BatchOffset getBatchOffset() const { return data.batchOffset; }
+ void setResponseId(ResponseId id) { data.responseId = id; }
+ void setRequestId(RequestId id) { data.requestId = id; }
+ void setBatchOffset(BatchOffset id) { data.batchOffset = id; }
+
+ bool isResponse() const { return true; }
+ protected:
+ static const uint32_t baseSize() { return AMQMethodBody::baseSize()+20; }
+ void printPrefix(std::ostream& out) const;
+
+ private:
+ Data data;
+};
+
+}} // namespace qpid::framing
+
+
+
+#endif /*!_framing_AMQResponseBody_h*/
diff --git a/cpp/lib/common/framing/BasicHeaderProperties.cpp b/cpp/lib/common/framing/BasicHeaderProperties.cpp
new file mode 100644
index 0000000000..930ec9f4dd
--- /dev/null
+++ b/cpp/lib/common/framing/BasicHeaderProperties.cpp
@@ -0,0 +1,103 @@
+/*
+ *
+ * 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 <BasicHeaderProperties.h>
+
+//TODO: This could be easily generated from the spec
+
+qpid::framing::BasicHeaderProperties::BasicHeaderProperties() : deliveryMode(0), priority(0), timestamp(0){}
+qpid::framing::BasicHeaderProperties::~BasicHeaderProperties(){}
+
+uint32_t qpid::framing::BasicHeaderProperties::size() const{
+ uint32_t bytes = 2;//flags
+ if(contentType.length() > 0) bytes += contentType.length() + 1;
+ if(contentEncoding.length() > 0) bytes += contentEncoding.length() + 1;
+ if(headers.count() > 0) bytes += headers.size();
+ if(deliveryMode != 0) bytes += 1;
+ if(priority != 0) bytes += 1;
+ if(correlationId.length() > 0) bytes += correlationId.length() + 1;
+ if(replyTo.length() > 0) bytes += replyTo.length() + 1;
+ if(expiration.length() > 0) bytes += expiration.length() + 1;
+ if(messageId.length() > 0) bytes += messageId.length() + 1;
+ if(timestamp != 0) bytes += 8;
+ if(type.length() > 0) bytes += type.length() + 1;
+ if(userId.length() > 0) bytes += userId.length() + 1;
+ if(appId.length() > 0) bytes += appId.length() + 1;
+ if(clusterId.length() > 0) bytes += clusterId.length() + 1;
+
+ return bytes;
+}
+
+void qpid::framing::BasicHeaderProperties::encode(qpid::framing::Buffer& buffer) const{
+ uint16_t flags = getFlags();
+ buffer.putShort(flags);
+
+ if(contentType.length() > 0) buffer.putShortString(contentType);
+ if(contentEncoding.length() > 0) buffer.putShortString(contentEncoding);
+ if(headers.count() > 0) buffer.putFieldTable(headers);
+ if(deliveryMode != 0) buffer.putOctet(deliveryMode);
+ if(priority != 0) buffer.putOctet(priority);
+ if(correlationId.length() > 0) buffer.putShortString(correlationId);
+ if(replyTo.length() > 0) buffer.putShortString(replyTo);
+ if(expiration.length() > 0) buffer.putShortString(expiration);
+ if(messageId.length() > 0) buffer.putShortString(messageId);
+ if(timestamp != 0) buffer.putLongLong(timestamp);;
+ if(type.length() > 0) buffer.putShortString(type);
+ if(userId.length() > 0) buffer.putShortString(userId);
+ if(appId.length() > 0) buffer.putShortString(appId);
+ if(clusterId.length() > 0) buffer.putShortString(clusterId);
+}
+
+void qpid::framing::BasicHeaderProperties::decode(qpid::framing::Buffer& buffer, uint32_t /*size*/){
+ uint16_t flags = buffer.getShort();
+ if(flags & (1 << 15)) buffer.getShortString(contentType);
+ if(flags & (1 << 14)) buffer.getShortString(contentEncoding);
+ if(flags & (1 << 13)) buffer.getFieldTable(headers);
+ if(flags & (1 << 12)) deliveryMode = buffer.getOctet();
+ if(flags & (1 << 11)) priority = buffer.getOctet();
+ if(flags & (1 << 10)) buffer.getShortString(correlationId);
+ if(flags & (1 << 9)) buffer.getShortString(replyTo);
+ if(flags & (1 << 8)) buffer.getShortString(expiration);
+ if(flags & (1 << 7)) buffer.getShortString(messageId);
+ if(flags & (1 << 6)) timestamp = buffer.getLongLong();
+ if(flags & (1 << 5)) buffer.getShortString(type);
+ if(flags & (1 << 4)) buffer.getShortString(userId);
+ if(flags & (1 << 3)) buffer.getShortString(appId);
+ if(flags & (1 << 2)) buffer.getShortString(clusterId);
+}
+
+uint16_t qpid::framing::BasicHeaderProperties::getFlags() const{
+ uint16_t flags(0);
+ if(contentType.length() > 0) flags |= (1 << 15);
+ if(contentEncoding.length() > 0) flags |= (1 << 14);
+ if(headers.count() > 0) flags |= (1 << 13);
+ if(deliveryMode != 0) flags |= (1 << 12);
+ if(priority != 0) flags |= (1 << 11);
+ if(correlationId.length() > 0) flags |= (1 << 10);
+ if(replyTo.length() > 0) flags |= (1 << 9);
+ if(expiration.length() > 0) flags |= (1 << 8);
+ if(messageId.length() > 0) flags |= (1 << 7);
+ if(timestamp != 0) flags |= (1 << 6);
+ if(type.length() > 0) flags |= (1 << 5);
+ if(userId.length() > 0) flags |= (1 << 4);
+ if(appId.length() > 0) flags |= (1 << 3);
+ if(clusterId.length() > 0) flags |= (1 << 2);
+ return flags;
+}
diff --git a/cpp/lib/common/framing/BasicHeaderProperties.h b/cpp/lib/common/framing/BasicHeaderProperties.h
new file mode 100644
index 0000000000..1f3fd31250
--- /dev/null
+++ b/cpp/lib/common/framing/BasicHeaderProperties.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * 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 <amqp_types.h>
+#include <Buffer.h>
+#include <FieldTable.h>
+#include <HeaderProperties.h>
+
+#ifndef _BasicHeaderProperties_
+#define _BasicHeaderProperties_
+
+namespace qpid {
+namespace framing {
+ enum delivery_mode {TRANSIENT = 1, PERSISTENT = 2};
+
+ //TODO: This could be easily generated from the spec
+ class BasicHeaderProperties : public HeaderProperties
+ {
+ string contentType;
+ string contentEncoding;
+ FieldTable headers;
+ uint8_t deliveryMode;
+ uint8_t priority;
+ string correlationId;
+ string replyTo;
+ string expiration;
+ string messageId;
+ uint64_t timestamp;
+ string type;
+ string userId;
+ string appId;
+ string clusterId;
+
+ uint16_t getFlags() const;
+
+ public:
+ BasicHeaderProperties();
+ virtual ~BasicHeaderProperties();
+ virtual uint32_t size() const;
+ virtual void encode(Buffer& buffer) const;
+ virtual void decode(Buffer& buffer, uint32_t size);
+
+ inline virtual uint8_t classId() { return BASIC; }
+
+ inline const string& getContentType() const { return contentType; }
+ inline const string& getContentEncoding() const { return contentEncoding; }
+ inline FieldTable& getHeaders() { return headers; }
+ inline uint8_t getDeliveryMode() const { return deliveryMode; }
+ inline uint8_t getPriority() const { return priority; }
+ inline const string& getCorrelationId() const {return correlationId; }
+ inline const string& getReplyTo() const { return replyTo; }
+ inline const string& getExpiration() const { return expiration; }
+ inline const string& getMessageId() const {return messageId; }
+ inline uint64_t getTimestamp() const { return timestamp; }
+ inline const string& getType() const { return type; }
+ inline const string& getUserId() const { return userId; }
+ inline const string& getAppId() const { return appId; }
+ inline const string& getClusterId() const { return clusterId; }
+
+ void inline setContentType(const string& _type){ contentType = _type; }
+ void inline setContentEncoding(const string& encoding){ contentEncoding = encoding; }
+ void inline setHeaders(const FieldTable& _headers){ headers = _headers; }
+ void inline setDeliveryMode(uint8_t mode){ deliveryMode = mode; }
+ void inline setPriority(uint8_t _priority){ priority = _priority; }
+ void inline setCorrelationId(const string& _correlationId){ correlationId = _correlationId; }
+ void inline setReplyTo(const string& _replyTo){ replyTo = _replyTo;}
+ void inline setExpiration(const string& _expiration){ expiration = _expiration; }
+ void inline setMessageId(const string& _messageId){ messageId = _messageId; }
+ void inline setTimestamp(uint64_t _timestamp){ timestamp = _timestamp; }
+ void inline setType(const string& _type){ type = _type; }
+ void inline setUserId(const string& _userId){ userId = _userId; }
+ void inline setAppId(const string& _appId){appId = _appId; }
+ void inline setClusterId(const string& _clusterId){ clusterId = _clusterId; }
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/framing/BodyHandler.cpp b/cpp/lib/common/framing/BodyHandler.cpp
new file mode 100644
index 0000000000..5dd0c0c23d
--- /dev/null
+++ b/cpp/lib/common/framing/BodyHandler.cpp
@@ -0,0 +1,60 @@
+/*
+ *
+ * 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 "QpidError.h"
+#include "BodyHandler.h"
+#include <AMQRequestBody.h>
+#include <AMQResponseBody.h>
+#include <AMQMethodBody.h>
+#include <AMQHeaderBody.h>
+#include <AMQContentBody.h>
+#include <AMQHeartbeatBody.h>
+
+using namespace qpid::framing;
+using namespace boost;
+
+BodyHandler::~BodyHandler() {}
+
+void BodyHandler::handleBody(shared_ptr<AMQBody> body) {
+ switch(body->type())
+ {
+ case REQUEST_BODY:
+ handleRequest(shared_polymorphic_cast<AMQRequestBody>(body));
+ break;
+ case RESPONSE_BODY:
+ handleResponse(shared_polymorphic_cast<AMQResponseBody>(body));
+ break;
+ case METHOD_BODY:
+ handleMethod(shared_polymorphic_cast<AMQMethodBody>(body));
+ break;
+ case HEADER_BODY:
+ handleHeader(shared_polymorphic_cast<AMQHeaderBody>(body));
+ break;
+ case CONTENT_BODY:
+ handleContent(shared_polymorphic_cast<AMQContentBody>(body));
+ break;
+ case HEARTBEAT_BODY:
+ handleHeartbeat(shared_polymorphic_cast<AMQHeartbeatBody>(body));
+ break;
+ default:
+ QPID_ERROR(PROTOCOL_ERROR, "Unknown frame type "+body->type());
+ }
+}
+
diff --git a/cpp/lib/common/framing/BodyHandler.h b/cpp/lib/common/framing/BodyHandler.h
new file mode 100644
index 0000000000..cb3f0997b0
--- /dev/null
+++ b/cpp/lib/common/framing/BodyHandler.h
@@ -0,0 +1,61 @@
+#ifndef _BodyHandler_
+#define _BodyHandler_
+
+/*
+ *
+ * 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 <boost/shared_ptr.hpp>
+
+#include "Requester.h"
+#include "Responder.h"
+
+namespace qpid {
+namespace framing {
+
+class AMQRequestBody;
+class AMQResponseBody;
+class AMQMethodBody;
+class AMQHeaderBody;
+class AMQContentBody;
+class AMQHeartbeatBody;
+
+/**
+ * Interface to handle incoming frame bodies.
+ * Derived classes provide logic for each frame type.
+ */
+class BodyHandler {
+ public:
+ virtual ~BodyHandler();
+ virtual void handleBody(boost::shared_ptr<AMQBody> body);
+
+ protected:
+ virtual void handleRequest(boost::shared_ptr<AMQRequestBody>) = 0;
+ virtual void handleResponse(boost::shared_ptr<AMQResponseBody>) = 0;
+ virtual void handleMethod(boost::shared_ptr<AMQMethodBody>) = 0;
+ virtual void handleHeader(boost::shared_ptr<AMQHeaderBody>) = 0;
+ virtual void handleContent(boost::shared_ptr<AMQContentBody>) = 0;
+ virtual void handleHeartbeat(boost::shared_ptr<AMQHeartbeatBody>) = 0;
+};
+
+}}
+
+
+#endif
diff --git a/cpp/lib/common/framing/Buffer.cpp b/cpp/lib/common/framing/Buffer.cpp
new file mode 100644
index 0000000000..52c9a42d55
--- /dev/null
+++ b/cpp/lib/common/framing/Buffer.cpp
@@ -0,0 +1,183 @@
+/*
+ *
+ * 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 <Buffer.h>
+#include <FramingContent.h>
+#include <FieldTable.h>
+
+qpid::framing::Buffer::Buffer(uint32_t _size) : size(_size), owner(true), position(0), limit(_size){
+ data = new char[size];
+}
+
+qpid::framing::Buffer::Buffer(char* _data, uint32_t _size) : size(_size), owner(false), data(_data), position(0), limit(_size){
+}
+
+qpid::framing::Buffer::~Buffer(){
+ if(owner) delete[] data;
+}
+
+void qpid::framing::Buffer::flip(){
+ limit = position;
+ position = 0;
+}
+
+void qpid::framing::Buffer::clear(){
+ limit = size;
+ position = 0;
+}
+
+void qpid::framing::Buffer::compact(){
+ uint32_t p = limit - position;
+ //copy p chars from position to 0
+ memmove(data, data + position, p);
+ limit = size;
+ position = p;
+}
+
+void qpid::framing::Buffer::record(){
+ r_position = position;
+ r_limit = limit;
+}
+
+void qpid::framing::Buffer::restore(){
+ position = r_position;
+ limit = r_limit;
+}
+
+uint32_t qpid::framing::Buffer::available(){
+ return limit - position;
+}
+
+char* qpid::framing::Buffer::start(){
+ return data + position;
+}
+
+void qpid::framing::Buffer::move(uint32_t bytes){
+ position += bytes;
+}
+
+void qpid::framing::Buffer::putOctet(uint8_t i){
+ data[position++] = i;
+}
+
+void qpid::framing::Buffer::putShort(uint16_t i){
+ uint16_t b = i;
+ data[position++] = (uint8_t) (0xFF & (b >> 8));
+ data[position++] = (uint8_t) (0xFF & b);
+}
+
+void qpid::framing::Buffer::putLong(uint32_t i){
+ uint32_t b = i;
+ data[position++] = (uint8_t) (0xFF & (b >> 24));
+ data[position++] = (uint8_t) (0xFF & (b >> 16));
+ data[position++] = (uint8_t) (0xFF & (b >> 8));
+ data[position++] = (uint8_t) (0xFF & b);
+}
+
+void qpid::framing::Buffer::putLongLong(uint64_t i){
+ uint32_t hi = i >> 32;
+ uint32_t lo = i;
+ putLong(hi);
+ putLong(lo);
+}
+
+uint8_t qpid::framing::Buffer::getOctet(){
+ return (uint8_t) data[position++];
+}
+
+uint16_t qpid::framing::Buffer::getShort(){
+ uint16_t hi = (unsigned char) data[position++];
+ hi = hi << 8;
+ hi |= (unsigned char) data[position++];
+ return hi;
+}
+
+uint32_t qpid::framing::Buffer::getLong(){
+ uint32_t a = (unsigned char) data[position++];
+ uint32_t b = (unsigned char) data[position++];
+ uint32_t c = (unsigned char) data[position++];
+ uint32_t d = (unsigned char) data[position++];
+ a = a << 24;
+ a |= b << 16;
+ a |= c << 8;
+ a |= d;
+ return a;
+}
+
+uint64_t qpid::framing::Buffer::getLongLong(){
+ uint64_t hi = getLong();
+ uint64_t lo = getLong();
+ hi = hi << 32;
+ return hi | lo;
+}
+
+
+void qpid::framing::Buffer::putShortString(const string& s){
+ uint8_t len = s.length();
+ putOctet(len);
+ s.copy(data + position, len);
+ position += len;
+}
+
+void qpid::framing::Buffer::putLongString(const string& s){
+ uint32_t len = s.length();
+ putLong(len);
+ s.copy(data + position, len);
+ position += len;
+}
+
+void qpid::framing::Buffer::getShortString(string& s){
+ uint8_t len = getOctet();
+ s.assign(data + position, len);
+ position += len;
+}
+
+void qpid::framing::Buffer::getLongString(string& s){
+ uint32_t len = getLong();
+ s.assign(data + position, len);
+ position += len;
+}
+
+void qpid::framing::Buffer::putFieldTable(const FieldTable& t){
+ t.encode(*this);
+}
+
+void qpid::framing::Buffer::getFieldTable(FieldTable& t){
+ t.decode(*this);
+}
+
+void qpid::framing::Buffer::putContent(const Content& c){
+ c.encode(*this);
+}
+
+void qpid::framing::Buffer::getContent(Content& c){
+ c.decode(*this);
+}
+
+void qpid::framing::Buffer::putRawData(const string& s){
+ uint32_t len = s.length();
+ s.copy(data + position, len);
+ position += len;
+}
+
+void qpid::framing::Buffer::getRawData(string& s, uint32_t len){
+ s.assign(data + position, len);
+ position += len;
+}
diff --git a/cpp/lib/common/framing/Buffer.h b/cpp/lib/common/framing/Buffer.h
new file mode 100644
index 0000000000..63a15c7c3d
--- /dev/null
+++ b/cpp/lib/common/framing/Buffer.h
@@ -0,0 +1,86 @@
+/*
+ *
+ * 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 <amqp_types.h>
+
+#ifndef _Buffer_
+#define _Buffer_
+
+namespace qpid {
+namespace framing {
+
+class Content;
+class FieldTable;
+
+class Buffer
+{
+ const uint32_t size;
+ const bool owner;//indicates whether the data is owned by this instance
+ char* data;
+ uint32_t position;
+ uint32_t limit;
+ uint32_t r_position;
+ uint32_t r_limit;
+
+public:
+
+ Buffer(uint32_t size);
+ Buffer(char* data, uint32_t size);
+ ~Buffer();
+
+ void flip();
+ void clear();
+ void compact();
+ void record();
+ void restore();
+ uint32_t available();
+ char* start();
+ void move(uint32_t bytes);
+
+ void putOctet(uint8_t i);
+ void putShort(uint16_t i);
+ void putLong(uint32_t i);
+ void putLongLong(uint64_t i);
+
+ uint8_t getOctet();
+ uint16_t getShort();
+ uint32_t getLong();
+ uint64_t getLongLong();
+
+ void putShortString(const string& s);
+ void putLongString(const string& s);
+ void getShortString(string& s);
+ void getLongString(string& s);
+
+ void putFieldTable(const FieldTable& t);
+ void getFieldTable(FieldTable& t);
+
+ void putContent(const Content& c);
+ void getContent(Content& c);
+
+ void putRawData(const string& s);
+ void getRawData(string& s, uint32_t size);
+
+};
+
+}} // namespace qpid::framing
+
+
+#endif
diff --git a/cpp/lib/common/framing/ChannelAdapter.cpp b/cpp/lib/common/framing/ChannelAdapter.cpp
new file mode 100644
index 0000000000..8a1ff39ee5
--- /dev/null
+++ b/cpp/lib/common/framing/ChannelAdapter.cpp
@@ -0,0 +1,99 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <boost/format.hpp>
+
+#include "ChannelAdapter.h"
+#include "AMQFrame.h"
+#include "Exception.h"
+
+using boost::format;
+
+namespace qpid {
+namespace framing {
+
+void ChannelAdapter::init(
+ ChannelId i, OutputHandler& o, ProtocolVersion v)
+{
+ assertChannelNotOpen();
+ id = i;
+ out = &o;
+ version = v;
+}
+
+RequestId ChannelAdapter::send(AMQBody::shared_ptr body) {
+ RequestId result = 0;
+ assertChannelOpen();
+ switch (body->type()) {
+ case REQUEST_BODY: {
+ AMQRequestBody::shared_ptr request =
+ boost::shared_polymorphic_downcast<AMQRequestBody>(body);
+ requester.sending(request->getData());
+ result = request->getData().requestId;
+ break;
+ }
+ case RESPONSE_BODY: {
+ AMQResponseBody::shared_ptr response =
+ boost::shared_polymorphic_downcast<AMQResponseBody>(body);
+ responder.sending(response->getData());
+ break;
+ }
+ }
+ out->send(new AMQFrame(getVersion(), getId(), body));
+ return result;
+}
+
+void ChannelAdapter::handleRequest(AMQRequestBody::shared_ptr request) {
+ assertMethodOk(*request);
+ AMQRequestBody::Data& requestData = request->getData();
+ responder.received(requestData);
+ handleMethodInContext(request, MethodContext(this, request));
+}
+
+void ChannelAdapter::handleResponse(AMQResponseBody::shared_ptr response) {
+ assertMethodOk(*response);
+ // TODO aconway 2007-01-30: Consider a response handled on receipt.
+ // Review - any cases where this is not the case?
+ AMQResponseBody::Data& responseData = response->getData();
+ requester.processed(responseData);
+ handleMethod(response);
+}
+
+void ChannelAdapter::handleMethod(AMQMethodBody::shared_ptr method) {
+ assertMethodOk(*method);
+ handleMethodInContext(method, MethodContext(this, method));
+}
+
+void ChannelAdapter::assertMethodOk(AMQMethodBody& method) const {
+ if (getId() != 0 && method.amqpClassId() == ConnectionOpenBody::CLASS_ID)
+ throw ConnectionException(
+ 504, format("Connection method on non-0 channel %d.")%getId());
+}
+
+void ChannelAdapter::assertChannelOpen() const {
+ if (getId() != 0 && !isOpen())
+ throw ConnectionException(
+ 504, format("Channel %d is not open.")%getId());
+}
+
+void ChannelAdapter::assertChannelNotOpen() const {
+ if (getId() != 0 && isOpen())
+ throw ConnectionException(
+ 504, format("Channel %d is already open.") % getId());
+}
+
+}} // namespace qpid::framing
diff --git a/cpp/lib/common/framing/ChannelAdapter.h b/cpp/lib/common/framing/ChannelAdapter.h
new file mode 100644
index 0000000000..f6e3986eed
--- /dev/null
+++ b/cpp/lib/common/framing/ChannelAdapter.h
@@ -0,0 +1,105 @@
+#ifndef _ChannelAdapter_
+#define _ChannelAdapter_
+
+/*
+ *
+ * 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 <boost/shared_ptr.hpp>
+
+#include "BodyHandler.h"
+#include "Requester.h"
+#include "Responder.h"
+#include "framing/amqp_types.h"
+
+namespace qpid {
+namespace framing {
+
+class MethodContext;
+
+// FIXME aconway 2007-02-20: Rename as ChannelBase or just Channel.
+
+/**
+ * Base class for client and broker channels.
+ *
+ * - receives frame bodies from the network.
+ * - Updates request/response data.
+ * - Dispatches requests with a MethodContext for responses.
+ *
+ * send()
+ * - Updates request/resposne ID data.
+ * - Forwards frame to the peer.
+ *
+ * Thread safety: OBJECT UNSAFE. Instances must not be called
+ * concurrently. AMQP defines channels to be serialized.
+ */
+class ChannelAdapter : public BodyHandler {
+ public:
+ /**
+ *@param output Processed frames are forwarded to this handler.
+ */
+ ChannelAdapter(ChannelId id_=0, OutputHandler* out_=0,
+ ProtocolVersion ver=ProtocolVersion())
+ : id(id_), out(out_), version(ver) {}
+
+ /** Initialize the channel adapter. */
+ void init(ChannelId, OutputHandler&, ProtocolVersion);
+
+ ChannelId getId() const { return id; }
+ ProtocolVersion getVersion() const { return version; }
+
+ /**
+ * Wrap body in a frame and send the frame.
+ * Takes ownership of body.
+ */
+ RequestId send(AMQBody::shared_ptr body);
+ RequestId send(AMQBody* body) { return send(AMQBody::shared_ptr(body)); }
+
+ void handleMethod(boost::shared_ptr<qpid::framing::AMQMethodBody>);
+ void handleRequest(boost::shared_ptr<qpid::framing::AMQRequestBody>);
+ void handleResponse(boost::shared_ptr<qpid::framing::AMQResponseBody>);
+
+ virtual bool isOpen() const = 0;
+
+ protected:
+ void assertMethodOk(AMQMethodBody& method) const;
+ void assertChannelOpen() const;
+ void assertChannelNotOpen() const;
+
+ virtual void handleMethodInContext(
+ boost::shared_ptr<qpid::framing::AMQMethodBody> method,
+ const MethodContext& context) = 0;
+
+ RequestId getFirstAckRequest() { return requester.getFirstAckRequest(); }
+ RequestId getLastAckRequest() { return requester.getLastAckRequest(); }
+ RequestId getNextSendRequestId() { return requester.getNextId(); }
+
+ private:
+ ChannelId id;
+ OutputHandler* out;
+ ProtocolVersion version;
+ Requester requester;
+ Responder responder;
+};
+
+}}
+
+
+#endif
diff --git a/cpp/lib/common/framing/FieldTable.cpp b/cpp/lib/common/framing/FieldTable.cpp
new file mode 100644
index 0000000000..5bbc4651d3
--- /dev/null
+++ b/cpp/lib/common/framing/FieldTable.cpp
@@ -0,0 +1,150 @@
+/*
+ *
+ * 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 <FieldTable.h>
+#include <QpidError.h>
+#include <Buffer.h>
+#include <Value.h>
+#include <assert.h>
+
+namespace qpid {
+namespace framing {
+
+FieldTable::~FieldTable() {}
+
+uint32_t FieldTable::size() const {
+ uint32_t len(4);
+ for(ValueMap::const_iterator i = values.begin(); i != values.end(); ++i) {
+ // 2 = shortstr_len_byyte + type_char_byte
+ len += 2 + (i->first).size() + (i->second)->size();
+ }
+ return len;
+}
+
+int FieldTable::count() const {
+ return values.size();
+}
+
+namespace
+{
+std::ostream& operator<<(std::ostream& out, const FieldTable::ValueMap::value_type& i) {
+ return out << i.first << ":" << *i.second;
+}
+}
+
+std::ostream& operator<<(std::ostream& out, const FieldTable& t) {
+ out << "{";
+ FieldTable::ValueMap::const_iterator i = t.getMap().begin();
+ if (i != t.getMap().end()) out << *i++;
+ while (i != t.getMap().end())
+ {
+ out << "," << *i++;
+ }
+ return out << "}";
+}
+
+void FieldTable::setString(const std::string& name, const std::string& value){
+ values[name] = ValuePtr(new StringValue(value));
+}
+
+void FieldTable::setInt(const std::string& name, int value){
+ values[name] = ValuePtr(new IntegerValue(value));
+}
+
+void FieldTable::setTimestamp(const std::string& name, uint64_t value){
+ values[name] = ValuePtr(new TimeValue(value));
+}
+
+void FieldTable::setTable(const std::string& name, const FieldTable& value){
+ values[name] = ValuePtr(new FieldTableValue(value));
+}
+
+namespace {
+template <class T> T default_value() { return T(); }
+template <> int default_value<int>() { return 0; }
+template <> uint64_t default_value<uint64_t>() { return 0; }
+}
+
+template <class T>
+T FieldTable::getValue(const std::string& name) const
+{
+ ValueMap::const_iterator i = values.find(name);
+ if (i == values.end()) return default_value<T>();
+ const ValueOps<T> *vt = dynamic_cast<const ValueOps<T>*>(i->second.get());
+ return vt->getValue();
+}
+
+std::string FieldTable::getString(const std::string& name) const {
+ return getValue<std::string>(name);
+}
+
+int FieldTable::getInt(const std::string& name) const {
+ return getValue<int>(name);
+}
+
+uint64_t FieldTable::getTimestamp(const std::string& name) const {
+ return getValue<uint64_t>(name);
+}
+
+void FieldTable::getTable(const std::string& name, FieldTable& value) const {
+ value = getValue<FieldTable>(name);
+}
+
+void FieldTable::encode(Buffer& buffer) const{
+ buffer.putLong(size() - 4);
+ for (ValueMap::const_iterator i = values.begin(); i!=values.end(); ++i) {
+ buffer.putShortString(i->first);
+ buffer.putOctet(i->second->getType());
+ i->second->encode(buffer);
+ }
+}
+
+void FieldTable::decode(Buffer& buffer){
+ uint32_t len = buffer.getLong();
+ uint32_t available = buffer.available();
+ if (available < len)
+ THROW_QPID_ERROR(FRAMING_ERROR, "Not enough data for field table.");
+ uint32_t leftover = available - len;
+ while(buffer.available() > leftover){
+ std::string name;
+ buffer.getShortString(name);
+ std::auto_ptr<Value> value(Value::decode_value(buffer));
+ values[name] = ValuePtr(value.release());
+ }
+}
+
+
+bool FieldTable::operator==(const FieldTable& x) const {
+ if (values.size() != x.values.size()) return false;
+ for (ValueMap::const_iterator i = values.begin(); i != values.end(); ++i) {
+ ValueMap::const_iterator j = x.values.find(i->first);
+ if (j == x.values.end()) return false;
+ if (*(i->second) != *(j->second)) return false;
+ }
+ return true;
+}
+
+void FieldTable::erase(const std::string& name)
+{
+ values.erase(values.find(name));
+}
+
+}
+}
diff --git a/cpp/lib/common/framing/FieldTable.h b/cpp/lib/common/framing/FieldTable.h
new file mode 100644
index 0000000000..e25a7d3f8c
--- /dev/null
+++ b/cpp/lib/common/framing/FieldTable.h
@@ -0,0 +1,90 @@
+/*
+ *
+ * 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 <iostream>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <map>
+#include <amqp_types.h>
+
+#ifndef _FieldTable_
+#define _FieldTable_
+
+namespace qpid {
+ /**
+ * The framing namespace contains classes that are used to create,
+ * send and receive the basic packets from which AMQP is built.
+ */
+namespace framing {
+
+class Value;
+class Buffer;
+
+/**
+ * A set of name-value pairs. (See the AMQP spec for more details on
+ * AMQP field tables).
+ *
+ * \ingroup clientapi
+ */
+class FieldTable
+{
+ public:
+ typedef boost::shared_ptr<Value> ValuePtr;
+ typedef std::map<std::string, ValuePtr> ValueMap;
+
+ ~FieldTable();
+ uint32_t size() const;
+ int count() const;
+ void setString(const std::string& name, const std::string& value);
+ void setInt(const std::string& name, int value);
+ void setTimestamp(const std::string& name, uint64_t value);
+ void setTable(const std::string& name, const FieldTable& value);
+ //void setDecimal(string& name, xxx& value);
+ std::string getString(const std::string& name) const;
+ int getInt(const std::string& name) const;
+ uint64_t getTimestamp(const std::string& name) const;
+ void getTable(const std::string& name, FieldTable& value) const;
+ //void getDecimal(string& name, xxx& value);
+ void erase(const std::string& name);
+
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+
+ bool operator==(const FieldTable& other) const;
+
+ // TODO aconway 2006-09-26: Yeuch! Rework FieldTable to have
+ // a map-like interface.
+ const ValueMap& getMap() const { return values; }
+ ValueMap& getMap() { return values; }
+
+ private:
+ friend std::ostream& operator<<(std::ostream& out, const FieldTable& body);
+ ValueMap values;
+ template<class T> T getValue(const std::string& name) const;
+};
+
+class FieldNotFoundException{};
+class UnknownFieldName : public FieldNotFoundException{};
+class IncorrectFieldType : public FieldNotFoundException{};
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/framing/FramingContent.cpp b/cpp/lib/common/framing/FramingContent.cpp
new file mode 100644
index 0000000000..24efa38dcb
--- /dev/null
+++ b/cpp/lib/common/framing/FramingContent.cpp
@@ -0,0 +1,75 @@
+/*
+ *
+ * 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 <assert.h>
+
+#include "Buffer.h"
+#include "FramingContent.h"
+#include <QpidError.h>
+#include <sstream>
+
+namespace qpid {
+namespace framing {
+
+Content::Content() : discriminator(0) {}
+
+Content::Content(uint8_t _discriminator, const string& _value): discriminator(_discriminator), value(_value) {
+ validate();
+}
+
+void Content::validate() {
+ if (discriminator == REFERENCE) {
+ if(value.empty()) {
+ THROW_QPID_ERROR(FRAMING_ERROR, "Reference cannot be empty");
+ }
+ }else if (discriminator != INLINE) {
+ std::stringstream out;
+ out << "Invalid discriminator: " << (int) discriminator;
+ THROW_QPID_ERROR(FRAMING_ERROR, out.str());
+ }
+}
+
+Content::~Content() {}
+
+void Content::encode(Buffer& buffer) const {
+ buffer.putOctet(discriminator);
+ buffer.putLongString(value);
+}
+
+void Content::decode(Buffer& buffer) {
+ discriminator = buffer.getOctet();
+ buffer.getLongString(value);
+ validate();
+}
+
+size_t Content::size() const {
+ return 1/*discriminator*/ + 4/*for recording size of long string*/ + value.size();
+}
+
+std::ostream& operator<<(std::ostream& out, const Content& content) {
+ if (content.discriminator == REFERENCE) {
+ out << "{REF:" << content.value << "}";
+ } else if (content.discriminator == INLINE) {
+ out << "{INLINE:" << content.value.size() << " bytes}";
+ }
+ return out;
+}
+
+}} // namespace framing::qpid
diff --git a/cpp/lib/common/framing/FramingContent.h b/cpp/lib/common/framing/FramingContent.h
new file mode 100644
index 0000000000..696bcc7c1a
--- /dev/null
+++ b/cpp/lib/common/framing/FramingContent.h
@@ -0,0 +1,40 @@
+#ifndef _framing_FramingContent_h
+#define _framing_FramingContent_h
+
+#include <ostream>
+
+namespace qpid {
+namespace framing {
+
+enum discriminator_types { INLINE = 0, REFERENCE = 1 };
+
+/**
+ * A representation of the AMQP 'content' data type (used for message
+ * bodies) which can hold inline data or a reference.
+ */
+class Content
+{
+ uint8_t discriminator;
+ string value;
+
+ void validate();
+
+ public:
+ Content();
+ Content(uint8_t _discriminator, const string& _value);
+ ~Content();
+
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+ size_t size() const;
+ bool isInline() const { return discriminator == INLINE; }
+ bool isReference() const { return discriminator == REFERENCE; }
+ const string& getValue() const { return value; }
+
+ friend std::ostream& operator<<(std::ostream&, const Content&);
+};
+
+}} // namespace qpid::framing
+
+
+#endif /*!_framing_FramingContent_h*/
diff --git a/cpp/lib/common/framing/HeaderProperties.h b/cpp/lib/common/framing/HeaderProperties.h
new file mode 100644
index 0000000000..1ec4840309
--- /dev/null
+++ b/cpp/lib/common/framing/HeaderProperties.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * 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 <amqp_types.h>
+#include <Buffer.h>
+
+#ifndef _HeaderProperties_
+#define _HeaderProperties_
+
+namespace qpid {
+namespace framing {
+
+ enum header_classes{BASIC = 60};
+
+ class HeaderProperties
+ {
+
+ public:
+ inline virtual ~HeaderProperties(){}
+ virtual uint8_t classId() = 0;
+ virtual uint32_t size() const = 0;
+ virtual void encode(Buffer& buffer) const = 0;
+ virtual void decode(Buffer& buffer, uint32_t size) = 0;
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/framing/InitiationHandler.cpp b/cpp/lib/common/framing/InitiationHandler.cpp
new file mode 100644
index 0000000000..dd92c9859b
--- /dev/null
+++ b/cpp/lib/common/framing/InitiationHandler.cpp
@@ -0,0 +1,24 @@
+/*
+ *
+ * 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 <InitiationHandler.h>
+
+qpid::framing::InitiationHandler::~InitiationHandler() {}
diff --git a/cpp/lib/common/framing/InitiationHandler.h b/cpp/lib/common/framing/InitiationHandler.h
new file mode 100644
index 0000000000..d94fc58d2c
--- /dev/null
+++ b/cpp/lib/common/framing/InitiationHandler.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * 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 <string>
+
+#ifndef _InitiationHandler_
+#define _InitiationHandler_
+
+#include <ProtocolInitiation.h>
+
+namespace qpid {
+namespace framing {
+
+ class InitiationHandler{
+ public:
+ virtual ~InitiationHandler();
+ virtual void initiated(ProtocolInitiation* header) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/framing/InputHandler.h b/cpp/lib/common/framing/InputHandler.h
new file mode 100644
index 0000000000..4e2d4bcc9b
--- /dev/null
+++ b/cpp/lib/common/framing/InputHandler.h
@@ -0,0 +1,39 @@
+#ifndef _InputHandler_
+#define _InputHandler_
+/*
+ *
+ * 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 <AMQFrame.h>
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace framing {
+
+class InputHandler : private boost::noncopyable {
+ public:
+ virtual ~InputHandler() {}
+ virtual void received(AMQFrame* frame) = 0;
+};
+
+}}
+
+
+#endif
diff --git a/cpp/lib/common/framing/MethodContext.cpp b/cpp/lib/common/framing/MethodContext.cpp
new file mode 100644
index 0000000000..73af73f8e5
--- /dev/null
+++ b/cpp/lib/common/framing/MethodContext.cpp
@@ -0,0 +1,31 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "MethodContext.h"
+#include "amqp_types.h"
+#include "AMQRequestBody.h"
+
+namespace qpid {
+namespace framing {
+
+RequestId MethodContext::getRequestId() const {
+ return boost::shared_polymorphic_downcast<AMQRequestBody>(methodBody)
+ ->getRequestId();
+}
+
+}} // namespace qpid::framing
diff --git a/cpp/lib/common/framing/MethodContext.h b/cpp/lib/common/framing/MethodContext.h
new file mode 100644
index 0000000000..3493924bf6
--- /dev/null
+++ b/cpp/lib/common/framing/MethodContext.h
@@ -0,0 +1,80 @@
+#ifndef _framing_MethodContext_h
+#define _framing_MethodContext_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <boost/shared_ptr.hpp>
+
+#include "OutputHandler.h"
+#include "ProtocolVersion.h"
+
+namespace qpid {
+namespace framing {
+
+class BodyHandler;
+class AMQMethodBody;
+class ChannelAdapter;
+
+/**
+ * Invocation context for an AMQP method.
+ *
+ * It provides the method being processed and the channel on which
+ * it arrived.
+ *
+ * All Handler functions take a MethodContext as the last parameter.
+ */
+struct MethodContext
+{
+ typedef boost::shared_ptr<AMQMethodBody> BodyPtr;
+
+ MethodContext(ChannelAdapter* ch=0, BodyPtr method=BodyPtr())
+ : channel(ch), methodBody(method) {}
+
+ /**
+ * Channel on which the method being processed arrived.
+ * 0 if the method was constructed by the caller
+ * rather than received from a channel.
+ */
+ ChannelAdapter* channel;
+
+ /**
+ * Body of the method being processed.
+ * It's useful for passing around instead of unpacking all its parameters.
+ * It's also provides the request ID when constructing a response.
+ */
+ BodyPtr methodBody;
+
+ /**
+ * Return methodBody's request ID.
+ * It is an error to call this if methodBody is not a request.
+ */
+ RequestId getRequestId() const;
+};
+
+// FIXME aconway 2007-02-01: Method context only required on Handler
+// functions, not on Proxy functions. If we add set/getChannel(ChannelAdapter*)
+// on AMQBody and set it during decodeing then we could get rid of the context.
+
+
+
+}} // namespace qpid::framing
+
+
+
+#endif /*!_framing_MethodContext_h*/
diff --git a/cpp/lib/common/framing/OutputHandler.h b/cpp/lib/common/framing/OutputHandler.h
new file mode 100644
index 0000000000..9ffd4227d8
--- /dev/null
+++ b/cpp/lib/common/framing/OutputHandler.h
@@ -0,0 +1,39 @@
+#ifndef _OutputHandler_
+#define _OutputHandler_
+
+/*
+ *
+ * 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 <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace framing {
+class AMQFrame;
+
+class OutputHandler : private boost::noncopyable {
+ public:
+ virtual ~OutputHandler() {}
+ virtual void send(AMQFrame* frame) = 0;
+};
+
+}}
+
+
+#endif
diff --git a/cpp/lib/common/framing/ProtocolInitiation.cpp b/cpp/lib/common/framing/ProtocolInitiation.cpp
new file mode 100644
index 0000000000..de53488f7b
--- /dev/null
+++ b/cpp/lib/common/framing/ProtocolInitiation.cpp
@@ -0,0 +1,63 @@
+/*
+ *
+ * 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 <ProtocolInitiation.h>
+
+namespace qpid {
+namespace framing {
+
+ProtocolInitiation::ProtocolInitiation(){}
+
+ProtocolInitiation::ProtocolInitiation(uint8_t _major, uint8_t _minor) : version(_major, _minor) {}
+
+ProtocolInitiation::ProtocolInitiation(ProtocolVersion p) : version(p) {}
+
+ProtocolInitiation::~ProtocolInitiation(){}
+
+void ProtocolInitiation::encode(Buffer& buffer){
+ buffer.putOctet('A');
+ buffer.putOctet('M');
+ buffer.putOctet('Q');
+ buffer.putOctet('P');
+ buffer.putOctet(1);//class
+ buffer.putOctet(1);//instance
+ buffer.putOctet(version.getMajor());
+ buffer.putOctet(version.getMinor());
+}
+
+bool ProtocolInitiation::decode(Buffer& buffer){
+ if(buffer.available() >= 8){
+ buffer.getOctet();//A
+ buffer.getOctet();//M
+ buffer.getOctet();//Q
+ buffer.getOctet();//P
+ buffer.getOctet();//class
+ buffer.getOctet();//instance
+ version.setMajor(buffer.getOctet());
+ version.setMinor(buffer.getOctet());
+ return true;
+ }else{
+ return false;
+ }
+}
+
+//TODO: this should prbably be generated from the spec at some point to keep the version numbers up to date
+
+}} // namespace qpid::framing
diff --git a/cpp/lib/common/framing/ProtocolInitiation.h b/cpp/lib/common/framing/ProtocolInitiation.h
new file mode 100644
index 0000000000..ed7b59e94e
--- /dev/null
+++ b/cpp/lib/common/framing/ProtocolInitiation.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * 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 <amqp_types.h>
+#include <Buffer.h>
+#include <AMQDataBlock.h>
+#include <ProtocolVersion.h>
+
+#ifndef _ProtocolInitiation_
+#define _ProtocolInitiation_
+
+namespace qpid {
+namespace framing {
+
+class ProtocolInitiation : public AMQDataBlock
+{
+private:
+ ProtocolVersion version;
+
+public:
+ ProtocolInitiation();
+ ProtocolInitiation(uint8_t major, uint8_t minor);
+ ProtocolInitiation(ProtocolVersion p);
+ virtual ~ProtocolInitiation();
+ virtual void encode(Buffer& buffer);
+ virtual bool decode(Buffer& buffer);
+ inline virtual uint32_t size() const { return 8; }
+ inline uint8_t getMajor() const { return version.getMajor(); }
+ inline uint8_t getMinor() const { return version.getMinor(); }
+ inline ProtocolVersion getVersion() const { return version; }
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/framing/ProtocolVersion.cpp b/cpp/lib/common/framing/ProtocolVersion.cpp
new file mode 100644
index 0000000000..fd4b1a645f
--- /dev/null
+++ b/cpp/lib/common/framing/ProtocolVersion.cpp
@@ -0,0 +1,44 @@
+/*
+ *
+ * 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 <ProtocolVersion.h>
+#include <sstream>
+
+using namespace qpid::framing;
+
+const std::string ProtocolVersion::toString() const
+{
+ std::stringstream ss;
+ ss << major_ << "-" << minor_;
+ return ss.str();
+}
+
+ProtocolVersion& ProtocolVersion::operator=(ProtocolVersion p)
+{
+ major_ = p.major_;
+ minor_ = p.minor_;
+ return *this;
+}
+
+bool ProtocolVersion::operator==(ProtocolVersion p) const
+{
+ return major_ == p.major_ && minor_ == p.minor_;
+}
+
diff --git a/cpp/lib/common/framing/ProtocolVersion.h b/cpp/lib/common/framing/ProtocolVersion.h
new file mode 100644
index 0000000000..5e1429c1ea
--- /dev/null
+++ b/cpp/lib/common/framing/ProtocolVersion.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ProtocolVersion_
+#define _ProtocolVersion_
+
+#include <amqp_types.h>
+
+namespace qpid
+{
+namespace framing
+{
+
+class ProtocolVersion
+{
+private:
+ uint8_t major_;
+ uint8_t minor_;
+
+public:
+ ProtocolVersion(uint8_t _major=0, uint8_t _minor=0)
+ : major_(_major), minor_(_minor) {}
+
+ uint8_t getMajor() const { return major_; }
+ void setMajor(uint8_t major) { major_ = major; }
+ uint8_t getMinor() const { return minor_; }
+ void setMinor(uint8_t minor) { minor_ = minor; }
+ const std::string toString() const;
+
+ ProtocolVersion& operator=(ProtocolVersion p);
+
+ bool operator==(ProtocolVersion p) const;
+ bool operator!=(ProtocolVersion p) const { return ! (*this == p); }
+};
+
+} // namespace framing
+} // namespace qpid
+
+
+#endif // ifndef _ProtocolVersion_
diff --git a/cpp/lib/common/framing/ProtocolVersionException.cpp b/cpp/lib/common/framing/ProtocolVersionException.cpp
new file mode 100644
index 0000000000..9088422f6f
--- /dev/null
+++ b/cpp/lib/common/framing/ProtocolVersionException.cpp
@@ -0,0 +1,33 @@
+/*
+ *
+ * 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 <boost/format.hpp>
+#include <ProtocolVersionException.h>
+
+
+using namespace qpid::framing;
+
+void ProtocolVersionException::init(const std::string& msg)
+{
+ whatStr = boost::str(
+ boost::format("ProtocolVersionException: %s found: %s")
+ % versionFound.toString() % msg);
+}
+
diff --git a/cpp/lib/common/framing/ProtocolVersionException.h b/cpp/lib/common/framing/ProtocolVersionException.h
new file mode 100644
index 0000000000..8e2de8b843
--- /dev/null
+++ b/cpp/lib/common/framing/ProtocolVersionException.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef _ProtocolVersionException_
+#define _ProtocolVersionException_
+
+#include <Exception.h>
+#include <ProtocolVersion.h>
+#include <string>
+#include <vector>
+
+namespace qpid {
+namespace framing {
+
+class ProtocolVersionException : public qpid::Exception
+{
+protected:
+ ProtocolVersion versionFound;
+
+public:
+ ~ProtocolVersionException() throw() {}
+
+ template <class T>
+ ProtocolVersionException(
+ ProtocolVersion ver, const T& msg) throw () : versionFound(ver)
+ { init(boost::lexical_cast<std::string>(msg)); }
+
+ template <class T>
+ ProtocolVersionException(const T& msg) throw ()
+ { init(boost::lexical_cast<std::string>(msg)); }
+
+ private:
+ void init(const std::string& msg);
+};
+
+}} // namespace qpid::framing
+
+#endif //ifndef _ProtocolVersionException_
diff --git a/cpp/lib/common/framing/Proxy.cpp b/cpp/lib/common/framing/Proxy.cpp
new file mode 100644
index 0000000000..0b2a882a49
--- /dev/null
+++ b/cpp/lib/common/framing/Proxy.cpp
@@ -0,0 +1,32 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "Proxy.h"
+#include "ChannelAdapter.h"
+#include "ProtocolVersion.h"
+
+namespace qpid {
+namespace framing {
+
+Proxy::~Proxy() {}
+
+ProtocolVersion Proxy::getProtocolVersion() const {
+ return channel.getVersion();
+}
+
+}} // namespace qpid::framing
diff --git a/cpp/lib/common/framing/Proxy.h b/cpp/lib/common/framing/Proxy.h
new file mode 100644
index 0000000000..8ed46ed748
--- /dev/null
+++ b/cpp/lib/common/framing/Proxy.h
@@ -0,0 +1,51 @@
+#ifndef _framing_Proxy_h
+#define _framing_Proxy_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "ProtocolVersion.h"
+
+namespace qpid {
+namespace framing {
+
+class ChannelAdapter;
+class FieldTable;
+class Content;
+
+/**
+ * Base class for proxies.
+ */
+class Proxy
+{
+
+ public:
+ Proxy(ChannelAdapter& ch) : channel(ch) {}
+ virtual ~Proxy();
+
+ ProtocolVersion getProtocolVersion() const;
+
+ protected:
+ ChannelAdapter& channel;
+};
+
+}} // namespace qpid::framing
+
+
+
+#endif /*!_framing_Proxy_h*/
diff --git a/cpp/lib/common/framing/Requester.cpp b/cpp/lib/common/framing/Requester.cpp
new file mode 100644
index 0000000000..9ee809e2ee
--- /dev/null
+++ b/cpp/lib/common/framing/Requester.cpp
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <boost/format.hpp>
+
+#include "Requester.h"
+#include "QpidError.h"
+
+namespace qpid {
+namespace framing {
+
+Requester::Requester() : lastId(0), responseMark(0) {}
+
+void Requester::sending(AMQRequestBody::Data& request) {
+ request.requestId = ++lastId;
+ request.responseMark = responseMark;
+}
+
+void Requester::processed(const AMQResponseBody::Data& response) {
+ responseMark = response.responseId;
+ firstAckRequest = response.requestId;
+ lastAckRequest = firstAckRequest + response.batchOffset;
+}
+
+}} // namespace qpid::framing
diff --git a/cpp/lib/common/framing/Requester.h b/cpp/lib/common/framing/Requester.h
new file mode 100644
index 0000000000..dcc4460041
--- /dev/null
+++ b/cpp/lib/common/framing/Requester.h
@@ -0,0 +1,67 @@
+#ifndef _framing_Requester_h
+#define _framing_Requester_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <set>
+#include "AMQRequestBody.h"
+#include "AMQResponseBody.h"
+
+namespace qpid {
+namespace framing {
+
+class AMQRequestBody;
+class AMQResponseBody;
+
+/**
+ * Manage request IDs and the response mark for locally initiated requests.
+ *
+ * THREAD UNSAFE: This class is called as frames are sent or received
+ * sequentially on a connection, so it does not need to be thread safe.
+ */
+class Requester
+{
+ public:
+ Requester();
+
+ /** Called before sending a request to set request data. */
+ void sending(AMQRequestBody::Data&);
+
+ /** Called after processing a response. */
+ void processed(const AMQResponseBody::Data&);
+
+ /** Get the next request id to be used. */
+ RequestId getNextId() { return lastId + 1; }
+ /** Get the first request acked by this response */
+ RequestId getFirstAckRequest() { return firstAckRequest; }
+ /** Get the last request acked by this response */
+ RequestId getLastAckRequest() { return lastAckRequest; }
+
+ private:
+ RequestId lastId;
+ ResponseId responseMark;
+ ResponseId firstAckRequest;
+ ResponseId lastAckRequest;
+};
+
+}} // namespace qpid::framing
+
+
+
+#endif /*!_framing_Requester_h*/
diff --git a/cpp/lib/common/framing/Responder.cpp b/cpp/lib/common/framing/Responder.cpp
new file mode 100644
index 0000000000..c8c5ce8dcc
--- /dev/null
+++ b/cpp/lib/common/framing/Responder.cpp
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <boost/format.hpp>
+
+#include "Responder.h"
+#include "QpidError.h"
+
+namespace qpid {
+namespace framing {
+
+Responder::Responder() : lastId(0), responseMark(0) {}
+
+void Responder::received(const AMQRequestBody::Data& request) {
+ if (request.responseMark < responseMark || request.responseMark > lastId)
+ THROW_QPID_ERROR(
+ PROTOCOL_ERROR, boost::format("Invalid response mark %d.")
+ %request.responseMark);
+ responseMark = request.responseMark;
+}
+
+void Responder::sending(AMQResponseBody::Data& response) {
+ response.responseId = ++lastId;
+ assert(response.requestId); // Should be already set.
+ response.batchOffset = 0;
+}
+
+}} // namespace qpid::framing
+
diff --git a/cpp/lib/common/framing/Responder.h b/cpp/lib/common/framing/Responder.h
new file mode 100644
index 0000000000..0e1785256b
--- /dev/null
+++ b/cpp/lib/common/framing/Responder.h
@@ -0,0 +1,61 @@
+#ifndef _framing_Responder_h
+#define _framing_Responder_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "AMQRequestBody.h"
+#include "AMQResponseBody.h"
+
+namespace qpid {
+namespace framing {
+
+/**
+ * Manage response ids and response mark remotely initianted requests.
+ *
+ * THREAD UNSAFE: This class is called as frames are sent or received
+ * sequentially on a connection, so it does not need to be thread safe.
+ */
+class Responder
+{
+ public:
+ Responder();
+
+ /** Called after receiving a request. */
+ void received(const AMQRequestBody::Data& request);
+
+ /** Called before sending a response to set respose data. */
+ void sending(AMQResponseBody::Data& response);
+
+ /** Get the ID of the highest response acknowledged by the peer. */
+ ResponseId getResponseMark() { return responseMark; }
+
+ // TODO aconway 2007-01-14: Batching support - store unsent
+ // Response for equality comparison with subsequent responses.
+ //
+
+ private:
+ ResponseId lastId;
+ ResponseId responseMark;
+};
+
+}} // namespace qpid::framing
+
+
+
+#endif /*!_framing_Responder_h*/
diff --git a/cpp/lib/common/framing/Value.cpp b/cpp/lib/common/framing/Value.cpp
new file mode 100644
index 0000000000..03e005e384
--- /dev/null
+++ b/cpp/lib/common/framing/Value.cpp
@@ -0,0 +1,122 @@
+/*
+ *
+ * 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 <Value.h>
+#include <Buffer.h>
+#include <FieldTable.h>
+#include <QpidError.h>
+#include <sstream>
+
+namespace qpid {
+namespace framing {
+
+Value::~Value() {}
+
+void StringValue::encode(Buffer& buffer){
+ buffer.putLongString(value);
+}
+void StringValue::decode(Buffer& buffer){
+ buffer.getLongString(value);
+}
+
+void IntegerValue::encode(Buffer& buffer){
+ buffer.putLong((uint32_t) value);
+}
+void IntegerValue::decode(Buffer& buffer){
+ value = buffer.getLong();
+}
+
+void TimeValue::encode(Buffer& buffer){
+ buffer.putLongLong(value);
+}
+void TimeValue::decode(Buffer& buffer){
+ value = buffer.getLongLong();
+}
+
+void DecimalValue::encode(Buffer& buffer){
+ buffer.putOctet(value.decimals);
+ buffer.putLong(value.value);
+}
+void DecimalValue::decode(Buffer& buffer){
+ value = Decimal(buffer.getLong(), buffer.getOctet());
+}
+
+void FieldTableValue::encode(Buffer& buffer){
+ buffer.putFieldTable(value);
+}
+void FieldTableValue::decode(Buffer& buffer){
+ buffer.getFieldTable(value);
+}
+
+std::auto_ptr<Value> Value::decode_value(Buffer& buffer)
+{
+ std::auto_ptr<Value> value;
+ uint8_t type = buffer.getOctet();
+ switch(type){
+ case 'S':
+ value.reset(new StringValue());
+ break;
+ case 'I':
+ value.reset(new IntegerValue());
+ break;
+ case 'D':
+ value.reset(new DecimalValue());
+ break;
+ case 'T':
+ value.reset(new TimeValue());
+ break;
+ case 'F':
+ value.reset(new FieldTableValue());
+ break;
+
+ //non-standard types, introduced in java client for JMS compliance
+ case 'x':
+ value.reset(new BinaryValue());
+ break;
+ default:
+ std::stringstream out;
+ out << "Unknown field table value type: " << type;
+ THROW_QPID_ERROR(FRAMING_ERROR, out.str());
+ }
+ value->decode(buffer);
+ return value;
+}
+
+EmptyValue::~EmptyValue() {}
+
+void EmptyValue::print(std::ostream& out) const
+{
+ out << "<empty field value>";
+}
+
+std::ostream& operator<<(std::ostream& out, const Value& v) {
+ v.print(out);
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const Decimal& d)
+{
+ return out << "Decimal(" << d.value << "," << d.decimals << ")";
+}
+
+}}
+
+
+
diff --git a/cpp/lib/common/framing/Value.h b/cpp/lib/common/framing/Value.h
new file mode 100644
index 0000000000..8752b02f40
--- /dev/null
+++ b/cpp/lib/common/framing/Value.h
@@ -0,0 +1,171 @@
+/*
+ *
+ * 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 <iostream>
+#include <vector>
+#include <amqp_types.h>
+#include <FieldTable.h>
+
+#ifndef _Value_
+#define _Value_
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+
+/**
+ * Represents a decimal value.
+ * No arithmetic functionality for now, we only care about encoding/decoding.
+ */
+struct Decimal {
+ uint32_t value;
+ uint8_t decimals;
+
+ Decimal(uint32_t value_=0, uint8_t decimals_=0) : value(value_), decimals(decimals_) {}
+ bool operator==(const Decimal& d) const {
+ return decimals == d.decimals && value == d.value;
+ }
+ bool operator!=(const Decimal& d) const { return !(*this == d); }
+};
+
+std::ostream& operator<<(std::ostream& out, const Decimal& d);
+
+/**
+ * Polymorpic base class for values.
+ */
+class Value {
+ public:
+ virtual ~Value();
+ virtual uint32_t size() const = 0;
+ virtual char getType() const = 0;
+ virtual void encode(Buffer& buffer) = 0;
+ virtual void decode(Buffer& buffer) = 0;
+ virtual bool operator==(const Value&) const = 0;
+ bool operator!=(const Value& v) const { return !(*this == v); }
+ virtual void print(std::ostream& out) const = 0;
+
+ /** Create a new value by decoding from the buffer */
+ static std::auto_ptr<Value> decode_value(Buffer& buffer);
+};
+
+std::ostream& operator<<(std::ostream& out, const Value& d);
+
+
+/**
+ * Template for common operations on Value sub-classes.
+ */
+template <class T>
+class ValueOps : public Value
+{
+ protected:
+ T value;
+ public:
+ ValueOps() {}
+ ValueOps(const T& v) : value(v) {}
+ const T& getValue() const { return value; }
+ T& getValue() { return value; }
+
+ virtual bool operator==(const Value& v) const {
+ const ValueOps<T>* vo = dynamic_cast<const ValueOps<T>*>(&v);
+ if (vo == 0) return false;
+ else return value == vo->value;
+ }
+
+ void print(std::ostream& out) const { out << value; }
+};
+
+
+class StringValue : public ValueOps<std::string> {
+ public:
+ StringValue(const std::string& v) : ValueOps<std::string>(v) {}
+ StringValue() {}
+ virtual uint32_t size() const { return 4 + value.length(); }
+ virtual char getType() const { return 'S'; }
+ virtual void encode(Buffer& buffer);
+ virtual void decode(Buffer& buffer);
+};
+
+class IntegerValue : public ValueOps<int> {
+ public:
+ IntegerValue(int v) : ValueOps<int>(v) {}
+ IntegerValue(){}
+ virtual uint32_t size() const { return 4; }
+ virtual char getType() const { return 'I'; }
+ virtual void encode(Buffer& buffer);
+ virtual void decode(Buffer& buffer);
+};
+
+class TimeValue : public ValueOps<uint64_t> {
+ public:
+ TimeValue(uint64_t v) : ValueOps<uint64_t>(v){}
+ TimeValue(){}
+ virtual uint32_t size() const { return 8; }
+ virtual char getType() const { return 'T'; }
+ virtual void encode(Buffer& buffer);
+ virtual void decode(Buffer& buffer);
+};
+
+class DecimalValue : public ValueOps<Decimal> {
+ public:
+ DecimalValue(const Decimal& d) : ValueOps<Decimal>(d) {}
+ DecimalValue(uint32_t value_=0, uint8_t decimals_=0) :
+ ValueOps<Decimal>(Decimal(value_, decimals_)){}
+ virtual uint32_t size() const { return 5; }
+ virtual char getType() const { return 'D'; }
+ virtual void encode(Buffer& buffer);
+ virtual void decode(Buffer& buffer);
+};
+
+
+class FieldTableValue : public ValueOps<FieldTable> {
+ public:
+ FieldTableValue(const FieldTable& v) : ValueOps<FieldTable>(v){}
+ FieldTableValue(){}
+ virtual uint32_t size() const { return 4 + value.size(); }
+ virtual char getType() const { return 'F'; }
+ virtual void encode(Buffer& buffer);
+ virtual void decode(Buffer& buffer);
+};
+
+class EmptyValue : public Value {
+ public:
+ ~EmptyValue();
+ virtual uint32_t size() const { return 0; }
+ virtual char getType() const { return 0; }
+ virtual void encode(Buffer& ) {}
+ virtual void decode(Buffer& ) {}
+ virtual bool operator==(const Value& v) const {
+ return dynamic_cast<const EmptyValue*>(&v);
+ }
+ virtual void print(std::ostream& out) const;
+};
+
+//non-standard types, introduced in java client for JMS compliance
+class BinaryValue : public StringValue {
+ public:
+ BinaryValue(const std::string& v) : StringValue(v) {}
+ BinaryValue() {}
+ virtual char getType() const { return 'x'; }
+};
+
+}} // qpid::framing
+
+#endif
diff --git a/cpp/lib/common/framing/amqp_framing.h b/cpp/lib/common/framing/amqp_framing.h
new file mode 100644
index 0000000000..62f87352f8
--- /dev/null
+++ b/cpp/lib/common/framing/amqp_framing.h
@@ -0,0 +1,36 @@
+/*
+ *
+ * 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 <amqp_types.h>
+#include <AMQFrame.h>
+#include <AMQBody.h>
+#include <BodyHandler.h>
+#include <AMQMethodBody.h>
+#include <AMQHeaderBody.h>
+#include <AMQContentBody.h>
+#include <AMQHeartbeatBody.h>
+#include <AMQP_MethodVersionMap.h>
+#include <InputHandler.h>
+#include <OutputHandler.h>
+#include <InitiationHandler.h>
+#include <ProtocolInitiation.h>
+#include <BasicHeaderProperties.h>
+#include <ProtocolVersion.h>
+#include <ProtocolVersionException.h>
diff --git a/cpp/lib/common/framing/amqp_types.h b/cpp/lib/common/framing/amqp_types.h
new file mode 100644
index 0000000000..49963bd570
--- /dev/null
+++ b/cpp/lib/common/framing/amqp_types.h
@@ -0,0 +1,57 @@
+#ifndef AMQP_TYPES_H
+#define AMQP_TYPES_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.
+ *
+ */
+
+/** \file
+ * Type definitions and forward declarations of all types used to
+ * in AMQP messages.
+ */
+
+#include <string>
+#ifdef _WINDOWS
+#include "windows.h"
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned __int64 uint64_t;
+#endif
+#ifndef _WINDOWS
+#include "stdint.h"
+#endif
+
+namespace qpid {
+namespace framing {
+
+using std::string;
+typedef uint16_t ChannelId;
+typedef uint64_t RequestId;
+typedef uint64_t ResponseId;
+typedef uint32_t BatchOffset;
+typedef uint16_t ClassId;
+typedef uint16_t MethodId;
+typedef uint16_t ReplyCode;
+
+// Types represented by classes.
+class Content;
+class FieldTable;
+}} // namespace qpid::framing
+#endif
diff --git a/cpp/lib/common/framing/amqp_types_full.h b/cpp/lib/common/framing/amqp_types_full.h
new file mode 100644
index 0000000000..6a24a99d38
--- /dev/null
+++ b/cpp/lib/common/framing/amqp_types_full.h
@@ -0,0 +1,36 @@
+#ifndef _framing_amqp_types_decl_h
+#define _framing_amqp_types_decl_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.
+ *
+ */
+
+/** \file
+ * Type definitions and full declarations of all types used to
+ * in AMQP messages.
+ *
+ * Its better to include amqp_types.h in another header instead of this file
+ * unless the header actually needs the full declarations. Including
+ * full declarations when forward declarations would do increases compile
+ * times.
+ */
+
+#include "amqp_types.h"
+#include "FramingContent.h"
+#include "FieldTable.h"
+
+#endif /*!_framing_amqp_types_decl_h*/
diff --git a/cpp/lib/common/sys/Acceptor.h b/cpp/lib/common/sys/Acceptor.h
new file mode 100644
index 0000000000..f571dcbddd
--- /dev/null
+++ b/cpp/lib/common/sys/Acceptor.h
@@ -0,0 +1,47 @@
+#ifndef _sys_Acceptor_h
+#define _sys_Acceptor_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 <stdint.h>
+#include <SharedObject.h>
+
+namespace qpid {
+namespace sys {
+
+class ConnectionInputHandlerFactory;
+
+class Acceptor : public qpid::SharedObject<Acceptor>
+{
+ public:
+ static Acceptor::shared_ptr create(int16_t port, int backlog, int threads, bool trace = false);
+ virtual ~Acceptor() = 0;
+ virtual int16_t getPort() const = 0;
+ virtual void run(qpid::sys::ConnectionInputHandlerFactory* factory) = 0;
+ virtual void shutdown() = 0;
+};
+
+}}
+
+
+
+#endif /*!_sys_Acceptor_h*/
diff --git a/cpp/lib/common/sys/AtomicCount.h b/cpp/lib/common/sys/AtomicCount.h
new file mode 100644
index 0000000000..63670cbf00
--- /dev/null
+++ b/cpp/lib/common/sys/AtomicCount.h
@@ -0,0 +1,53 @@
+#ifndef _posix_AtomicCount_h
+#define _posix_AtomicCount_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <boost/detail/atomic_count.hpp>
+#include "ScopedIncrement.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Atomic counter.
+ */
+class AtomicCount : boost::noncopyable {
+ public:
+ typedef ScopedDecrement<AtomicCount> ScopedDecrement;
+ typedef ScopedIncrement<AtomicCount> ScopedIncrement;
+
+ AtomicCount(long value = 0) : count(value) {}
+
+ void operator++() { ++count ; }
+
+ long operator--() { return --count; }
+
+ operator long() const { return count; }
+
+
+ private:
+ boost::detail::atomic_count count;
+};
+
+
+}}
+
+
+#endif // _posix_AtomicCount_h
diff --git a/cpp/lib/common/sys/Condition.h b/cpp/lib/common/sys/Condition.h
new file mode 100644
index 0000000000..9d70af5b84
--- /dev/null
+++ b/cpp/lib/common/sys/Condition.h
@@ -0,0 +1,128 @@
+#ifndef _sys_Condition_h
+#define _sys_Condition_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 <sys/errno.h>
+#include <boost/noncopyable.hpp>
+#include <sys/Mutex.h>
+#include <sys/Time.h>
+
+#ifdef USE_APR
+# include <apr_thread_cond.h>
+#endif
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A condition variable for thread synchronization.
+ */
+class Condition
+{
+ public:
+ inline Condition();
+ inline ~Condition();
+ inline void wait(Mutex&);
+ inline bool wait(Mutex&, const Time& absoluteTime);
+ inline void notify();
+ inline void notifyAll();
+
+ private:
+#ifdef USE_APR
+ apr_thread_cond_t* condition;
+#else
+ pthread_cond_t condition;
+#endif
+};
+
+
+// APR ================================================================
+#ifdef USE_APR
+
+Condition::Condition() {
+ CHECK_APR_SUCCESS(apr_thread_cond_create(&condition, APRPool::get()));
+}
+
+Condition::~Condition() {
+ CHECK_APR_SUCCESS(apr_thread_cond_destroy(condition));
+}
+
+void Condition::wait(Mutex& mutex) {
+ CHECK_APR_SUCCESS(apr_thread_cond_wait(condition, mutex.mutex));
+}
+
+bool Condition::wait(Mutex& mutex, const Time& absoluteTime){
+ // APR uses microseconds.
+ apr_status_t status =
+ apr_thread_cond_timedwait(
+ condition, mutex.mutex, absoluteTime/TIME_USEC);
+ if(status != APR_TIMEUP) CHECK_APR_SUCCESS(status);
+ return status == 0;
+}
+
+void Condition::notify(){
+ CHECK_APR_SUCCESS(apr_thread_cond_signal(condition));
+}
+
+void Condition::notifyAll(){
+ CHECK_APR_SUCCESS(apr_thread_cond_broadcast(condition));
+}
+
+#else
+// POSIX ================================================================
+
+Condition::Condition() {
+ QPID_POSIX_THROW_IF(pthread_cond_init(&condition, 0));
+}
+
+Condition::~Condition() {
+ QPID_POSIX_THROW_IF(pthread_cond_destroy(&condition));
+}
+
+void Condition::wait(Mutex& mutex) {
+ QPID_POSIX_THROW_IF(pthread_cond_wait(&condition, &mutex.mutex));
+}
+
+bool Condition::wait(Mutex& mutex, const Time& absoluteTime){
+ struct timespec ts;
+ toTimespec(ts, absoluteTime);
+ int status = pthread_cond_timedwait(&condition, &mutex.mutex, &ts);
+ if (status != 0) {
+ if (status == ETIMEDOUT) return false;
+ throw QPID_POSIX_ERROR(status);
+ }
+ return true;
+}
+
+void Condition::notify(){
+ QPID_POSIX_THROW_IF(pthread_cond_signal(&condition));
+}
+
+void Condition::notifyAll(){
+ QPID_POSIX_THROW_IF(pthread_cond_broadcast(&condition));
+}
+#endif /*USE_APR*/
+
+
+}}
+#endif /*!_sys_Condition_h*/
diff --git a/cpp/lib/common/sys/ConnectionInputHandler.h b/cpp/lib/common/sys/ConnectionInputHandler.h
new file mode 100644
index 0000000000..fa70dfaf48
--- /dev/null
+++ b/cpp/lib/common/sys/ConnectionInputHandler.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ConnectionInputHandler_
+#define _ConnectionInputHandler_
+
+#include <InputHandler.h>
+#include <InitiationHandler.h>
+#include <ProtocolInitiation.h>
+#include <sys/TimeoutHandler.h>
+
+namespace qpid {
+namespace sys {
+
+ class ConnectionInputHandler :
+ public qpid::framing::InitiationHandler,
+ public qpid::framing::InputHandler,
+ public TimeoutHandler
+ {
+ public:
+ virtual void closed() = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/sys/ConnectionInputHandlerFactory.h b/cpp/lib/common/sys/ConnectionInputHandlerFactory.h
new file mode 100644
index 0000000000..af7d411928
--- /dev/null
+++ b/cpp/lib/common/sys/ConnectionInputHandlerFactory.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ConnectionInputHandlerFactory_
+#define _ConnectionInputHandlerFactory_
+
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace sys {
+
+class ConnectionOutputHandler;
+class ConnectionInputHandler;
+
+/**
+ * Callback interface used by the Acceptor to
+ * create a ConnectionInputHandler for each new connection.
+ */
+class ConnectionInputHandlerFactory : private boost::noncopyable
+{
+ public:
+ virtual ConnectionInputHandler* create(ConnectionOutputHandler* ctxt) = 0;
+ virtual ~ConnectionInputHandlerFactory(){}
+};
+
+}}
+
+
+#endif
diff --git a/cpp/lib/common/sys/ConnectionOutputHandler.h b/cpp/lib/common/sys/ConnectionOutputHandler.h
new file mode 100644
index 0000000000..91849e1dfb
--- /dev/null
+++ b/cpp/lib/common/sys/ConnectionOutputHandler.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ConnectionOutputHandler_
+#define _ConnectionOutputHandler_
+
+#include <OutputHandler.h>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Provides the output handler associated with a connection.
+ */
+class ConnectionOutputHandler : public virtual qpid::framing::OutputHandler
+{
+ public:
+ virtual void close() = 0;
+};
+
+}}
+
+
+#endif
diff --git a/cpp/lib/common/sys/Module.h b/cpp/lib/common/sys/Module.h
new file mode 100644
index 0000000000..9bf5d6e1fc
--- /dev/null
+++ b/cpp/lib/common/sys/Module.h
@@ -0,0 +1,161 @@
+#ifndef _sys_Module_h
+#define _sys_Module_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 <boost/noncopyable.hpp>
+#include <iostream>
+#include <QpidError.h>
+
+namespace qpid {
+namespace sys {
+#if USE_APR
+#include <apr_dso.h>
+ typedef apr_dso_handle_t* dso_handle_t;
+#else
+ typedef void* dso_handle_t;
+#endif
+
+ template <class T> class Module : private boost::noncopyable
+ {
+ typedef T* create_t();
+ typedef void destroy_t(T*);
+
+ dso_handle_t handle;
+ destroy_t* destroy;
+ T* ptr;
+
+ void load(const std::string& name);
+ void unload();
+ void* getSymbol(const std::string& name);
+
+ public:
+ Module(const std::string& name);
+ T* operator->();
+ T* get();
+ ~Module() throw();
+ };
+
+}
+}
+
+using namespace qpid::sys;
+
+template <class T> Module<T>::Module(const std::string& module) : destroy(0), ptr(0)
+{
+ load(module);
+ //TODO: need a better strategy for symbol names to allow multiple
+ //modules to be loaded without clashes...
+
+ //Note: need the double cast to avoid errors in casting from void* to function pointer with -pedantic
+ create_t* create = reinterpret_cast<create_t*>(reinterpret_cast<intptr_t>(getSymbol("create")));
+ destroy = reinterpret_cast<destroy_t*>(reinterpret_cast<intptr_t>(getSymbol("destroy")));
+ ptr = create();
+}
+
+template <class T> T* Module<T>::operator->()
+{
+ return ptr;
+}
+
+template <class T> T* Module<T>::get()
+{
+ return ptr;
+}
+
+template <class T> Module<T>::~Module() throw()
+{
+ try {
+ if (handle && ptr) {
+ destroy(ptr);
+ }
+ if (handle) unload();
+ } catch (std::exception& e) {
+ std::cout << "Error while destroying module: " << e.what() << std::endl;
+ }
+ destroy = 0;
+ handle = 0;
+ ptr = 0;
+}
+
+// APR ================================================================
+#if USE_APR
+
+#include <apr/APRBase.h>
+#include <apr/APRPool.h>
+
+template <class T> void Module<T>::load(const std::string& name)
+{
+ CHECK_APR_SUCCESS(apr_dso_load(&handle, name.c_str(), APRPool::get()));
+}
+
+template <class T> void Module<T>::unload()
+{
+ CHECK_APR_SUCCESS(apr_dso_unload(handle));
+}
+
+template <class T> void* Module<T>::getSymbol(const std::string& name)
+{
+ apr_dso_handle_sym_t symbol;
+ CHECK_APR_SUCCESS(apr_dso_sym(&symbol, handle, name.c_str()));
+ return (void*) symbol;
+}
+
+// POSIX================================================================
+#else
+
+#include <dlfcn.h>
+
+template <class T> void Module<T>::load(const std::string& name)
+{
+ dlerror();
+ handle = dlopen(name.c_str(), RTLD_NOW);
+ const char* error = dlerror();
+ if (error) {
+ THROW_QPID_ERROR(INTERNAL_ERROR, error);
+ }
+}
+
+template <class T> void Module<T>::unload()
+{
+ dlerror();
+ dlclose(handle);
+ const char* error = dlerror();
+ if (error) {
+ THROW_QPID_ERROR(INTERNAL_ERROR, error);
+ }
+}
+
+template <class T> void* Module<T>::getSymbol(const std::string& name)
+{
+ dlerror();
+ void* sym = dlsym(handle, name.c_str());
+ const char* error = dlerror();
+ if (error) {
+ THROW_QPID_ERROR(INTERNAL_ERROR, error);
+ }
+ return sym;
+}
+
+#endif //if USE_APR
+
+#endif //ifndef _sys_Module_h
+
diff --git a/cpp/lib/common/sys/Monitor.h b/cpp/lib/common/sys/Monitor.h
new file mode 100644
index 0000000000..a3bbd3c5aa
--- /dev/null
+++ b/cpp/lib/common/sys/Monitor.h
@@ -0,0 +1,55 @@
+#ifndef _sys_Monitor_h
+#define _sys_Monitor_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 <sys/errno.h>
+#include <sys/Condition.h>
+
+#ifdef USE_APR
+# include <apr_thread_cond.h>
+#endif
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A monitor is a condition variable and a mutex
+ */
+class Monitor : public Mutex, public Condition {
+ public:
+ using Condition::wait;
+ inline void wait();
+ inline bool wait(const Time& absoluteTime);
+};
+
+
+void Monitor::wait() {
+ Condition::wait(*this);
+}
+
+bool Monitor::wait(const Time& absoluteTime) {
+ return Condition::wait(*this, absoluteTime);
+}
+
+}}
+#endif /*!_sys_Monitor_h*/
diff --git a/cpp/lib/common/sys/Mutex.h b/cpp/lib/common/sys/Mutex.h
new file mode 100644
index 0000000000..9db9be0981
--- /dev/null
+++ b/cpp/lib/common/sys/Mutex.h
@@ -0,0 +1,165 @@
+#ifndef _sys_Mutex_h
+#define _sys_Mutex_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.
+ *
+ */
+
+#ifdef USE_APR
+# include <apr_thread_mutex.h>
+# include <apr/APRBase.h>
+# include <apr/APRPool.h>
+#else
+# include <pthread.h>
+# include <posix/check.h>
+#endif
+#include <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace sys {
+
+class Condition;
+
+/**
+ * Scoped lock template: calls lock() in ctor, unlock() in dtor.
+ * L can be any class with lock() and unlock() functions.
+ */
+template <class L>
+class ScopedLock
+{
+ public:
+ ScopedLock(L& l) : mutex(l) { l.lock(); }
+ ~ScopedLock() { mutex.unlock(); }
+ private:
+ L& mutex;
+};
+
+template <class L>
+class ScopedUnlock
+{
+ public:
+ ScopedUnlock(L& l) : mutex(l) { l.unlock(); }
+ ~ScopedUnlock() { mutex.lock(); }
+ private:
+ L& mutex;
+};
+
+/**
+ * Mutex lock.
+ */
+class Mutex : private boost::noncopyable {
+ public:
+ typedef ScopedLock<Mutex> ScopedLock;
+ typedef ScopedUnlock<Mutex> ScopedUnlock;
+
+ inline Mutex();
+ inline ~Mutex();
+ inline void lock();
+ inline void unlock();
+ inline void trylock();
+
+ protected:
+#ifdef USE_APR
+ apr_thread_mutex_t* mutex;
+#else
+ pthread_mutex_t mutex;
+#endif
+ friend class Condition;
+};
+
+#ifdef USE_APR
+// APR ================================================================
+
+Mutex::Mutex() {
+ CHECK_APR_SUCCESS(apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, APRPool::get()));
+}
+
+Mutex::~Mutex(){
+ CHECK_APR_SUCCESS(apr_thread_mutex_destroy(mutex));
+}
+
+void Mutex::lock() {
+ CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
+}
+void Mutex::unlock() {
+ CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex));
+}
+
+void Mutex::trylock() {
+ CHECK_APR_SUCCESS(apr_thread_mutex_trylock(mutex));
+}
+
+#else
+// POSIX ================================================================
+
+/**
+ * PODMutex is a POD, can be static-initialized with
+ * PODMutex m = QPID_PODMUTEX_INITIALIZER
+ */
+struct PODMutex
+{
+ typedef ScopedLock<PODMutex> ScopedLock;
+
+ inline void lock();
+ inline void unlock();
+ inline void trylock();
+
+ // Must be public to be a POD:
+ pthread_mutex_t mutex;
+};
+
+#define QPID_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
+
+
+void PODMutex::lock() {
+ QPID_POSIX_THROW_IF(pthread_mutex_lock(&mutex));
+}
+void PODMutex::unlock() {
+ QPID_POSIX_THROW_IF(pthread_mutex_unlock(&mutex));
+}
+
+void PODMutex::trylock() {
+ QPID_POSIX_THROW_IF(pthread_mutex_trylock(&mutex));
+}
+
+
+Mutex::Mutex() {
+ QPID_POSIX_THROW_IF(pthread_mutex_init(&mutex, 0));
+}
+
+Mutex::~Mutex(){
+ QPID_POSIX_THROW_IF(pthread_mutex_destroy(&mutex));
+}
+
+void Mutex::lock() {
+ QPID_POSIX_THROW_IF(pthread_mutex_lock(&mutex));
+}
+void Mutex::unlock() {
+ QPID_POSIX_THROW_IF(pthread_mutex_unlock(&mutex));
+}
+
+void Mutex::trylock() {
+ QPID_POSIX_THROW_IF(pthread_mutex_trylock(&mutex));
+}
+
+#endif // USE_APR
+
+}}
+
+
+
+#endif /*!_sys_Mutex_h*/
diff --git a/cpp/lib/common/sys/ProducerConsumer.cpp b/cpp/lib/common/sys/ProducerConsumer.cpp
new file mode 100644
index 0000000000..3f6156f230
--- /dev/null
+++ b/cpp/lib/common/sys/ProducerConsumer.cpp
@@ -0,0 +1,141 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "QpidError.h"
+#include "ScopedIncrement.h"
+#include "ProducerConsumer.h"
+
+namespace qpid {
+namespace sys {
+
+// // ================ ProducerConsumer
+
+ProducerConsumer::ProducerConsumer(size_t init_items)
+ : items(init_items), waiters(0), stopped(false)
+{}
+
+void ProducerConsumer::stop() {
+ Mutex::ScopedLock l(monitor);
+ stopped = true;
+ monitor.notifyAll();
+ // Wait for waiting consumers to wake up.
+ while (waiters > 0)
+ monitor.wait();
+}
+
+size_t ProducerConsumer::available() const {
+ Mutex::ScopedLock l(monitor);
+ return items;
+}
+
+size_t ProducerConsumer::consumers() const {
+ Mutex::ScopedLock l(monitor);
+ return waiters;
+}
+
+// ================ Lock
+
+ProducerConsumer::Lock::Lock(ProducerConsumer& p)
+ : pc(p), lock(p.monitor), status(INCOMPLETE) {}
+
+bool ProducerConsumer::Lock::isOk() const {
+ return !pc.isStopped() && status==INCOMPLETE;
+}
+
+void ProducerConsumer::Lock::checkOk() const {
+ assert(!pc.isStopped());
+ assert(status == INCOMPLETE);
+}
+
+ProducerConsumer::Lock::~Lock() {
+ assert(status != INCOMPLETE || pc.isStopped());
+}
+
+void ProducerConsumer::Lock::confirm() {
+ checkOk();
+ status = CONFIRMED;
+}
+
+void ProducerConsumer::Lock::cancel() {
+ checkOk();
+ status = CANCELLED;
+}
+
+// ================ ProducerLock
+
+ProducerConsumer::ProducerLock::ProducerLock(ProducerConsumer& p) : Lock(p)
+{}
+
+
+ProducerConsumer::ProducerLock::~ProducerLock() {
+ if (status == CONFIRMED) {
+ pc.items++;
+ pc.monitor.notify(); // Notify a consumer.
+ }
+}
+
+// ================ ConsumerLock
+
+ProducerConsumer::ConsumerLock::ConsumerLock(ProducerConsumer& p) : Lock(p)
+{
+ if (isOk()) {
+ ScopedIncrement<size_t> inc(pc.waiters);
+ while (pc.items == 0 && !pc.stopped) {
+ pc.monitor.wait();
+ }
+ }
+}
+
+ProducerConsumer::ConsumerLock::ConsumerLock(
+ ProducerConsumer& p, const Time& timeout) : Lock(p)
+{
+ if (isOk()) {
+ // Don't wait if timeout==0
+ if (timeout == 0) {
+ if (pc.items == 0)
+ status = TIMEOUT;
+ return;
+ }
+ else {
+ Time deadline = now() + timeout;
+ ScopedIncrement<size_t> inc(pc.waiters);
+ while (pc.items == 0 && !pc.stopped) {
+ if (!pc.monitor.wait(deadline)) {
+ status = TIMEOUT;
+ return;
+ }
+ }
+ }
+ }
+}
+
+ProducerConsumer::ConsumerLock::~ConsumerLock() {
+ if (pc.isStopped()) {
+ if (pc.waiters == 0)
+ pc.monitor.notifyAll(); // All waiters woken, notify stop thread(s)
+ }
+ else if (status==CONFIRMED) {
+ pc.items--;
+ if (pc.items > 0)
+ pc.monitor.notify(); // Notify another consumer.
+ }
+}
+
+
+}} // namespace qpid::sys
diff --git a/cpp/lib/common/sys/ProducerConsumer.h b/cpp/lib/common/sys/ProducerConsumer.h
new file mode 100644
index 0000000000..742639323b
--- /dev/null
+++ b/cpp/lib/common/sys/ProducerConsumer.h
@@ -0,0 +1,165 @@
+#ifndef _sys_ProducerConsumer_h
+#define _sys_ProducerConsumer_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <boost/noncopyable.hpp>
+#include "Exception.h"
+#include "sys/Monitor.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Producer-consumer synchronisation.
+ *
+ * Producers increase the number of available items, consumers reduce it.
+ * Consumers wait till an item is available. Waiting threads can be
+ * woken for shutdown using stop().
+ *
+ * Note: Currently implements unbounded producer-consumer, i.e. no limit
+ * to available items, producers never block. Can be extended to support
+ * bounded PC if required.
+ *
+ // TODO aconway 2007-02-13: example, from tests.
+*/
+class ProducerConsumer
+{
+ public:
+ ProducerConsumer(size_t init_items=0);
+
+ ~ProducerConsumer() { stop(); }
+
+ /**
+ * Wake any threads waiting for ProducerLock or ConsumerLock.
+ *@post No threads are waiting in Producer or Consumer locks.
+ */
+ void stop();
+
+ /** True if queue is stopped */
+ bool isStopped() { return stopped; }
+
+ /** Number of items available for consumers */
+ size_t available() const;
+
+ /** Number of consumers waiting for items */
+ size_t consumers() const;
+
+ /** True if available == 0 */
+ bool empty() const { return available() == 0; }
+
+ /**
+ * Base class for producer and consumer locks.
+ */
+ class Lock : private boost::noncopyable {
+ public:
+
+ /**
+ * You must call isOk() after creating a lock to verify its state.
+ *
+ *@return true means the lock succeeded. You MUST call either
+ *confirm() or cancel() before the lock goes out of scope.
+ *
+ * false means the lock failed - timed out or the
+ * ProducerConsumer is stopped. You should not do anything in
+ * the scope of the lock.
+ */
+ bool isOk() const;
+
+ /**
+ * Confirm that an item was produced/consumed.
+ *@pre isOk()
+ */
+ void confirm();
+
+ /**
+ * Cancel the lock to indicate nothing was produced/consumed.
+ * Note that locks are not actually released until destroyed.
+ *
+ *@pre isOk()
+ */
+ void cancel();
+
+ /** True if this lock experienced a timeout */
+ bool isTimedOut() const { return status == TIMEOUT; }
+
+ /** True if we have been stopped */
+ bool isStopped() const { return pc.isStopped(); }
+
+ ProducerConsumer& pc;
+
+ protected:
+ /** Lock status */
+ enum Status { INCOMPLETE, CONFIRMED, CANCELLED, TIMEOUT };
+
+ Lock(ProducerConsumer& p);
+ ~Lock();
+ void checkOk() const;
+ Mutex::ScopedLock lock;
+ Status status;
+ };
+
+ /** Lock for code that produces items. */
+ struct ProducerLock : public Lock {
+ /**
+ * Acquire locks to produce an item.
+ *@post If isOk() the calling thread has exclusive access
+ * to produce an item.
+ */
+ ProducerLock(ProducerConsumer& p);
+
+ /** Release locks, signal waiting consumers if confirm() was called. */
+ ~ProducerLock();
+ };
+
+ /** Lock for code that consumes items */
+ struct ConsumerLock : public Lock {
+ /**
+ * Wait for an item to consume and acquire locks.
+ *
+ *@post If isOk() there is at least one item available and the
+ *calling thread has exclusive access to consume it.
+ */
+ ConsumerLock(ProducerConsumer& p);
+
+ /**
+ * Wait up to timeout to acquire lock.
+ *@post If isOk() caller has a producer lock.
+ * If isTimedOut() there was a timeout.
+ * If neither then we were stopped.
+ */
+ ConsumerLock(ProducerConsumer& p, const Time& timeout);
+
+ /** Release locks */
+ ~ConsumerLock();
+ };
+
+ private:
+ mutable Monitor monitor;
+ size_t items;
+ size_t waiters;
+ bool stopped;
+
+ friend class Lock;
+ friend class ProducerLock;
+ friend class ConsumerLock;
+};
+
+}} // namespace qpid::sys
+
+#endif /*!_sys_ProducerConsumer_h*/
diff --git a/cpp/lib/common/sys/Runnable.cpp b/cpp/lib/common/sys/Runnable.cpp
new file mode 100644
index 0000000000..30122c682f
--- /dev/null
+++ b/cpp/lib/common/sys/Runnable.cpp
@@ -0,0 +1,32 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "Runnable.h"
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace sys {
+
+Runnable::~Runnable() {}
+
+Runnable::Functor Runnable::functor()
+{
+ return boost::bind(&Runnable::run, this);
+}
+
+}}
diff --git a/cpp/lib/common/sys/Runnable.h b/cpp/lib/common/sys/Runnable.h
new file mode 100644
index 0000000000..fb3927c612
--- /dev/null
+++ b/cpp/lib/common/sys/Runnable.h
@@ -0,0 +1,50 @@
+#ifndef _Runnable_
+#define _Runnable_
+/*
+ *
+ * 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 <boost/function.hpp>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Interface for objects that can be run, e.g. in a thread.
+ */
+class Runnable
+{
+ public:
+ /** Type to represent a runnable as a Functor */
+ typedef boost::function0<void> Functor;
+
+ virtual ~Runnable();
+
+ /** Derived classes override run(). */
+ virtual void run() = 0;
+
+ /** Create a functor object that will call this->run(). */
+ Functor functor();
+};
+
+}}
+
+
+#endif
diff --git a/cpp/lib/common/sys/ScopedIncrement.h b/cpp/lib/common/sys/ScopedIncrement.h
new file mode 100644
index 0000000000..f14461ddaf
--- /dev/null
+++ b/cpp/lib/common/sys/ScopedIncrement.h
@@ -0,0 +1,59 @@
+#ifndef _posix_ScopedIncrement_h
+#define _posix_ScopedIncrement_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <boost/noncopyable.hpp>
+
+namespace qpid {
+namespace sys {
+
+/** Increment counter in constructor and decrement in destructor. */
+template <class T>
+class ScopedIncrement : boost::noncopyable
+{
+ public:
+ ScopedIncrement(T& c) : count(c) { ++count; }
+ ~ScopedIncrement() { --count; }
+ private:
+ T& count;
+};
+
+
+/** Decrement counter in constructor and increment in destructor. */
+template <class T>
+class ScopedDecrement : boost::noncopyable
+{
+ public:
+ ScopedDecrement(T& c) : count(c) { value = --count; }
+ ~ScopedDecrement() { ++count; }
+
+ /** Return the value after the decrement. */
+ operator long() { return value; }
+
+ private:
+ T& count;
+ long value;
+};
+
+
+}}
+
+
+#endif // _posix_ScopedIncrement_h
diff --git a/cpp/lib/common/sys/ShutdownHandler.h b/cpp/lib/common/sys/ShutdownHandler.h
new file mode 100644
index 0000000000..88baecb5b6
--- /dev/null
+++ b/cpp/lib/common/sys/ShutdownHandler.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ShutdownHandler_
+#define _ShutdownHandler_
+
+namespace qpid {
+namespace sys {
+
+ class ShutdownHandler
+ {
+ public:
+ virtual void shutdown() = 0;
+ virtual ~ShutdownHandler(){}
+ };
+
+}
+}
+
+#endif
diff --git a/cpp/lib/common/sys/Socket.h b/cpp/lib/common/sys/Socket.h
new file mode 100644
index 0000000000..d793a240c6
--- /dev/null
+++ b/cpp/lib/common/sys/Socket.h
@@ -0,0 +1,88 @@
+#ifndef _sys_Socket_h
+#define _sys_Socket_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 <string>
+#include <sys/Time.h>
+
+#ifdef USE_APR
+# include <apr_network_io.h>
+#endif
+
+namespace qpid {
+namespace sys {
+
+class Socket
+{
+ public:
+ /** Create an initialized TCP socket */
+ static Socket createTcp();
+
+ /** Create a socket wrapper for descriptor. */
+#ifdef USE_APR
+ Socket(apr_socket_t* descriptor = 0);
+#else
+ Socket(int descriptor = 0);
+#endif
+
+ /** Set timeout for read and write */
+ void setTimeout(Time interval);
+
+ void connect(const std::string& host, int port);
+
+ void close();
+
+ enum { SOCKET_TIMEOUT=-2, SOCKET_EOF=-3 } ErrorCode;
+
+ /** Returns bytes sent or an ErrorCode value < 0. */
+ ssize_t send(const void* data, size_t size);
+
+ /**
+ * Returns bytes received, an ErrorCode value < 0 or 0
+ * if the connection closed in an orderly manner.
+ */
+ ssize_t recv(void* data, size_t size);
+
+ /** Bind to a port and start listening.
+ *@param port 0 means choose an available port.
+ *@param backlog maximum number of pending connections.
+ *@return The bound port.
+ */
+ int listen(int port = 0, int backlog = 10);
+
+ /** Get file descriptor */
+ int fd();
+
+ private:
+#ifdef USE_APR
+ apr_socket_t* socket;
+#else
+ void init() const;
+ mutable int socket; // Initialized on demand.
+#endif
+};
+
+}}
+
+
+#endif /*!_sys_Socket_h*/
diff --git a/cpp/lib/common/sys/Thread.h b/cpp/lib/common/sys/Thread.h
new file mode 100644
index 0000000000..47b95b6234
--- /dev/null
+++ b/cpp/lib/common/sys/Thread.h
@@ -0,0 +1,142 @@
+#ifndef _sys_Thread_h
+#define _sys_Thread_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 <sys/Runnable.h>
+
+#ifdef USE_APR
+# include <apr_thread_proc.h>
+# include <apr_portable.h>
+# include <apr/APRPool.h>
+# include <apr/APRBase.h>
+#else
+# include <posix/check.h>
+# include <pthread.h>
+#endif
+
+namespace qpid {
+namespace sys {
+
+class Thread
+{
+ public:
+ inline static Thread current();
+ inline static void yield();
+
+ inline Thread();
+ inline explicit Thread(qpid::sys::Runnable*);
+ inline explicit Thread(qpid::sys::Runnable&);
+
+ inline void join();
+
+ inline long id();
+
+ private:
+#ifdef USE_APR
+ static void* APR_THREAD_FUNC runRunnable(apr_thread_t* thread, void *data);
+ inline Thread(apr_thread_t* t);
+ apr_thread_t* thread;
+#else
+ static void* runRunnable(void* runnable);
+ inline Thread(pthread_t);
+ pthread_t thread;
+#endif
+};
+
+
+Thread::Thread() : thread(0) {}
+
+// APR ================================================================
+#ifdef USE_APR
+
+Thread::Thread(Runnable* runnable) {
+ CHECK_APR_SUCCESS(
+ apr_thread_create(&thread, 0, runRunnable, runnable, APRPool::get()));
+}
+
+Thread::Thread(Runnable& runnable) {
+ CHECK_APR_SUCCESS(
+ apr_thread_create(&thread, 0, runRunnable, &runnable, APRPool::get()));
+}
+
+void Thread::join(){
+ apr_status_t status;
+ if (thread != 0)
+ CHECK_APR_SUCCESS(apr_thread_join(&status, thread));
+}
+
+long Thread::id() {
+ return long(thread);
+}
+
+Thread::Thread(apr_thread_t* t) : thread(t) {}
+
+Thread Thread::current(){
+ apr_thread_t* thr;
+ apr_os_thread_t osthr = apr_os_thread_current();
+ CHECK_APR_SUCCESS(apr_os_thread_put(&thr, &osthr, APRPool::get()));
+ return Thread(thr);
+}
+
+void Thread::yield()
+{
+ apr_thread_yield();
+}
+
+
+// POSIX ================================================================
+#else
+
+Thread::Thread(Runnable* runnable) {
+ QPID_POSIX_THROW_IF(pthread_create(&thread, NULL, runRunnable, runnable));
+}
+
+Thread::Thread(Runnable& runnable) {
+ QPID_POSIX_THROW_IF(pthread_create(&thread, NULL, runRunnable, &runnable));
+}
+
+void Thread::join(){
+ QPID_POSIX_THROW_IF(pthread_join(thread, 0));
+}
+
+long Thread::id() {
+ return long(thread);
+}
+
+Thread::Thread(pthread_t thr) : thread(thr) {}
+
+Thread Thread::current() {
+ return Thread(pthread_self());
+}
+
+void Thread::yield()
+{
+ QPID_POSIX_THROW_IF(pthread_yield());
+}
+
+
+#endif
+
+}}
+
+#endif /*!_sys_Thread_h*/
diff --git a/cpp/lib/common/sys/ThreadSafeQueue.h b/cpp/lib/common/sys/ThreadSafeQueue.h
new file mode 100644
index 0000000000..ff949a3e16
--- /dev/null
+++ b/cpp/lib/common/sys/ThreadSafeQueue.h
@@ -0,0 +1,98 @@
+#ifndef _sys_ThreadSafeQueue_h
+#define _sys_ThreadSafeQueue_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <deque>
+#include "ProducerConsumer.h"
+#include "Exception.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ * A thread safe queue template.
+ */
+template <class T, class ContainerType=std::deque<T> >
+class ThreadSafeQueue
+{
+ public:
+
+ ThreadSafeQueue() {}
+
+ /** Push a value onto the back of the queue */
+ void push(const T& value) {
+ ProducerConsumer::ProducerLock producer(pc);
+ if (producer.isOk()) {
+ producer.confirm();
+ container.push_back(value);
+ }
+ }
+
+ /** Pop a value from the front of the queue. Waits till value is available.
+ *@throw ShutdownException if queue is stopped while waiting.
+ */
+ T pop() {
+ ProducerConsumer::ConsumerLock consumer(pc);
+ if (consumer.isOk()) {
+ consumer.confirm();
+ T value(container.front());
+ container.pop_front();
+ return value;
+ }
+ throw ShutdownException();
+ }
+
+ /**
+ * If a value becomes available within the timeout, set outValue
+ * and return true. Otherwise return false;
+ */
+ bool pop(T& outValue, const Time& timeout) {
+ ProducerConsumer::ConsumerLock consumer(pc, timeout);
+ if (consumer.isOk()) {
+ consumer.confirm();
+ outValue = container.front();
+ container.pop_front();
+ return true;
+ }
+ return false;
+ }
+
+ /** Interrupt threads waiting in pop() */
+ void stop() { pc.stop(); }
+
+ /** True if queue is stopped */
+ bool isStopped() { return pc.isStopped(); }
+
+ /** Size of the queue */
+ size_t size() { ProducerConsumer::Lock l(pc); return container.size(); }
+
+ /** True if queue is empty */
+ bool empty() { ProducerConsumer::Lock l(pc); return container.empty(); }
+
+ private:
+ ProducerConsumer pc;
+ ContainerType container;
+};
+
+}} // namespace qpid::sys
+
+
+
+#endif /*!_sys_ThreadSafeQueue_h*/
diff --git a/cpp/lib/common/sys/Time.cpp b/cpp/lib/common/sys/Time.cpp
new file mode 100644
index 0000000000..ad6185b966
--- /dev/null
+++ b/cpp/lib/common/sys/Time.cpp
@@ -0,0 +1,60 @@
+/*
+ *
+ * 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 "Time.h"
+
+namespace qpid {
+namespace sys {
+
+// APR ================================================================
+#if USE_APR
+
+Time now() { return apr_time_now() * TIME_USEC; }
+
+// POSIX================================================================
+#else
+
+Time now() {
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return toTime(ts);
+}
+
+struct timespec toTimespec(const Time& t) {
+ struct timespec ts;
+ toTimespec(ts, t);
+ return ts;
+}
+
+struct timespec& toTimespec(struct timespec& ts, const Time& t) {
+ ts.tv_sec = t / TIME_SEC;
+ ts.tv_nsec = t % TIME_SEC;
+ return ts;
+}
+
+Time toTime(const struct timespec& ts) {
+ return ts.tv_sec*TIME_SEC + ts.tv_nsec;
+}
+
+
+#endif
+}}
+
diff --git a/cpp/lib/common/sys/Time.h b/cpp/lib/common/sys/Time.h
new file mode 100644
index 0000000000..3dd46741d8
--- /dev/null
+++ b/cpp/lib/common/sys/Time.h
@@ -0,0 +1,58 @@
+#ifndef _sys_Time_h
+#define _sys_Time_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 <stdint.h>
+
+#ifdef USE_APR
+# include <apr_time.h>
+#else
+# include <time.h>
+#endif
+
+namespace qpid {
+namespace sys {
+
+/** Time in nanoseconds */
+typedef int64_t Time;
+
+Time now();
+
+/** Nanoseconds per second. */
+const Time TIME_SEC = 1000*1000*1000;
+/** Nanoseconds per millisecond */
+const Time TIME_MSEC = 1000*1000;
+/** Nanoseconds per microseconds. */
+const Time TIME_USEC = 1000;
+/** Nanoseconds per nanosecond. */
+const Time TIME_NSEC = 1;
+
+#ifndef USE_APR
+struct timespec toTimespec(const Time& t);
+struct timespec& toTimespec(struct timespec& ts, const Time& t);
+Time toTime(const struct timespec& ts);
+#endif
+
+}}
+
+#endif /*!_sys_Time_h*/
diff --git a/cpp/lib/common/sys/TimeoutHandler.h b/cpp/lib/common/sys/TimeoutHandler.h
new file mode 100644
index 0000000000..0c10709bbf
--- /dev/null
+++ b/cpp/lib/common/sys/TimeoutHandler.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _TimeoutHandler_
+#define _TimeoutHandler_
+
+namespace qpid {
+namespace sys {
+
+ class TimeoutHandler
+ {
+ public:
+ virtual void idleOut() = 0;
+ virtual void idleIn() = 0;
+ virtual ~TimeoutHandler(){}
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/sys/apr/APRAcceptor.cpp b/cpp/lib/common/sys/apr/APRAcceptor.cpp
new file mode 100644
index 0000000000..52384857ed
--- /dev/null
+++ b/cpp/lib/common/sys/apr/APRAcceptor.cpp
@@ -0,0 +1,122 @@
+/*
+ *
+ * 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 <sys/Acceptor.h>
+#include <sys/ConnectionInputHandlerFactory.h>
+#include "LFProcessor.h"
+#include "LFSessionContext.h"
+#include "APRBase.h"
+#include "APRPool.h"
+
+namespace qpid {
+namespace sys {
+
+class APRAcceptor : public Acceptor
+{
+ public:
+ APRAcceptor(int16_t port, int backlog, int threads, bool trace);
+ virtual int16_t getPort() const;
+ virtual void run(qpid::sys::ConnectionInputHandlerFactory* factory);
+ virtual void shutdown();
+
+ private:
+ void shutdownImpl();
+
+ private:
+ int16_t port;
+ bool trace;
+ LFProcessor processor;
+ apr_socket_t* socket;
+ volatile bool running;
+ Mutex shutdownLock;
+};
+
+// Define generic Acceptor::create() to return APRAcceptor.
+Acceptor::shared_ptr Acceptor::create(int16_t port, int backlog, int threads, bool trace)
+{
+ return Acceptor::shared_ptr(new APRAcceptor(port, backlog, threads, trace));
+}
+// Must define Acceptor virtual dtor.
+Acceptor::~Acceptor() {}
+
+APRAcceptor::APRAcceptor(int16_t port_, int backlog, int threads, bool trace_) :
+ port(port_),
+ trace(trace_),
+ processor(APRPool::get(), threads, 1000, 5000000),
+ running(false)
+{
+ apr_sockaddr_t* address;
+ CHECK_APR_SUCCESS(apr_sockaddr_info_get(&address, APR_ANYADDR, APR_UNSPEC, port, APR_IPV4_ADDR_OK, APRPool::get()));
+ CHECK_APR_SUCCESS(apr_socket_create(&socket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, APRPool::get()));
+ CHECK_APR_SUCCESS(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1));
+ CHECK_APR_SUCCESS(apr_socket_bind(socket, address));
+ CHECK_APR_SUCCESS(apr_socket_listen(socket, backlog));
+}
+
+int16_t APRAcceptor::getPort() const {
+ apr_sockaddr_t* address;
+ CHECK_APR_SUCCESS(apr_socket_addr_get(&address, APR_LOCAL, socket));
+ return address->port;
+}
+
+void APRAcceptor::run(ConnectionInputHandlerFactory* factory) {
+ running = true;
+ processor.start();
+ std::cout << "Listening on port " << getPort() << "..." << std::endl;
+ while(running){
+ apr_socket_t* client;
+ apr_status_t status = apr_socket_accept(&client, socket, APRPool::get());
+ if(status == APR_SUCCESS){
+ //make this socket non-blocking:
+ CHECK_APR_SUCCESS(apr_socket_timeout_set(client, 0));
+ CHECK_APR_SUCCESS(apr_socket_opt_set(client, APR_SO_NONBLOCK, 1));
+ CHECK_APR_SUCCESS(apr_socket_opt_set(client, APR_TCP_NODELAY, 1));
+ CHECK_APR_SUCCESS(apr_socket_opt_set(client, APR_SO_SNDBUF, 32768));
+ CHECK_APR_SUCCESS(apr_socket_opt_set(client, APR_SO_RCVBUF, 32768));
+ LFSessionContext* session = new LFSessionContext(APRPool::get(), client, &processor, trace);
+ session->init(factory->create(session));
+ }else{
+ Mutex::ScopedLock locker(shutdownLock);
+ if(running) {
+ if(status != APR_EINTR){
+ std::cout << "ERROR: " << get_desc(status) << std::endl;
+ }
+ shutdownImpl();
+ }
+ }
+ }
+}
+
+void APRAcceptor::shutdown() {
+ Mutex::ScopedLock locker(shutdownLock);
+ if (running) {
+ shutdownImpl();
+ }
+}
+
+void APRAcceptor::shutdownImpl() {
+ Mutex::ScopedLock locker(shutdownLock);
+ running = false;
+ processor.stop();
+ CHECK_APR_SUCCESS(apr_socket_close(socket));
+}
+
+
+}}
diff --git a/cpp/lib/common/sys/apr/APRBase.cpp b/cpp/lib/common/sys/apr/APRBase.cpp
new file mode 100644
index 0000000000..861071499f
--- /dev/null
+++ b/cpp/lib/common/sys/apr/APRBase.cpp
@@ -0,0 +1,90 @@
+/*
+ *
+ * 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 <iostream>
+#include <QpidError.h>
+#include "APRBase.h"
+
+using namespace qpid::sys;
+
+APRBase* APRBase::instance = 0;
+
+APRBase* APRBase::getInstance(){
+ if(instance == 0){
+ instance = new APRBase();
+ }
+ return instance;
+}
+
+
+APRBase::APRBase() : count(0){
+ apr_initialize();
+ CHECK_APR_SUCCESS(apr_pool_create(&pool, 0));
+ CHECK_APR_SUCCESS(apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, pool));
+}
+
+APRBase::~APRBase(){
+ CHECK_APR_SUCCESS(apr_thread_mutex_destroy(mutex));
+ apr_pool_destroy(pool);
+ apr_terminate();
+}
+
+bool APRBase::_increment(){
+ bool deleted(false);
+ CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
+ if(this == instance){
+ count++;
+ }else{
+ deleted = true;
+ }
+ CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex));
+ return !deleted;
+}
+
+void APRBase::_decrement(){
+ APRBase* copy = 0;
+ CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
+ if(--count == 0){
+ copy = instance;
+ instance = 0;
+ }
+ CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex));
+ if(copy != 0){
+ delete copy;
+ }
+}
+
+void APRBase::increment(){
+ int count = 0;
+ while(count++ < 2 && !getInstance()->_increment()){
+ std::cout << "WARNING: APR initialization triggered concurrently with termination." << std::endl;
+ }
+}
+
+void APRBase::decrement(){
+ getInstance()->_decrement();
+}
+
+std::string qpid::sys::get_desc(apr_status_t status){
+ const int size = 50;
+ char tmp[size];
+ return std::string(apr_strerror(status, tmp, size));
+}
+
diff --git a/cpp/lib/common/sys/apr/APRBase.h b/cpp/lib/common/sys/apr/APRBase.h
new file mode 100644
index 0000000000..6a866a554a
--- /dev/null
+++ b/cpp/lib/common/sys/apr/APRBase.h
@@ -0,0 +1,78 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _APRBase_
+#define _APRBase_
+
+#include <string>
+#include <apr_thread_mutex.h>
+#include <apr_errno.h>
+#include <QpidError.h>
+
+namespace qpid {
+namespace sys {
+
+ /**
+ * Use of APR libraries necessitates explicit init and terminate
+ * calls. Any class using APR libs should obtain the reference to
+ * this singleton and increment on construction, decrement on
+ * destruction. This class can then correctly initialise apr
+ * before the first use and terminate after the last use.
+ */
+ class APRBase{
+ static APRBase* instance;
+ apr_pool_t* pool;
+ apr_thread_mutex_t* mutex;
+ int count;
+
+ APRBase();
+ ~APRBase();
+ static APRBase* getInstance();
+ bool _increment();
+ void _decrement();
+ public:
+ static void increment();
+ static void decrement();
+ };
+
+ //this is also a convenient place for a helper function for error checking:
+ void check(apr_status_t status, const char* file, const int line);
+ std::string get_desc(apr_status_t status);
+
+#define CHECK_APR_SUCCESS(A) qpid::sys::check(A, __FILE__, __LINE__);
+
+}
+}
+
+// Inlined as it is called *a lot*
+void inline qpid::sys::check(apr_status_t status, const char* file, const int line){
+ if (status != APR_SUCCESS){
+ const int size = 50;
+ char tmp[size];
+ std::string msg(apr_strerror(status, tmp, size));
+ throw qpid::QpidError(APR_ERROR + ((int) status), msg,
+ qpid::SrcLine(file, line));
+ }
+}
+
+
+
+
+#endif
diff --git a/cpp/lib/common/sys/apr/APRPool.cpp b/cpp/lib/common/sys/apr/APRPool.cpp
new file mode 100644
index 0000000000..e8b71f6e8a
--- /dev/null
+++ b/cpp/lib/common/sys/apr/APRPool.cpp
@@ -0,0 +1,41 @@
+/*
+ *
+ * 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 "APRPool.h"
+#include "APRBase.h"
+#include <boost/pool/detail/singleton.hpp>
+
+using namespace qpid::sys;
+
+APRPool::APRPool(){
+ APRBase::increment();
+ CHECK_APR_SUCCESS(apr_pool_create(&pool, NULL));
+}
+
+APRPool::~APRPool(){
+ apr_pool_destroy(pool);
+ APRBase::decrement();
+}
+
+apr_pool_t* APRPool::get() {
+ return boost::details::pool::singleton_default<APRPool>::instance().pool;
+}
+
diff --git a/cpp/lib/common/sys/apr/APRPool.h b/cpp/lib/common/sys/apr/APRPool.h
new file mode 100644
index 0000000000..da7661fcfa
--- /dev/null
+++ b/cpp/lib/common/sys/apr/APRPool.h
@@ -0,0 +1,50 @@
+#ifndef _APRPool_
+#define _APRPool_
+
+/*
+ *
+ * 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 <boost/noncopyable.hpp>
+#include <apr_pools.h>
+
+namespace qpid {
+namespace sys {
+/**
+ * Singleton APR memory pool.
+ */
+class APRPool : private boost::noncopyable {
+ public:
+ APRPool();
+ ~APRPool();
+
+ /** Get singleton instance */
+ static apr_pool_t* get();
+
+ private:
+ apr_pool_t* pool;
+};
+
+}}
+
+
+
+
+
+#endif /*!_APRPool_*/
diff --git a/cpp/lib/common/sys/apr/APRSocket.cpp b/cpp/lib/common/sys/apr/APRSocket.cpp
new file mode 100644
index 0000000000..96dbd132a1
--- /dev/null
+++ b/cpp/lib/common/sys/apr/APRSocket.cpp
@@ -0,0 +1,78 @@
+/*
+ *
+ * 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 "APRBase.h"
+#include "APRSocket.h"
+#include <assert.h>
+#include <iostream>
+
+using namespace qpid::sys;
+using namespace qpid::framing;
+
+APRSocket::APRSocket(apr_socket_t* _socket) : socket(_socket), closed(false){
+
+}
+
+void APRSocket::read(qpid::framing::Buffer& buffer){
+ apr_size_t bytes;
+ bytes = buffer.available();
+ apr_status_t s = apr_socket_recv(socket, buffer.start(), &bytes);
+ buffer.move(bytes);
+ if(APR_STATUS_IS_TIMEUP(s)){
+ //timed out
+ }else if(APR_STATUS_IS_EOF(s)){
+ close();
+ }
+}
+
+void APRSocket::write(qpid::framing::Buffer& buffer){
+ apr_size_t bytes;
+ do{
+ bytes = buffer.available();
+ apr_socket_send(socket, buffer.start(), &bytes);
+ buffer.move(bytes);
+ }while(bytes > 0);
+}
+
+void APRSocket::close(){
+ if(!closed){
+ std::cout << "Closing socket " << socket << "@" << this << std::endl;
+ CHECK_APR_SUCCESS(apr_socket_close(socket));
+ closed = true;
+ }
+}
+
+bool APRSocket::isOpen() const {
+ return !closed;
+}
+
+uint8_t APRSocket::read(){
+ char data[1];
+ apr_size_t bytes = 1;
+ apr_status_t s = apr_socket_recv(socket, data, &bytes);
+ if(APR_STATUS_IS_EOF(s) || bytes == 0){
+ return 0;
+ }else{
+ return *data;
+ }
+}
+
+APRSocket::~APRSocket(){
+}
diff --git a/cpp/lib/common/sys/apr/APRSocket.h b/cpp/lib/common/sys/apr/APRSocket.h
new file mode 100644
index 0000000000..a55dfc06b0
--- /dev/null
+++ b/cpp/lib/common/sys/apr/APRSocket.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _APRSocket_
+#define _APRSocket_
+
+#include <apr_network_io.h>
+#include <Buffer.h>
+
+namespace qpid {
+namespace sys {
+
+ class APRSocket
+ {
+ apr_socket_t* const socket;
+ volatile bool closed;
+ public:
+ APRSocket(apr_socket_t* socket);
+ void read(qpid::framing::Buffer& b);
+ void write(qpid::framing::Buffer& b);
+ void close();
+ bool isOpen() const;
+ uint8_t read();
+ ~APRSocket();
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/sys/apr/LFProcessor.cpp b/cpp/lib/common/sys/apr/LFProcessor.cpp
new file mode 100644
index 0000000000..2b6fc92623
--- /dev/null
+++ b/cpp/lib/common/sys/apr/LFProcessor.cpp
@@ -0,0 +1,179 @@
+/*
+ *
+ * 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 <sstream>
+#include <QpidError.h>
+#include "LFProcessor.h"
+#include "APRBase.h"
+#include "LFSessionContext.h"
+
+using namespace qpid::sys;
+using qpid::QpidError;
+
+// TODO aconway 2006-10-12: stopped is read outside locks.
+//
+
+LFProcessor::LFProcessor(apr_pool_t* pool, int _workers, int _size, int _timeout) :
+ size(_size),
+ timeout(_timeout),
+ signalledCount(0),
+ current(0),
+ count(0),
+ workerCount(_workers),
+ hasLeader(false),
+ workers(new Thread[_workers]),
+ stopped(false)
+{
+
+ CHECK_APR_SUCCESS(apr_pollset_create(&pollset, size, pool, APR_POLLSET_THREADSAFE));
+}
+
+
+LFProcessor::~LFProcessor(){
+ if (!stopped) stop();
+ delete[] workers;
+ CHECK_APR_SUCCESS(apr_pollset_destroy(pollset));
+}
+
+void LFProcessor::start(){
+ for(int i = 0; i < workerCount; i++){
+ workers[i] = Thread(this);
+ }
+}
+
+void LFProcessor::add(const apr_pollfd_t* const fd){
+ CHECK_APR_SUCCESS(apr_pollset_add(pollset, fd));
+ Monitor::ScopedLock l(countLock);
+ sessions.push_back(reinterpret_cast<LFSessionContext*>(fd->client_data));
+ count++;
+}
+
+void LFProcessor::remove(const apr_pollfd_t* const fd){
+ CHECK_APR_SUCCESS(apr_pollset_remove(pollset, fd));
+ Monitor::ScopedLock l(countLock);
+ sessions.erase(find(sessions.begin(), sessions.end(), reinterpret_cast<LFSessionContext*>(fd->client_data)));
+ count--;
+}
+
+void LFProcessor::reactivate(const apr_pollfd_t* const fd){
+ CHECK_APR_SUCCESS(apr_pollset_add(pollset, fd));
+}
+
+void LFProcessor::deactivate(const apr_pollfd_t* const fd){
+ CHECK_APR_SUCCESS(apr_pollset_remove(pollset, fd));
+}
+
+void LFProcessor::update(const apr_pollfd_t* const fd){
+ CHECK_APR_SUCCESS(apr_pollset_remove(pollset, fd));
+ CHECK_APR_SUCCESS(apr_pollset_add(pollset, fd));
+}
+
+bool LFProcessor::full(){
+ Mutex::ScopedLock locker(countLock);
+ return count == size;
+}
+
+bool LFProcessor::empty(){
+ Mutex::ScopedLock locker(countLock);
+ return count == 0;
+}
+
+void LFProcessor::poll() {
+ apr_status_t status = APR_EGENERAL;
+ do{
+ current = 0;
+ if(!stopped){
+ status = apr_pollset_poll(pollset, timeout, &signalledCount, &signalledFDs);
+ }
+ }while(status != APR_SUCCESS && !stopped);
+}
+
+void LFProcessor::run(){
+ try{
+ while(!stopped){
+ const apr_pollfd_t* event = 0;
+ LFSessionContext* session = 0;
+ {
+ Monitor::ScopedLock l(leadLock);
+ waitToLead();
+ event = getNextEvent();
+ if(!event) return;
+ session = reinterpret_cast<LFSessionContext*>(
+ event->client_data);
+ session->startProcessing();
+ relinquishLead();
+ }
+
+ //process event:
+ if(event->rtnevents & APR_POLLIN) session->read();
+ if(event->rtnevents & APR_POLLOUT) session->write();
+
+ if(session->isClosed()){
+ session->handleClose();
+ Monitor::ScopedLock l(countLock);
+ sessions.erase(find(sessions.begin(),sessions.end(), session));
+ count--;
+ }else{
+ session->stopProcessing();
+ }
+ }
+ }catch(std::exception e){
+ std::cout << e.what() << std::endl;
+ }
+}
+
+void LFProcessor::waitToLead(){
+ while(hasLeader && !stopped) leadLock.wait();
+ hasLeader = !stopped;
+}
+
+void LFProcessor::relinquishLead(){
+ hasLeader = false;
+ leadLock.notify();
+}
+
+const apr_pollfd_t* LFProcessor::getNextEvent(){
+ while(true){
+ if(stopped){
+ return 0;
+ }else if(current < signalledCount){
+ //use result of previous poll if one is available
+ return signalledFDs + (current++);
+ }else{
+ //else poll to get new events
+ poll();
+ }
+ }
+}
+
+void LFProcessor::stop(){
+ stopped = true;
+ {
+ Monitor::ScopedLock l(leadLock);
+ leadLock.notifyAll();
+ }
+ for(int i = 0; i < workerCount; i++){
+ workers[i].join();
+ }
+ for(iterator i = sessions.begin(); i < sessions.end(); i++){
+ (*i)->shutdown();
+ }
+}
+
diff --git a/cpp/lib/common/sys/apr/LFProcessor.h b/cpp/lib/common/sys/apr/LFProcessor.h
new file mode 100644
index 0000000000..de90199472
--- /dev/null
+++ b/cpp/lib/common/sys/apr/LFProcessor.h
@@ -0,0 +1,121 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _LFProcessor_
+#define _LFProcessor_
+
+#include <apr_poll.h>
+#include <iostream>
+#include <vector>
+#include <sys/Monitor.h>
+#include <sys/Runnable.h>
+#include <sys/Thread.h>
+
+namespace qpid {
+namespace sys {
+
+ class LFSessionContext;
+
+ /**
+ * This class processes a poll set using the leaders-followers
+ * pattern for thread synchronization: the leader will poll and on
+ * the poll returning, it will remove a session, promote a
+ * follower to leadership, then process the session.
+ */
+ class LFProcessor : private virtual qpid::sys::Runnable
+ {
+ typedef std::vector<LFSessionContext*>::iterator iterator;
+
+ const int size;
+ const apr_interval_time_t timeout;
+ apr_pollset_t* pollset;
+ int signalledCount;
+ int current;
+ const apr_pollfd_t* signalledFDs;
+ int count;
+ const int workerCount;
+ bool hasLeader;
+ qpid::sys::Thread* workers;
+ qpid::sys::Monitor leadLock;
+ qpid::sys::Mutex countLock;
+ std::vector<LFSessionContext*> sessions;
+ volatile bool stopped;
+
+ const apr_pollfd_t* getNextEvent();
+ void waitToLead();
+ void relinquishLead();
+ void poll();
+ virtual void run();
+
+ public:
+ LFProcessor(apr_pool_t* pool, int workers, int size, int timeout);
+ /**
+ * Add the fd to the poll set. Relies on the client_data being
+ * an instance of LFSessionContext.
+ */
+ void add(const apr_pollfd_t* const fd);
+ /**
+ * Remove the fd from the poll set.
+ */
+ void remove(const apr_pollfd_t* const fd);
+ /**
+ * Signal that the fd passed in, already part of the pollset,
+ * has had its flags altered.
+ */
+ void update(const apr_pollfd_t* const fd);
+ /**
+ * Add an fd back to the poll set after deactivation.
+ */
+ void reactivate(const apr_pollfd_t* const fd);
+ /**
+ * Temporarily remove the fd from the poll set. Called when processing
+ * is about to begin.
+ */
+ void deactivate(const apr_pollfd_t* const fd);
+ /**
+ * Indicates whether the capacity of this processor has been
+ * reached (or whether it can still handle further fd's).
+ */
+ bool full();
+ /**
+ * Indicates whether there are any fd's registered.
+ */
+ bool empty();
+ /**
+ * Stop processing.
+ */
+ void stop();
+ /**
+ * Start processing.
+ */
+ void start();
+ /**
+ * Is processing stopped?
+ */
+ bool isStopped();
+
+ ~LFProcessor();
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/sys/apr/LFSessionContext.cpp b/cpp/lib/common/sys/apr/LFSessionContext.cpp
new file mode 100644
index 0000000000..503dfddbb7
--- /dev/null
+++ b/cpp/lib/common/sys/apr/LFSessionContext.cpp
@@ -0,0 +1,179 @@
+/*
+ *
+ * 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 "LFSessionContext.h"
+#include "APRBase.h"
+#include <QpidError.h>
+#include <assert.h>
+
+using namespace qpid::sys;
+using namespace qpid::sys;
+using namespace qpid::framing;
+
+LFSessionContext::LFSessionContext(apr_pool_t* _pool, apr_socket_t* _socket,
+ LFProcessor* const _processor,
+ bool _debug) :
+ debug(_debug),
+ socket(_socket),
+ initiated(false),
+ in(65536),
+ out(65536),
+ processor(_processor),
+ processing(false),
+ closing(false)
+{
+
+ fd.p = _pool;
+ fd.desc_type = APR_POLL_SOCKET;
+ fd.reqevents = APR_POLLIN;
+ fd.client_data = this;
+ fd.desc.s = _socket;
+
+ out.flip();
+}
+
+LFSessionContext::~LFSessionContext(){
+
+}
+
+void LFSessionContext::read(){
+ socket.read(in);
+ in.flip();
+ if(initiated){
+ AMQFrame frame;
+ try{
+ while(frame.decode(in)){
+ if(debug) log("RECV", &frame);
+ handler->received(&frame);
+ }
+ }catch(QpidError error){
+ std::cout << "Error [" << error.code << "] " << error.msg
+ << " (" << error.loc.file << ":" << error.loc.line
+ << ")" << std::endl;
+ }
+ }else{
+ ProtocolInitiation protocolInit;
+ if(protocolInit.decode(in)){
+ handler->initiated(&protocolInit);
+ initiated = true;
+ if(debug) std::cout << "INIT [" << &socket << "]" << std::endl;
+ }
+ }
+ in.compact();
+}
+
+void LFSessionContext::write(){
+ bool done = isClosed();
+ while(!done){
+ if(out.available() > 0){
+ socket.write(out);
+ if(out.available() > 0){
+
+ //incomplete write, leave flags to receive notification of readiness to write
+ done = true;//finished processing for now, but write is still in progress
+ }
+ }else{
+ //do we have any frames to write?
+ Mutex::ScopedLock l(writeLock);
+ if(!framesToWrite.empty()){
+ out.clear();
+ bool encoded(false);
+ AMQFrame* frame = framesToWrite.front();
+ while(frame && out.available() >= frame->size()){
+ encoded = true;
+ frame->encode(out);
+ if(debug) log("SENT", frame);
+ delete frame;
+ framesToWrite.pop();
+ frame = framesToWrite.empty() ? 0 : framesToWrite.front();
+ }
+ if(!encoded) THROW_QPID_ERROR(FRAMING_ERROR, "Could not write frame, too large for buffer.");
+ out.flip();
+ }else{
+ //reset flags, don't care about writability anymore
+ fd.reqevents = APR_POLLIN;
+ done = true;
+
+ if(closing){
+ socket.close();
+ }
+ }
+ }
+ }
+}
+
+void LFSessionContext::send(AMQFrame* frame){
+ Mutex::ScopedLock l(writeLock);
+ if(!closing){
+ framesToWrite.push(frame);
+ if(!(fd.reqevents & APR_POLLOUT)){
+ fd.reqevents |= APR_POLLOUT;
+ if(!processing){
+ processor->update(&fd);
+ }
+ }
+ }
+}
+
+void LFSessionContext::startProcessing(){
+ Mutex::ScopedLock l(writeLock);
+ processing = true;
+ processor->deactivate(&fd);
+}
+
+void LFSessionContext::stopProcessing(){
+ Mutex::ScopedLock l(writeLock);
+ processor->reactivate(&fd);
+ processing = false;
+}
+
+void LFSessionContext::close(){
+ Mutex::ScopedLock l(writeLock);
+ closing = true;
+ if(!processing){
+ //allow pending frames to be written to socket
+ fd.reqevents = APR_POLLOUT;
+ processor->update(&fd);
+ }
+}
+
+void LFSessionContext::handleClose(){
+ handler->closed();
+ std::cout << "Session closed [" << &socket << "]" << std::endl;
+ delete handler;
+ delete this;
+}
+
+void LFSessionContext::shutdown(){
+ socket.close();
+ handleClose();
+}
+
+void LFSessionContext::init(ConnectionInputHandler* _handler){
+ handler = _handler;
+ processor->add(&fd);
+}
+
+void LFSessionContext::log(const std::string& desc, AMQFrame* const frame){
+ Mutex::ScopedLock l(logLock);
+ std::cout << desc << " [" << &socket << "]: " << *frame << std::endl;
+}
+
+Mutex LFSessionContext::logLock;
diff --git a/cpp/lib/common/sys/apr/LFSessionContext.h b/cpp/lib/common/sys/apr/LFSessionContext.h
new file mode 100644
index 0000000000..81cfc0efda
--- /dev/null
+++ b/cpp/lib/common/sys/apr/LFSessionContext.h
@@ -0,0 +1,90 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _LFSessionContext_
+#define _LFSessionContext_
+
+#include <queue>
+
+#include <apr_network_io.h>
+#include <apr_poll.h>
+#include <apr_time.h>
+
+#include <AMQFrame.h>
+#include <Buffer.h>
+#include <sys/Monitor.h>
+#include <sys/ConnectionOutputHandler.h>
+#include <sys/ConnectionInputHandler.h>
+
+#include "APRSocket.h"
+#include "LFProcessor.h"
+
+namespace qpid {
+namespace sys {
+
+
+class LFSessionContext : public virtual qpid::sys::ConnectionOutputHandler
+{
+ const bool debug;
+ APRSocket socket;
+ bool initiated;
+
+ qpid::framing::Buffer in;
+ qpid::framing::Buffer out;
+
+ qpid::sys::ConnectionInputHandler* handler;
+ LFProcessor* const processor;
+
+ apr_pollfd_t fd;
+
+ std::queue<qpid::framing::AMQFrame*> framesToWrite;
+ qpid::sys::Mutex writeLock;
+
+ bool processing;
+ bool closing;
+
+ static qpid::sys::Mutex logLock;
+ void log(const std::string& desc,
+ qpid::framing::AMQFrame* const frame);
+
+
+ public:
+ LFSessionContext(apr_pool_t* pool, apr_socket_t* socket,
+ LFProcessor* const processor,
+ bool debug = false);
+ virtual ~LFSessionContext();
+ virtual void send(qpid::framing::AMQFrame* frame);
+ virtual void close();
+ void read();
+ void write();
+ void init(qpid::sys::ConnectionInputHandler* handler);
+ void startProcessing();
+ void stopProcessing();
+ void handleClose();
+ void shutdown();
+ inline apr_pollfd_t* const getFd(){ return &fd; }
+ inline bool isClosed(){ return !socket.isOpen(); }
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/lib/common/sys/apr/Socket.cpp b/cpp/lib/common/sys/apr/Socket.cpp
new file mode 100644
index 0000000000..bca4da6c96
--- /dev/null
+++ b/cpp/lib/common/sys/apr/Socket.cpp
@@ -0,0 +1,86 @@
+/*
+ *
+ * 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 <sys/Socket.h>
+#include <apr/APRBase.h>
+#include <apr/APRPool.h>
+
+
+using namespace qpid::sys;
+
+Socket Socket::createTcp() {
+ Socket s;
+ CHECK_APR_SUCCESS(
+ apr_socket_create(
+ &s.socket, APR_INET, SOCK_STREAM, APR_PROTO_TCP,
+ APRPool::get()));
+ return s;
+}
+
+Socket::Socket(apr_socket_t* s) {
+ socket = s;
+}
+
+void Socket::setTimeout(Time interval) {
+ apr_socket_timeout_set(socket, interval/TIME_USEC);
+}
+
+void Socket::connect(const std::string& host, int port) {
+ apr_sockaddr_t* address;
+ CHECK_APR_SUCCESS(
+ apr_sockaddr_info_get(
+ &address, host.c_str(), APR_UNSPEC, port, APR_IPV4_ADDR_OK,
+ APRPool::get()));
+ CHECK_APR_SUCCESS(apr_socket_connect(socket, address));
+}
+
+void Socket::close() {
+ if (socket == 0) return;
+ CHECK_APR_SUCCESS(apr_socket_close(socket));
+ socket = 0;
+}
+
+ssize_t Socket::send(const void* data, size_t size)
+{
+ apr_size_t sent = size;
+ apr_status_t status =
+ apr_socket_send(socket, reinterpret_cast<const char*>(data), &sent);
+ if (APR_STATUS_IS_TIMEUP(status)) return SOCKET_TIMEOUT;
+ if (APR_STATUS_IS_EOF(status)) return SOCKET_EOF;
+ CHECK_APR_SUCCESS(status);
+ return sent;
+}
+
+ssize_t Socket::recv(void* data, size_t size)
+{
+ apr_size_t received = size;
+ apr_status_t status =
+ apr_socket_recv(socket, reinterpret_cast<char*>(data), &received);
+ if (APR_STATUS_IS_TIMEUP(status))
+ return SOCKET_TIMEOUT;
+ if (APR_STATUS_IS_EOF(status))
+ return SOCKET_EOF;
+ CHECK_APR_SUCCESS(status);
+ return received;
+}
+
+
diff --git a/cpp/lib/common/sys/apr/Thread.cpp b/cpp/lib/common/sys/apr/Thread.cpp
new file mode 100644
index 0000000000..5c4799aa96
--- /dev/null
+++ b/cpp/lib/common/sys/apr/Thread.cpp
@@ -0,0 +1,33 @@
+/*
+ *
+ * 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 <sys/Thread.h>
+
+using namespace qpid::sys;
+using qpid::sys::Runnable;
+
+void* APR_THREAD_FUNC Thread::runRunnable(apr_thread_t* thread, void *data) {
+ reinterpret_cast<Runnable*>(data)->run();
+ CHECK_APR_SUCCESS(apr_thread_exit(thread, APR_SUCCESS));
+ return NULL;
+}
+
+
diff --git a/cpp/lib/common/sys/posix/EventChannel.cpp b/cpp/lib/common/sys/posix/EventChannel.cpp
new file mode 100644
index 0000000000..16c7ec9c3f
--- /dev/null
+++ b/cpp/lib/common/sys/posix/EventChannel.cpp
@@ -0,0 +1,325 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <mqueue.h>
+#include <string.h>
+#include <iostream>
+
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/epoll.h>
+
+#include <typeinfo>
+#include <iostream>
+#include <queue>
+
+#include <boost/ptr_container/ptr_map.hpp>
+#include <boost/current_function.hpp>
+
+#include <QpidError.h>
+#include <sys/Monitor.h>
+
+#include "check.h"
+#include "EventChannel.h"
+
+using namespace std;
+
+
+// Convenience template to zero out a struct.
+template <class S> struct ZeroStruct : public S {
+ ZeroStruct() { memset(this, 0, sizeof(*this)); }
+};
+
+namespace qpid {
+namespace sys {
+
+
+/**
+ * EventHandler wraps an epoll file descriptor. Acts as private
+ * interface between EventChannel and subclasses.
+ *
+ * Also implements Event interface for events that are not associated
+ * with a file descriptor and are passed via the message queue.
+ */
+class EventHandler : public Event, private Monitor
+{
+ public:
+ EventHandler(int epollSize = 256);
+ ~EventHandler();
+
+ int getEpollFd() { return epollFd; }
+ void epollAdd(int fd, uint32_t epollEvents, Event* event);
+ void epollMod(int fd, uint32_t epollEvents, Event* event);
+ void epollDel(int fd);
+
+ void mqPut(Event* event);
+ Event* mqGet();
+
+ protected:
+ // Should never be called, only complete.
+ void prepare(EventHandler&) { assert(0); }
+ Event* complete(EventHandler& eh);
+
+ private:
+ int epollFd;
+ std::string mqName;
+ int mqFd;
+ std::queue<Event*> mqEvents;
+};
+
+EventHandler::EventHandler(int epollSize)
+{
+ epollFd = epoll_create(epollSize);
+ if (epollFd < 0) throw QPID_POSIX_ERROR(errno);
+
+ // Create a POSIX message queue for non-fd events.
+ // We write one byte and never read it is always ready for read
+ // when we add it to epoll.
+ //
+ ZeroStruct<struct mq_attr> attr;
+ attr.mq_maxmsg = 1;
+ attr.mq_msgsize = 1;
+ do {
+ char tmpnam[L_tmpnam];
+ tmpnam_r(tmpnam);
+ mqName = tmpnam + 4; // Skip "tmp/"
+ mqFd = mq_open(
+ mqName.c_str(), O_CREAT|O_EXCL|O_RDWR|O_NONBLOCK, S_IRWXU, &attr);
+ if (mqFd < 0) throw QPID_POSIX_ERROR(errno);
+ } while (mqFd == EEXIST); // Name already taken, try again.
+
+ static char zero = '\0';
+ mq_send(mqFd, &zero, 1, 0);
+ epollAdd(mqFd, 0, this);
+}
+
+EventHandler::~EventHandler() {
+ mq_close(mqFd);
+ mq_unlink(mqName.c_str());
+}
+
+void EventHandler::mqPut(Event* event) {
+ ScopedLock l(*this);
+ assert(event != 0);
+ mqEvents.push(event);
+ epollMod(mqFd, EPOLLIN|EPOLLONESHOT, this);
+}
+
+Event* EventHandler::mqGet() {
+ ScopedLock l(*this);
+ if (mqEvents.empty())
+ return 0;
+ Event* event = mqEvents.front();
+ mqEvents.pop();
+ if(!mqEvents.empty())
+ epollMod(mqFd, EPOLLIN|EPOLLONESHOT, this);
+ return event;
+}
+
+void EventHandler::epollAdd(int fd, uint32_t epollEvents, Event* event)
+{
+ ZeroStruct<struct epoll_event> ee;
+ ee.data.ptr = event;
+ ee.events = epollEvents;
+ if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &ee) < 0)
+ throw QPID_POSIX_ERROR(errno);
+}
+
+void EventHandler::epollMod(int fd, uint32_t epollEvents, Event* event)
+{
+ ZeroStruct<struct epoll_event> ee;
+ ee.data.ptr = event;
+ ee.events = epollEvents;
+ if (epoll_ctl(epollFd, EPOLL_CTL_MOD, fd, &ee) < 0)
+ throw QPID_POSIX_ERROR(errno);
+}
+
+void EventHandler::epollDel(int fd) {
+ if (epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, 0) < 0)
+ throw QPID_POSIX_ERROR(errno);
+}
+
+Event* EventHandler::complete(EventHandler& eh)
+{
+ assert(&eh == this);
+ Event* event = mqGet();
+ return event==0 ? 0 : event->complete(eh);
+}
+
+// ================================================================
+// EventChannel
+
+EventChannel::shared_ptr EventChannel::create() {
+ return shared_ptr(new EventChannel());
+}
+
+EventChannel::EventChannel() : handler(new EventHandler()) {}
+
+EventChannel::~EventChannel() {}
+
+void EventChannel::postEvent(Event& e)
+{
+ e.prepare(*handler);
+}
+
+Event* EventChannel::getEvent()
+{
+ static const int infiniteTimeout = -1;
+ ZeroStruct<struct epoll_event> epollEvent;
+
+ // Loop until we can complete the event. Some events may re-post
+ // themselves and return 0 from complete, e.g. partial reads. //
+ Event* event = 0;
+ while (event == 0) {
+ int eventCount = epoll_wait(handler->getEpollFd(),
+ &epollEvent, 1, infiniteTimeout);
+ if (eventCount < 0) {
+ if (errno != EINTR) {
+ // TODO aconway 2006-11-28: Proper handling/logging of errors.
+ cerr << BOOST_CURRENT_FUNCTION << " ignoring error "
+ << PosixError::getMessage(errno) << endl;
+ assert(0);
+ }
+ }
+ else if (eventCount == 1) {
+ event = reinterpret_cast<Event*>(epollEvent.data.ptr);
+ assert(event != 0);
+ try {
+ event = event->complete(*handler);
+ }
+ catch (const Exception& e) {
+ if (event)
+ event->setError(e);
+ }
+ catch (const std::exception& e) {
+ if (event)
+ event->setError(e);
+ }
+ }
+ }
+ return event;
+}
+
+Event::~Event() {}
+
+void Event::prepare(EventHandler& handler)
+{
+ handler.mqPut(this);
+}
+
+bool Event::hasError() const {
+ return error;
+}
+
+void Event::throwIfError() throw (Exception) {
+ if (hasError())
+ error.throwSelf();
+}
+
+Event* Event::complete(EventHandler&)
+{
+ return this;
+}
+
+void Event::dispatch()
+{
+ try {
+ if (!callback.empty())
+ callback();
+ } catch (const std::exception&) {
+ throw;
+ } catch (...) {
+ throw QPID_ERROR(INTERNAL_ERROR, "Unknown exception.");
+ }
+}
+
+void Event::setError(const ExceptionHolder& e) {
+ error = e;
+}
+
+void ReadEvent::prepare(EventHandler& handler)
+{
+ handler.epollAdd(descriptor, EPOLLIN | EPOLLONESHOT, this);
+}
+
+ssize_t ReadEvent::doRead() {
+ ssize_t n = ::read(descriptor, static_cast<char*>(buffer) + received,
+ size - received);
+ if (n > 0) received += n;
+ return n;
+}
+
+Event* ReadEvent::complete(EventHandler& handler)
+{
+ // Read as much as possible without blocking.
+ ssize_t n = doRead();
+ while (n > 0 && received < size) doRead();
+
+ if (received == size) {
+ handler.epollDel(descriptor);
+ received = 0; // Reset for re-use.
+ return this;
+ }
+ else if (n <0 && (errno == EAGAIN)) {
+ // Keep polling for more.
+ handler.epollMod(descriptor, EPOLLIN | EPOLLONESHOT, this);
+ return 0;
+ }
+ else {
+ // Unexpected EOF or error. Throw ENODATA for EOF.
+ handler.epollDel(descriptor);
+ received = 0; // Reset for re-use.
+ throw QPID_POSIX_ERROR((n < 0) ? errno : ENODATA);
+ }
+}
+
+void WriteEvent::prepare(EventHandler& handler)
+{
+ handler.epollAdd(descriptor, EPOLLOUT | EPOLLONESHOT, this);
+}
+
+Event* WriteEvent::complete(EventHandler& handler)
+{
+ ssize_t n = write(descriptor, static_cast<const char*>(buffer) + written,
+ size - written);
+ if (n < 0) throw QPID_POSIX_ERROR(errno);
+ written += n;
+ if(written < size) {
+ // Keep polling.
+ handler.epollMod(descriptor, EPOLLOUT | EPOLLONESHOT, this);
+ return 0;
+ }
+ written = 0; // Reset for re-use.
+ handler.epollDel(descriptor);
+ return this;
+}
+
+void AcceptEvent::prepare(EventHandler& handler)
+{
+ handler.epollAdd(descriptor, EPOLLIN | EPOLLONESHOT, this);
+}
+
+Event* AcceptEvent::complete(EventHandler& handler)
+{
+ handler.epollDel(descriptor);
+ accepted = ::accept(descriptor, 0, 0);
+ if (accepted < 0) throw QPID_POSIX_ERROR(errno);
+ return this;
+}
+
+}}
diff --git a/cpp/lib/common/sys/posix/EventChannel.h b/cpp/lib/common/sys/posix/EventChannel.h
new file mode 100644
index 0000000000..49c7fce740
--- /dev/null
+++ b/cpp/lib/common/sys/posix/EventChannel.h
@@ -0,0 +1,176 @@
+#ifndef _sys_EventChannel_h
+#define _sys_EventChannel_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <SharedObject.h>
+#include <ExceptionHolder.h>
+#include <boost/function.hpp>
+#include <memory>
+
+namespace qpid {
+namespace sys {
+
+class Event;
+class EventHandler;
+class EventChannel;
+
+/**
+ * Base class for all Events.
+ */
+class Event
+{
+ public:
+ /** Type for callback when event is dispatched */
+ typedef boost::function0<void> Callback;
+
+ /**
+ * Create an event with optional callback.
+ * Instances of Event are sent directly through the channel.
+ * Derived classes define additional waiting behaviour.
+ *@param cb A callback functor that is invoked when dispatch() is called.
+ */
+ Event(Callback cb = 0) : callback(cb) {}
+
+ virtual ~Event();
+
+ /** Call the callback provided to the constructor, if any. */
+ void dispatch();
+
+ /** True if there was an error processing this event */
+ bool hasError() const;
+
+ /** If hasError() throw the corresponding exception. */
+ void throwIfError() throw(Exception);
+
+ protected:
+ virtual void prepare(EventHandler&);
+ virtual Event* complete(EventHandler&);
+ void setError(const ExceptionHolder& e);
+
+ Callback callback;
+ ExceptionHolder error;
+
+ friend class EventChannel;
+ friend class EventHandler;
+};
+
+template <class BufT>
+class IOEvent : public Event {
+ public:
+ void getDescriptor() const { return descriptor; }
+ size_t getSize() const { return size; }
+ BufT getBuffer() const { return buffer; }
+
+ protected:
+ IOEvent(int fd, Callback cb, size_t sz, BufT buf) :
+ Event(cb), descriptor(fd), buffer(buf), size(sz) {}
+
+ int descriptor;
+ BufT buffer;
+ size_t size;
+};
+
+/** Asynchronous read event */
+class ReadEvent : public IOEvent<void*>
+{
+ public:
+ explicit ReadEvent(int fd=-1, void* buf=0, size_t sz=0, Callback cb=0) :
+ IOEvent<void*>(fd, cb, sz, buf), received(0) {}
+
+ private:
+ void prepare(EventHandler&);
+ Event* complete(EventHandler&);
+ ssize_t doRead();
+
+ size_t received;
+};
+
+/** Asynchronous write event */
+class WriteEvent : public IOEvent<const void*>
+{
+ public:
+ explicit WriteEvent(int fd=-1, const void* buf=0, size_t sz=0,
+ Callback cb=0) :
+ IOEvent<const void*>(fd, cb, sz, buf), written(0) {}
+
+ protected:
+ void prepare(EventHandler&);
+ Event* complete(EventHandler&);
+
+ private:
+ ssize_t doWrite();
+ size_t written;
+};
+
+/** Asynchronous socket accept event */
+class AcceptEvent : public Event
+{
+ public:
+ /** Accept a connection on fd. */
+ explicit AcceptEvent(int fd=-1, Callback cb=0) :
+ Event(cb), descriptor(fd), accepted(0) {}
+
+ /** Get descriptor for server socket */
+ int getAcceptedDesscriptor() const { return accepted; }
+
+ private:
+ void prepare(EventHandler&);
+ Event* complete(EventHandler&);
+
+ int descriptor;
+ int accepted;
+};
+
+
+class QueueSet;
+
+/**
+ * Channel to post and wait for events.
+ */
+class EventChannel : public qpid::SharedObject<EventChannel>
+{
+ public:
+ static shared_ptr create();
+
+ ~EventChannel();
+
+ /** Post an event to the channel. */
+ void postEvent(Event& event);
+
+ /** Post an event to the channel. Must not be 0. */
+ void postEvent(Event* event) { postEvent(*event); }
+
+ /**
+ * Wait for the next complete event.
+ *@return Pointer to event. Will never return 0.
+ */
+ Event* getEvent();
+
+ private:
+ EventChannel();
+ boost::shared_ptr<EventHandler> handler;
+};
+
+
+}}
+
+
+
+#endif /*!_sys_EventChannel_h*/
diff --git a/cpp/lib/common/sys/posix/EventChannelAcceptor.cpp b/cpp/lib/common/sys/posix/EventChannelAcceptor.cpp
new file mode 100644
index 0000000000..548fbd1881
--- /dev/null
+++ b/cpp/lib/common/sys/posix/EventChannelAcceptor.cpp
@@ -0,0 +1,149 @@
+/*
+ *
+ * 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 <iostream>
+
+#include <boost/assert.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/ptr_container/ptr_deque.hpp>
+#include <boost/bind.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <sys/ConnectionOutputHandler.h>
+#include <sys/ConnectionInputHandler.h>
+#include <sys/ConnectionInputHandlerFactory.h>
+#include <sys/Acceptor.h>
+#include <sys/Socket.h>
+#include <framing/Buffer.h>
+#include <framing/AMQFrame.h>
+#include <Exception.h>
+
+#include "EventChannelConnection.h"
+
+namespace qpid {
+namespace sys {
+
+using namespace qpid::framing;
+using namespace std;
+
+class EventChannelAcceptor : public Acceptor {
+ public:
+
+
+ EventChannelAcceptor(
+ int16_t port_, int backlog, int nThreads, bool trace_
+ );
+
+ int getPort() const;
+
+ void run(ConnectionInputHandlerFactory& factory);
+
+ void shutdown();
+
+ private:
+
+ void accept();
+
+ Mutex lock;
+ Socket listener;
+ const int port;
+ const bool isTrace;
+ bool isRunning;
+ boost::ptr_vector<EventChannelConnection> connections;
+ AcceptEvent acceptEvent;
+ ConnectionInputHandlerFactory* factory;
+ bool isShutdown;
+ EventChannelThreads::shared_ptr threads;
+};
+
+Acceptor::shared_ptr Acceptor::create(
+ int16_t port, int backlog, int threads, bool trace)
+{
+ return Acceptor::shared_ptr(
+ new EventChannelAcceptor(port, backlog, threads, trace));
+}
+
+// Must define Acceptor virtual dtor.
+Acceptor::~Acceptor() {}
+
+EventChannelAcceptor::EventChannelAcceptor(
+ int16_t port_, int backlog, int nThreads, bool trace_
+) : listener(Socket::createTcp()),
+ port(listener.listen(int(port_), backlog)),
+ isTrace(trace_),
+ isRunning(false),
+ acceptEvent(listener.fd(),
+ boost::bind(&EventChannelAcceptor::accept, this)),
+ factory(0),
+ isShutdown(false),
+ threads(EventChannelThreads::create(EventChannel::create(), nThreads))
+{ }
+
+int EventChannelAcceptor::getPort() const {
+ return port; // Immutable no need for lock.
+}
+
+void EventChannelAcceptor::run(ConnectionInputHandlerFactory& f) {
+ {
+ Mutex::ScopedLock l(lock);
+ if (!isRunning && !isShutdown) {
+ isRunning = true;
+ factory = &f;
+ threads->post(acceptEvent);
+ }
+ }
+ threads->join(); // Wait for shutdown.
+}
+
+void EventChannelAcceptor::shutdown() {
+ bool doShutdown = false;
+ {
+ Mutex::ScopedLock l(lock);
+ doShutdown = !isShutdown; // I'm the shutdown thread.
+ isShutdown = true;
+ }
+ if (doShutdown) {
+ ::close(acceptEvent.getDescriptor());
+ threads->shutdown();
+ for_each(connections.begin(), connections.end(),
+ boost::bind(&EventChannelConnection::close, _1));
+ }
+ threads->join();
+}
+
+void EventChannelAcceptor::accept()
+{
+ // No lock, we only post one accept event at a time.
+ if (isShutdown)
+ return;
+ if (acceptEvent.getException()) {
+ Exception::log(*acceptEvent.getException(),
+ "EventChannelAcceptor::accept");
+ shutdown();
+ return;
+ }
+ // TODO aconway 2006-11-29: Need to reap closed connections also.
+ int fd = acceptEvent.getAcceptedDesscriptor();
+ connections.push_back(
+ new EventChannelConnection(threads, *factory, fd, fd, isTrace));
+ threads->post(acceptEvent); // Keep accepting.
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/lib/common/sys/posix/EventChannelConnection.cpp b/cpp/lib/common/sys/posix/EventChannelConnection.cpp
new file mode 100644
index 0000000000..4449dc3035
--- /dev/null
+++ b/cpp/lib/common/sys/posix/EventChannelConnection.cpp
@@ -0,0 +1,229 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <iostream>
+
+#include <boost/bind.hpp>
+#include <boost/assert.hpp>
+
+#include "EventChannelConnection.h"
+#include "sys/ConnectionInputHandlerFactory.h"
+#include "QpidError.h"
+
+using namespace std;
+using namespace qpid;
+using namespace qpid::framing;
+
+namespace qpid {
+namespace sys {
+
+const size_t EventChannelConnection::bufferSize = 65536;
+
+EventChannelConnection::EventChannelConnection(
+ EventChannelThreads::shared_ptr threads_,
+ ConnectionInputHandlerFactory& factory_,
+ int rfd,
+ int wfd,
+ bool isTrace_
+) :
+ readFd(rfd),
+ writeFd(wfd ? wfd : rfd),
+ readCallback(boost::bind(&EventChannelConnection::closeOnException,
+ this, &EventChannelConnection::endInitRead)),
+
+ isWriting(false),
+ isClosed(false),
+ threads(threads_),
+ handler(factory_.create(this)),
+ in(bufferSize),
+ out(bufferSize),
+ isTrace(isTrace_)
+{
+ BOOST_ASSERT(readFd > 0);
+ BOOST_ASSERT(writeFd > 0);
+ closeOnException(&EventChannelConnection::startRead);
+}
+
+
+void EventChannelConnection::send(std::auto_ptr<AMQFrame> frame) {
+ {
+ Monitor::ScopedLock lock(monitor);
+ assert(frame.get());
+ writeFrames.push_back(frame.release());
+ }
+ closeOnException(&EventChannelConnection::startWrite);
+}
+
+void EventChannelConnection::close() {
+ {
+ Monitor::ScopedLock lock(monitor);
+ if (isClosed)
+ return;
+ isClosed = true;
+ }
+ ::close(readFd);
+ ::close(writeFd);
+ {
+ Monitor::ScopedLock lock(monitor);
+ while (busyThreads > 0)
+ monitor.wait();
+ }
+ handler->closed();
+}
+
+void EventChannelConnection::closeNoThrow() {
+ Exception::tryCatchLog<void>(
+ boost::bind(&EventChannelConnection::close, this),
+ false,
+ "Exception closing channel"
+ );
+}
+
+/**
+ * Call f in a try/catch block and close the connection if
+ * an exception is thrown.
+ */
+void EventChannelConnection::closeOnException(MemberFnPtr f)
+{
+ try {
+ Exception::tryCatchLog<void>(
+ boost::bind(f, this),
+ "Closing connection due to exception"
+ );
+ return;
+ } catch (...) {
+ // Exception was already logged by tryCatchLog
+ closeNoThrow();
+ }
+}
+
+// Post the write event.
+// Always called inside closeOnException.
+// Called by endWrite and send, but only one thread writes at a time.
+//
+void EventChannelConnection::startWrite() {
+ FrameQueue::auto_type frame;
+ {
+ Monitor::ScopedLock lock(monitor);
+ // Stop if closed or a write event is already in progress.
+ if (isClosed || isWriting)
+ return;
+ if (writeFrames.empty()) {
+ isWriting = false;
+ return;
+ }
+ isWriting = true;
+ frame = writeFrames.pop_front();
+ }
+ // No need to lock here - only one thread can be writing at a time.
+ out.clear();
+ if (isTrace)
+ cout << "Send on socket " << writeFd << ": " << *frame << endl;
+ frame->encode(out);
+ out.flip();
+ writeEvent = WriteEvent(
+ writeFd, out.start(), out.available(),
+ boost::bind(&EventChannelConnection::closeOnException,
+ this, &EventChannelConnection::endWrite));
+ threads->post(writeEvent);
+}
+
+// ScopedBusy ctor increments busyThreads.
+// dtor decrements and calls monitor.notifyAll if it reaches 0.
+//
+struct EventChannelConnection::ScopedBusy : public AtomicCount::ScopedIncrement
+{
+ ScopedBusy(EventChannelConnection& ecc)
+ : AtomicCount::ScopedIncrement(
+ ecc.busyThreads, boost::bind(&Monitor::notifyAll, &ecc.monitor))
+ {}
+};
+
+// Write event completed.
+// Always called by a channel thread inside closeOnException.
+//
+void EventChannelConnection::endWrite() {
+ ScopedBusy(*this);
+ {
+ Monitor::ScopedLock lock(monitor);
+ isWriting = false;
+ if (isClosed)
+ return;
+ writeEvent.throwIfException();
+ }
+ // Check if there's more in to write in the write queue.
+ startWrite();
+}
+
+
+// Post the read event.
+// Always called inside closeOnException.
+// Called from ctor and end[Init]Read, so only one call at a time
+// is possible since we only post one read event at a time.
+//
+void EventChannelConnection::startRead() {
+ // Non blocking read, as much as we can swallow.
+ readEvent = ReadEvent(
+ readFd, in.start(), in.available(), readCallback,true);
+ threads->post(readEvent);
+}
+
+// Completion of initial read, expect protocolInit.
+// Always called inside closeOnException in channel thread.
+// Only called by one thread at a time.
+void EventChannelConnection::endInitRead() {
+ ScopedBusy(*this);
+ if (!isClosed) {
+ readEvent.throwIfException();
+ in.move(readEvent.getBytesRead());
+ in.flip();
+ ProtocolInitiation protocolInit;
+ if(protocolInit.decode(in)){
+ handler->initiated(&protocolInit);
+ readCallback = boost::bind(
+ &EventChannelConnection::closeOnException,
+ this, &EventChannelConnection::endRead);
+ }
+ in.compact();
+ // Continue reading.
+ startRead();
+ }
+}
+
+// Normal reads, expect a frame.
+// Always called inside closeOnException in channel thread.
+void EventChannelConnection::endRead() {
+ ScopedBusy(*this);
+ if (!isClosed) {
+ readEvent.throwIfException();
+ in.move(readEvent.getBytesRead());
+ in.flip();
+ AMQFrame frame;
+ while (frame.decode(in)) {
+ // TODO aconway 2006-11-30: received should take Frame&
+ if (isTrace)
+ cout << "Received on socket " << readFd
+ << ": " << frame << endl;
+ handler->received(&frame);
+ }
+ in.compact();
+ startRead();
+ }
+}
+
+}} // namespace qpid::sys
diff --git a/cpp/lib/common/sys/posix/EventChannelConnection.h b/cpp/lib/common/sys/posix/EventChannelConnection.h
new file mode 100644
index 0000000000..da7b6dca27
--- /dev/null
+++ b/cpp/lib/common/sys/posix/EventChannelConnection.h
@@ -0,0 +1,102 @@
+#ifndef _posix_EventChannelConnection_h
+#define _posix_EventChannelConnection_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <boost/ptr_container/ptr_deque.hpp>
+
+#include "EventChannelThreads.h"
+#include "sys/Monitor.h"
+#include "sys/ConnectionOutputHandler.h"
+#include "sys/ConnectionInputHandler.h"
+#include "sys/AtomicCount.h"
+#include "framing/AMQFrame.h"
+
+namespace qpid {
+namespace sys {
+
+class ConnectionInputHandlerFactory;
+
+/**
+ * Implements ConnectionOutputHandler and delegates to a ConnectionInputHandler
+ * for a connection via the EventChannel.
+ *@param readDescriptor file descriptor for reading.
+ *@param writeDescriptor file descriptor for writing,
+ * by default same as readDescriptor
+ */
+class EventChannelConnection : public ConnectionOutputHandler {
+ public:
+ EventChannelConnection(
+ EventChannelThreads::shared_ptr threads,
+ ConnectionInputHandlerFactory& factory,
+ int readDescriptor,
+ int writeDescriptor = 0,
+ bool isTrace = false
+ );
+
+ // TODO aconway 2006-11-30: ConnectionOutputHandler::send should take auto_ptr
+ virtual void send(qpid::framing::AMQFrame* frame) {
+ send(std::auto_ptr<qpid::framing::AMQFrame>(frame));
+ }
+
+ virtual void send(std::auto_ptr<qpid::framing::AMQFrame> frame);
+
+ virtual void close();
+
+ private:
+ typedef boost::ptr_deque<qpid::framing::AMQFrame> FrameQueue;
+ typedef void (EventChannelConnection::*MemberFnPtr)();
+ struct ScopedBusy;
+
+ void startWrite();
+ void endWrite();
+ void startRead();
+ void endInitRead();
+ void endRead();
+ void closeNoThrow();
+ void closeOnException(MemberFnPtr);
+ bool shouldContinue(bool& flag);
+
+ static const size_t bufferSize;
+
+ Monitor monitor;
+
+ int readFd, writeFd;
+ ReadEvent readEvent;
+ WriteEvent writeEvent;
+ Event::Callback readCallback;
+ bool isWriting;
+ bool isClosed;
+ AtomicCount busyThreads;
+
+ EventChannelThreads::shared_ptr threads;
+ std::auto_ptr<ConnectionInputHandler> handler;
+ qpid::framing::Buffer in, out;
+ FrameQueue writeFrames;
+ bool isTrace;
+
+ friend struct ScopedBusy;
+};
+
+
+}} // namespace qpid::sys
+
+
+
+#endif /*!_posix_EventChannelConnection_h*/
diff --git a/cpp/lib/common/sys/posix/EventChannelThreads.cpp b/cpp/lib/common/sys/posix/EventChannelThreads.cpp
new file mode 100644
index 0000000000..95e699e0b0
--- /dev/null
+++ b/cpp/lib/common/sys/posix/EventChannelThreads.cpp
@@ -0,0 +1,119 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 "EventChannelThreads.h"
+#include <sys/Runnable.h>
+#include <iostream>
+using namespace std;
+#include <boost/bind.hpp>
+
+namespace qpid {
+namespace sys {
+
+EventChannelThreads::shared_ptr EventChannelThreads::create(
+ EventChannel::shared_ptr ec)
+{
+ return EventChannelThreads::shared_ptr(new EventChannelThreads(ec));
+}
+
+EventChannelThreads::EventChannelThreads(EventChannel::shared_ptr ec) :
+ channel(ec), nWaiting(0), state(RUNNING)
+{
+ // TODO aconway 2006-11-15: Estimate initial threads based on CPUs.
+ addThread();
+}
+
+EventChannelThreads::~EventChannelThreads() {
+ shutdown();
+ join();
+}
+
+void EventChannelThreads::shutdown()
+{
+ ScopedLock lock(*this);
+ if (state != RUNNING) // Already shutting down.
+ return;
+ for (size_t i = 0; i < workers.size(); ++i) {
+ channel->postEvent(terminate);
+ }
+ state = TERMINATE_SENT;
+ notify(); // Wake up one join() thread.
+}
+
+void EventChannelThreads::join()
+{
+ {
+ ScopedLock lock(*this);
+ while (state == RUNNING) // Wait for shutdown to start.
+ wait();
+ if (state == SHUTDOWN) // Shutdown is complete
+ return;
+ if (state == JOINING) {
+ // Someone else is doing the join.
+ while (state != SHUTDOWN)
+ wait();
+ return;
+ }
+ // I'm the joining thread
+ assert(state == TERMINATE_SENT);
+ state = JOINING;
+ } // Drop the lock.
+
+ for (size_t i = 0; i < workers.size(); ++i) {
+ assert(state == JOINING); // Only this thread can change JOINING.
+ workers[i].join();
+ }
+ state = SHUTDOWN;
+ notifyAll(); // Notify other join() threaeds.
+}
+
+void EventChannelThreads::addThread() {
+ ScopedLock l(*this);
+ workers.push_back(Thread(*this));
+}
+
+void EventChannelThreads::run()
+{
+ // Start life waiting. Decrement on exit.
+ AtomicCount::ScopedIncrement inc(nWaiting);
+ try {
+ while (true) {
+ Event* e = channel->getEvent();
+ assert(e != 0);
+ if (e == &terminate) {
+ return;
+ }
+ AtomicCount::ScopedDecrement dec(nWaiting);
+ // I'm no longer waiting, make sure someone is.
+ if (dec == 0)
+ addThread();
+ e->dispatch();
+ }
+ }
+ catch (const std::exception& e) {
+ // TODO aconway 2006-11-15: need better logging across the board.
+ std::cerr << "EventChannelThreads::run() caught: " << e.what()
+ << std::endl;
+ }
+ catch (...) {
+ std::cerr << "EventChannelThreads::run() caught unknown exception."
+ << std::endl;
+ }
+}
+
+}}
diff --git a/cpp/lib/common/sys/posix/EventChannelThreads.h b/cpp/lib/common/sys/posix/EventChannelThreads.h
new file mode 100644
index 0000000000..98403c0869
--- /dev/null
+++ b/cpp/lib/common/sys/posix/EventChannelThreads.h
@@ -0,0 +1,92 @@
+#ifndef _posix_EventChannelThreads_h
+#define _sys_EventChannelThreads_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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 <vector>
+
+#include <Exception.h>
+#include <sys/Time.h>
+#include <sys/Monitor.h>
+#include <sys/Thread.h>
+#include <sys/AtomicCount.h>
+#include "EventChannel.h"
+
+namespace qpid {
+namespace sys {
+
+/**
+ Dynamic thread pool serving an EventChannel.
+
+ Threads run a loop { e = getEvent(); e->dispatch(); }
+ The size of the thread pool is automatically adjusted to optimal size.
+*/
+class EventChannelThreads :
+ public qpid::SharedObject<EventChannelThreads>,
+ public sys::Monitor, private sys::Runnable
+{
+ public:
+ /** Create the thread pool and start initial threads. */
+ static EventChannelThreads::shared_ptr create(
+ EventChannel::shared_ptr channel
+ );
+
+ ~EventChannelThreads();
+
+ /** Post event to the underlying channel */
+ void postEvent(Event& event) { channel->postEvent(event); }
+
+ /** Post event to the underlying channel Must not be 0. */
+ void postEvent(Event* event) { channel->postEvent(event); }
+
+ /**
+ * Terminate all threads.
+ *
+ * Returns immediately, use join() to wait till all threads are
+ * shut down.
+ */
+ void shutdown();
+
+ /** Wait for all threads to terminate. */
+ void join();
+
+ private:
+ typedef std::vector<sys::Thread> Threads;
+ typedef enum {
+ RUNNING, TERMINATE_SENT, JOINING, SHUTDOWN
+ } State;
+
+ EventChannelThreads(EventChannel::shared_ptr underlyingChannel);
+ void addThread();
+
+ void run();
+ bool keepRunning();
+ void adjustThreads();
+
+ EventChannel::shared_ptr channel;
+ Threads workers;
+ sys::AtomicCount nWaiting;
+ State state;
+ Event terminate;
+};
+
+
+}}
+
+
+#endif /*!_sys_EventChannelThreads_h*/
diff --git a/cpp/lib/common/sys/posix/PosixAcceptor.cpp b/cpp/lib/common/sys/posix/PosixAcceptor.cpp
new file mode 100644
index 0000000000..a80a6c61f7
--- /dev/null
+++ b/cpp/lib/common/sys/posix/PosixAcceptor.cpp
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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 <sys/Acceptor.h>
+#include <Exception.h>
+
+namespace qpid {
+namespace sys {
+
+namespace {
+void fail() { throw qpid::Exception("PosixAcceptor not implemented"); }
+}
+
+class PosixAcceptor : public Acceptor {
+ public:
+ virtual int16_t getPort() const { fail(); return 0; }
+ virtual void run(qpid::sys::ConnectionInputHandlerFactory* ) { fail(); }
+ virtual void shutdown() { fail(); }
+};
+
+// Define generic Acceptor::create() to return APRAcceptor.
+ Acceptor::shared_ptr Acceptor::create(int16_t , int, int, bool)
+{
+ return Acceptor::shared_ptr(new PosixAcceptor());
+}
+
+// Must define Acceptor virtual dtor.
+Acceptor::~Acceptor() {}
+
+}}
diff --git a/cpp/lib/common/sys/posix/Socket.cpp b/cpp/lib/common/sys/posix/Socket.cpp
new file mode 100644
index 0000000000..5bd13742f6
--- /dev/null
+++ b/cpp/lib/common/sys/posix/Socket.cpp
@@ -0,0 +1,118 @@
+/*
+ *
+ * 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 <sys/socket.h>
+#include <sys/errno.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <boost/format.hpp>
+
+#include <QpidError.h>
+#include <posix/check.h>
+#include <sys/Socket.h>
+
+using namespace qpid::sys;
+
+Socket Socket::createTcp()
+{
+ int s = ::socket (PF_INET, SOCK_STREAM, 0);
+ if (s < 0) throw QPID_POSIX_ERROR(errno);
+ return s;
+}
+
+Socket::Socket(int descriptor) : socket(descriptor) {}
+
+void Socket::setTimeout(Time interval)
+{
+ struct timeval tv;
+ tv.tv_sec = interval/TIME_SEC;
+ tv.tv_usec = (interval%TIME_SEC)/TIME_USEC;
+ setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+ setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+}
+
+void Socket::connect(const std::string& host, int port)
+{
+ struct sockaddr_in name;
+ name.sin_family = AF_INET;
+ name.sin_port = htons(port);
+ struct hostent* hp = gethostbyname ( host.c_str() );
+ if (hp == 0) throw QPID_POSIX_ERROR(errno);
+ memcpy(&name.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
+ if (::connect(socket, (struct sockaddr*)(&name), sizeof(name)) < 0)
+ throw QPID_POSIX_ERROR(errno);
+}
+
+void
+Socket::close()
+{
+ if (socket == 0) return;
+ if (::close(socket) < 0) throw QPID_POSIX_ERROR(errno);
+ socket = 0;
+}
+
+ssize_t
+Socket::send(const void* data, size_t size)
+{
+ ssize_t sent = ::send(socket, data, size, 0);
+ if (sent < 0) {
+ if (errno == ECONNRESET) return SOCKET_EOF;
+ if (errno == ETIMEDOUT) return SOCKET_TIMEOUT;
+ throw QPID_POSIX_ERROR(errno);
+ }
+ return sent;
+}
+
+ssize_t
+Socket::recv(void* data, size_t size)
+{
+ ssize_t received = ::recv(socket, data, size, 0);
+ if (received < 0) {
+ if (errno == ETIMEDOUT) return SOCKET_TIMEOUT;
+ throw QPID_POSIX_ERROR(errno);
+ }
+ return received;
+}
+
+int Socket::listen(int port, int backlog)
+{
+ struct sockaddr_in name;
+ name.sin_family = AF_INET;
+ name.sin_port = htons(port);
+ name.sin_addr.s_addr = 0;
+ if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) < 0)
+ throw QPID_POSIX_ERROR(errno);
+ if (::listen(socket, backlog) < 0)
+ throw QPID_POSIX_ERROR(errno);
+
+ socklen_t namelen = sizeof(name);
+ if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0)
+ throw QPID_POSIX_ERROR(errno);
+
+ return ntohs(name.sin_port);
+}
+
+
+int Socket::fd()
+{
+ return socket;
+}
diff --git a/cpp/lib/common/sys/posix/Thread.cpp b/cpp/lib/common/sys/posix/Thread.cpp
new file mode 100644
index 0000000000..f524799556
--- /dev/null
+++ b/cpp/lib/common/sys/posix/Thread.cpp
@@ -0,0 +1,28 @@
+/*
+ *
+ * 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 <sys/Thread.h>
+
+void* qpid::sys::Thread::runRunnable(void* p)
+{
+ static_cast<Runnable*>(p)->run();
+ return 0;
+}
diff --git a/cpp/lib/common/sys/posix/check.cpp b/cpp/lib/common/sys/posix/check.cpp
new file mode 100644
index 0000000000..408679caa8
--- /dev/null
+++ b/cpp/lib/common/sys/posix/check.cpp
@@ -0,0 +1,39 @@
+/*
+ *
+ * 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 <cerrno>
+#include "check.h"
+
+namespace qpid {
+namespace sys {
+
+std::string
+PosixError::getMessage(int errNo)
+{
+ char buf[512];
+ return std::string(strerror_r(errNo, buf, sizeof(buf)));
+}
+
+PosixError::PosixError(int errNo, const qpid::SrcLine& loc) throw()
+ : qpid::QpidError(INTERNAL_ERROR + errNo, getMessage(errNo), loc)
+{ }
+
+}}
diff --git a/cpp/lib/common/sys/posix/check.h b/cpp/lib/common/sys/posix/check.h
new file mode 100644
index 0000000000..57b5a5757c
--- /dev/null
+++ b/cpp/lib/common/sys/posix/check.h
@@ -0,0 +1,62 @@
+#ifndef _posix_check_h
+#define _posix_check_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 <cerrno>
+#include <string>
+#include <QpidError.h>
+
+namespace qpid {
+namespace sys {
+
+/**
+ * Exception with message from errno.
+ */
+class PosixError : public qpid::QpidError
+{
+ public:
+ static std::string getMessage(int errNo);
+
+ PosixError(int errNo, const qpid::SrcLine& location) throw();
+
+ ~PosixError() throw() {}
+
+ int getErrNo() { return errNo; }
+
+ Exception* clone() const throw() { return new PosixError(*this); }
+
+ void throwSelf() const { throw *this; }
+
+ private:
+ int errNo;
+};
+
+}}
+
+/** Create a PosixError for the current file/line and errno. */
+#define QPID_POSIX_ERROR(errNo) ::qpid::sys::PosixError(errNo, SRCLINE)
+
+/** Throw a posix error if errNo is non-zero */
+#define QPID_POSIX_THROW_IF(ERRNO) \
+ if ((ERRNO) != 0) throw QPID_POSIX_ERROR((ERRNO))
+#endif /*!_posix_check_h*/