summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp')
-rw-r--r--cpp/DESIGN89
-rw-r--r--cpp/Makefile53
-rw-r--r--cpp/README48
-rw-r--r--cpp/broker/Makefile47
-rw-r--r--cpp/broker/inc/AutoDelete.h54
-rw-r--r--cpp/broker/inc/Binding.h35
-rw-r--r--cpp/broker/inc/Channel.h87
-rw-r--r--cpp/broker/inc/Configuration.h125
-rw-r--r--cpp/broker/inc/ConnectionToken.h35
-rw-r--r--cpp/broker/inc/Consumer.h34
-rw-r--r--cpp/broker/inc/DirectExchange.h55
-rw-r--r--cpp/broker/inc/Exchange.h39
-rw-r--r--cpp/broker/inc/ExchangeBinding.h45
-rw-r--r--cpp/broker/inc/ExchangeRegistry.h42
-rw-r--r--cpp/broker/inc/FanOutExchange.h58
-rw-r--r--cpp/broker/inc/Message.h73
-rw-r--r--cpp/broker/inc/NameGenerator.h36
-rw-r--r--cpp/broker/inc/Queue.h106
-rw-r--r--cpp/broker/inc/QueueRegistry.h88
-rw-r--r--cpp/broker/inc/SessionHandlerFactoryImpl.h49
-rw-r--r--cpp/broker/inc/SessionHandlerImpl.h230
-rw-r--r--cpp/broker/inc/TopicExchange.h55
-rw-r--r--cpp/broker/src/AutoDelete.cpp93
-rw-r--r--cpp/broker/src/Broker.cpp92
-rw-r--r--cpp/broker/src/Channel.cpp148
-rw-r--r--cpp/broker/src/Configuration.cpp195
-rw-r--r--cpp/broker/src/DirectExchange.cpp72
-rw-r--r--cpp/broker/src/ExchangeBinding.cpp32
-rw-r--r--cpp/broker/src/ExchangeRegistry.cpp43
-rw-r--r--cpp/broker/src/FanOutExchange.cpp56
-rw-r--r--cpp/broker/src/Message.cpp97
-rw-r--r--cpp/broker/src/NameGenerator.cpp29
-rw-r--r--cpp/broker/src/Queue.cpp148
-rw-r--r--cpp/broker/src/QueueRegistry.cpp72
-rw-r--r--cpp/broker/src/SessionHandlerFactoryImpl.cpp40
-rw-r--r--cpp/broker/src/SessionHandlerImpl.cpp378
-rw-r--r--cpp/broker/src/TopicExchange.cpp62
-rw-r--r--cpp/broker/test/Makefile20
-rw-r--r--cpp/broker/test/QueueRegistryTest.cpp79
-rw-r--r--cpp/broker/test/exchange_test.cpp68
-rw-r--r--cpp/broker/test/message_test.cpp57
-rw-r--r--cpp/broker/test/queue_test.cpp138
-rw-r--r--cpp/client/Makefile43
-rw-r--r--cpp/client/inc/Channel.h127
-rw-r--r--cpp/client/inc/Connection.h105
-rw-r--r--cpp/client/inc/Exchange.h49
-rw-r--r--cpp/client/inc/IncomingMessage.h60
-rw-r--r--cpp/client/inc/Message.h86
-rw-r--r--cpp/client/inc/MessageListener.h37
-rw-r--r--cpp/client/inc/Queue.h47
-rw-r--r--cpp/client/inc/ResponseHandler.h49
-rw-r--r--cpp/client/inc/ReturnedMessageHandler.h37
-rw-r--r--cpp/client/src/Channel.cpp432
-rw-r--r--cpp/client/src/Connection.cpp237
-rw-r--r--cpp/client/src/Exchange.cpp30
-rw-r--r--cpp/client/src/IncomingMessage.cpp85
-rw-r--r--cpp/client/src/Message.cpp147
-rw-r--r--cpp/client/src/Queue.cpp47
-rw-r--r--cpp/client/src/ResponseHandler.cpp63
-rw-r--r--cpp/client/test/Makefile45
-rw-r--r--cpp/client/test/client_test.cpp97
-rw-r--r--cpp/client/test/topic_listener.cpp180
-rw-r--r--cpp/client/test/topic_publisher.cpp253
-rw-r--r--cpp/common/Makefile51
-rw-r--r--cpp/common/concurrent/inc/APRBase.h63
-rw-r--r--cpp/common/concurrent/inc/APRMonitor.h48
-rw-r--r--cpp/common/concurrent/inc/APRThread.h48
-rw-r--r--cpp/common/concurrent/inc/APRThreadFactory.h44
-rw-r--r--cpp/common/concurrent/inc/APRThreadPool.h67
-rw-r--r--cpp/common/concurrent/inc/LMonitor.h44
-rw-r--r--cpp/common/concurrent/inc/LThreadFactory.h37
-rw-r--r--cpp/common/concurrent/inc/LockedQueue.h68
-rw-r--r--cpp/common/concurrent/inc/Monitor.h59
-rw-r--r--cpp/common/concurrent/inc/MonitorImpl.h57
-rw-r--r--cpp/common/concurrent/inc/Runnable.h34
-rw-r--r--cpp/common/concurrent/inc/TaskQueue.h200
-rw-r--r--cpp/common/concurrent/inc/Thread.h37
-rw-r--r--cpp/common/concurrent/inc/ThreadFactory.h38
-rw-r--r--cpp/common/concurrent/inc/ThreadFactoryImpl.h52
-rw-r--r--cpp/common/concurrent/inc/ThreadPool.h40
-rw-r--r--cpp/common/concurrent/src/APRBase.cpp97
-rw-r--r--cpp/common/concurrent/src/APRMonitor.cpp60
-rw-r--r--cpp/common/concurrent/src/APRThread.cpp50
-rw-r--r--cpp/common/concurrent/src/APRThreadFactory.cpp35
-rw-r--r--cpp/common/concurrent/src/APRThreadPool.cpp85
-rw-r--r--cpp/common/error/inc/QpidError.h47
-rw-r--r--cpp/common/error/inc/QpidErrorIO.h29
-rw-r--r--cpp/common/framing/Makefile28
-rw-r--r--cpp/common/framing/generated/Makefile41
-rw-r--r--cpp/common/framing/generated/stylesheets/amqp_client.xsl155
-rw-r--r--cpp/common/framing/generated/stylesheets/amqp_client_handler_impl.xsl187
-rw-r--r--cpp/common/framing/generated/stylesheets/amqp_client_operations.xsl105
-rw-r--r--cpp/common/framing/generated/stylesheets/amqp_consts.xsl77
-rw-r--r--cpp/common/framing/generated/stylesheets/amqp_server.xsl155
-rw-r--r--cpp/common/framing/generated/stylesheets/amqp_server_handler_impl.xsl187
-rw-r--r--cpp/common/framing/generated/stylesheets/amqp_server_operations.xsl113
-rw-r--r--cpp/common/framing/generated/stylesheets/code_gen.xsl91
-rw-r--r--cpp/common/framing/generated/stylesheets/code_utils.xsl210
-rw-r--r--cpp/common/framing/generated/stylesheets/convert_0.81.xsl407
-rw-r--r--cpp/common/framing/generated/stylesheets/cpp.xsl318
-rw-r--r--cpp/common/framing/generated/stylesheets/framing.xsl49
-rw-r--r--cpp/common/framing/generated/stylesheets/prepare1.xsl104
-rw-r--r--cpp/common/framing/generated/stylesheets/prepare2.xsl54
-rw-r--r--cpp/common/framing/generated/stylesheets/prepare3.xsl54
-rw-r--r--cpp/common/framing/generated/stylesheets/registry.xsl12
-rw-r--r--cpp/common/framing/generated/stylesheets/utils.xsl194
-rw-r--r--cpp/common/framing/inc/AMQBody.h46
-rw-r--r--cpp/common/framing/inc/AMQContentBody.h49
-rw-r--r--cpp/common/framing/inc/AMQDataBlock.h39
-rw-r--r--cpp/common/framing/inc/AMQFrame.h61
-rw-r--r--cpp/common/framing/inc/AMQHeaderBody.h55
-rw-r--r--cpp/common/framing/inc/AMQHeartbeatBody.h43
-rw-r--r--cpp/common/framing/inc/AMQMethodBody.h56
-rw-r--r--cpp/common/framing/inc/BasicHeaderProperties.h93
-rw-r--r--cpp/common/framing/inc/BodyHandler.h50
-rw-r--r--cpp/common/framing/inc/Buffer.h77
-rw-r--r--cpp/common/framing/inc/FieldTable.h68
-rw-r--r--cpp/common/framing/inc/HeaderProperties.h43
-rw-r--r--cpp/common/framing/inc/InitiationHandler.h37
-rw-r--r--cpp/common/framing/inc/InputHandler.h37
-rw-r--r--cpp/common/framing/inc/NamedValue.h49
-rw-r--r--cpp/common/framing/inc/OutputHandler.h37
-rw-r--r--cpp/common/framing/inc/ProtocolInitiation.h48
-rw-r--r--cpp/common/framing/inc/Value.h109
-rw-r--r--cpp/common/framing/inc/amqp_framing.h31
-rw-r--r--cpp/common/framing/inc/amqp_types.h36
-rw-r--r--cpp/common/framing/src/AMQContentBody.cpp35
-rw-r--r--cpp/common/framing/src/AMQFrame.cpp147
-rw-r--r--cpp/common/framing/src/AMQHeaderBody.cpp60
-rw-r--r--cpp/common/framing/src/AMQMethodBody.cpp43
-rw-r--r--cpp/common/framing/src/BasicHeaderProperties.cpp102
-rw-r--r--cpp/common/framing/src/BodyHandler.cpp49
-rw-r--r--cpp/common/framing/src/Buffer.cpp167
-rw-r--r--cpp/common/framing/src/FieldTable.cpp127
-rw-r--r--cpp/common/framing/src/NamedValue.cpp67
-rw-r--r--cpp/common/framing/src/ProtocolInitiation.cpp53
-rw-r--r--cpp/common/framing/src/Value.cpp57
-rw-r--r--cpp/common/framing/test/BodyHandlerTest.cpp107
-rw-r--r--cpp/common/framing/test/Makefile21
-rw-r--r--cpp/common/framing/test/field_table_test.cpp55
-rw-r--r--cpp/common/framing/test/framing_test.cpp147
-rw-r--r--cpp/common/framing/test/header_test.cpp144
-rw-r--r--cpp/common/io/Makefile35
-rw-r--r--cpp/common/io/inc/APRConnector.h95
-rw-r--r--cpp/common/io/inc/APRIOProcessor.h86
-rw-r--r--cpp/common/io/inc/APRSocket.h45
-rw-r--r--cpp/common/io/inc/Acceptor.h38
-rw-r--r--cpp/common/io/inc/BlockingAPRAcceptor.h62
-rw-r--r--cpp/common/io/inc/BlockingAPRSessionContext.h94
-rw-r--r--cpp/common/io/inc/Connector.h56
-rw-r--r--cpp/common/io/inc/ConnectorImpl.h53
-rw-r--r--cpp/common/io/inc/IOSession.h45
-rw-r--r--cpp/common/io/inc/LConnector.h48
-rw-r--r--cpp/common/io/inc/LFAcceptor.h71
-rw-r--r--cpp/common/io/inc/LFProcessor.h116
-rw-r--r--cpp/common/io/inc/LFSessionContext.h89
-rw-r--r--cpp/common/io/inc/SessionContext.h37
-rw-r--r--cpp/common/io/inc/SessionHandler.h42
-rw-r--r--cpp/common/io/inc/SessionHandlerFactory.h38
-rw-r--r--cpp/common/io/inc/SessionManager.h40
-rw-r--r--cpp/common/io/inc/ShutdownHandler.h34
-rw-r--r--cpp/common/io/inc/TimeoutHandler.h36
-rw-r--r--cpp/common/io/src/APRConnector.cpp198
-rw-r--r--cpp/common/io/src/APRIOProcessor.cpp100
-rw-r--r--cpp/common/io/src/APRSocket.cpp76
-rw-r--r--cpp/common/io/src/BlockingAPRAcceptor.cpp81
-rw-r--r--cpp/common/io/src/BlockingAPRSessionContext.cpp177
-rw-r--r--cpp/common/io/src/LFAcceptor.cpp80
-rw-r--r--cpp/common/io/src/LFProcessor.cpp191
-rw-r--r--cpp/common/io/src/LFSessionContext.cpp187
-rw-r--r--cpp/common/utils/inc/logger.h82
-rw-r--r--cpp/common/utils/inc/memory.h17
-rw-r--r--cpp/common/utils/src/Makefile40
-rw-r--r--cpp/common/utils/src/logger.cpp209
-rw-r--r--cpp/common/utils/src/logger_test.cpp78
-rw-r--r--cpp/doxygen/Makefile23
-rw-r--r--cpp/doxygen/doxygen.cfg1238
-rw-r--r--cpp/options.mk54
-rw-r--r--cpp/test_plugins.mk42
-rw-r--r--cpp/tools/saxon8.jarbin0 -> 3118502 bytes
180 files changed, 16067 insertions, 0 deletions
diff --git a/cpp/DESIGN b/cpp/DESIGN
new file mode 100644
index 0000000000..476fd42bfa
--- /dev/null
+++ b/cpp/DESIGN
@@ -0,0 +1,89 @@
+Qpid C++ AMQP implementation
+=============================
+
+The following is a brief description of the logical design of the
+Qpid C++ code.
+
+Layout
+
+There are three top level modules. The first two, client and broker,
+containi the code required for an AMQP client and an AMQP broker
+respectively. The third, common, contains code that is common to both
+client and broker implementations. [Note that at present only the
+client has been started].
+
+Within the common module there are currently four sub-modules. The
+largest of these is framing, containing the definitions of classes
+corresponding to key AMQP concepts such as frames, content & header
+bodies, particular method bodies etc as well as some interfaces and
+utilities used in the encoding and decoding of the wire protocol.
+
+Two of the other sub-modules in common, io and concurrent, provide
+abstractions of core io and concurrency constructs used in the client
+and broker code. The intention is to allow these to be implemented in
+different ways.interaction with the wire protocol. At present the
+implementation of the io and concurrency abstractions is based on APR
+(Apache Portable Runtime). [Note: the io module currently only
+contains the abstractions as seen from the client - the Connector. It
+will in due time likely have the analogous broker-side abstraction -
+the Acceptor].
+
+The final common sub-module is error, containing a simple exception
+definition used in all the error handling.
+
+Client Design
+
+The client module is primarily concerned with presenting the
+functionality offered by AMQP to users through a simple API that
+nevertheless allows all the protocol functionality to be exploited.
+[Note: it is currently nothing like complete in this regard!]
+
+The code in the client module is concerned with the logic of the AMQP
+protocol and interacts with the lower level transport issues through
+the InputHandler and OutputHandler abstractions defined in
+common/framing. It uses these in conjunction with the Connector
+interface, defined in common/io, for establishing a connection to the
+broker and interacting with it through the sending and receiving of
+messages represented by AMQFrame (defined in common/framing).
+
+The Connector implementation is responsible for connection set up,
+threading strategy and getting data on and off the wire. It delegates
+to the framing module for encode/decode operations. The interface
+between the io and the framing modules is primarily through the Buffer
+and AMQFrame classes.
+
+A Buffer allows 'raw' data to be read or written in terms of the AMQP
+defined 'types' (octet, short, long, long long, short string, long
+string, field table etc.). AMQP is defined in terms frames with
+specific bodies and the frame (as well as these different bodies) are
+defined in terms of these 'types'. The AMQFrame class allows a frame
+to be decoded by reading from the supplied buffer, or it allows a
+particular frame to be constructed and then encoded by writing to the
+supplied buffer. The io layer can then access the raw data that
+'backs' the buffer to either out it on the wire or to populate it from
+the wire.
+
+One minor exception to this is the protocol initiation. AMQP defines
+a protocol 'header', that is not a frame, and is sent by a client to
+intiate a connection. The Connector allows (indeed requires) such a
+frame to be passed in to initialise the connection (the Acceptor, when
+defined, will allow an InitiationHandler to be set allowing the broker
+to hook into the connection initiation). In order to remove
+duplication, the ProtocolInitiation class and the AMQFrame class both
+implement a AMQDataBlock class that defines the encode and decode
+methods. This allows both types to be treated generically for the
+purposes of encoding. In decoding, the context determines which type
+is expected and should be used for decoding (this is only relevant to
+the broker).
+
+
+
+
+ --------api--------
+ Client Impl ...............uses.....
+input handler --> --------- --------- <-- output handler .
+ A | .
+ | | framing utils
+ | V .
+ ------------------- <-- connector .
+ IO Layer ................uses....
diff --git a/cpp/Makefile b/cpp/Makefile
new file mode 100644
index 0000000000..7f83847b04
--- /dev/null
+++ b/cpp/Makefile
@@ -0,0 +1,53 @@
+#
+# 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.
+
+#
+# Master make file for c++ Qpid project (AMQP)
+#
+# Calls the makefiles in the various subdirectories in order to
+# build them in the correct sequence.
+#
+
+include options.mk
+
+UNITTESTS=$(wildcard common/*/test/*.so broker/test/*.so)
+
+.PHONY: all clean doxygen
+
+test: all
+ @$(MAKE) -C common test
+ @$(MAKE) -C broker test
+ @$(MAKE) -C client test
+ @$(MAKE) runtests
+
+runtests:
+ $(CPPUNIT_HOME)/bin/DllPlugInTester -t -b $(UNITTESTS)
+ bin/qpidd >> qpidd.log &
+ cd ../python ; ./run-tests -v -I cpp_failing.txt
+
+all:
+ @$(MAKE) -C common all
+ @$(MAKE) -C broker all
+ @$(MAKE) -C client all
+
+clean:
+ @$(MAKE) -C common clean
+ @$(MAKE) -C broker clean
+ @$(MAKE) -C client clean
+ @$(MAKE) -C doxygen clean
+ -@rm qpidd.log
+
+doxygen:
+ @$(MAKE) -C doxygen all
diff --git a/cpp/README b/cpp/README
new file mode 100644
index 0000000000..427a0c15c8
--- /dev/null
+++ b/cpp/README
@@ -0,0 +1,48 @@
+= Developer guide to C++ codebase =
+
+== Prerequisites ==
+
+Apache Portable Runtime 1.2.7: http://apr.apache.org/
+Install in /usr/local/apr or update options.mk if installed elsewhere.
+
+CppUnit: http://cppunit.sourceforge.net
+
+Optional: to generate source code documentation you need:
+ * doxygen: http://sourceforge.net/projects/doxygen/
+ * graphviz - http://www.graphviz.org/
+
+== Build and test ==
+
+make
+
+Default target builds and tests everything, see Makefile for other
+targets.
+
+=== Unit tests ===
+Unit tests are built as .so files containing CppUnit plugins.
+
+DllPlugInTester is provided as part of cppunit. You can use it to run
+any subset of the unit tests. See Makefile for examples.
+
+=== System tests ===
+
+The Python test suite ../python/run_tests is the main set of broker
+system tests.
+
+There are some C++ client test executables built under client/test.
+
+== Doxygen ==
+
+Doxygen generates documentation in several formats from source code
+using special comments. You can use javadoc style comments if you know
+javadoc, if you don't or want to know the fully story on doxygen
+markup see http://www.stack.nl/~dimitri/doxygen/
+
+Even even if the code is completely uncommented, doxygen generates
+UML-esque dependency diagrams that are ''extremely'' useful in navigating
+around the code, especially for newcomers.
+
+To try it out "make doxygen" then open doxygen/html/index.html
+
+
+
diff --git a/cpp/broker/Makefile b/cpp/broker/Makefile
new file mode 100644
index 0000000000..58ba3a41b5
--- /dev/null
+++ b/cpp/broker/Makefile
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+
+#
+# Build broker library and executable.
+#
+
+QPID_HOME = ../..
+include ${QPID_HOME}/cpp/options.mk
+
+SOURCES= $(wildcard src/*.cpp)
+OBJECTS= $(subst .cpp,.o,$(SOURCES))
+LIB_OBJECTS= $(subst src/Broker.o,,$(OBJECTS))
+EXE_OBJECTS= src/Broker.o
+
+
+.PHONY: all clean test
+
+all: $(BROKER)
+
+test:
+ @$(MAKE) -C test all
+
+clean:
+ -@rm -f ${OBJECTS} src/*.d ${BROKER} $(BROKER_LIB)
+ @$(MAKE) -C test clean
+
+$(BROKER): $(BROKER_LIB) $(EXE_OBJECTS)
+ ${CXX} -o $@ $(EXE_OBJECTS) $(LDFLAGS) -lapr-1 $(COMMON_LIB) $(BROKER_LIB)
+
+$(BROKER_LIB): $(LIB_OBJECTS)
+ $(CXX) -shared -o $@ $(LDFLAGS) $(LIB_OBJECTS) -lapr-1 $(COMMON_LIB) $(LIBDIR)
+
+-include $(SOURCES:.cpp=.d)
diff --git a/cpp/broker/inc/AutoDelete.h b/cpp/broker/inc/AutoDelete.h
new file mode 100644
index 0000000000..864d68358f
--- /dev/null
+++ b/cpp/broker/inc/AutoDelete.h
@@ -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.
+ *
+ */
+#ifndef _AutoDelete_
+#define _AutoDelete_
+
+#include <iostream>
+#include <queue>
+#include "MonitorImpl.h"
+#include "Queue.h"
+#include "QueueRegistry.h"
+#include "ThreadFactoryImpl.h"
+
+namespace qpid {
+ namespace broker{
+ class AutoDelete : private virtual qpid::concurrent::Runnable{
+ qpid::concurrent::ThreadFactoryImpl factory;
+ qpid::concurrent::MonitorImpl lock;
+ qpid::concurrent::MonitorImpl monitor;
+ std::queue<Queue::shared_ptr> queues;
+ QueueRegistry* const registry;
+ const u_int32_t period;
+ volatile bool stopped;
+ qpid::concurrent::Thread* runner;
+
+ Queue::shared_ptr const pop();
+ void process();
+ virtual void run();
+
+ public:
+ AutoDelete(QueueRegistry* const registry, u_int32_t period);
+ void add(Queue::shared_ptr const);
+ void start();
+ void stop();
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/broker/inc/Binding.h b/cpp/broker/inc/Binding.h
new file mode 100644
index 0000000000..b11419e92c
--- /dev/null
+++ b/cpp/broker/inc/Binding.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * 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.
+ *
+ */
+#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/broker/inc/Channel.h b/cpp/broker/inc/Channel.h
new file mode 100644
index 0000000000..aaf2ce569b
--- /dev/null
+++ b/cpp/broker/inc/Channel.h
@@ -0,0 +1,87 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Channel_
+#define _Channel_
+
+#include <map>
+#include "AMQContentBody.h"
+#include "AMQHeaderBody.h"
+#include "BasicPublishBody.h"
+#include "Binding.h"
+#include "Consumer.h"
+#include "Message.h"
+#include "MonitorImpl.h"
+#include "NameGenerator.h"
+#include "OutputHandler.h"
+#include "Queue.h"
+
+namespace qpid {
+ namespace broker {
+ class Channel{
+ private:
+ class ConsumerImpl : public virtual Consumer{
+ ConnectionToken* const connection;
+ Channel* parent;
+ string tag;
+ Queue::shared_ptr queue;
+ public:
+ ConsumerImpl(Channel* parent, string& tag, Queue::shared_ptr queue, ConnectionToken* const connection);
+ virtual bool deliver(Message::shared_ptr& msg);
+ void cancel();
+ };
+
+ typedef std::map<string,ConsumerImpl*>::iterator consumer_iterator;
+
+ const int id;
+ qpid::framing::OutputHandler* out;
+ u_int64_t deliveryTag;
+ Queue::shared_ptr defaultQueue;
+ bool transactional;
+ std::map<string, ConsumerImpl*> consumers;
+ u_int32_t prefetchSize;
+ u_int16_t prefetchCount;
+ u_int32_t framesize;
+ Message::shared_ptr message;
+ NameGenerator tagGenerator;
+
+ void deliver(Message::shared_ptr& msg, string& tag);
+ void publish(ExchangeRegistry* exchanges);
+
+ public:
+ Channel(qpid::framing::OutputHandler* out, int id, u_int32_t framesize);
+ ~Channel();
+ inline void setDefaultQueue(Queue::shared_ptr queue){ defaultQueue = queue; }
+ inline Queue::shared_ptr getDefaultQueue(){ return defaultQueue; }
+ inline u_int32_t setPrefetchSize(u_int32_t size){ prefetchSize = size; }
+ inline u_int16_t setPrefetchCount(u_int16_t count){ prefetchCount = count; }
+ void handlePublish(Message* msg);
+ void handleHeader(qpid::framing::AMQHeaderBody::shared_ptr header, ExchangeRegistry* exchanges);
+ void handleContent(qpid::framing::AMQContentBody::shared_ptr content, ExchangeRegistry* exchanges);
+ bool exists(string& consumerTag);
+ void consume(string& tag, Queue::shared_ptr queue, bool acks, bool exclusive, ConnectionToken* const connection = 0);
+ void cancel(string& tag);
+ void begin();
+ void close();
+ void commit();
+ void rollback();
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/broker/inc/Configuration.h b/cpp/broker/inc/Configuration.h
new file mode 100644
index 0000000000..5ec70a839b
--- /dev/null
+++ b/cpp/broker/inc/Configuration.h
@@ -0,0 +1,125 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Configuration_
+#define _Configuration_
+
+#include <cstdlib>
+#include <iostream>
+#include <vector>
+
+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);
+ };
+
+ 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);
+ };
+
+ BoolOption trace;
+ IntOption port;
+ IntOption workerThreads;
+ IntOption maxConnections;
+ IntOption connectionBacklog;
+ StringOption acceptor;
+ BoolOption help;
+
+ typedef std::vector<Option*>::iterator op_iterator;
+ std::vector<Option*> options;
+
+ public:
+ class ParseException{
+ public:
+ const std::string& error;
+ ParseException(const std::string& _error) : error(_error) {}
+ };
+
+
+ Configuration();
+ ~Configuration();
+
+ void parse(int argc, char** argv);
+
+ bool isHelp();
+ bool isTrace();
+ int getPort();
+ int getWorkerThreads();
+ int getMaxConnections();
+ int getConnectionBacklog();
+ const std::string& getAcceptor();
+
+ void usage();
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/broker/inc/ConnectionToken.h b/cpp/broker/inc/ConnectionToken.h
new file mode 100644
index 0000000000..1faefec2cc
--- /dev/null
+++ b/cpp/broker/inc/ConnectionToken.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * 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.
+ *
+ */
+#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/broker/inc/Consumer.h b/cpp/broker/inc/Consumer.h
new file mode 100644
index 0000000000..af2d5d7812
--- /dev/null
+++ b/cpp/broker/inc/Consumer.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Consumer_
+#define _Consumer_
+
+#include "Message.h"
+
+namespace qpid {
+ namespace broker {
+ class Consumer{
+ public:
+ virtual bool deliver(Message::shared_ptr& msg) = 0;
+ virtual ~Consumer(){}
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/broker/inc/DirectExchange.h b/cpp/broker/inc/DirectExchange.h
new file mode 100644
index 0000000000..bf8c5f0b37
--- /dev/null
+++ b/cpp/broker/inc/DirectExchange.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _DirectExchange_
+#define _DirectExchange_
+
+#include <map>
+#include <vector>
+#include "Exchange.h"
+#include "FieldTable.h"
+#include "Message.h"
+#include "MonitorImpl.h"
+#include "Queue.h"
+
+namespace qpid {
+namespace broker {
+ class DirectExchange : public virtual Exchange{
+ const string name;
+ std::map<string, std::vector<Queue::shared_ptr> > bindings;
+ qpid::concurrent::MonitorImpl lock;
+
+ public:
+ static const std::string typeName;
+
+ DirectExchange(const string& name);
+
+ inline virtual const string& getName(){ return name; }
+
+ virtual void bind(Queue::shared_ptr queue, const string& routingKey, qpid::framing::FieldTable* args);
+
+ virtual void unbind(Queue::shared_ptr queue, const string& routingKey, qpid::framing::FieldTable* args);
+
+ virtual void route(Message::shared_ptr& msg, const string& routingKey, qpid::framing::FieldTable* args);
+
+ virtual ~DirectExchange();
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/broker/inc/Exchange.h b/cpp/broker/inc/Exchange.h
new file mode 100644
index 0000000000..5f5dc5ce71
--- /dev/null
+++ b/cpp/broker/inc/Exchange.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Exchange_
+#define _Exchange_
+
+#include "FieldTable.h"
+#include "Message.h"
+#include "Queue.h"
+
+namespace qpid {
+namespace broker {
+ class Exchange{
+ public:
+ virtual const string& getName() = 0;
+ virtual void bind(Queue::shared_ptr queue, const string& routingKey, qpid::framing::FieldTable* args) = 0;
+ virtual void unbind(Queue::shared_ptr queue, const string& routingKey, qpid::framing::FieldTable* args) = 0;
+ virtual void route(Message::shared_ptr& msg, const string& routingKey, qpid::framing::FieldTable* args) = 0;
+ virtual ~Exchange(){}
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/broker/inc/ExchangeBinding.h b/cpp/broker/inc/ExchangeBinding.h
new file mode 100644
index 0000000000..4cbb73acbf
--- /dev/null
+++ b/cpp/broker/inc/ExchangeBinding.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ExchangeBinding_
+#define _ExchangeBinding_
+
+#include "Binding.h"
+#include "FieldTable.h"
+#include "Queue.h"
+
+namespace qpid {
+ namespace broker {
+ class Exchange;
+ class Queue;
+
+ class ExchangeBinding : public virtual Binding{
+ Exchange* e;
+ Queue::shared_ptr q;
+ const string key;
+ qpid::framing::FieldTable* args;
+ public:
+ ExchangeBinding(Exchange* _e, Queue::shared_ptr _q, const string& _key, qpid::framing::FieldTable* _args);
+ virtual void cancel();
+ virtual ~ExchangeBinding();
+ };
+ }
+}
+
+
+#endif
+
diff --git a/cpp/broker/inc/ExchangeRegistry.h b/cpp/broker/inc/ExchangeRegistry.h
new file mode 100644
index 0000000000..0f0eaae0d0
--- /dev/null
+++ b/cpp/broker/inc/ExchangeRegistry.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ExchangeRegistry_
+#define _ExchangeRegistry_
+
+#include <map>
+#include "Exchange.h"
+#include "Monitor.h"
+
+namespace qpid {
+namespace broker {
+ class ExchangeRegistry{
+ std::map<string, Exchange*> exchanges;
+ qpid::concurrent::Monitor* lock;
+ public:
+ ExchangeRegistry();
+ void declare(Exchange* exchange);
+ void destroy(const string& name);
+ Exchange* get(const string& name);
+ inline qpid::concurrent::Monitor* getLock(){ return lock; }
+ ~ExchangeRegistry();
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/broker/inc/FanOutExchange.h b/cpp/broker/inc/FanOutExchange.h
new file mode 100644
index 0000000000..9d0d32bbf8
--- /dev/null
+++ b/cpp/broker/inc/FanOutExchange.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _FanOutExchange_
+#define _FanOutExchange_
+
+#include <map>
+#include <vector>
+#include "Exchange.h"
+#include "FieldTable.h"
+#include "Message.h"
+#include "MonitorImpl.h"
+#include "Queue.h"
+
+namespace qpid {
+namespace broker {
+
+class FanOutExchange : public virtual Exchange {
+ const string name;
+ std::vector<Queue::shared_ptr> bindings;
+ qpid::concurrent::MonitorImpl lock;
+
+ public:
+ static const std::string typeName;
+
+ FanOutExchange(const string& name);
+
+ inline virtual const string& getName(){ return name; }
+
+ virtual void bind(Queue::shared_ptr queue, const string& routingKey, qpid::framing::FieldTable* args);
+
+ virtual void unbind(Queue::shared_ptr queue, const string& routingKey, qpid::framing::FieldTable* args);
+
+ virtual void route(Message::shared_ptr& msg, const string& routingKey, qpid::framing::FieldTable* args);
+
+ virtual ~FanOutExchange();
+};
+
+}
+}
+
+
+
+#endif
diff --git a/cpp/broker/inc/Message.h b/cpp/broker/inc/Message.h
new file mode 100644
index 0000000000..37a0c9b2c8
--- /dev/null
+++ b/cpp/broker/inc/Message.h
@@ -0,0 +1,73 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Message_
+#define _Message_
+
+#include "memory.h"
+#include "AMQContentBody.h"
+#include "AMQHeaderBody.h"
+#include "BasicHeaderProperties.h"
+#include "BasicPublishBody.h"
+#include "ConnectionToken.h"
+#include "OutputHandler.h"
+
+namespace qpid {
+ namespace broker {
+ class ExchangeRegistry;
+
+ class Message{
+ typedef std::vector<qpid::framing::AMQContentBody::shared_ptr> content_list;
+ typedef content_list::iterator content_iterator;
+
+ const ConnectionToken* const publisher;
+ string exchange;
+ string routingKey;
+ const bool mandatory;
+ const bool immediate;
+ qpid::framing::AMQHeaderBody::shared_ptr header;
+ content_list content;
+
+ u_int64_t contentSize();
+ qpid::framing::BasicHeaderProperties* getHeaderProperties();
+
+
+ public:
+ typedef std::tr1::shared_ptr<Message> shared_ptr;
+
+ Message(const ConnectionToken* const publisher,
+ const string& exchange, const string& routingKey,
+ bool mandatory, bool immediate);
+ ~Message();
+ void setHeader(qpid::framing::AMQHeaderBody::shared_ptr header);
+ void addContent(qpid::framing::AMQContentBody::shared_ptr data);
+ bool isComplete();
+ const ConnectionToken* const getPublisher();
+
+ void deliver(qpid::framing::OutputHandler* out, int channel,
+ string& consumerTag, u_int64_t deliveryTag,
+ u_int32_t framesize);
+
+ friend bool route(Message::shared_ptr& msg, ExchangeRegistry* registry);
+
+ };
+ bool route(Message::shared_ptr& msg, ExchangeRegistry* registry);
+ }
+}
+
+
+#endif
diff --git a/cpp/broker/inc/NameGenerator.h b/cpp/broker/inc/NameGenerator.h
new file mode 100644
index 0000000000..6e6e0acf28
--- /dev/null
+++ b/cpp/broker/inc/NameGenerator.h
@@ -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.
+ *
+ */
+#ifndef _NameGenerator_
+#define _NameGenerator_
+
+#include "Message.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/broker/inc/Queue.h b/cpp/broker/inc/Queue.h
new file mode 100644
index 0000000000..2229ba6235
--- /dev/null
+++ b/cpp/broker/inc/Queue.h
@@ -0,0 +1,106 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Queue_
+#define _Queue_
+
+#include <vector>
+#include <queue>
+#include "memory.h"
+#include "apr_time.h"
+#include "amqp_types.h"
+#include "Binding.h"
+#include "ConnectionToken.h"
+#include "Consumer.h"
+#include "Message.h"
+#include "MonitorImpl.h"
+
+namespace qpid {
+ namespace broker {
+
+ /**
+ * Thrown when exclusive access would be violated.
+ */
+ struct ExclusiveAccessException{};
+
+ /**
+ * 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{
+ const string name;
+ const u_int32_t autodelete;
+ const bool durable;
+ const ConnectionToken* const owner;
+ std::vector<Consumer*> consumers;
+ std::queue<Binding*> bindings;
+ std::queue<Message::shared_ptr> messages;
+ bool queueing;
+ bool dispatching;
+ int next;
+ mutable qpid::concurrent::MonitorImpl lock;
+ apr_time_t lastUsed;
+ Consumer* exclusive;
+
+ bool startDispatching();
+ bool dispatch(Message::shared_ptr& msg);
+
+ public:
+
+ typedef std::tr1::shared_ptr<Queue> shared_ptr;
+
+ typedef std::vector<shared_ptr> vector;
+
+ Queue(const string& name, bool durable = false, u_int32_t autodelete = 0, const ConnectionToken* const owner = 0);
+ ~Queue();
+ /**
+ * 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 from where it will be
+ * dispatched to immediately to a consumer if one is
+ * available or stored for dequeue or later dispatch if
+ * not.
+ */
+ void deliver(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);
+ Message::shared_ptr dequeue();
+ u_int32_t purge();
+ u_int32_t getMessageCount() const;
+ u_int32_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; }
+ bool canAutoDelete() const;
+ };
+ }
+}
+
+
+#endif
diff --git a/cpp/broker/inc/QueueRegistry.h b/cpp/broker/inc/QueueRegistry.h
new file mode 100644
index 0000000000..ac12aa8f88
--- /dev/null
+++ b/cpp/broker/inc/QueueRegistry.h
@@ -0,0 +1,88 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _QueueRegistry_
+#define _QueueRegistry_
+
+#include <map>
+#include "MonitorImpl.h"
+#include "Queue.h"
+
+namespace qpid {
+namespace broker {
+
+class SessionHandlerImpl;
+
+/**
+ * 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();
+ ~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, u_int32_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();
+
+ private:
+ typedef std::map<string, Queue::shared_ptr> QueueMap;
+ QueueMap queues;
+ qpid::concurrent::MonitorImpl lock;
+ int counter;
+
+};
+
+
+}
+}
+
+
+#endif
diff --git a/cpp/broker/inc/SessionHandlerFactoryImpl.h b/cpp/broker/inc/SessionHandlerFactoryImpl.h
new file mode 100644
index 0000000000..2317a6667b
--- /dev/null
+++ b/cpp/broker/inc/SessionHandlerFactoryImpl.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _SessionHandlerFactoryImpl_
+#define _SessionHandlerFactoryImpl_
+
+#include "AMQFrame.h"
+#include "AutoDelete.h"
+#include "DirectExchange.h"
+#include "ExchangeRegistry.h"
+#include "ProtocolInitiation.h"
+#include "QueueRegistry.h"
+#include "SessionHandlerFactory.h"
+#include "TimeoutHandler.h"
+
+namespace qpid {
+ namespace broker {
+
+ class SessionHandlerFactoryImpl : public virtual qpid::io::SessionHandlerFactory
+ {
+ QueueRegistry queues;
+ ExchangeRegistry exchanges;
+ const u_int32_t timeout;//timeout for auto-deleted queues (in ms)
+ AutoDelete cleaner;
+ public:
+ SessionHandlerFactoryImpl(u_int32_t timeout = 30000);
+ virtual qpid::io::SessionHandler* create(qpid::io::SessionContext* ctxt);
+ virtual ~SessionHandlerFactoryImpl();
+ };
+
+ }
+}
+
+
+#endif
diff --git a/cpp/broker/inc/SessionHandlerImpl.h b/cpp/broker/inc/SessionHandlerImpl.h
new file mode 100644
index 0000000000..14a6404c78
--- /dev/null
+++ b/cpp/broker/inc/SessionHandlerImpl.h
@@ -0,0 +1,230 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _SessionHandlerImpl_
+#define _SessionHandlerImpl_
+
+#include <map>
+#include <sstream>
+#include <vector>
+#include <exception>
+#include "AMQFrame.h"
+#include "AMQP_ServerOperations.h"
+#include "AutoDelete.h"
+#include "ExchangeRegistry.h"
+#include "Channel.h"
+#include "ConnectionToken.h"
+#include "DirectExchange.h"
+#include "OutputHandler.h"
+#include "ProtocolInitiation.h"
+#include "QueueRegistry.h"
+#include "SessionContext.h"
+#include "SessionHandler.h"
+#include "TimeoutHandler.h"
+#include "TopicExchange.h"
+
+namespace qpid {
+namespace broker {
+
+struct ChannelException : public std::exception {
+ u_int16_t code;
+ string text;
+ ChannelException(u_int16_t _code, string _text) : code(_code), text(_text) {}
+ ~ChannelException() throw() {}
+ const char* what() const throw() { return text.c_str(); }
+};
+
+struct ConnectionException : public std::exception {
+ u_int16_t code;
+ string text;
+ ConnectionException(u_int16_t _code, string _text) : code(_code), text(_text) {}
+ ~ConnectionException() throw() {}
+ const char* what() const throw() { return text.c_str(); }
+};
+
+class SessionHandlerImpl : public virtual qpid::io::SessionHandler,
+ public virtual qpid::framing::AMQP_ServerOperations,
+ public virtual ConnectionToken
+{
+ typedef std::map<u_int16_t, Channel*>::iterator channel_iterator;
+ typedef std::vector<Queue::shared_ptr>::iterator queue_iterator;
+
+ qpid::io::SessionContext* context;
+ QueueRegistry* queues;
+ ExchangeRegistry* const exchanges;
+ AutoDelete* const cleaner;
+ const u_int32_t timeout;//timeout for auto-deleted queues (in ms)
+
+ ConnectionHandler* connectionHandler;
+ ChannelHandler* channelHandler;
+ BasicHandler* basicHandler;
+ ExchangeHandler* exchangeHandler;
+ QueueHandler* queueHandler;
+
+ std::map<u_int16_t, Channel*> channels;
+ std::vector<Queue::shared_ptr> exclusiveQueues;
+
+ u_int32_t framemax;
+ u_int16_t heartbeat;
+
+ void handleHeader(u_int16_t channel, qpid::framing::AMQHeaderBody::shared_ptr body);
+ void handleContent(u_int16_t channel, qpid::framing::AMQContentBody::shared_ptr body);
+ void handleHeartbeat(qpid::framing::AMQHeartbeatBody::shared_ptr body);
+
+ /**
+ * 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 no queue specified and channel has not declared one.
+ */
+ Queue::shared_ptr getQueue(const string& name, u_int16_t channel);
+
+ Exchange* findExchange(const string& name);
+
+ public:
+ SessionHandlerImpl(qpid::io::SessionContext* context, QueueRegistry* queues,
+ ExchangeRegistry* exchanges, AutoDelete* cleaner, const u_int32_t timeout);
+ virtual void received(qpid::framing::AMQFrame* frame);
+ virtual void initiated(qpid::framing::ProtocolInitiation* header);
+ virtual void idleOut();
+ virtual void idleIn();
+ virtual void closed();
+ virtual ~SessionHandlerImpl();
+
+ class ConnectionHandlerImpl : public virtual ConnectionHandler{
+ SessionHandlerImpl* parent;
+ public:
+ inline ConnectionHandlerImpl(SessionHandlerImpl* _parent) : parent(_parent) {}
+
+ virtual void startOk(u_int16_t channel, qpid::framing::FieldTable& clientProperties, string& mechanism,
+ string& response, string& locale);
+
+ virtual void secureOk(u_int16_t channel, string& response);
+
+ virtual void tuneOk(u_int16_t channel, u_int16_t channelMax, u_int32_t frameMax, u_int16_t heartbeat);
+
+ virtual void open(u_int16_t channel, string& virtualHost, string& capabilities, bool insist);
+
+ virtual void close(u_int16_t channel, u_int16_t replyCode, string& replyText, u_int16_t classId,
+ u_int16_t methodId);
+
+ virtual void closeOk(u_int16_t channel);
+
+ virtual ~ConnectionHandlerImpl(){}
+ };
+
+ class ChannelHandlerImpl : public virtual ChannelHandler{
+ SessionHandlerImpl* parent;
+ public:
+ inline ChannelHandlerImpl(SessionHandlerImpl* _parent) : parent(_parent) {}
+
+ virtual void open(u_int16_t channel, string& outOfBand);
+
+ virtual void flow(u_int16_t channel, bool active);
+
+ virtual void flowOk(u_int16_t channel, bool active);
+
+ virtual void close(u_int16_t channel, u_int16_t replyCode, string& replyText,
+ u_int16_t classId, u_int16_t methodId);
+
+ virtual void closeOk(u_int16_t channel);
+
+ virtual ~ChannelHandlerImpl(){}
+ };
+
+ class ExchangeHandlerImpl : public virtual ExchangeHandler{
+ SessionHandlerImpl* parent;
+ public:
+ inline ExchangeHandlerImpl(SessionHandlerImpl* _parent) : parent(_parent) {}
+
+ virtual void declare(u_int16_t channel, u_int16_t ticket, string& exchange, string& type,
+ bool passive, bool durable, bool autoDelete, bool internal, bool nowait,
+ qpid::framing::FieldTable& arguments);
+
+ virtual void delete_(u_int16_t channel, u_int16_t ticket, string& exchange, bool ifUnused, bool nowait);
+
+ virtual ~ExchangeHandlerImpl(){}
+ };
+
+
+ class QueueHandlerImpl : public virtual QueueHandler{
+ SessionHandlerImpl* parent;
+ public:
+ inline QueueHandlerImpl(SessionHandlerImpl* _parent) : parent(_parent) {}
+
+ virtual void declare(u_int16_t channel, u_int16_t ticket, string& queue,
+ bool passive, bool durable, bool exclusive,
+ bool autoDelete, bool nowait, qpid::framing::FieldTable& arguments);
+
+ virtual void bind(u_int16_t channel, u_int16_t ticket, string& queue,
+ string& exchange, string& routingKey, bool nowait,
+ qpid::framing::FieldTable& arguments);
+
+ virtual void purge(u_int16_t channel, u_int16_t ticket, string& queue,
+ bool nowait);
+
+ virtual void delete_(u_int16_t channel, u_int16_t ticket, string& queue, bool ifUnused, bool ifEmpty,
+ bool nowait);
+
+ virtual ~QueueHandlerImpl(){}
+ };
+
+ class BasicHandlerImpl : public virtual BasicHandler{
+ SessionHandlerImpl* parent;
+ public:
+ inline BasicHandlerImpl(SessionHandlerImpl* _parent) : parent(_parent) {}
+
+ virtual void qos(u_int16_t channel, u_int32_t prefetchSize, u_int16_t prefetchCount, bool global);
+
+ virtual void consume(u_int16_t channel, u_int16_t ticket, string& queue, string& consumerTag,
+ bool noLocal, bool noAck, bool exclusive, bool nowait);
+
+ virtual void cancel(u_int16_t channel, string& consumerTag, bool nowait);
+
+ virtual void publish(u_int16_t channel, u_int16_t ticket, string& exchange, string& routingKey,
+ bool mandatory, bool immediate);
+
+ virtual void get(u_int16_t channel, u_int16_t ticket, string& queue, bool noAck);
+
+ virtual void ack(u_int16_t channel, u_int64_t deliveryTag, bool multiple);
+
+ virtual void reject(u_int16_t channel, u_int64_t deliveryTag, bool requeue);
+
+ virtual void recover(u_int16_t channel, bool requeue);
+
+ virtual ~BasicHandlerImpl(){}
+ };
+
+ inline virtual ChannelHandler* getChannelHandler(){ return channelHandler; }
+ inline virtual ConnectionHandler* getConnectionHandler(){ return connectionHandler; }
+ inline virtual BasicHandler* getBasicHandler(){ return basicHandler; }
+ inline virtual ExchangeHandler* getExchangeHandler(){ return exchangeHandler; }
+ inline virtual QueueHandler* getQueueHandler(){ return queueHandler; }
+
+ inline virtual AccessHandler* getAccessHandler(){ return 0; }
+ inline virtual FileHandler* getFileHandler(){ return 0; }
+ inline virtual StreamHandler* getStreamHandler(){ return 0; }
+ inline virtual TxHandler* getTxHandler(){ return 0; }
+ inline virtual DtxHandler* getDtxHandler(){ return 0; }
+ inline virtual TunnelHandler* getTunnelHandler(){ return 0; }
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/broker/inc/TopicExchange.h b/cpp/broker/inc/TopicExchange.h
new file mode 100644
index 0000000000..d9ff62ecc6
--- /dev/null
+++ b/cpp/broker/inc/TopicExchange.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _TopicExchange_
+#define _TopicExchange_
+
+#include <map>
+#include <vector>
+#include "Exchange.h"
+#include "FieldTable.h"
+#include "Message.h"
+#include "MonitorImpl.h"
+#include "Queue.h"
+
+namespace qpid {
+namespace broker {
+ class TopicExchange : public virtual Exchange{
+ const string name;
+ std::map<string, std::vector<Queue::shared_ptr> > bindings;//NOTE: pattern matching not yet supported
+ qpid::concurrent::MonitorImpl lock;
+
+ public:
+ static const std::string typeName;
+
+ TopicExchange(const string& name);
+
+ inline virtual const string& getName(){ return name; }
+
+ virtual void bind(Queue::shared_ptr queue, const string& routingKey, qpid::framing::FieldTable* args);
+
+ virtual void unbind(Queue::shared_ptr queue, const string& routingKey, qpid::framing::FieldTable* args);
+
+ virtual void route(Message::shared_ptr& msg, const string& routingKey, qpid::framing::FieldTable* args);
+
+ virtual ~TopicExchange();
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/broker/src/AutoDelete.cpp b/cpp/broker/src/AutoDelete.cpp
new file mode 100644
index 0000000000..6793ec449d
--- /dev/null
+++ b/cpp/broker/src/AutoDelete.cpp
@@ -0,0 +1,93 @@
+/*
+ *
+ * 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 "AutoDelete.h"
+
+using namespace qpid::broker;
+
+AutoDelete::AutoDelete(QueueRegistry* const _registry, u_int32_t _period) : registry(_registry),
+ period(_period),
+ stopped(true),
+ runner(0){}
+
+void AutoDelete::add(Queue::shared_ptr const queue){
+ lock.acquire();
+ queues.push(queue);
+ lock.release();
+}
+
+Queue::shared_ptr const AutoDelete::pop(){
+ Queue::shared_ptr next;
+ lock.acquire();
+ if(!queues.empty()){
+ next = queues.front();
+ queues.pop();
+ }
+ lock.release();
+ 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.acquire();
+ while(!stopped){
+ process();
+ monitor.wait(period);
+ }
+ monitor.release();
+}
+
+void AutoDelete::start(){
+ monitor.acquire();
+ if(stopped){
+ runner = factory.create(this);
+ stopped = false;
+ monitor.release();
+ runner->start();
+ }else{
+ monitor.release();
+ }
+}
+
+void AutoDelete::stop(){
+ monitor.acquire();
+ if(!stopped){
+ stopped = true;
+ monitor.notify();
+ monitor.release();
+ runner->join();
+ delete runner;
+ }else{
+ monitor.release();
+ }
+}
diff --git a/cpp/broker/src/Broker.cpp b/cpp/broker/src/Broker.cpp
new file mode 100644
index 0000000000..5d59b63622
--- /dev/null
+++ b/cpp/broker/src/Broker.cpp
@@ -0,0 +1,92 @@
+/*
+ *
+ * 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 <memory>
+#include "apr_signal.h"
+
+#include "Acceptor.h"
+#include "Configuration.h"
+#include "QpidError.h"
+#include "SessionHandlerFactoryImpl.h"
+
+//optional includes:
+#ifdef _USE_APR_IO_
+
+#include "BlockingAPRAcceptor.h"
+#include "LFAcceptor.h"
+
+#endif
+
+using namespace qpid::broker;
+using namespace qpid::io;
+
+void handle_signal(int signal);
+
+Acceptor* createAcceptor(Configuration& config);
+
+int main(int argc, char** argv)
+{
+ SessionHandlerFactoryImpl factory;
+ Configuration config;
+ try{
+
+ config.parse(argc, argv);
+ if(config.isHelp()){
+ config.usage();
+ }else{
+#ifdef _USE_APR_IO_
+ apr_signal(SIGINT, handle_signal);
+#endif
+ try{
+ std::auto_ptr<Acceptor> acceptor(createAcceptor(config));
+ try{
+ acceptor->bind(config.getPort(), &factory);
+ }catch(qpid::QpidError error){
+ std::cout << "Error [" << error.code << "] " << error.msg << " (" << error.file << ":" << error.line << ")" << std::endl;
+ }
+ }catch(qpid::QpidError error){
+ std::cout << "Error [" << error.code << "] " << error.msg << " (" << error.file << ":" << error.line << ")" << std::endl;
+ }
+ }
+ }catch(Configuration::ParseException error){
+ std::cout << "Error: " << error.error << std::endl;
+ }
+
+ return 1;
+}
+
+Acceptor* createAcceptor(Configuration& config){
+ const string type(config.getAcceptor());
+#ifdef _USE_APR_IO_
+ if("blocking" == type){
+ std::cout << "Using blocking acceptor " << std::endl;
+ return new BlockingAPRAcceptor(config.isTrace(), config.getConnectionBacklog());
+ }else if("non-blocking" == type){
+ std::cout << "Using non-blocking acceptor " << std::endl;
+ return new LFAcceptor(config.isTrace(),
+ config.getConnectionBacklog(),
+ config.getWorkerThreads(),
+ config.getMaxConnections());
+ }
+#endif
+ throw Configuration::ParseException("Unrecognised acceptor: " + type);
+}
+
+void handle_signal(int signal){
+ std::cout << "Shutting down..." << std::endl;
+}
diff --git a/cpp/broker/src/Channel.cpp b/cpp/broker/src/Channel.cpp
new file mode 100644
index 0000000000..6980fe5a1b
--- /dev/null
+++ b/cpp/broker/src/Channel.cpp
@@ -0,0 +1,148 @@
+/*
+ *
+ * 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 "Channel.h"
+#include "QpidError.h"
+#include <iostream>
+#include <sstream>
+#include <assert.h>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::concurrent;
+
+Channel::Channel(OutputHandler* _out, int _id, u_int32_t _framesize) : out(_out),
+ id(_id),
+ framesize(_framesize),
+ transactional(false),
+ deliveryTag(1),
+ tagGenerator("sgen"){}
+
+Channel::~Channel(){
+ for(consumer_iterator i = consumers.begin(); i != consumers.end(); i = consumers.begin() ){
+ std::cout << "ERROR: Channel consumer appears not to have been cancelled before channel was destroyed." << std::endl;
+ delete (i->second);
+ }
+}
+
+bool Channel::exists(string& consumerTag){
+ return consumers.find(consumerTag) != consumers.end();
+}
+
+void Channel::consume(string& tag, Queue::shared_ptr queue, bool acks, bool exclusive, ConnectionToken* const connection){
+ if(tag.empty()) tag = tagGenerator.generate();
+
+ ConsumerImpl* c(new ConsumerImpl(this, tag, queue, connection));
+ try{
+ queue->consume(c, exclusive);//may throw exception
+ consumers[tag] = c;
+ }catch(ExclusiveAccessException& e){
+ delete c;
+ throw e;
+ }
+}
+
+void Channel::cancel(string& tag){
+ ConsumerImpl* c = consumers[tag];
+ if(c){
+ c->cancel();
+ consumers.erase(tag);
+ delete c;
+ }
+}
+
+void Channel::close(){
+ //cancel all consumers
+ for(consumer_iterator i = consumers.begin(); i != consumers.end(); i = consumers.begin() ){
+ ConsumerImpl* c = i->second;
+ c->cancel();
+ consumers.erase(i);
+ delete c;
+ }
+}
+
+void Channel::begin(){
+ transactional = true;
+}
+
+void Channel::commit(){
+
+}
+
+void Channel::rollback(){
+
+}
+
+void Channel::deliver(Message::shared_ptr& msg, string& consumerTag){
+ //send deliver method, header and content(s)
+ msg->deliver(out, id, consumerTag, deliveryTag++, framesize);
+}
+
+Channel::ConsumerImpl::ConsumerImpl(Channel* _parent, string& _tag,
+ Queue::shared_ptr _queue,
+ ConnectionToken* const _connection) : parent(_parent),
+ tag(_tag),
+ queue(_queue),
+ connection(_connection){
+}
+
+bool Channel::ConsumerImpl::deliver(Message::shared_ptr& msg){
+ if(connection != msg->getPublisher()){
+ parent->deliver(msg, tag);
+ return true;
+ }else{
+ return false;
+ }
+}
+
+void Channel::ConsumerImpl::cancel(){
+ if(queue) queue->cancel(this);
+}
+
+void Channel::handlePublish(Message* msg){
+ if(message.get()){
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Invalid message sequence: got publish before previous content was completed.");
+ }
+ message = Message::shared_ptr(msg);
+}
+
+void Channel::handleHeader(AMQHeaderBody::shared_ptr header, ExchangeRegistry* exchanges){
+ if(!message.get()){
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Invalid message sequence: got header before publish.");
+ }
+ message->setHeader(header);
+ if(message->isComplete()){
+ publish(exchanges);
+ }
+}
+
+void Channel::handleContent(AMQContentBody::shared_ptr content, ExchangeRegistry* exchanges){
+ if(!message.get()){
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Invalid message sequence: got content before publish.");
+ }
+ message->addContent(content);
+ if(message->isComplete()){
+ publish(exchanges);
+ }
+}
+
+void Channel::publish(ExchangeRegistry* exchanges){
+ if(!route(message, exchanges)){
+ std::cout << "WARNING: Could not route message." << std::endl;
+ }
+ message.reset();
+}
diff --git a/cpp/broker/src/Configuration.cpp b/cpp/broker/src/Configuration.cpp
new file mode 100644
index 0000000000..aceb35bc87
--- /dev/null
+++ b/cpp/broker/src/Configuration.cpp
@@ -0,0 +1,195 @@
+/*
+ *
+ * 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 "Configuration.h"
+
+using namespace qpid::broker;
+using namespace std;
+
+Configuration::Configuration() :
+ trace('t', "trace", "Print incoming & outgoing frames to the console (default=false)", false),
+ port('p', "port", "Sets the port to listen on (default=5672)", 5672),
+ workerThreads("worker-threads", "Sets the number of worker threads to use (default=5). Only valid for non-blocking acceptor.", 5),
+ maxConnections("max-connections", "Sets the maximum number of connections the broker can accept (default=500). Only valid for non-blocking acceptor.", 500),
+ connectionBacklog("connection-backlog", "Sets the connection backlog for the servers socket (default=10)", 10),
+ acceptor('a', "acceptor", "Sets the acceptor to use. Currently only two values are recognised, blocking and non-blocking (which is the default)", "non-blocking"),
+ help("help", "Prints usage information", false)
+{
+ options.push_back(&trace);
+ options.push_back(&port);
+ options.push_back(&workerThreads);
+ options.push_back(&maxConnections);
+ options.push_back(&connectionBacklog);
+ options.push_back(&acceptor);
+ options.push_back(&help);
+}
+
+Configuration::~Configuration(){}
+
+void Configuration::parse(int argc, char** argv){
+ 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){
+ std::cout << "Warning: skipping unrecognised option " << argv[position] << std::endl;
+ position++;
+ }
+ }
+}
+
+void Configuration::usage(){
+ for(op_iterator i = options.begin(); i < options.end(); i++){
+ (*i)->print(std::cout);
+ }
+}
+
+bool Configuration::isHelp(){
+ return help.getValue();
+}
+
+bool Configuration::isTrace(){
+ return trace.getValue();
+}
+
+int Configuration::getPort(){
+ return port.getValue();
+}
+
+int Configuration::getWorkerThreads(){
+ return workerThreads.getValue();
+}
+
+int Configuration::getMaxConnections(){
+ return maxConnections.getValue();
+}
+
+int Configuration::getConnectionBacklog(){
+ return connectionBacklog.getValue();
+}
+
+const string& Configuration::getAcceptor(){
+ return acceptor.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 << " or ";
+ }
+ 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());
+}
+
+// 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& _value){
+ value = true;
+}
diff --git a/cpp/broker/src/DirectExchange.cpp b/cpp/broker/src/DirectExchange.cpp
new file mode 100644
index 0000000000..70f7ee838f
--- /dev/null
+++ b/cpp/broker/src/DirectExchange.cpp
@@ -0,0 +1,72 @@
+/*
+ *
+ * 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 "DirectExchange.h"
+#include "ExchangeBinding.h"
+#include <iostream>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+DirectExchange::DirectExchange(const string& _name) : name(_name) {
+
+}
+
+void DirectExchange::bind(Queue::shared_ptr queue, const string& routingKey, FieldTable* args){
+ lock.acquire();
+ 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));
+ }
+ lock.release();
+}
+
+void DirectExchange::unbind(Queue::shared_ptr queue, const string& routingKey, FieldTable* args){
+ lock.acquire();
+ 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);
+ }
+ }
+ lock.release();
+}
+
+void DirectExchange::route(Message::shared_ptr& msg, const string& routingKey, FieldTable* args){
+ lock.acquire();
+ 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++){
+ (*i)->deliver(msg);
+ }
+ if(!count){
+ std::cout << "WARNING: DirectExchange " << name << " could not route message with key " << routingKey << std::endl;
+ }
+ lock.release();
+}
+
+DirectExchange::~DirectExchange(){
+
+}
+
+
+const std::string DirectExchange::typeName("direct");
diff --git a/cpp/broker/src/ExchangeBinding.cpp b/cpp/broker/src/ExchangeBinding.cpp
new file mode 100644
index 0000000000..6160a67fd3
--- /dev/null
+++ b/cpp/broker/src/ExchangeBinding.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 "ExchangeBinding.h"
+#include "Exchange.h"
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+ExchangeBinding::ExchangeBinding(Exchange* _e, Queue::shared_ptr _q, const string& _key, 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/broker/src/ExchangeRegistry.cpp b/cpp/broker/src/ExchangeRegistry.cpp
new file mode 100644
index 0000000000..0ee581af2f
--- /dev/null
+++ b/cpp/broker/src/ExchangeRegistry.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 "ExchangeRegistry.h"
+#include "MonitorImpl.h"
+
+using namespace qpid::broker;
+using namespace qpid::concurrent;
+
+ExchangeRegistry::ExchangeRegistry() : lock(new MonitorImpl()){}
+
+ExchangeRegistry::~ExchangeRegistry(){
+ delete lock;
+}
+
+void ExchangeRegistry::declare(Exchange* exchange){
+ exchanges[exchange->getName()] = exchange;
+}
+
+void ExchangeRegistry::destroy(const string& name){
+ if(exchanges[name]){
+ delete exchanges[name];
+ exchanges.erase(name);
+ }
+}
+
+Exchange* ExchangeRegistry::get(const string& name){
+ return exchanges[name];
+}
diff --git a/cpp/broker/src/FanOutExchange.cpp b/cpp/broker/src/FanOutExchange.cpp
new file mode 100644
index 0000000000..7f261d5eda
--- /dev/null
+++ b/cpp/broker/src/FanOutExchange.cpp
@@ -0,0 +1,56 @@
+/*
+ *
+ * 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 "FanOutExchange.h"
+#include "ExchangeBinding.h"
+#include <algorithm>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::concurrent;
+
+FanOutExchange::FanOutExchange(const string& _name) : name(_name) {}
+
+void FanOutExchange::bind(Queue::shared_ptr queue, const string& routingKey, FieldTable* args){
+ Locker 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, FieldTable* args){
+ Locker 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(Message::shared_ptr& msg, const string& routingKey, FieldTable* args){
+ Locker locker(lock);
+ for(Queue::vector::iterator i = bindings.begin(); i != bindings.end(); ++i){
+ (*i)->deliver(msg);
+ }
+}
+
+FanOutExchange::~FanOutExchange() {}
+
+const std::string FanOutExchange::typeName("fanout");
diff --git a/cpp/broker/src/Message.cpp b/cpp/broker/src/Message.cpp
new file mode 100644
index 0000000000..7afcd97934
--- /dev/null
+++ b/cpp/broker/src/Message.cpp
@@ -0,0 +1,97 @@
+/*
+ *
+ * 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 "MonitorImpl.h"
+#include "Message.h"
+#include "ExchangeRegistry.h"
+#include <iostream>
+
+using namespace std::tr1;//for *_pointer_cast methods
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::concurrent;
+
+
+Message::Message(const ConnectionToken* const _publisher,
+ const string& _exchange, const string& _routingKey,
+ bool _mandatory, bool _immediate) : publisher(_publisher),
+ exchange(_exchange),
+ routingKey(_routingKey),
+ mandatory(_mandatory),
+ immediate(_immediate){
+
+}
+
+Message::~Message(){
+}
+
+void Message::setHeader(AMQHeaderBody::shared_ptr header){
+ this->header = header;
+}
+
+void Message::addContent(AMQContentBody::shared_ptr data){
+ content.push_back(data);
+}
+
+bool Message::isComplete(){
+ return header.get() && (header->getContentSize() == contentSize());
+}
+
+void Message::deliver(OutputHandler* out, int channel,
+ string& consumerTag, u_int64_t deliveryTag,
+ u_int32_t framesize){
+
+ out->send(new AMQFrame(channel, new BasicDeliverBody(consumerTag, deliveryTag, false, exchange, routingKey)));
+ AMQBody::shared_ptr headerBody = static_pointer_cast<AMQBody, AMQHeaderBody>(header);
+ out->send(new AMQFrame(channel, headerBody));
+ for(content_iterator i = content.begin(); i != content.end(); i++){
+ if((*i)->size() > framesize){
+ //TODO: need to split it
+ std::cout << "WARNING: Dropped message. Re-fragmentation not yet implemented." << std::endl;
+ }else{
+ AMQBody::shared_ptr contentBody = static_pointer_cast<AMQBody, AMQContentBody>(*i);
+ out->send(new AMQFrame(channel, contentBody));
+ }
+ }
+}
+
+BasicHeaderProperties* Message::getHeaderProperties(){
+ return dynamic_cast<BasicHeaderProperties*>(header->getProperties());
+}
+
+u_int64_t Message::contentSize(){
+ u_int64_t size(0);
+ for(content_iterator i = content.begin(); i != content.end(); i++){
+ size += (*i)->size();
+ }
+ return size;
+}
+
+const ConnectionToken* const Message::getPublisher(){
+ return publisher;
+}
+
+bool qpid::broker::route(Message::shared_ptr& msg, ExchangeRegistry* registry){
+ Exchange* exchange = registry->get(msg->exchange);
+ if(exchange){
+ exchange->route(msg, msg->routingKey, &(msg->getHeaderProperties()->getHeaders()));
+ return true;
+ }else{
+ return false;
+ }
+}
+
diff --git a/cpp/broker/src/NameGenerator.cpp b/cpp/broker/src/NameGenerator.cpp
new file mode 100644
index 0000000000..46aa385a7e
--- /dev/null
+++ b/cpp/broker/src/NameGenerator.cpp
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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 "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/broker/src/Queue.cpp b/cpp/broker/src/Queue.cpp
new file mode 100644
index 0000000000..f7b8605b03
--- /dev/null
+++ b/cpp/broker/src/Queue.cpp
@@ -0,0 +1,148 @@
+/*
+ *
+ * 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 "Queue.h"
+#include "MonitorImpl.h"
+#include <iostream>
+
+using namespace qpid::broker;
+using namespace qpid::concurrent;
+
+Queue::Queue(const string& _name, bool _durable, u_int32_t _autodelete, const ConnectionToken* const _owner) : name(_name),
+ durable(_durable),
+ autodelete(_autodelete),
+ owner(_owner),
+ queueing(false),
+ dispatching(false),
+ next(0),
+ lastUsed(0),
+ exclusive(0){
+
+ if(autodelete) lastUsed = apr_time_as_msec(apr_time_now());
+}
+
+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){
+ Locker locker(lock);
+ if(queueing || !dispatch(msg)){
+ queueing = true;
+ messages.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(){
+ Locker locker(lock);
+ if(queueing && !dispatching){
+ dispatching = true;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+void Queue::dispatch(){
+ bool proceed = startDispatching();
+ while(proceed){
+ Locker locker(lock);
+ if(!messages.empty() && dispatch(messages.front())){
+ messages.pop();
+ }else{
+ dispatching = false;
+ proceed = false;
+ queueing = !messages.empty();
+ }
+ }
+}
+
+void Queue::consume(Consumer* c, bool requestExclusive){
+ Locker locker(lock);
+ if(exclusive) throw ExclusiveAccessException();
+ if(requestExclusive){
+ if(!consumers.empty()) throw ExclusiveAccessException();
+ exclusive = c;
+ }
+
+ if(autodelete && consumers.empty()) lastUsed = 0;
+ consumers.push_back(c);
+}
+
+void Queue::cancel(Consumer* c){
+ Locker locker(lock);
+ consumers.erase(find(consumers.begin(), consumers.end(), c));
+ if(autodelete && consumers.empty()) lastUsed = apr_time_as_msec(apr_time_now());
+ if(exclusive == c) exclusive = 0;
+}
+
+Message::shared_ptr Queue::dequeue(){
+
+}
+
+u_int32_t Queue::purge(){
+ Locker locker(lock);
+ int count = messages.size();
+ while(!messages.empty()) messages.pop();
+ return count;
+}
+
+u_int32_t Queue::getMessageCount() const{
+ Locker locker(lock);
+ return messages.size();
+}
+
+u_int32_t Queue::getConsumerCount() const{
+ Locker locker(lock);
+ return consumers.size();
+}
+
+bool Queue::canAutoDelete() const{
+ Locker locker(lock);
+ return lastUsed && ((apr_time_as_msec(apr_time_now()) - lastUsed) > autodelete);
+}
diff --git a/cpp/broker/src/QueueRegistry.cpp b/cpp/broker/src/QueueRegistry.cpp
new file mode 100644
index 0000000000..f807415314
--- /dev/null
+++ b/cpp/broker/src/QueueRegistry.cpp
@@ -0,0 +1,72 @@
+/*
+ *
+ * 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 "QueueRegistry.h"
+#include "MonitorImpl.h"
+#include "SessionHandlerImpl.h"
+#include <sstream>
+#include <assert.h>
+
+using namespace qpid::broker;
+using namespace qpid::concurrent;
+
+QueueRegistry::QueueRegistry() : counter(1){}
+
+QueueRegistry::~QueueRegistry(){}
+
+std::pair<Queue::shared_ptr, bool>
+QueueRegistry::declare(const string& declareName, bool durable, u_int32_t autoDelete, const ConnectionToken* owner)
+{
+ Locker 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, durable, autoDelete, 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){
+ Locker locker(lock);
+ queues.erase(name);
+}
+
+Queue::shared_ptr QueueRegistry::find(const string& name){
+ Locker 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;
+}
diff --git a/cpp/broker/src/SessionHandlerFactoryImpl.cpp b/cpp/broker/src/SessionHandlerFactoryImpl.cpp
new file mode 100644
index 0000000000..661cb4ef81
--- /dev/null
+++ b/cpp/broker/src/SessionHandlerFactoryImpl.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 "SessionHandlerFactoryImpl.h"
+#include "SessionHandlerImpl.h"
+#include "FanOutExchange.h"
+
+using namespace qpid::broker;
+using namespace qpid::io;
+
+SessionHandlerFactoryImpl::SessionHandlerFactoryImpl(u_int32_t _timeout) : timeout(_timeout), cleaner(&queues, timeout/10){
+ exchanges.declare(new DirectExchange("amq.direct"));
+ exchanges.declare(new TopicExchange("amq.topic"));
+ exchanges.declare(new FanOutExchange("amq.fanout"));
+ cleaner.start();
+}
+
+SessionHandler* SessionHandlerFactoryImpl::create(SessionContext* ctxt){
+ return new SessionHandlerImpl(ctxt, &queues, &exchanges, &cleaner, timeout);
+}
+
+SessionHandlerFactoryImpl::~SessionHandlerFactoryImpl(){
+ cleaner.stop();
+ exchanges.destroy("amq.direct");
+ exchanges.destroy("amq.topic");
+}
diff --git a/cpp/broker/src/SessionHandlerImpl.cpp b/cpp/broker/src/SessionHandlerImpl.cpp
new file mode 100644
index 0000000000..19e243a01b
--- /dev/null
+++ b/cpp/broker/src/SessionHandlerImpl.cpp
@@ -0,0 +1,378 @@
+/*
+ *
+ * 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 "SessionHandlerImpl.h"
+#include "FanOutExchange.h"
+#include "assert.h"
+
+using namespace std::tr1;
+using namespace qpid::broker;
+using namespace qpid::io;
+using namespace qpid::framing;
+using namespace qpid::concurrent;
+
+SessionHandlerImpl::SessionHandlerImpl(SessionContext* _context,
+ QueueRegistry* _queues,
+ ExchangeRegistry* _exchanges,
+ AutoDelete* _cleaner,
+ const u_int32_t _timeout) : context(_context),
+ queues(_queues),
+ exchanges(_exchanges),
+ cleaner(_cleaner),
+ timeout(_timeout),
+ channelHandler(new ChannelHandlerImpl(this)),
+ connectionHandler(new ConnectionHandlerImpl(this)),
+ basicHandler(new BasicHandlerImpl(this)),
+ exchangeHandler(new ExchangeHandlerImpl(this)),
+ queueHandler(new QueueHandlerImpl(this)),
+ framemax(65536),
+ heartbeat(0){
+
+}
+
+SessionHandlerImpl::~SessionHandlerImpl(){
+ // TODO aconway 2006-09-07: Should be auto_ptr or plain members.
+ delete channelHandler;
+ delete connectionHandler;
+ delete basicHandler;
+ delete exchangeHandler;
+ delete queueHandler;
+}
+
+Queue::shared_ptr SessionHandlerImpl::getQueue(const string& name, u_int16_t channel){
+ Queue::shared_ptr queue;
+ if (name.empty()) {
+ queue = channels[channel]->getDefaultQueue();
+ if (!queue) throw ConnectionException( 530, "Queue must be specified or previously declared" );
+ } else {
+ queue = queues->find(name);
+ if (queue == 0) {
+ throw ChannelException( 404, "Queue not found: " + name);
+ }
+ }
+ return queue;
+}
+
+
+Exchange* SessionHandlerImpl::findExchange(const string& name){
+ exchanges->getLock()->acquire();
+ Exchange* exchange(exchanges->get(name));
+ exchanges->getLock()->release();
+ return exchange;
+}
+
+void SessionHandlerImpl::received(qpid::framing::AMQFrame* frame){
+ u_int16_t channel = frame->getChannel();
+ AMQBody::shared_ptr body = frame->getBody();
+ AMQMethodBody::shared_ptr method;
+
+ switch(body->type())
+ {
+ case METHOD_BODY:
+ method = dynamic_pointer_cast<AMQMethodBody, AMQBody>(body);
+ try{
+ method->invoke(*this, channel);
+ }catch(ChannelException& e){
+ channels[channel]->close();
+ channels.erase(channel);
+ context->send(new AMQFrame(channel, new ChannelCloseBody(e.code, e.text, method->amqpClassId(), method->amqpMethodId())));
+ }catch(ConnectionException& e){
+ context->send(new AMQFrame(0, new ConnectionCloseBody(e.code, e.text, method->amqpClassId(), method->amqpMethodId())));
+ }
+ break;
+
+ case HEADER_BODY:
+ this->handleHeader(channel, dynamic_pointer_cast<AMQHeaderBody, AMQBody>(body));
+ break;
+
+ case CONTENT_BODY:
+ this->handleContent(channel, dynamic_pointer_cast<AMQContentBody, AMQBody>(body));
+ break;
+
+ case HEARTBEAT_BODY:
+ //channel must be 0
+ this->handleHeartbeat(dynamic_pointer_cast<AMQHeartbeatBody, AMQBody>(body));
+ break;
+ }
+}
+
+void SessionHandlerImpl::initiated(qpid::framing::ProtocolInitiation* header){
+ //send connection start
+ FieldTable properties;
+ string mechanisms("PLAIN");
+ string locales("en_US");
+ context->send(new AMQFrame(0, new ConnectionStartBody(8, 0, properties, mechanisms, locales)));
+}
+
+void SessionHandlerImpl::idleOut(){
+
+}
+
+void SessionHandlerImpl::idleIn(){
+
+}
+
+void SessionHandlerImpl::closed(){
+ for(channel_iterator i = channels.begin(); i != channels.end(); i = channels.begin()){
+ Channel* c = i->second;
+ channels.erase(i);
+ c->close();
+ delete c;
+ }
+ for(queue_iterator i = exclusiveQueues.begin(); i < exclusiveQueues.end(); i = exclusiveQueues.begin()){
+ string name = (*i)->getName();
+ queues->destroy(name);
+ exclusiveQueues.erase(i);
+ }
+}
+
+void SessionHandlerImpl::handleHeader(u_int16_t channel, AMQHeaderBody::shared_ptr body){
+ channels[channel]->handleHeader(body, exchanges);
+}
+
+void SessionHandlerImpl::handleContent(u_int16_t channel, AMQContentBody::shared_ptr body){
+ channels[channel]->handleContent(body, exchanges);
+}
+
+void SessionHandlerImpl::handleHeartbeat(AMQHeartbeatBody::shared_ptr body){
+ std::cout << "SessionHandlerImpl::handleHeartbeat()" << std::endl;
+}
+
+void SessionHandlerImpl::ConnectionHandlerImpl::startOk(u_int16_t channel, FieldTable& clientProperties, string& mechanism,
+ string& response, string& locale){
+
+ parent->context->send(new AMQFrame(0, new ConnectionTuneBody(100, parent->framemax, parent->heartbeat)));
+}
+
+void SessionHandlerImpl::ConnectionHandlerImpl::secureOk(u_int16_t channel, string& response){}
+
+void SessionHandlerImpl::ConnectionHandlerImpl::tuneOk(u_int16_t channel, u_int16_t channelmax, u_int32_t framemax, u_int16_t heartbeat){
+ parent->framemax = framemax;
+ parent->heartbeat = heartbeat;
+}
+
+void SessionHandlerImpl::ConnectionHandlerImpl::open(u_int16_t channel, string& virtualHost, string& capabilities, bool insist){
+ string knownhosts;
+ parent->context->send(new AMQFrame(0, new ConnectionOpenOkBody(knownhosts)));
+}
+
+void SessionHandlerImpl::ConnectionHandlerImpl::close(u_int16_t channel, u_int16_t replyCode, string& replyText,
+ u_int16_t classId, u_int16_t methodId){
+
+ parent->context->send(new AMQFrame(0, new ConnectionCloseOkBody()));
+ parent->context->close();
+}
+
+void SessionHandlerImpl::ConnectionHandlerImpl::closeOk(u_int16_t channel){
+ parent->context->close();
+}
+
+
+
+void SessionHandlerImpl::ChannelHandlerImpl::open(u_int16_t channel, string& outOfBand){
+ parent->channels[channel] = new Channel(parent->context, channel, parent->framemax);
+ parent->context->send(new AMQFrame(channel, new ChannelOpenOkBody()));
+}
+
+void SessionHandlerImpl::ChannelHandlerImpl::flow(u_int16_t channel, bool active){}
+void SessionHandlerImpl::ChannelHandlerImpl::flowOk(u_int16_t channel, bool active){}
+
+void SessionHandlerImpl::ChannelHandlerImpl::close(u_int16_t channel, u_int16_t replyCode, string& replyText,
+ u_int16_t classId, u_int16_t methodId){
+ Channel* c = parent->channels[channel];
+ parent->channels.erase(channel);
+ c->close();
+ delete c;
+ parent->context->send(new AMQFrame(channel, new ChannelCloseOkBody()));
+}
+
+void SessionHandlerImpl::ChannelHandlerImpl::closeOk(u_int16_t channel){}
+
+
+
+void SessionHandlerImpl::ExchangeHandlerImpl::declare(u_int16_t channel, u_int16_t ticket, string& exchange, string& type,
+ bool passive, bool durable, bool autoDelete, bool internal, bool nowait,
+ FieldTable& arguments){
+
+ if(!passive && (
+ type != TopicExchange::typeName &&
+ type != DirectExchange::typeName &&
+ type != FanOutExchange::typeName)
+ )
+ {
+ throw ChannelException(540, "Exchange type not implemented: " + type);
+ }
+
+ parent->exchanges->getLock()->acquire();
+ if(!parent->exchanges->get(exchange)){
+ if(type == TopicExchange::typeName){
+ parent->exchanges->declare(new TopicExchange(exchange));
+ }else if(type == DirectExchange::typeName){
+ parent->exchanges->declare(new DirectExchange(exchange));
+ }else if(type == FanOutExchange::typeName){
+ parent->exchanges->declare(new DirectExchange(exchange));
+ }
+ }
+ parent->exchanges->getLock()->release();
+ if(!nowait){
+ parent->context->send(new AMQFrame(channel, new ExchangeDeclareOkBody()));
+ }
+}
+
+void SessionHandlerImpl::ExchangeHandlerImpl::delete_(u_int16_t channel, u_int16_t ticket, string& exchange, bool ifUnused, bool nowait){
+ //TODO: implement unused
+ parent->exchanges->getLock()->acquire();
+ parent->exchanges->destroy(exchange);
+ parent->exchanges->getLock()->release();
+ if(!nowait) parent->context->send(new AMQFrame(channel, new ExchangeDeleteOkBody()));
+}
+
+
+
+
+void SessionHandlerImpl::QueueHandlerImpl::declare(u_int16_t channel, u_int16_t ticket, string& name,
+ bool passive, bool durable, bool exclusive,
+ bool autoDelete, bool nowait, FieldTable& arguments){
+ Queue::shared_ptr queue;
+ if (passive && !name.empty()) {
+ queue = parent->getQueue(name, channel);
+ } else {
+ std::pair<Queue::shared_ptr, bool> queue_created = parent->queues->declare(name, durable, autoDelete ? parent->timeout : 0, exclusive ? parent : 0);
+ queue = queue_created.first;
+ assert(queue);
+ if (queue_created.second) { // This is a new queue
+ parent->channels[channel]->setDefaultQueue(queue);
+ //add default binding:
+ parent->exchanges->get("amq.direct")->bind(queue, name, 0);
+ if(exclusive){
+ parent->exclusiveQueues.push_back(queue);
+ } else if(autoDelete){
+ parent->cleaner->add(queue);
+ }
+ }
+ }
+ if(exclusive && !queue->isExclusiveOwner(parent)){
+ throw ChannelException(405, "Cannot grant exclusive access to queue");
+ }
+ if(!nowait){
+ name = queue->getName();
+ QueueDeclareOkBody* response = new QueueDeclareOkBody(name, queue->getMessageCount(), queue->getConsumerCount());
+ parent->context->send(new AMQFrame(channel, response));
+ }
+}
+
+void SessionHandlerImpl::QueueHandlerImpl::bind(u_int16_t channel, u_int16_t ticket, string& queueName,
+ string& exchangeName, string& routingKey, bool nowait,
+ FieldTable& arguments){
+
+ Queue::shared_ptr queue = parent->getQueue(queueName, channel);
+ Exchange* exchange = parent->exchanges->get(exchangeName);
+ if(exchange){
+ if(routingKey.size() == 0 && queueName.size() == 0) routingKey = queue->getName();
+ exchange->bind(queue, routingKey, &arguments);
+ if(!nowait) parent->context->send(new AMQFrame(channel, new QueueBindOkBody()));
+ }else{
+ throw ChannelException(404, "Bind failed. No such exchange: " + exchangeName);
+ }
+}
+
+void SessionHandlerImpl::QueueHandlerImpl::purge(u_int16_t channel, u_int16_t ticket, string& queueName, bool nowait){
+
+ Queue::shared_ptr queue = parent->getQueue(queueName, channel);
+ int count = queue->purge();
+ if(!nowait) parent->context->send(new AMQFrame(channel, new QueuePurgeOkBody(count)));
+}
+
+void SessionHandlerImpl::QueueHandlerImpl::delete_(u_int16_t channel, u_int16_t ticket, string& queue,
+ bool ifUnused, bool ifEmpty, bool nowait){
+ ChannelException error(0, "");
+ int count(0);
+ Queue::shared_ptr q = parent->getQueue(queue, channel);
+ 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(parent)){
+ queue_iterator i = find(parent->exclusiveQueues.begin(), parent->exclusiveQueues.end(), q);
+ if(i < parent->exclusiveQueues.end()) parent->exclusiveQueues.erase(i);
+ }
+ count = q->getMessageCount();
+ parent->queues->destroy(queue);
+ }
+ if(!nowait) parent->context->send(new AMQFrame(channel, new QueueDeleteOkBody(count)));
+}
+
+
+
+
+void SessionHandlerImpl::BasicHandlerImpl::qos(u_int16_t channel, u_int32_t prefetchSize, u_int16_t prefetchCount, bool global){
+ //TODO: handle global
+ //TODO: channel doesn't do anything with these qos parameters yet
+ parent->channels[channel]->setPrefetchSize(prefetchSize);
+ parent->channels[channel]->setPrefetchCount(prefetchCount);
+ parent->context->send(new AMQFrame(channel, new BasicQosOkBody()));
+}
+
+void SessionHandlerImpl::BasicHandlerImpl::consume(u_int16_t channelId, u_int16_t ticket,
+ string& queueName, string& consumerTag,
+ bool noLocal, bool noAck, bool exclusive,
+ bool nowait){
+
+ //TODO: implement nolocal
+ Queue::shared_ptr queue = parent->getQueue(queueName, channelId);
+ Channel* channel = parent->channels[channelId];
+ if(!consumerTag.empty() && channel->exists(consumerTag)){
+ throw ConnectionException(530, "Consumer tags must be unique");
+ }
+
+ try{
+ channel->consume(consumerTag, queue, !noAck, exclusive, noLocal ? parent : 0);
+ if(!nowait) parent->context->send(new AMQFrame(channelId, new BasicConsumeOkBody(consumerTag)));
+
+ //allow messages to be dispatched if required as there is now a consumer:
+ queue->dispatch();
+ }catch(ExclusiveAccessException& e){
+ if(exclusive) throw ChannelException(403, "Exclusive access cannot be granted");
+ else throw ChannelException(403, "Access would violate previously granted exclusivity");
+ }
+
+}
+
+void SessionHandlerImpl::BasicHandlerImpl::cancel(u_int16_t channel, string& consumerTag, bool nowait){
+ parent->channels[channel]->cancel(consumerTag);
+ if(!nowait) parent->context->send(new AMQFrame(channel, new BasicCancelOkBody(consumerTag)));
+}
+
+void SessionHandlerImpl::BasicHandlerImpl::publish(u_int16_t channel, u_int16_t ticket,
+ string& exchange, string& routingKey,
+ bool mandatory, bool immediate){
+
+ Message* msg = new Message(parent, exchange.length() ? exchange : "amq.direct", routingKey, mandatory, immediate);
+ parent->channels[channel]->handlePublish(msg);
+}
+
+void SessionHandlerImpl::BasicHandlerImpl::get(u_int16_t channel, u_int16_t ticket, string& queue, bool noAck){}
+
+void SessionHandlerImpl::BasicHandlerImpl::ack(u_int16_t channel, u_int64_t deliveryTag, bool multiple){}
+
+void SessionHandlerImpl::BasicHandlerImpl::reject(u_int16_t channel, u_int64_t deliveryTag, bool requeue){}
+
+void SessionHandlerImpl::BasicHandlerImpl::recover(u_int16_t channel, bool requeue){}
+
diff --git a/cpp/broker/src/TopicExchange.cpp b/cpp/broker/src/TopicExchange.cpp
new file mode 100644
index 0000000000..e0248958f9
--- /dev/null
+++ b/cpp/broker/src/TopicExchange.cpp
@@ -0,0 +1,62 @@
+/*
+ *
+ * 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 "TopicExchange.h"
+#include "ExchangeBinding.h"
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+TopicExchange::TopicExchange(const string& _name) : name(_name) {
+
+}
+
+void TopicExchange::bind(Queue::shared_ptr queue, const string& routingKey, FieldTable* args){
+ lock.acquire();
+ bindings[routingKey].push_back(queue);
+ queue->bound(new ExchangeBinding(this, queue, routingKey, args));
+ lock.release();
+}
+
+void TopicExchange::unbind(Queue::shared_ptr queue, const string& routingKey, FieldTable* args){
+ lock.acquire();
+ 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);
+ }
+ }
+ lock.release();
+}
+
+void TopicExchange::route(Message::shared_ptr& msg, const string& routingKey, FieldTable* args){
+ lock.acquire();
+ std::vector<Queue::shared_ptr>& queues(bindings[routingKey]);
+ for(std::vector<Queue::shared_ptr>::iterator i = queues.begin(); i != queues.end(); i++){
+ (*i)->deliver(msg);
+ }
+ lock.release();
+}
+
+TopicExchange::~TopicExchange(){
+
+}
+
+const std::string TopicExchange::typeName("topic");
diff --git a/cpp/broker/test/Makefile b/cpp/broker/test/Makefile
new file mode 100644
index 0000000000..172ce564bf
--- /dev/null
+++ b/cpp/broker/test/Makefile
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+QPID_HOME = ../../..
+LDLIBS=-lapr-1 -lcppunit $(COMMON_LIB) $(BROKER_LIB)
+include ${QPID_HOME}/cpp/test_plugins.mk
+
diff --git a/cpp/broker/test/QueueRegistryTest.cpp b/cpp/broker/test/QueueRegistryTest.cpp
new file mode 100644
index 0000000000..c4ad40b5cd
--- /dev/null
+++ b/cpp/broker/test/QueueRegistryTest.cpp
@@ -0,0 +1,79 @@
+#include "QueueRegistry.h"
+#include <cppunit/TestCase.h>
+#include <cppunit/TextTestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+#include <string>
+
+using namespace qpid::broker;
+
+class QueueRegistryTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(QueueRegistryTest);
+ CPPUNIT_TEST(testDeclare);
+ CPPUNIT_TEST(testDeclareTmp);
+ CPPUNIT_TEST(testFind);
+ CPPUNIT_TEST(testDestroy);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ std::string foo, bar;
+ QueueRegistry reg;
+ std::pair<Queue::shared_ptr, bool> qc;
+
+ public:
+ void setUp() {
+ foo = "foo";
+ bar = "bar";
+ }
+
+ void testDeclare() {
+ qc = reg.declare(foo, false, 0, 0);
+ Queue::shared_ptr q = qc.first;
+ CPPUNIT_ASSERT(q);
+ CPPUNIT_ASSERT(qc.second); // New queue
+ CPPUNIT_ASSERT_EQUAL(foo, q->getName());
+
+ qc = reg.declare(foo, false, 0, 0);
+ CPPUNIT_ASSERT_EQUAL(q, qc.first);
+ CPPUNIT_ASSERT(!qc.second);
+
+ qc = reg.declare(bar, false, 0, 0);
+ q = qc.first;
+ CPPUNIT_ASSERT(q);
+ CPPUNIT_ASSERT_EQUAL(true, qc.second);
+ CPPUNIT_ASSERT_EQUAL(bar, q->getName());
+ }
+
+ void testDeclareTmp()
+ {
+ qc = reg.declare(std::string(), false, 0, 0);
+ CPPUNIT_ASSERT(qc.second);
+ CPPUNIT_ASSERT_EQUAL(std::string("tmp_1"), qc.first->getName());
+ }
+
+ void testFind() {
+ CPPUNIT_ASSERT(reg.find(foo) == 0);
+
+ reg.declare(foo, false, 0, 0);
+ reg.declare(bar, false, 0, 0);
+ Queue::shared_ptr q = reg.find(bar);
+ CPPUNIT_ASSERT(q);
+ CPPUNIT_ASSERT_EQUAL(bar, q->getName());
+ }
+
+ void testDestroy() {
+ qc = reg.declare(foo, false, 0, 0);
+ reg.destroy(foo);
+ // Queue is gone from the registry.
+ CPPUNIT_ASSERT(reg.find(foo) == 0);
+ // Queue is not actually destroyed till we drop our reference.
+ CPPUNIT_ASSERT_EQUAL(foo, qc.first->getName());
+ // We shoud be the only reference.
+ CPPUNIT_ASSERT_EQUAL(1L, qc.first.use_count());
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(QueueRegistryTest);
diff --git a/cpp/broker/test/exchange_test.cpp b/cpp/broker/test/exchange_test.cpp
new file mode 100644
index 0000000000..6605f2685b
--- /dev/null
+++ b/cpp/broker/test/exchange_test.cpp
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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 "DirectExchange.h"
+#include "Exchange.h"
+#include "Queue.h"
+#include "TopicExchange.h"
+#include <cppunit/TestCase.h>
+#include <cppunit/TextTestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+#include <iostream>
+
+using namespace qpid::broker;
+using namespace qpid::concurrent;
+
+class ExchangeTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(ExchangeTest);
+ CPPUNIT_TEST(testMe);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ // TODO aconway 2006-09-12: Need more detailed tests.
+
+ void testMe()
+ {
+ Queue::shared_ptr queue(new Queue("queue", true, true));
+ Queue::shared_ptr queue2(new Queue("queue2", true, true));
+
+ TopicExchange topic("topic");
+ topic.bind(queue, "abc", 0);
+ topic.bind(queue2, "abc", 0);
+
+ DirectExchange direct("direct");
+ direct.bind(queue, "abc", 0);
+ direct.bind(queue2, "abc", 0);
+
+ queue.reset();
+ queue2.reset();
+
+ Message::shared_ptr msg = Message::shared_ptr(new Message(0, "e", "A", true, true));
+ topic.route(msg, "abc", 0);
+ direct.route(msg, "abc", 0);
+
+ // TODO aconway 2006-09-12: TODO Why no assertions?
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(ExchangeTest);
diff --git a/cpp/broker/test/message_test.cpp b/cpp/broker/test/message_test.cpp
new file mode 100644
index 0000000000..94d25a831e
--- /dev/null
+++ b/cpp/broker/test/message_test.cpp
@@ -0,0 +1,57 @@
+/*
+ *
+ * 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 "APRBase.h"
+#include "Message.h"
+#include <cppunit/TestCase.h>
+#include <cppunit/TextTestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+#include <iostream>
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::concurrent;
+
+class MessageTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(MessageTest);
+ CPPUNIT_TEST(testMe);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ // TODO aconway 2006-09-12: Need more detailed tests,
+ // need tests to assert something!
+ //
+ void testMe()
+ {
+ APRBase::increment();
+ const int size(10);
+ for(int i = 0; i < size; i++){
+ Message::shared_ptr msg = Message::shared_ptr(new Message(0, "A", "B", true, true));
+ msg->setHeader(AMQHeaderBody::shared_ptr(new AMQHeaderBody()));
+ msg->addContent(AMQContentBody::shared_ptr(new AMQContentBody()));
+ msg.reset();
+ }
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(MessageTest);
+
diff --git a/cpp/broker/test/queue_test.cpp b/cpp/broker/test/queue_test.cpp
new file mode 100644
index 0000000000..aa423e7e08
--- /dev/null
+++ b/cpp/broker/test/queue_test.cpp
@@ -0,0 +1,138 @@
+ /*
+ *
+ * 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 "Queue.h"
+#include "QueueRegistry.h"
+#include <cppunit/TestCase.h>
+#include <cppunit/TextTestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+#include <iostream>
+
+using namespace qpid::broker;
+using namespace qpid::concurrent;
+
+
+class TestBinding : public virtual Binding{
+ bool cancelled;
+
+public:
+ TestBinding();
+ virtual void cancel();
+ bool isCancelled();
+};
+
+class TestConsumer : public virtual Consumer{
+public:
+ Message::shared_ptr last;
+
+ virtual bool deliver(Message::shared_ptr& msg);
+};
+
+
+class QueueTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(QueueTest);
+ CPPUNIT_TEST(testMe);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void testMe()
+ {
+ Queue::shared_ptr queue(new Queue("my_queue", true, true));
+
+ //Test adding consumers:
+ TestConsumer c1;
+ TestConsumer c2;
+ queue->consume(&c1);
+ queue->consume(&c2);
+
+ CPPUNIT_ASSERT_EQUAL(u_int32_t(2), queue->getConsumerCount());
+
+ //Test basic delivery:
+ Message::shared_ptr msg1 = Message::shared_ptr(new Message(0, "e", "A", true, true));
+ Message::shared_ptr msg2 = Message::shared_ptr(new Message(0, "e", "B", true, true));
+ Message::shared_ptr msg3 = Message::shared_ptr(new Message(0, "e", "C", true, true));
+
+ queue->deliver(msg1);
+ CPPUNIT_ASSERT_EQUAL(msg1.get(), c1.last.get());
+
+ queue->deliver(msg2);
+ CPPUNIT_ASSERT_EQUAL(msg2.get(), c2.last.get());
+
+ queue->deliver(msg3);
+ CPPUNIT_ASSERT_EQUAL(msg3.get(), c1.last.get());
+
+ //Test cancellation:
+ queue->cancel(&c1);
+ CPPUNIT_ASSERT_EQUAL(u_int32_t(1), queue->getConsumerCount());
+ queue->cancel(&c2);
+ CPPUNIT_ASSERT_EQUAL(u_int32_t(0), queue->getConsumerCount());
+
+ //Test bindings:
+ TestBinding a;
+ TestBinding b;
+ queue->bound(&a);
+ queue->bound(&b);
+
+ queue.reset();
+
+ CPPUNIT_ASSERT(a.isCancelled());
+ CPPUNIT_ASSERT(b.isCancelled());
+
+ //Test use of queues in registry:
+ QueueRegistry registry;
+ registry.declare("queue1", true, true);
+ registry.declare("queue2", true, true);
+ registry.declare("queue3", true, true);
+
+ CPPUNIT_ASSERT(registry.find("queue1"));
+ CPPUNIT_ASSERT(registry.find("queue2"));
+ CPPUNIT_ASSERT(registry.find("queue3"));
+
+ registry.destroy("queue1");
+ registry.destroy("queue2");
+ registry.destroy("queue3");
+
+ CPPUNIT_ASSERT(!registry.find("queue1"));
+ CPPUNIT_ASSERT(!registry.find("queue2"));
+ CPPUNIT_ASSERT(!registry.find("queue3"));
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(QueueTest);
+
+//TestBinding
+TestBinding::TestBinding() : cancelled(false) {}
+
+void TestBinding::cancel(){
+ CPPUNIT_ASSERT(!cancelled);
+ cancelled = true;
+}
+
+bool TestBinding::isCancelled(){
+ return cancelled;
+}
+
+//TestConsumer
+bool TestConsumer::deliver(Message::shared_ptr& msg){
+ last = msg;
+ return true;
+}
+
diff --git a/cpp/client/Makefile b/cpp/client/Makefile
new file mode 100644
index 0000000000..d08b92fe2b
--- /dev/null
+++ b/cpp/client/Makefile
@@ -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.
+#
+
+#
+# Build client library.
+#
+
+QPID_HOME = ../..
+include ${QPID_HOME}/cpp/options.mk
+
+SOURCES := $(wildcard src/*.cpp)
+OBJECTS := $(subst .cpp,.o,$(SOURCES))
+CLIENT_LIB=$(LIB_DIR)/libqpid_client.so.1.0
+
+.PHONY: all test clean
+
+all: $(CLIENT_LIB)
+
+test:
+ @$(MAKE) -C test all
+
+clean:
+ -@rm -f $(CLIENT_LIB) $(OBJECTS) src/*.d
+ $(MAKE) -C test clean
+
+$(CLIENT_LIB): $(OBJECTS)
+ $(CXX) -shared -o $@ $^ $(LDFLAGS) $(COMMON_LIB)
+
+# Dependencies
+-include $(SOURCES:.cpp=.d)
diff --git a/cpp/client/inc/Channel.h b/cpp/client/inc/Channel.h
new file mode 100644
index 0000000000..debecf922e
--- /dev/null
+++ b/cpp/client/inc/Channel.h
@@ -0,0 +1,127 @@
+/*
+ *
+ * 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 <map>
+#include <string>
+#include <queue>
+#include "sys/types.h"
+
+#ifndef _Channel_
+#define _Channel_
+
+#include "amqp_framing.h"
+
+#include "ThreadFactory.h"
+
+#include "Connection.h"
+#include "Exchange.h"
+#include "IncomingMessage.h"
+#include "Message.h"
+#include "MessageListener.h"
+#include "Queue.h"
+#include "ResponseHandler.h"
+#include "ReturnedMessageHandler.h"
+
+namespace qpid {
+namespace client {
+ enum ack_modes {NO_ACK=0, AUTO_ACK=1, LAZY_ACK=2, CLIENT_ACK=3};
+
+ class Channel : private virtual qpid::framing::BodyHandler, public virtual qpid::concurrent::Runnable{
+ struct Consumer{
+ MessageListener* listener;
+ int ackMode;
+ int count;
+ u_int64_t lastDeliveryTag;
+ };
+ typedef std::map<string,Consumer*>::iterator consumer_iterator;
+
+ u_int16_t id;
+ Connection* con;
+ qpid::concurrent::ThreadFactory* threadFactory;
+ qpid::concurrent::Thread* dispatcher;
+ qpid::framing::OutputHandler* out;
+ IncomingMessage* incoming;
+ ResponseHandler responses;
+ std::queue<IncomingMessage*> messages;//holds returned messages or those delivered for a consume
+ IncomingMessage* retrieved;//holds response to basic.get
+ qpid::concurrent::Monitor* dispatchMonitor;
+ qpid::concurrent::Monitor* retrievalMonitor;
+ std::map<std::string, Consumer*> consumers;
+ ReturnedMessageHandler* returnsHandler;
+ bool closed;
+
+ u_int16_t prefetch;
+ const bool transactional;
+
+ void enqueue();
+ void retrieve(Message& msg);
+ IncomingMessage* dequeue();
+ void dispatch();
+ void stop();
+ void sendAndReceive(qpid::framing::AMQFrame* frame, const qpid::framing::AMQMethodBody& body);
+ void deliver(Consumer* consumer, Message& msg);
+ void setQos();
+ void cancelAll();
+
+ virtual void handleMethod(qpid::framing::AMQMethodBody::shared_ptr body);
+ virtual void handleHeader(qpid::framing::AMQHeaderBody::shared_ptr body);
+ virtual void handleContent(qpid::framing::AMQContentBody::shared_ptr body);
+ virtual void handleHeartbeat(qpid::framing::AMQHeartbeatBody::shared_ptr body);
+
+ public:
+ Channel(bool transactional = false, u_int16_t prefetch = 500);
+ ~Channel();
+
+ void declareExchange(Exchange& exchange, bool synch = true);
+ void deleteExchange(Exchange& exchange, bool synch = true);
+ void declareQueue(Queue& queue, bool synch = true);
+ void deleteQueue(Queue& queue, bool ifunused = false, bool ifempty = false, bool synch = true);
+ void bind(const Exchange& exchange, const Queue& queue, const std::string& key,
+ const qpid::framing::FieldTable& args, bool synch = true);
+ void consume(Queue& queue, std::string& tag, MessageListener* listener,
+ int ackMode = NO_ACK, bool noLocal = false, bool synch = true);
+ void cancel(std::string& tag, bool synch = true);
+ bool get(Message& msg, const Queue& queue, int ackMode = NO_ACK);
+ void publish(Message& msg, const Exchange& exchange, const std::string& routingKey,
+ bool mandatory = false, bool immediate = false);
+
+ void commit();
+ void rollback();
+
+ void setPrefetch(u_int16_t prefetch);
+
+ /**
+ * Start message dispatching on a new thread
+ */
+ void start();
+ /**
+ * Do message dispatching on this thread
+ */
+ void run();
+
+ void close();
+
+ void setReturnedMessageHandler(ReturnedMessageHandler* handler);
+
+ friend class Connection;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/client/inc/Connection.h b/cpp/client/inc/Connection.h
new file mode 100644
index 0000000000..89169e92b1
--- /dev/null
+++ b/cpp/client/inc/Connection.h
@@ -0,0 +1,105 @@
+/*
+ *
+ * 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 <map>
+#include <string>
+
+#ifndef _Connection_
+#define _Connection_
+
+#include "QpidError.h"
+#include "Connector.h"
+#include "ShutdownHandler.h"
+#include "TimeoutHandler.h"
+
+#include "amqp_framing.h"
+#include "Exchange.h"
+#include "IncomingMessage.h"
+#include "Message.h"
+#include "MessageListener.h"
+#include "Queue.h"
+#include "ResponseHandler.h"
+
+namespace qpid {
+namespace client {
+
+ class Channel;
+
+ class Connection : public virtual qpid::framing::InputHandler,
+ public virtual qpid::io::TimeoutHandler,
+ public virtual qpid::io::ShutdownHandler,
+ private virtual qpid::framing::BodyHandler{
+
+ typedef std::map<int, Channel*>::iterator iterator;
+
+ static u_int16_t channelIdCounter;
+
+ std::string host;
+ int port;
+ const u_int32_t max_frame_size;
+ std::map<int, Channel*> channels;
+ qpid::io::Connector* connector;
+ qpid::framing::OutputHandler* out;
+ ResponseHandler responses;
+ volatile bool closed;
+
+ void channelException(Channel* channel, qpid::framing::AMQMethodBody* body, QpidError& e);
+ void error(int code, const string& msg, int classid = 0, int methodid = 0);
+ void closeChannel(Channel* channel, u_int16_t code, string& text, u_int16_t classId = 0, u_int16_t methodId = 0);
+ void sendAndReceive(qpid::framing::AMQFrame* frame, const qpid::framing::AMQMethodBody& body);
+
+ virtual void handleMethod(qpid::framing::AMQMethodBody::shared_ptr body);
+ virtual void handleHeader(qpid::framing::AMQHeaderBody::shared_ptr body);
+ virtual void handleContent(qpid::framing::AMQContentBody::shared_ptr body);
+ virtual void handleHeartbeat(qpid::framing::AMQHeartbeatBody::shared_ptr body);
+
+ public:
+
+ Connection(bool debug = false, u_int32_t max_frame_size = 65536);
+ ~Connection();
+ void open(const std::string& host, int port = 5672,
+ const std::string& uid = "guest", const std::string& pwd = "guest",
+ const std::string& virtualhost = "/");
+ void close();
+ void openChannel(Channel* channel);
+ /*
+ * Requests that the server close this channel, then removes
+ * the association to the channel from this connection
+ */
+ void closeChannel(Channel* channel);
+ /*
+ * Removes the channel from association with this connection,
+ * without sending a close request to the server.
+ */
+ void removeChannel(Channel* channel);
+
+ virtual void received(qpid::framing::AMQFrame* frame);
+
+ virtual void idleOut();
+ virtual void idleIn();
+
+ virtual void shutdown();
+
+ inline u_int32_t getMaxFrameSize(){ return max_frame_size; }
+ };
+
+
+}
+}
+
+
+#endif
diff --git a/cpp/client/inc/Exchange.h b/cpp/client/inc/Exchange.h
new file mode 100644
index 0000000000..66593a41cc
--- /dev/null
+++ b/cpp/client/inc/Exchange.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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>
+
+#ifndef _Exchange_
+#define _Exchange_
+
+namespace qpid {
+namespace client {
+
+ class Exchange{
+ const std::string name;
+ const std::string type;
+
+ public:
+
+ static const std::string DIRECT_EXCHANGE;
+ static const std::string TOPIC_EXCHANGE;
+ static const std::string HEADERS_EXCHANGE;
+
+ static const Exchange DEFAULT_DIRECT_EXCHANGE;
+ static const Exchange DEFAULT_TOPIC_EXCHANGE;
+ static const Exchange DEFAULT_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/client/inc/IncomingMessage.h b/cpp/client/inc/IncomingMessage.h
new file mode 100644
index 0000000000..1fee6af433
--- /dev/null
+++ b/cpp/client/inc/IncomingMessage.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * 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 "amqp_framing.h"
+
+#ifndef _IncomingMessage_
+#define _IncomingMessage_
+
+#include "Message.h"
+
+namespace qpid {
+namespace client {
+
+ class IncomingMessage{
+ //content will be preceded by one of these method frames
+ qpid::framing::BasicDeliverBody::shared_ptr delivered;
+ qpid::framing::BasicReturnBody::shared_ptr returned;
+ qpid::framing::BasicGetOkBody::shared_ptr response;
+ qpid::framing::AMQHeaderBody::shared_ptr header;
+ std::vector<qpid::framing::AMQContentBody::shared_ptr> content;
+
+ long contentSize();
+ public:
+ IncomingMessage(qpid::framing::BasicDeliverBody::shared_ptr intro);
+ IncomingMessage(qpid::framing::BasicReturnBody::shared_ptr intro);
+ IncomingMessage(qpid::framing::BasicGetOkBody::shared_ptr intro);
+ ~IncomingMessage();
+ void setHeader(qpid::framing::AMQHeaderBody::shared_ptr header);
+ void addContent(qpid::framing::AMQContentBody::shared_ptr content);
+ bool isComplete();
+ bool isReturn();
+ bool isDelivery();
+ bool isResponse();
+ string& getConsumerTag();//only relevant if isDelivery()
+ qpid::framing::AMQHeaderBody::shared_ptr& getHeader();
+ u_int64_t getDeliveryTag();
+ void getData(string& data);
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/client/inc/Message.h b/cpp/client/inc/Message.h
new file mode 100644
index 0000000000..f8a5aef565
--- /dev/null
+++ b/cpp/client/inc/Message.h
@@ -0,0 +1,86 @@
+/*
+ *
+ * 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 "amqp_framing.h"
+
+#ifndef _Message_
+#define _Message_
+
+
+namespace qpid {
+namespace client {
+
+ class Message{
+ qpid::framing::AMQHeaderBody::shared_ptr header;
+ string data;
+ bool redelivered;
+ u_int64_t deliveryTag;
+
+ qpid::framing::BasicHeaderProperties* getHeaderProperties();
+ Message(qpid::framing::AMQHeaderBody::shared_ptr& header);
+ public:
+ Message();
+ ~Message();
+
+ inline std::string getData(){ return data; }
+ inline void setData(const std::string& data){ this->data = data; }
+
+ inline bool isRedelivered(){ return redelivered; }
+ inline void setRedelivered(bool redelivered){ this->redelivered = redelivered; }
+
+ inline u_int64_t getDeliveryTag(){ return deliveryTag; }
+
+ std::string& getContentType();
+ std::string& getContentEncoding();
+ qpid::framing::FieldTable& getHeaders();
+ u_int8_t getDeliveryMode();
+ u_int8_t getPriority();
+ std::string& getCorrelationId();
+ std::string& getReplyTo();
+ std::string& getExpiration();
+ std::string& getMessageId();
+ u_int64_t getTimestamp();
+ std::string& getType();
+ std::string& getUserId();
+ std::string& getAppId();
+ std::string& getClusterId();
+
+ void setContentType(std::string& type);
+ void setContentEncoding(std::string& encoding);
+ void setHeaders(qpid::framing::FieldTable& headers);
+ void setDeliveryMode(u_int8_t mode);
+ void setPriority(u_int8_t priority);
+ void setCorrelationId(std::string& correlationId);
+ void setReplyTo(std::string& replyTo);
+ void setExpiration(std::string& expiration);
+ void setMessageId(std::string& messageId);
+ void setTimestamp(u_int64_t timestamp);
+ void setType(std::string& type);
+ void setUserId(std::string& userId);
+ void setAppId(std::string& appId);
+ void setClusterId(std::string& clusterId);
+
+
+ friend class Channel;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/client/inc/MessageListener.h b/cpp/client/inc/MessageListener.h
new file mode 100644
index 0000000000..47307a4df5
--- /dev/null
+++ b/cpp/client/inc/MessageListener.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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>
+
+#ifndef _MessageListener_
+#define _MessageListener_
+
+#include "Message.h"
+
+namespace qpid {
+namespace client {
+
+ class MessageListener{
+ public:
+ virtual void received(Message& msg) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/client/inc/Queue.h b/cpp/client/inc/Queue.h
new file mode 100644
index 0000000000..e0964af774
--- /dev/null
+++ b/cpp/client/inc/Queue.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * 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>
+
+#ifndef _Queue_
+#define _Queue_
+
+namespace qpid {
+namespace client {
+
+ class Queue{
+ std::string name;
+ const bool autodelete;
+ const bool exclusive;
+
+ public:
+
+ Queue();
+ Queue(std::string name);
+ Queue(std::string name, bool temp);
+ Queue(std::string name, bool autodelete, bool exclusive);
+ const std::string& getName() const;
+ void setName(const std::string&);
+ bool isAutoDelete() const;
+ bool isExclusive() const;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/client/inc/ResponseHandler.h b/cpp/client/inc/ResponseHandler.h
new file mode 100644
index 0000000000..f5392c954d
--- /dev/null
+++ b/cpp/client/inc/ResponseHandler.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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 "amqp_framing.h"
+#include "Monitor.h"
+
+#ifndef _ResponseHandler_
+#define _ResponseHandler_
+
+namespace qpid {
+ namespace client {
+
+ class ResponseHandler{
+ bool waiting;
+ qpid::framing::AMQMethodBody::shared_ptr response;
+ qpid::concurrent::Monitor* monitor;
+
+ public:
+ ResponseHandler();
+ ~ResponseHandler();
+ inline bool isWaiting(){ return waiting; }
+ inline qpid::framing::AMQMethodBody::shared_ptr getResponse(){ return response; }
+ bool validate(const qpid::framing::AMQMethodBody& expected);
+ void waitForResponse();
+ void signalResponse(qpid::framing::AMQMethodBody::shared_ptr response);
+ void receive(const qpid::framing::AMQMethodBody& expected);
+ void expect();//must be called before calling receive
+ };
+
+ }
+}
+
+
+#endif
diff --git a/cpp/client/inc/ReturnedMessageHandler.h b/cpp/client/inc/ReturnedMessageHandler.h
new file mode 100644
index 0000000000..0117778fde
--- /dev/null
+++ b/cpp/client/inc/ReturnedMessageHandler.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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>
+
+#ifndef _ReturnedMessageHandler_
+#define _ReturnedMessageHandler_
+
+#include "Message.h"
+
+namespace qpid {
+namespace client {
+
+ class ReturnedMessageHandler{
+ public:
+ virtual void returned(Message& msg) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/client/src/Channel.cpp b/cpp/client/src/Channel.cpp
new file mode 100644
index 0000000000..e965f7e5dd
--- /dev/null
+++ b/cpp/client/src/Channel.cpp
@@ -0,0 +1,432 @@
+/*
+ *
+ * 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 "Channel.h"
+#include "MonitorImpl.h"
+#include "ThreadFactoryImpl.h"
+#include "Message.h"
+#include "QpidError.h"
+
+using namespace std::tr1;//to use dynamic_pointer_cast
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::concurrent;
+
+Channel::Channel(bool _transactional, u_int16_t _prefetch) : id(0), incoming(0), con(0), out(0),
+ prefetch(_prefetch),
+ transactional(_transactional),
+ dispatcher(0),
+ closed(true){
+ threadFactory = new ThreadFactoryImpl();
+ dispatchMonitor = new MonitorImpl();
+ retrievalMonitor = new MonitorImpl();
+}
+
+Channel::~Channel(){
+ if(dispatcher){
+ stop();
+ delete dispatcher;
+ }
+ delete retrievalMonitor;
+ delete dispatchMonitor;
+ delete threadFactory;
+}
+
+void Channel::setPrefetch(u_int16_t prefetch){
+ this->prefetch = prefetch;
+ if(con != 0 && out != 0){
+ setQos();
+ }
+}
+
+void Channel::setQos(){
+ sendAndReceive(new AMQFrame(id, new BasicQosBody(0, prefetch, false)), basic_qos_ok);
+ if(transactional){
+ sendAndReceive(new AMQFrame(id, new TxSelectBody()), tx_select_ok);
+ }
+}
+
+void Channel::declareExchange(Exchange& exchange, bool synch){
+ string name = exchange.getName();
+ string type = exchange.getType();
+ FieldTable args;
+ AMQFrame* frame = new AMQFrame(id, new ExchangeDeclareBody(0, name, type, false, false, false, false, !synch, args));
+ if(synch){
+ sendAndReceive(frame, exchange_declare_ok);
+ }else{
+ out->send(frame);
+ }
+}
+
+void Channel::deleteExchange(Exchange& exchange, bool synch){
+ string name = exchange.getName();
+ AMQFrame* frame = new AMQFrame(id, new ExchangeDeleteBody(0, name, false, !synch));
+ if(synch){
+ sendAndReceive(frame, exchange_delete_ok);
+ }else{
+ out->send(frame);
+ }
+}
+
+void Channel::declareQueue(Queue& queue, bool synch){
+ string name = queue.getName();
+ FieldTable args;
+ AMQFrame* frame = new AMQFrame(id, new QueueDeclareBody(0, name, false, false,
+ queue.isExclusive(),
+ queue.isAutoDelete(), !synch, args));
+ if(synch){
+ sendAndReceive(frame, queue_declare_ok);
+ if(queue.getName().length() == 0){
+ QueueDeclareOkBody::shared_ptr response =
+ dynamic_pointer_cast<QueueDeclareOkBody, AMQMethodBody>(responses.getResponse());
+ queue.setName(response->getQueue());
+ }
+ }else{
+ out->send(frame);
+ }
+}
+
+void Channel::deleteQueue(Queue& queue, bool ifunused, bool ifempty, bool synch){
+ //ticket, queue, ifunused, ifempty, nowait
+ string name = queue.getName();
+ AMQFrame* frame = new AMQFrame(id, new QueueDeleteBody(0, name, ifunused, ifempty, !synch));
+ if(synch){
+ sendAndReceive(frame, queue_delete_ok);
+ }else{
+ out->send(frame);
+ }
+}
+
+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();
+ AMQFrame* frame = new AMQFrame(id, new QueueBindBody(0, q, e, (string&) key,!synch, (FieldTable&) args));
+ if(synch){
+ sendAndReceive(frame, queue_bind_ok);
+ }else{
+ out->send(frame);
+ }
+}
+
+void Channel::consume(Queue& queue, std::string& tag, MessageListener* listener,
+ int ackMode, bool noLocal, bool synch){
+
+ string q = queue.getName();
+ AMQFrame* frame = new AMQFrame(id, new BasicConsumeBody(0, q, (string&) tag, noLocal, ackMode == NO_ACK, false, !synch));
+ if(synch){
+ sendAndReceive(frame, basic_consume_ok);
+ BasicConsumeOkBody::shared_ptr response = dynamic_pointer_cast<BasicConsumeOkBody, AMQMethodBody>(responses.getResponse());
+ tag = response->getConsumerTag();
+ }else{
+ out->send(frame);
+ }
+ Consumer* c = new Consumer();
+ c->listener = listener;
+ c->ackMode = ackMode;
+ c->lastDeliveryTag = 0;
+ consumers[tag] = c;
+}
+
+void Channel::cancel(std::string& tag, bool synch){
+ Consumer* c = consumers[tag];
+ if(c->ackMode == LAZY_ACK && c->lastDeliveryTag > 0){
+ out->send(new AMQFrame(id, new BasicAckBody(c->lastDeliveryTag, true)));
+ }
+
+ AMQFrame* frame = new AMQFrame(id, new BasicCancelBody((string&) tag, !synch));
+ if(synch){
+ sendAndReceive(frame, basic_cancel_ok);
+ }else{
+ out->send(frame);
+ }
+ consumers.erase(tag);
+ if(c != 0){
+ delete c;
+ }
+}
+
+void Channel::cancelAll(){
+ int count(consumers.size());
+ for(consumer_iterator i = consumers.begin(); i != consumers.end(); i = consumers.begin()){
+ Consumer* c = i->second;
+ if((c->ackMode == LAZY_ACK || c->ackMode == AUTO_ACK) && c->lastDeliveryTag > 0){
+ out->send(new AMQFrame(id, new BasicAckBody(c->lastDeliveryTag, true)));
+ }
+ consumers.erase(i);
+ delete c;
+ }
+}
+
+void Channel::retrieve(Message& msg){
+ retrievalMonitor->acquire();
+ while(retrieved == 0){
+ retrievalMonitor->wait();
+ }
+
+ msg.header = retrieved->getHeader();
+ msg.deliveryTag = retrieved->getDeliveryTag();
+ retrieved->getData(msg.data);
+ delete retrieved;
+ retrieved = 0;
+
+ retrievalMonitor->release();
+}
+
+bool Channel::get(Message& msg, const Queue& queue, int ackMode){
+ string name = queue.getName();
+ AMQFrame* frame = new AMQFrame(id, new BasicGetBody(0, name, ackMode));
+ responses.expect();
+ out->send(frame);
+ responses.waitForResponse();
+ AMQMethodBody::shared_ptr response = responses.getResponse();
+ if(basic_get_ok.match(response.get())){
+ if(incoming != 0){
+ std::cout << "Existing message not complete" << std::endl;
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Existing message not complete");
+ }else{
+ incoming = new IncomingMessage(dynamic_pointer_cast<BasicGetOkBody, AMQMethodBody>(response));
+ }
+ retrieve(msg);
+ return true;
+ }if(basic_get_empty.match(response.get())){
+ return false;
+ }else{
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 500, "Unexpected response to basic.get.");
+ }
+}
+
+
+void Channel::publish(Message& msg, const Exchange& exchange, const std::string& routingKey, bool mandatory, bool immediate){
+ string e = exchange.getName();
+ string key = routingKey;
+
+ out->send(new AMQFrame(id, new BasicPublishBody(0, e, key, mandatory, immediate)));
+ //break msg up into header frame and content frame(s) and send these
+ string data = msg.getData();
+ msg.header->setContentSize(data.length());
+ AMQBody::shared_ptr body(static_pointer_cast<AMQBody, AMQHeaderBody>(msg.header));
+ out->send(new AMQFrame(id, body));
+
+ int data_length = data.length();
+ if(data_length > 0){
+ //TODO fragmentation of messages, need to know max frame size for connection
+ int frag_size = con->getMaxFrameSize() - 4;
+ if(data_length < frag_size){
+ out->send(new AMQFrame(id, new AMQContentBody(data)));
+ }else{
+ int frag_count = data_length / frag_size;
+ for(int i = 0; i < frag_count; i++){
+ int pos = i*frag_size;
+ int len = i < frag_count - 1 ? frag_size : data_length - pos;
+ string frag(data.substr(pos, len));
+ out->send(new AMQFrame(id, new AMQContentBody(frag)));
+ }
+ }
+ }
+}
+
+void Channel::commit(){
+ AMQFrame* frame = new AMQFrame(id, new TxCommitBody());
+ sendAndReceive(frame, tx_commit_ok);
+}
+
+void Channel::rollback(){
+ AMQFrame* frame = new AMQFrame(id, new TxRollbackBody());
+ sendAndReceive(frame, tx_rollback_ok);
+}
+
+void Channel::handleMethod(AMQMethodBody::shared_ptr body){
+ //channel.flow, channel.close, basic.deliver, basic.return or a response to a synchronous request
+ if(responses.isWaiting()){
+ responses.signalResponse(body);
+ }else if(basic_deliver.match(body.get())){
+ if(incoming != 0){
+ std::cout << "Existing message not complete [deliveryTag=" << incoming->getDeliveryTag() << "]" << std::endl;
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Existing message not complete");
+ }else{
+ incoming = new IncomingMessage(dynamic_pointer_cast<BasicDeliverBody, AMQMethodBody>(body));
+ }
+ }else if(basic_return.match(body.get())){
+ if(incoming != 0){
+ std::cout << "Existing message not complete" << std::endl;
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Existing message not complete");
+ }else{
+ incoming = new IncomingMessage(dynamic_pointer_cast<BasicReturnBody, AMQMethodBody>(body));
+ }
+ }else if(channel_close.match(body.get())){
+ con->removeChannel(this);
+ //need to signal application that channel has been closed through exception
+
+ }else if(channel_flow.match(body.get())){
+
+ }else{
+ //signal error
+ std::cout << "Unhandled method: " << *body << std::endl;
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Unhandled method");
+ }
+}
+
+void Channel::handleHeader(AMQHeaderBody::shared_ptr body){
+ if(incoming == 0){
+ //handle invalid frame sequence
+ std::cout << "Invalid message sequence: got header before return or deliver." << std::endl;
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Invalid message sequence: got header before return or deliver.");
+ }else{
+ incoming->setHeader(body);
+ if(incoming->isComplete()){
+ enqueue();
+ }
+ }
+}
+
+void Channel::handleContent(AMQContentBody::shared_ptr body){
+ if(incoming == 0){
+ //handle invalid frame sequence
+ std::cout << "Invalid message sequence: got content before return or deliver." << std::endl;
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Invalid message sequence: got content before return or deliver.");
+ }else{
+ incoming->addContent(body);
+ if(incoming->isComplete()){
+ enqueue();
+ }
+ }
+}
+
+void Channel::handleHeartbeat(AMQHeartbeatBody::shared_ptr body){
+ THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Channel received heartbeat");
+}
+
+void Channel::start(){
+ dispatcher = threadFactory->create(this);
+ dispatcher->start();
+}
+
+void Channel::stop(){
+ closed = true;
+ dispatchMonitor->acquire();
+ dispatchMonitor->notify();
+ dispatchMonitor->release();
+ if(dispatcher){
+ dispatcher->join();
+ }
+}
+
+void Channel::run(){
+ dispatch();
+}
+
+void Channel::enqueue(){
+ if(incoming->isResponse()){
+ retrievalMonitor->acquire();
+ retrieved = incoming;
+ retrievalMonitor->notify();
+ retrievalMonitor->release();
+ }else{
+ dispatchMonitor->acquire();
+ messages.push(incoming);
+ dispatchMonitor->notify();
+ dispatchMonitor->release();
+ }
+ incoming = 0;
+}
+
+IncomingMessage* Channel::dequeue(){
+ dispatchMonitor->acquire();
+ while(messages.empty() && !closed){
+ dispatchMonitor->wait();
+ }
+ IncomingMessage* msg = 0;
+ if(!messages.empty()){
+ msg = messages.front();
+ messages.pop();
+ }
+ dispatchMonitor->release();
+ return msg;
+}
+
+void Channel::deliver(Consumer* consumer, Message& msg){
+ //record delivery tag:
+ consumer->lastDeliveryTag = msg.getDeliveryTag();
+
+ //allow registered listener to handle the message
+ consumer->listener->received(msg);
+
+ //if the handler calls close on the channel or connection while
+ //handling this message, then consumer will now have been deleted.
+ if(!closed){
+ bool multiple(false);
+ switch(consumer->ackMode){
+ case LAZY_ACK:
+ multiple = true;
+ if(++(consumer->count) < prefetch) break;
+ //else drop-through
+ case AUTO_ACK:
+ out->send(new AMQFrame(id, new BasicAckBody(msg.getDeliveryTag(), multiple)));
+ consumer->lastDeliveryTag = 0;
+ }
+ }
+
+ //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 Channel::dispatch(){
+ while(!closed){
+ IncomingMessage* incomingMsg = dequeue();
+ if(incomingMsg){
+ //Note: msg is currently only valid for duration of this call
+ Message msg(incomingMsg->getHeader());
+ incomingMsg->getData(msg.data);
+ if(incomingMsg->isReturn()){
+ if(returnsHandler == 0){
+ //print warning to log/console
+ std::cout << "Message returned: " << msg.getData() << std::endl;
+ }else{
+ returnsHandler->returned(msg);
+ }
+ }else{
+ msg.deliveryTag = incomingMsg->getDeliveryTag();
+ std::string tag = incomingMsg->getConsumerTag();
+
+ if(consumers[tag] == 0){
+ //signal error
+ std::cout << "Unknown consumer: " << tag << std::endl;
+ }else{
+ deliver(consumers[tag], msg);
+ }
+ }
+ delete incomingMsg;
+ }
+ }
+}
+
+void Channel::setReturnedMessageHandler(ReturnedMessageHandler* handler){
+ returnsHandler = handler;
+}
+
+void Channel::sendAndReceive(AMQFrame* frame, const AMQMethodBody& body){
+ responses.expect();
+ out->send(frame);
+ responses.receive(body);
+}
+
+void Channel::close(){
+ if(con != 0){
+ con->closeChannel(this);
+ }
+}
diff --git a/cpp/client/src/Connection.cpp b/cpp/client/src/Connection.cpp
new file mode 100644
index 0000000000..eeb2330561
--- /dev/null
+++ b/cpp/client/src/Connection.cpp
@@ -0,0 +1,237 @@
+/*
+ *
+ * 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 "Connection.h"
+#include "Channel.h"
+#include "ConnectorImpl.h"
+#include "Message.h"
+#include "QpidError.h"
+#include <iostream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::io;
+using namespace qpid::concurrent;
+
+u_int16_t Connection::channelIdCounter;
+
+Connection::Connection(bool debug, u_int32_t _max_frame_size) : max_frame_size(_max_frame_size), closed(true){
+ connector = new ConnectorImpl(debug, _max_frame_size);
+}
+
+Connection::~Connection(){
+ delete connector;
+}
+
+void Connection::open(const std::string& host, int port, const std::string& uid, const std::string& pwd, const std::string& virtualhost){
+ this->host = host;
+ this->port = port;
+ connector->setInputHandler(this);
+ connector->setTimeoutHandler(this);
+ connector->setShutdownHandler(this);
+ out = connector->getOutputHandler();
+ connector->connect(host, port);
+
+ ProtocolInitiation* header = new ProtocolInitiation(8, 0);
+ responses.expect();
+ connector->init(header);
+ responses.receive(connection_start);
+
+ FieldTable props;
+ string mechanism("PLAIN");
+ string response = ((char)0) + uid + ((char)0) + pwd;
+ string locale("en_US");
+ responses.expect();
+ out->send(new AMQFrame(0, new ConnectionStartOkBody(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
+ out->send(new AMQFrame(0, new ConnectionSecureOkBody(response)));
+ **/
+
+ responses.receive(connection_tune);
+
+ ConnectionTuneBody::shared_ptr proposal = std::tr1::dynamic_pointer_cast<ConnectionTuneBody, AMQMethodBody>(responses.getResponse());
+ out->send(new AMQFrame(0, new ConnectionTuneOkBody(proposal->getChannelMax(), max_frame_size, proposal->getHeartbeat())));
+
+ u_int16_t heartbeat = proposal->getHeartbeat();
+ connector->setReadTimeout(heartbeat * 2);
+ connector->setWriteTimeout(heartbeat);
+
+ //send connection.open
+ string capabilities;
+ string vhost = virtualhost;
+ responses.expect();
+ out->send(new AMQFrame(0, new ConnectionOpenBody(vhost, capabilities, true)));
+ //receive connection.open-ok (or redirect, but ignore that for now esp. as using force=true).
+ responses.waitForResponse();
+ if(responses.validate(connection_open_ok)){
+ //ok
+ }else if(responses.validate(connection_redirect)){
+ //ignore for now
+ ConnectionRedirectBody::shared_ptr redirect(std::tr1::dynamic_pointer_cast<ConnectionRedirectBody, AMQMethodBody>(responses.getResponse()));
+ std::cout << "Received redirection to " << redirect->getHost() << std::endl;
+ }else{
+ THROW_QPID_ERROR(PROTOCOL_ERROR, "Bad response");
+ }
+
+}
+
+void Connection::close(){
+ if(!closed){
+ u_int16_t code(200);
+ string text("Ok");
+ u_int16_t classId(0);
+ u_int16_t methodId(0);
+
+ sendAndReceive(new AMQFrame(0, new ConnectionCloseBody(code, text, classId, methodId)), connection_close_ok);
+ connector->close();
+ }
+}
+
+void Connection::openChannel(Channel* channel){
+ channel->con = this;
+ channel->id = ++channelIdCounter;
+ channel->out = out;
+ channels[channel->id] = channel;
+ //now send frame to open channel and wait for response
+ string oob;
+ channel->sendAndReceive(new AMQFrame(channel->id, new ChannelOpenBody(oob)), channel_open_ok);
+ channel->setQos();
+ channel->closed = false;
+}
+
+void Connection::closeChannel(Channel* channel){
+ //send frame to close channel
+ u_int16_t code(200);
+ string text("Ok");
+ u_int16_t classId(0);
+ u_int16_t methodId(0);
+ closeChannel(channel, code, text, classId, methodId);
+}
+
+void Connection::closeChannel(Channel* channel, u_int16_t code, string& text, u_int16_t classId, u_int16_t methodId){
+ //send frame to close channel
+ channel->cancelAll();
+ channel->closed = true;
+ channel->sendAndReceive(new AMQFrame(channel->id, new ChannelCloseBody(code, text, classId, methodId)), channel_close_ok);
+ channel->con = 0;
+ channel->out = 0;
+ removeChannel(channel);
+}
+
+void Connection::removeChannel(Channel* channel){
+ //send frame to close channel
+
+ channels.erase(channel->id);
+ channel->out = 0;
+ channel->id = 0;
+ channel->con = 0;
+}
+
+void Connection::received(AMQFrame* frame){
+ u_int16_t channelId = frame->getChannel();
+
+ if(channelId == 0){
+ this->handleBody(frame->getBody());
+ }else{
+ Channel* channel = channels[channelId];
+ if(channel == 0){
+ error(504, "Unknown channel");
+ }else{
+ try{
+ channel->handleBody(frame->getBody());
+ }catch(qpid::QpidError e){
+ channelException(channel, dynamic_cast<AMQMethodBody*>(frame->getBody().get()), e);
+ }
+ }
+ }
+}
+
+void Connection::handleMethod(AMQMethodBody::shared_ptr body){
+ //connection.close, basic.deliver, basic.return or a response to a synchronous request
+ if(responses.isWaiting()){
+ responses.signalResponse(body);
+ }else if(connection_close.match(body.get())){
+ //send back close ok
+ //close socket
+ ConnectionCloseBody* request = dynamic_cast<ConnectionCloseBody*>(body.get());
+ std::cout << "Connection closed by server: " << request->getReplyCode() << ":" << request->getReplyText() << std::endl;
+ connector->close();
+ }else{
+ std::cout << "Unhandled method for connection: " << *body << std::endl;
+ error(504, "Unrecognised method", body->amqpClassId(), body->amqpMethodId());
+ }
+}
+
+void Connection::handleHeader(AMQHeaderBody::shared_ptr body){
+ error(504, "Channel error: received header body with channel 0.");
+}
+
+void Connection::handleContent(AMQContentBody::shared_ptr body){
+ error(504, "Channel error: received content body with channel 0.");
+}
+
+void Connection::handleHeartbeat(AMQHeartbeatBody::shared_ptr body){
+}
+
+void Connection::sendAndReceive(AMQFrame* frame, const AMQMethodBody& body){
+ responses.expect();
+ out->send(frame);
+ responses.receive(body);
+}
+
+void Connection::error(int code, const string& msg, int classid, int methodid){
+ std::cout << "Connection exception generated: " << code << msg;
+ if(classid || methodid){
+ std::cout << " [" << methodid << ":" << classid << "]";
+ }
+ std::cout << std::endl;
+ sendAndReceive(new AMQFrame(0, new ConnectionCloseBody(code, (string&) msg, classid, methodid)), connection_close_ok);
+ connector->close();
+}
+
+void Connection::channelException(Channel* channel, AMQMethodBody* method, QpidError& e){
+ std::cout << "Caught error from channel [" << e.code << "] " << e.msg << " (" << e.file << ":" << e.line << ")" << std::endl;
+ int code = e.code == PROTOCOL_ERROR ? e.code - PROTOCOL_ERROR : 500;
+ string msg = e.msg;
+ if(method == 0){
+ closeChannel(channel, code, msg);
+ }else{
+ closeChannel(channel, code, msg, method->amqpClassId(), method->amqpMethodId());
+ }
+}
+
+void Connection::idleIn(){
+ std::cout << "Connection timed out due to abscence of heartbeat." << std::endl;
+ connector->close();
+}
+
+void Connection::idleOut(){
+ out->send(new AMQFrame(0, new AMQHeartbeatBody()));
+}
+
+void Connection::shutdown(){
+ closed = true;
+ //close all channels
+ for(iterator i = channels.begin(); i != channels.end(); i++){
+ i->second->stop();
+ }
+}
diff --git a/cpp/client/src/Exchange.cpp b/cpp/client/src/Exchange.cpp
new file mode 100644
index 0000000000..681068dc4c
--- /dev/null
+++ b/cpp/client/src/Exchange.cpp
@@ -0,0 +1,30 @@
+/*
+ *
+ * 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 "Exchange.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_DIRECT_EXCHANGE("amq.direct", DIRECT_EXCHANGE);
+const qpid::client::Exchange qpid::client::Exchange::DEFAULT_TOPIC_EXCHANGE("amq.topic", TOPIC_EXCHANGE);
+const qpid::client::Exchange qpid::client::Exchange::DEFAULT_HEADERS_EXCHANGE("amq.headers", HEADERS_EXCHANGE);
diff --git a/cpp/client/src/IncomingMessage.cpp b/cpp/client/src/IncomingMessage.cpp
new file mode 100644
index 0000000000..8e2604c4cb
--- /dev/null
+++ b/cpp/client/src/IncomingMessage.cpp
@@ -0,0 +1,85 @@
+/*
+ *
+ * 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 "QpidError.h"
+#include <iostream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+IncomingMessage::IncomingMessage(BasicDeliverBody::shared_ptr intro) : delivered(intro){}
+IncomingMessage::IncomingMessage(BasicReturnBody::shared_ptr intro): returned(intro){}
+IncomingMessage::IncomingMessage(BasicGetOkBody::shared_ptr intro): response(intro){}
+
+IncomingMessage::~IncomingMessage(){
+}
+
+void IncomingMessage::setHeader(AMQHeaderBody::shared_ptr header){
+ this->header = header;
+}
+
+void IncomingMessage::addContent(AMQContentBody::shared_ptr content){
+ this->content.push_back(content);
+}
+
+bool IncomingMessage::isComplete(){
+ return header != 0 && header->getContentSize() == contentSize();
+}
+
+bool IncomingMessage::isReturn(){
+ return returned;
+}
+
+bool IncomingMessage::isDelivery(){
+ return delivered;
+}
+
+bool IncomingMessage::isResponse(){
+ return response;
+}
+
+string& IncomingMessage::getConsumerTag(){
+ if(!isDelivery()) THROW_QPID_ERROR(CLIENT_ERROR, "Consumer tag only valid for delivery");
+ return delivered->getConsumerTag();
+}
+
+u_int64_t IncomingMessage::getDeliveryTag(){
+ if(!isDelivery()) THROW_QPID_ERROR(CLIENT_ERROR, "Delivery tag only valid for delivery");
+ return delivered->getDeliveryTag();
+}
+
+AMQHeaderBody::shared_ptr& IncomingMessage::getHeader(){
+ return header;
+}
+
+void IncomingMessage::getData(string& s){
+ int count(content.size());
+ for(int i = 0; i < count; i++){
+ if(i == 0) s = content[i]->getData();
+ else s += content[i]->getData();
+ }
+}
+
+long IncomingMessage::contentSize(){
+ long size(0);
+ int count(content.size());
+ for(int i = 0; i < count; i++){
+ size += content[i]->size();
+ }
+ return size;
+}
diff --git a/cpp/client/src/Message.cpp b/cpp/client/src/Message.cpp
new file mode 100644
index 0000000000..71befe57b1
--- /dev/null
+++ b/cpp/client/src/Message.cpp
@@ -0,0 +1,147 @@
+/*
+ *
+ * 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 "Message.h"
+
+using namespace qpid::client;
+using namespace qpid::framing;
+
+Message::Message(){
+ header = AMQHeaderBody::shared_ptr(new AMQHeaderBody(BASIC));
+}
+
+Message::Message(AMQHeaderBody::shared_ptr& _header) : header(_header){
+}
+
+Message::~Message(){
+}
+
+BasicHeaderProperties* Message::getHeaderProperties(){
+ return dynamic_cast<BasicHeaderProperties*>(header->getProperties());
+}
+
+std::string& Message::getContentType(){
+ return getHeaderProperties()->getContentType();
+}
+
+std::string& Message::getContentEncoding(){
+ return getHeaderProperties()->getContentEncoding();
+}
+
+FieldTable& Message::getHeaders(){
+ return getHeaderProperties()->getHeaders();
+}
+
+u_int8_t Message::getDeliveryMode(){
+ return getHeaderProperties()->getDeliveryMode();
+}
+
+u_int8_t Message::getPriority(){
+ return getHeaderProperties()->getPriority();
+}
+
+std::string& Message::getCorrelationId(){
+ return getHeaderProperties()->getCorrelationId();
+}
+
+std::string& Message::getReplyTo(){
+ return getHeaderProperties()->getReplyTo();
+}
+
+std::string& Message::getExpiration(){
+ return getHeaderProperties()->getExpiration();
+}
+
+std::string& Message::getMessageId(){
+ return getHeaderProperties()->getMessageId();
+}
+
+u_int64_t Message::getTimestamp(){
+ return getHeaderProperties()->getTimestamp();
+}
+
+std::string& Message::getType(){
+ return getHeaderProperties()->getType();
+}
+
+std::string& Message::getUserId(){
+ return getHeaderProperties()->getUserId();
+}
+
+std::string& Message::getAppId(){
+ return getHeaderProperties()->getAppId();
+}
+
+std::string& Message::getClusterId(){
+ return getHeaderProperties()->getClusterId();
+}
+
+void Message::setContentType(std::string& type){
+ getHeaderProperties()->setContentType(type);
+}
+
+void Message::setContentEncoding(std::string& encoding){
+ getHeaderProperties()->setContentEncoding(encoding);
+}
+
+void Message::setHeaders(FieldTable& headers){
+ getHeaderProperties()->setHeaders(headers);
+}
+
+void Message::setDeliveryMode(u_int8_t mode){
+ getHeaderProperties()->setDeliveryMode(mode);
+}
+
+void Message::setPriority(u_int8_t priority){
+ getHeaderProperties()->setPriority(priority);
+}
+
+void Message::setCorrelationId(std::string& correlationId){
+ getHeaderProperties()->setCorrelationId(correlationId);
+}
+
+void Message::setReplyTo(std::string& replyTo){
+ getHeaderProperties()->setReplyTo(replyTo);
+}
+
+void Message::setExpiration(std::string& expiration){
+ getHeaderProperties()->setExpiration(expiration);
+}
+
+void Message::setMessageId(std::string& messageId){
+ getHeaderProperties()->setMessageId(messageId);
+}
+
+void Message::setTimestamp(u_int64_t timestamp){
+ getHeaderProperties()->setTimestamp(timestamp);
+}
+
+void Message::setType(std::string& type){
+ getHeaderProperties()->setType(type);
+}
+
+void Message::setUserId(std::string& userId){
+ getHeaderProperties()->setUserId(userId);
+}
+
+void Message::setAppId(std::string& appId){
+ getHeaderProperties()->setAppId(appId);
+}
+
+void Message::setClusterId(std::string& clusterId){
+ getHeaderProperties()->setClusterId(clusterId);
+}
diff --git a/cpp/client/src/Queue.cpp b/cpp/client/src/Queue.cpp
new file mode 100644
index 0000000000..cb957dd993
--- /dev/null
+++ b/cpp/client/src/Queue.cpp
@@ -0,0 +1,47 @@
+/*
+ *
+ * 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 "Queue.h"
+
+qpid::client::Queue::Queue() : name(""), autodelete(true), exclusive(true){}
+
+qpid::client::Queue::Queue(std::string _name) : name(_name), autodelete(false), exclusive(false){}
+
+qpid::client::Queue::Queue(std::string _name, bool temp) : name(_name), autodelete(temp), exclusive(temp){}
+
+qpid::client::Queue::Queue(std::string _name, bool _autodelete, bool _exclusive)
+ : name(_name), autodelete(_autodelete), exclusive(_exclusive){}
+
+const std::string& qpid::client::Queue::getName() const{
+ return name;
+}
+
+void qpid::client::Queue::setName(const std::string& name){
+ this->name = name;
+}
+
+bool qpid::client::Queue::isAutoDelete() const{
+ return autodelete;
+}
+
+bool qpid::client::Queue::isExclusive() const{
+ return exclusive;
+}
+
+
+
+
diff --git a/cpp/client/src/ResponseHandler.cpp b/cpp/client/src/ResponseHandler.cpp
new file mode 100644
index 0000000000..837bba37fd
--- /dev/null
+++ b/cpp/client/src/ResponseHandler.cpp
@@ -0,0 +1,63 @@
+/*
+ *
+ * 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 "ResponseHandler.h"
+#include "MonitorImpl.h"
+#include "QpidError.h"
+
+qpid::client::ResponseHandler::ResponseHandler() : waiting(false){
+ monitor = new qpid::concurrent::MonitorImpl();
+}
+
+qpid::client::ResponseHandler::~ResponseHandler(){
+ delete monitor;
+}
+
+bool qpid::client::ResponseHandler::validate(const qpid::framing::AMQMethodBody& expected){
+ return expected.match(response.get());
+}
+
+void qpid::client::ResponseHandler::waitForResponse(){
+ monitor->acquire();
+ if(waiting){
+ monitor->wait();
+ }
+ monitor->release();
+}
+
+void qpid::client::ResponseHandler::signalResponse(qpid::framing::AMQMethodBody::shared_ptr response){
+ this->response = response;
+ monitor->acquire();
+ waiting = false;
+ monitor->notify();
+ monitor->release();
+}
+
+void qpid::client::ResponseHandler::receive(const qpid::framing::AMQMethodBody& expected){
+ monitor->acquire();
+ if(waiting){
+ monitor->wait();
+ }
+ monitor->release();
+ if(!validate(expected)){
+ THROW_QPID_ERROR(PROTOCOL_ERROR, "Protocol Error");
+ }
+}
+
+void qpid::client::ResponseHandler::expect(){
+ waiting = true;
+}
diff --git a/cpp/client/test/Makefile b/cpp/client/test/Makefile
new file mode 100644
index 0000000000..f35aab3e17
--- /dev/null
+++ b/cpp/client/test/Makefile
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+
+QPID_HOME = ../../..
+include ${QPID_HOME}/cpp/options.mk
+
+# TODO aconway 2006-09-12: These are system tests, not unit tests.
+# We need client side unit tests.
+# We should separate them from the system tets.
+# We need an approach to automate the C++ client/server system tests.
+#
+
+SOURCES=$(wildcard *.cpp)
+TESTS=$(SOURCES:.cpp=)
+DEPS= $(SOURCES:.cpp=.d)
+
+INCLUDES = $(TEST_INCLUDES)
+LDLIBS= -lapr-1 $(COMMON_LIB) $(CLIENT_LIB)
+
+.PHONY: all clean
+
+all: $(TESTS)
+
+clean:
+ -@rm -f $(TESTS) $(DEPS)
+
+# Rule to build test programs.
+%: %.cpp
+ $(CXX) -o $@ $< $(CXXFLAGS) $(LDFLAGS) $(LDLIBS)
+
+# Dependencies
+-include $(DEPS)
diff --git a/cpp/client/test/client_test.cpp b/cpp/client/test/client_test.cpp
new file mode 100644
index 0000000000..e33beb3b67
--- /dev/null
+++ b/cpp/client/test/client_test.cpp
@@ -0,0 +1,97 @@
+/*
+ *
+ * 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 "QpidError.h"
+#include "Channel.h"
+#include "Connection.h"
+#include "FieldTable.h"
+#include "Message.h"
+#include "MessageListener.h"
+
+#include "MonitorImpl.h"
+
+
+using namespace qpid::client;
+using namespace qpid::concurrent;
+
+class SimpleListener : public virtual MessageListener{
+ Monitor* monitor;
+
+public:
+ inline SimpleListener(Monitor* _monitor) : monitor(_monitor){}
+
+ inline virtual void received(Message& msg){
+ std::cout << "Received message " /**<< msg **/<< std::endl;
+ monitor->acquire();
+ monitor->notify();
+ monitor->release();
+ }
+};
+
+int main(int argc, char** argv)
+{
+ try{
+ Connection con(argc > 1);
+ Channel channel;
+ Exchange exchange("MyExchange", Exchange::TOPIC_EXCHANGE);
+ Queue queue("MyQueue", true);
+
+ string host("localhost");
+
+ con.open(host);
+ std::cout << "Opened connection." << std::endl;
+ con.openChannel(&channel);
+ std::cout << "Opened channel." << std::endl;
+ channel.declareExchange(exchange);
+ std::cout << "Declared exchange." << std::endl;
+ channel.declareQueue(queue);
+ std::cout << "Declared queue." << std::endl;
+ qpid::framing::FieldTable args;
+ channel.bind(exchange, queue, "MyTopic", args);
+ std::cout << "Bound queue to exchange." << std::endl;
+
+ //set up a message listener
+ MonitorImpl monitor;
+ SimpleListener listener(&monitor);
+ string tag("MyTag");
+ channel.consume(queue, tag, &listener);
+ channel.start();
+ std::cout << "Registered consumer." << std::endl;
+
+ Message msg;
+ string data("MyMessage");
+ msg.setData(data);
+ channel.publish(msg, exchange, "MyTopic");
+ std::cout << "Published message." << std::endl;
+
+ monitor.acquire();
+ monitor.wait();
+ monitor.release();
+
+
+ con.closeChannel(&channel);
+ std::cout << "Closed channel." << std::endl;
+ con.close();
+ std::cout << "Closed connection." << std::endl;
+ }catch(qpid::QpidError error){
+ std::cout << "Error [" << error.code << "] " << error.msg << " (" << error.file << ":" << error.line << ")" << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/cpp/client/test/topic_listener.cpp b/cpp/client/test/topic_listener.cpp
new file mode 100644
index 0000000000..707b3443a1
--- /dev/null
+++ b/cpp/client/test/topic_listener.cpp
@@ -0,0 +1,180 @@
+/*
+ *
+ * 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 <sstream>
+#include "apr_time.h"
+#include "QpidError.h"
+#include "Channel.h"
+#include "Connection.h"
+#include "Exchange.h"
+#include "MessageListener.h"
+#include "Queue.h"
+
+using namespace qpid::client;
+
+class Listener : public MessageListener{
+ Channel* const channel;
+ const std::string responseQueue;
+ const bool transactional;
+ bool init;
+ int count;
+ apr_time_t start;
+
+ void shutdown();
+ void report();
+public:
+ Listener(Channel* channel, const std::string& reponseQueue, bool tx);
+ virtual void received(Message& msg);
+};
+
+class Args{
+ string host;
+ int port;
+ int ackMode;
+ bool transactional;
+ int prefetch;
+ bool trace;
+ bool help;
+public:
+ inline Args() : host("localhost"), port(5672), ackMode(NO_ACK), transactional(false), prefetch(1000), trace(false), help(false){}
+ void parse(int argc, char** argv);
+ void usage();
+
+ inline const string& getHost() const { return host;}
+ inline int getPort() const { return port; }
+ inline int getAckMode(){ return ackMode; }
+ inline bool getTransactional() const { return transactional; }
+ inline int getPrefetch(){ return prefetch; }
+ inline bool getTrace() const { return trace; }
+ inline bool getHelp() const { return help; }
+};
+
+int main(int argc, char** argv){
+ Args args;
+ args.parse(argc, argv);
+ if(args.getHelp()){
+ args.usage();
+ }else{
+ try{
+ Connection connection(args.getTrace());
+ connection.open(args.getHost(), args.getPort());
+ Channel channel(args.getTransactional(), args.getPrefetch());
+ connection.openChannel(&channel);
+
+ //declare exchange, queue and bind them:
+ Queue response("response");
+ channel.declareQueue(response);
+
+ Queue control;
+ channel.declareQueue(control);
+ qpid::framing::FieldTable bindArgs;
+ channel.bind(Exchange::DEFAULT_TOPIC_EXCHANGE, control, "topic_control", bindArgs);
+ //set up listener
+ Listener listener(&channel, response.getName(), args.getTransactional());
+ std::string tag;
+ channel.consume(control, tag, &listener, args.getAckMode());
+ channel.run();
+ connection.close();
+ }catch(qpid::QpidError error){
+ std::cout << "Error [" << error.code << "] " << error.msg << " (" << error.file << ":" << error.line << ")" << std::endl;
+ }
+ }
+}
+
+Listener::Listener(Channel* _channel, const std::string& _responseq, bool tx) :
+ channel(_channel), responseQueue(_responseq), transactional(tx), init(false), count(0){}
+
+void Listener::received(Message& message){
+ if(!init){
+ start = apr_time_as_msec(apr_time_now());
+ count = 0;
+ init = true;
+ }
+ std::string type(message.getHeaders().getString("TYPE"));
+
+ if(type == "TERMINATION_REQUEST"){
+ shutdown();
+ }else if(type == "REPORT_REQUEST"){
+ //send a report:
+ report();
+ init = false;
+ }else if (++count % 100 == 0){
+ std::cout <<"Received " << count << " messages." << std::endl;
+ }
+}
+
+void Listener::shutdown(){
+ channel->close();
+}
+
+void Listener::report(){
+ apr_time_t finish = apr_time_as_msec(apr_time_now());
+ apr_time_t time = finish - start;
+ std::stringstream report;
+ report << "Received " << count << " messages in " << time << " ms.";
+ Message msg;
+ msg.setData(report.str());
+ channel->publish(msg, Exchange::DEFAULT_DIRECT_EXCHANGE, responseQueue);
+ if(transactional){
+ channel->commit();
+ }
+}
+
+
+void Args::parse(int argc, char** argv){
+ for(int i = 1; i < argc; i++){
+ string name(argv[i]);
+ if("-help" == name){
+ help = true;
+ break;
+ }else if("-host" == name){
+ host = argv[++i];
+ }else if("-port" == name){
+ port = atoi(argv[++i]);
+ }else if("-ack_mode" == name){
+ ackMode = atoi(argv[++i]);
+ }else if("-transactional" == name){
+ transactional = true;
+ }else if("-prefetch" == name){
+ prefetch = atoi(argv[++i]);
+ }else if("-trace" == name){
+ trace = true;
+ }else{
+ std::cout << "Warning: unrecognised option " << name << std::endl;
+ }
+ }
+}
+
+void Args::usage(){
+ std::cout << "Options:" << std::endl;
+ std::cout << " -help" << std::endl;
+ std::cout << " Prints this usage message" << std::endl;
+ std::cout << " -host <host>" << std::endl;
+ std::cout << " Specifies host to connect to (default is localhost)" << std::endl;
+ std::cout << " -port <port>" << std::endl;
+ std::cout << " Specifies port to conect to (default is 5762)" << std::endl;
+ std::cout << " -ack_mode <mode>" << std::endl;
+ std::cout << " Sets the acknowledgement mode" << std::endl;
+ std::cout << " 0=NO_ACK (default), 1=AUTO_ACK, 2=LAZY_ACK" << std::endl;
+ std::cout << " -transactional" << std::endl;
+ std::cout << " Indicates the client should use transactions" << std::endl;
+ std::cout << " -prefetch <count>" << std::endl;
+ std::cout << " Specifies the prefetch count (default is 1000)" << std::endl;
+ std::cout << " -trace" << std::endl;
+ std::cout << " Indicates that the frames sent and received should be logged" << std::endl;
+}
diff --git a/cpp/client/test/topic_publisher.cpp b/cpp/client/test/topic_publisher.cpp
new file mode 100644
index 0000000000..fc6b7f3b30
--- /dev/null
+++ b/cpp/client/test/topic_publisher.cpp
@@ -0,0 +1,253 @@
+/*
+ *
+ * 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 <cstdlib>
+#include "unistd.h"
+#include "apr_time.h"
+#include "MonitorImpl.h"
+#include "QpidError.h"
+#include "Channel.h"
+#include "Connection.h"
+#include "Exchange.h"
+#include "MessageListener.h"
+#include "Queue.h"
+
+using namespace qpid::client;
+using namespace qpid::concurrent;
+
+class Publisher : public MessageListener{
+ Channel* const channel;
+ const std::string controlTopic;
+ const bool transactional;
+ MonitorImpl monitor;
+ int count;
+
+ void waitForCompletion(int msgs);
+ string generateData(int size);
+
+public:
+ Publisher(Channel* channel, const std::string& controlTopic, bool tx);
+ virtual void received(Message& msg);
+ apr_time_t publish(int msgs, int listeners, int size);
+ void terminate();
+};
+
+class Args{
+ string host;
+ int port;
+ int messages;
+ int subscribers;
+ int ackMode;
+ bool transactional;
+ int prefetch;
+ int batches;
+ int delay;
+ int size;
+ bool trace;
+ bool help;
+public:
+ inline Args() : host("localhost"), port(5672), messages(1000), subscribers(1),
+ ackMode(NO_ACK), transactional(false), prefetch(1000), batches(1),
+ delay(0), size(256), trace(false), help(false){}
+
+ void parse(int argc, char** argv);
+ void usage();
+
+ inline const string& getHost() const { return host;}
+ inline int getPort() const { return port; }
+ inline int getMessages() const { return messages; }
+ inline int getSubscribers() const { return subscribers; }
+ inline int getAckMode(){ return ackMode; }
+ inline bool getTransactional() const { return transactional; }
+ inline int getPrefetch(){ return prefetch; }
+ inline int getBatches(){ return batches; }
+ inline int getDelay(){ return delay; }
+ inline int getSize(){ return size; }
+ inline bool getTrace() const { return trace; }
+ inline bool getHelp() const { return help; }
+};
+
+int main(int argc, char** argv){
+ Args args;
+ args.parse(argc, argv);
+ if(args.getHelp()){
+ args.usage();
+ }else{
+ try{
+ Connection connection(args.getTrace());
+ connection.open(args.getHost(), args.getPort());
+ Channel channel(args.getTransactional(), args.getPrefetch());
+ connection.openChannel(&channel);
+
+ //declare queue (relying on default binding):
+ Queue response("response");
+ channel.declareQueue(response);
+
+ //set up listener
+ Publisher publisher(&channel, "topic_control", args.getTransactional());
+ std::string tag("mytag");
+ channel.consume(response, tag, &publisher, args.getAckMode());
+ channel.start();
+
+ int batchSize(args.getBatches());
+ apr_time_t max(0);
+ apr_time_t min(0);
+ apr_time_t sum(0);
+ for(int i = 0; i < batchSize; i++){
+ if(i > 0 && args.getDelay()) sleep(args.getDelay());
+ apr_time_t time = publisher.publish(args.getMessages(), args.getSubscribers(), args.getSize());
+ if(!max || time > max) max = time;
+ if(!min || time < min) min = time;
+ sum += time;
+ std::cout << "Completed " << (i+1) << " of " << batchSize << " in " << time << "ms" << std::endl;
+ }
+ publisher.terminate();
+ apr_time_t avg = sum / batchSize;
+ if(batchSize > 1){
+ std::cout << batchSize << " batches completed. avg=" << avg <<
+ ", max=" << max << ", min=" << min << std::endl;
+ }
+ channel.close();
+ connection.close();
+ }catch(qpid::QpidError error){
+ std::cout << "Error [" << error.code << "] " << error.msg << " (" << error.file << ":" << error.line << ")" << std::endl;
+ }
+ }
+}
+
+Publisher::Publisher(Channel* _channel, const std::string& _controlTopic, bool tx) :
+ channel(_channel), controlTopic(_controlTopic), transactional(tx){}
+
+void Publisher::received(Message& msg){
+ //count responses and when all are received end the current batch
+ monitor.acquire();
+ if(--count == 0){
+ monitor.notify();
+ }
+ std::cout << "Received report: " << msg.getData() << " (" << count << " remaining)." << std::endl;
+ monitor.release();
+}
+
+void Publisher::waitForCompletion(int msgs){
+ count = msgs;
+ monitor.wait();
+}
+
+apr_time_t Publisher::publish(int msgs, int listeners, int size){
+ monitor.acquire();
+ Message msg;
+ msg.setData(generateData(size));
+ apr_time_t start(apr_time_as_msec(apr_time_now()));
+ for(int i = 0; i < msgs; i++){
+ channel->publish(msg, Exchange::DEFAULT_TOPIC_EXCHANGE, controlTopic);
+ }
+ //send report request
+ Message reportRequest;
+ reportRequest.getHeaders().setString("TYPE", "REPORT_REQUEST");
+ channel->publish(reportRequest, Exchange::DEFAULT_TOPIC_EXCHANGE, controlTopic);
+ if(transactional){
+ channel->commit();
+ }
+
+ waitForCompletion(listeners);
+ monitor.release();
+ apr_time_t finish(apr_time_as_msec(apr_time_now()));
+
+ return finish - start;
+}
+
+string Publisher::generateData(int size){
+ string data;
+ for(int i = 0; i < size; i++){
+ data += ('A' + (i / 26));
+ }
+ return data;
+}
+
+void Publisher::terminate(){
+ //send termination request
+ Message terminationRequest;
+ terminationRequest.getHeaders().setString("TYPE", "TERMINATION_REQUEST");
+ channel->publish(terminationRequest, Exchange::DEFAULT_TOPIC_EXCHANGE, controlTopic);
+ if(transactional){
+ channel->commit();
+ }
+}
+
+void Args::parse(int argc, char** argv){
+ for(int i = 1; i < argc; i++){
+ string name(argv[i]);
+ if("-help" == name){
+ help = true;
+ break;
+ }else if("-host" == name){
+ host = argv[++i];
+ }else if("-port" == name){
+ port = atoi(argv[++i]);
+ }else if("-messages" == name){
+ messages = atoi(argv[++i]);
+ }else if("-subscribers" == name){
+ subscribers = atoi(argv[++i]);
+ }else if("-ack_mode" == name){
+ ackMode = atoi(argv[++i]);
+ }else if("-transactional" == name){
+ transactional = true;
+ }else if("-prefetch" == name){
+ prefetch = atoi(argv[++i]);
+ }else if("-batches" == name){
+ batches = atoi(argv[++i]);
+ }else if("-delay" == name){
+ delay = atoi(argv[++i]);
+ }else if("-size" == name){
+ size = atoi(argv[++i]);
+ }else if("-trace" == name){
+ trace = true;
+ }else{
+ std::cout << "Warning: unrecognised option " << name << std::endl;
+ }
+ }
+}
+
+void Args::usage(){
+ std::cout << "Options:" << std::endl;
+ std::cout << " -help" << std::endl;
+ std::cout << " Prints this usage message" << std::endl;
+ std::cout << " -host <host>" << std::endl;
+ std::cout << " Specifies host to connect to (default is localhost)" << std::endl;
+ std::cout << " -port <port>" << std::endl;
+ std::cout << " Specifies port to conect to (default is 5762)" << std::endl;
+ std::cout << " -messages <count>" << std::endl;
+ std::cout << " Specifies how many messages to send" << std::endl;
+ std::cout << " -subscribers <count>" << std::endl;
+ std::cout << " Specifies how many subscribers to expect reports from" << std::endl;
+ std::cout << " -ack_mode <mode>" << std::endl;
+ std::cout << " Sets the acknowledgement mode" << std::endl;
+ std::cout << " 0=NO_ACK (default), 1=AUTO_ACK, 2=LAZY_ACK" << std::endl;
+ std::cout << " -transactional" << std::endl;
+ std::cout << " Indicates the client should use transactions" << std::endl;
+ std::cout << " -prefetch <count>" << std::endl;
+ std::cout << " Specifies the prefetch count (default is 1000)" << std::endl;
+ std::cout << " -batches <count>" << std::endl;
+ std::cout << " Specifies how many batches to run" << std::endl;
+ std::cout << " -delay <seconds>" << std::endl;
+ std::cout << " Causes a delay between each batch" << std::endl;
+ std::cout << " -size <bytes>" << std::endl;
+ std::cout << " Sets the size of the published messages (default is 256 bytes)" << std::endl;
+ std::cout << " -trace" << std::endl;
+ std::cout << " Indicates that the frames sent and received should be logged" << std::endl;
+}
diff --git a/cpp/common/Makefile b/cpp/common/Makefile
new file mode 100644
index 0000000000..5fe815b8da
--- /dev/null
+++ b/cpp/common/Makefile
@@ -0,0 +1,51 @@
+#
+# 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.
+#
+
+#
+# Make file to build qpid_common library.
+#
+
+QPID_HOME=../..
+include $(QPID_HOME)/cpp/options.mk
+
+TARGET = $(LIB_DIR)/libqpid_common.so.1.0
+
+CXXFLAGS = $(DEBUG) $(OPT) -MMD -fpic $(COMMON_INCLUDES)
+
+SOURCES = $(wildcard */src/*.cpp framing/generated/*.cpp)
+OBJECTS = $(SOURCES:.cpp=.o)
+DEPS = $(SOURCES:.cpp=.d)
+
+GENERATED_OBJECTS = framing/generated/amqp_methods.o
+
+.PHONY: all test clean
+
+# We have to do two separate makes to ensure we pick up all generated files.
+all:
+ @$(MAKE) -C framing all
+ @make $(TARGET)
+
+test:
+ @$(MAKE) -C framing test
+
+clean:
+ @$(MAKE) -C framing clean
+ -@rm -f $(TARGET) $(OBJECTS) $(DEPS)
+
+$(TARGET): $(OBJECTS)
+ $(CXX) -shared -o $@ $(OBJECTS) $(LDFLAGS) -lapr-1
+
+-include $(DEPS)
diff --git a/cpp/common/concurrent/inc/APRBase.h b/cpp/common/concurrent/inc/APRBase.h
new file mode 100644
index 0000000000..e0b526faa1
--- /dev/null
+++ b/cpp/common/concurrent/inc/APRBase.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _APRBase_
+#define _APRBase_
+
+#include <string>
+#include "apr_thread_mutex.h"
+#include "apr_errno.h"
+
+namespace qpid {
+namespace concurrent {
+
+ /**
+ * 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 std::string& file, const int line);
+ std::string get_desc(apr_status_t status);
+
+#define CHECK_APR_SUCCESS(A) check(A, __FILE__, __LINE__);
+
+}
+}
+
+
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/APRMonitor.h b/cpp/common/concurrent/inc/APRMonitor.h
new file mode 100644
index 0000000000..bf72596564
--- /dev/null
+++ b/cpp/common/concurrent/inc/APRMonitor.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _APRMonitor_
+#define _APRMonitor_
+
+#include "apr_thread_mutex.h"
+#include "apr_thread_cond.h"
+#include "Monitor.h"
+
+namespace qpid {
+namespace concurrent {
+
+ class APRMonitor : public virtual Monitor
+ {
+ apr_pool_t* pool;
+ apr_thread_mutex_t* mutex;
+ apr_thread_cond_t* condition;
+
+ public:
+ APRMonitor();
+ virtual ~APRMonitor();
+ virtual void wait();
+ virtual void wait(u_int64_t time);
+ virtual void notify();
+ virtual void notifyAll();
+ virtual void acquire();
+ virtual void release();
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/APRThread.h b/cpp/common/concurrent/inc/APRThread.h
new file mode 100644
index 0000000000..d5034ce3b7
--- /dev/null
+++ b/cpp/common/concurrent/inc/APRThread.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _APRThread_
+#define _APRThread_
+
+#include "apr_thread_proc.h"
+#include "APRThread.h"
+#include "Runnable.h"
+#include "Thread.h"
+
+namespace qpid {
+namespace concurrent {
+
+ class APRThread : public virtual Thread
+ {
+ const Runnable* runnable;
+ apr_pool_t* pool;
+ apr_thread_t* runner;
+
+ public:
+ APRThread(apr_pool_t* pool, Runnable* runnable);
+ virtual ~APRThread();
+ virtual void start();
+ virtual void join();
+ virtual void interrupt();
+ static unsigned int currentThread();
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/APRThreadFactory.h b/cpp/common/concurrent/inc/APRThreadFactory.h
new file mode 100644
index 0000000000..87b240025d
--- /dev/null
+++ b/cpp/common/concurrent/inc/APRThreadFactory.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _APRThreadFactory_
+#define _APRThreadFactory_
+
+#include "apr_thread_proc.h"
+
+#include "APRThread.h"
+#include "Thread.h"
+#include "ThreadFactory.h"
+#include "Runnable.h"
+
+namespace qpid {
+namespace concurrent {
+
+ class APRThreadFactory : public virtual ThreadFactory
+ {
+ apr_pool_t* pool;
+ public:
+ APRThreadFactory();
+ virtual ~APRThreadFactory();
+ virtual Thread* create(Runnable* runnable);
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/APRThreadPool.h b/cpp/common/concurrent/inc/APRThreadPool.h
new file mode 100644
index 0000000000..cf6d30774c
--- /dev/null
+++ b/cpp/common/concurrent/inc/APRThreadPool.h
@@ -0,0 +1,67 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _APRThreadPool_
+#define _APRThreadPool_
+
+#include <queue>
+#include <vector>
+#include "APRMonitor.h"
+#include "Thread.h"
+#include "ThreadFactory.h"
+#include "ThreadPool.h"
+#include "Runnable.h"
+
+namespace qpid {
+namespace concurrent {
+
+ class APRThreadPool : public virtual ThreadPool
+ {
+ class Worker : public virtual Runnable{
+ APRThreadPool* pool;
+ public:
+ inline Worker(APRThreadPool* _pool) : pool(_pool){}
+ inline virtual void run(){
+ while(pool->running){
+ pool->runTask();
+ }
+ }
+ };
+ const bool deleteFactory;
+ const int size;
+ ThreadFactory* factory;
+ APRMonitor lock;
+ std::vector<Thread*> threads;
+ std::queue<Runnable*> tasks;
+ Worker* worker;
+ volatile bool running;
+
+ void runTask();
+ public:
+ APRThreadPool(int size);
+ APRThreadPool(int size, ThreadFactory* factory);
+ virtual void start();
+ virtual void stop();
+ virtual void addTask(Runnable* task);
+ virtual ~APRThreadPool();
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/LMonitor.h b/cpp/common/concurrent/inc/LMonitor.h
new file mode 100644
index 0000000000..8e2569921d
--- /dev/null
+++ b/cpp/common/concurrent/inc/LMonitor.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _LMonitor_
+#define _LMonitor_
+
+/* Native Linux Monitor - Based of Kernel patch 19/20 */
+
+#include "Monitor.h"
+
+namespace qpid {
+namespace concurrent {
+
+ class LMonitor : public virtual Monitor
+ {
+
+ public:
+ LMonitor();
+ virtual ~LMonitor();
+ virtual void wait();
+ virtual void notify();
+ virtual void notifyAll();
+ virtual void acquire();
+ virtual void release();
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/LThreadFactory.h b/cpp/common/concurrent/inc/LThreadFactory.h
new file mode 100644
index 0000000000..4a573d1bd1
--- /dev/null
+++ b/cpp/common/concurrent/inc/LThreadFactory.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _LAPRThreadFactory_
+#define _LAPRThreadFactory_
+
+
+namespace qpid {
+namespace concurrent {
+
+ class LThreadFactory
+ {
+ public:
+ LThreadFactory();
+ virtual ~LThreadFactory();
+ virtual Thread* create(Runnable* runnable);
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/LockedQueue.h b/cpp/common/concurrent/inc/LockedQueue.h
new file mode 100644
index 0000000000..ef3f0b8381
--- /dev/null
+++ b/cpp/common/concurrent/inc/LockedQueue.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _LockedQueue_
+#define _LockedQueue_
+
+#include <queue>
+#include "Monitor.h"
+
+/**
+ * A threadsafe queue abstraction
+ */
+namespace qpid {
+namespace concurrent {
+ template<class T, class L> class LockedQueue
+ {
+ L lock;
+ std::queue<T*> queue;
+
+ public:
+ void put(T* item);
+ T* take();
+ bool empty();
+ };
+
+ template<class T, class L> void LockedQueue<T, L>::put(T* item){
+ lock.acquire();
+ queue.push(item);
+ lock.release();
+ }
+
+ template<class T, class L> T* LockedQueue<T, L>::take(){
+ lock.acquire();
+ T* item = 0;
+ if(!queue.empty()){
+ item = queue.front();
+ queue.pop();
+ }
+ lock.release();
+ return item;
+ }
+
+ template<class T, class L> bool LockedQueue<T, L>::empty(){
+ lock.acquire();
+ bool result = queue.empty();
+ lock.release();
+ return result;
+ }
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/Monitor.h b/cpp/common/concurrent/inc/Monitor.h
new file mode 100644
index 0000000000..7f1a299c6a
--- /dev/null
+++ b/cpp/common/concurrent/inc/Monitor.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Monitor_
+#define _Monitor_
+
+#include "amqp_types.h"
+
+namespace qpid {
+namespace concurrent {
+
+class Monitor
+{
+ public:
+ virtual ~Monitor(){}
+ virtual void wait() = 0;
+ virtual void wait(u_int64_t time) = 0;
+ virtual void notify() = 0;
+ virtual void notifyAll() = 0;
+ virtual void acquire() = 0;
+ virtual void release() = 0;
+};
+
+/**
+ * Scoped locker for a monitor.
+ */
+class Locker
+{
+ public:
+ Locker(Monitor& lock_) : lock(lock_) { lock.acquire(); }
+ ~Locker() { lock.release(); }
+
+ private:
+ Monitor& lock;
+
+ // private and unimplemented to prevent copying
+ Locker(const Locker&);
+ void operator=(const Locker&);
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/MonitorImpl.h b/cpp/common/concurrent/inc/MonitorImpl.h
new file mode 100644
index 0000000000..e96e81d795
--- /dev/null
+++ b/cpp/common/concurrent/inc/MonitorImpl.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+#ifndef _MonitorImpl_
+#define _MonitorImpl_
+
+#ifdef _USE_APR_IO_
+#include "APRMonitor.h"
+#else /* use POSIX Monitor */
+#include "LMonitor.h"
+#endif
+
+
+namespace qpid {
+namespace concurrent {
+
+#ifdef _USE_APR_IO_
+ class MonitorImpl : public virtual APRMonitor
+ {
+
+ public:
+ MonitorImpl() : APRMonitor(){};
+ virtual ~MonitorImpl(){};
+
+ };
+#else
+ class MonitorImpl : public virtual LMonitor
+ {
+
+ public:
+ MonitorImpl() : LMonitor(){};
+ virtual ~MonitorImpl(){};
+
+ };
+#endif
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/Runnable.h b/cpp/common/concurrent/inc/Runnable.h
new file mode 100644
index 0000000000..523ad813f7
--- /dev/null
+++ b/cpp/common/concurrent/inc/Runnable.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Runnable_
+#define _Runnable_
+
+namespace qpid {
+namespace concurrent {
+
+ class Runnable
+ {
+ public:
+ virtual void run() = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/TaskQueue.h b/cpp/common/concurrent/inc/TaskQueue.h
new file mode 100644
index 0000000000..e06a3ce069
--- /dev/null
+++ b/cpp/common/concurrent/inc/TaskQueue.h
@@ -0,0 +1,200 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _TaskQueue_
+#define _TaskQueue_
+
+#include <iostream>
+#include <memory>
+#include <queue>
+#include "LockedQueue.h"
+#include "Runnable.h"
+#include "ThreadPool.h"
+
+namespace qpid {
+namespace concurrent {
+ template<class T, class L> class TaskQueue : public virtual Runnable
+ {
+ const int max_iterations_per_run;
+ L lock;
+ //LockedQueue<T, L> queue;
+ std::queue<T*> queue;
+ ThreadPool* const pool;
+ T* work;
+ bool running;
+ volatile bool stopped;
+ TaskQueue<T, L>* next;
+
+ volatile bool inrun;
+
+ bool hasWork();
+ void completed();
+
+ T* take();
+
+ protected:
+ /**
+ * Callback though which the task is executed
+ */
+ virtual void execute(T* t) = 0;
+ /**
+ * Allows a task to be completed asynchronously to the
+ * execute() call if required.
+ */
+ virtual bool isComplete(T* t);
+ /**
+ * Should be called to signal completion of a task that was
+ * signalled as not complete through the isComplete() methods
+ * return value. This will allow normal processing to resume.
+ */
+ virtual void complete();
+
+ public:
+ TaskQueue(ThreadPool* const pool, int max_iterations_per_run = 100);
+ virtual void run();
+ void trigger();
+ bool append(T* t);
+ void stop(bool drain);
+ inline void setNext(TaskQueue<T, L>* next){ this->next = next; }
+ };
+
+ template<class T, class L> TaskQueue<T, L>::TaskQueue(ThreadPool* const _pool, int _max_iterations_per_run) :
+ pool(_pool),
+ max_iterations_per_run(_max_iterations_per_run),
+ work(0),
+ running(false),
+ stopped(false),
+ next(0), inrun(false){
+ }
+
+ template<class T, class L> void TaskQueue<T, L>::run(){
+ if(inrun) std::cout << "Already running" << std::endl;
+ inrun = true;
+
+ bool blocked = false;
+ int count = max_iterations_per_run;
+ while(!blocked && hasWork() && count){
+ execute(work);
+ if(isComplete(work)){
+ completed();
+ }else{
+ blocked = true;
+ }
+ count--;
+ }
+ inrun = false;
+
+ if(!blocked && count == 0){//performed max_iterations_per_run, requeue task to ensure fairness
+ //running will still be true at this point
+ lock.acquire();
+ running = false;
+ if(stopped) lock.notify();
+ lock.release();
+
+ trigger();
+ }else if(hasWork()){//task was added to queue after we exited the loop above; should not need this?
+ trigger();
+ }
+ }
+
+ template<class T, class L> void TaskQueue<T, L>::trigger(){
+ lock.acquire();
+ if(!running){
+ running = true;
+ pool->addTask(this);
+ }
+ lock.release();
+ }
+
+ template<class T, class L> bool TaskQueue<T, L>::hasWork(){
+ lock.acquire();
+ if(!work) work = take();//queue.take();
+ if(!work){
+ running = false;
+ if(stopped) lock.notify();
+ }
+ lock.release();
+ return work;
+ }
+
+ template<class T, class L> bool TaskQueue<T, L>::append(T* item){
+ if(!stopped){
+ lock.acquire();
+
+ //queue.put(item);
+ queue.push(item);
+
+ if(!running){
+ running = true;
+ pool->addTask(this);
+ }
+ lock.release();
+ //}
+ return true;
+ }else{
+ return false;
+ }
+ }
+
+ template<class T, class L> bool TaskQueue<T, L>::isComplete(T* item){
+ return true;//by default assume all tasks are synchronous w.r.t. execute()
+ }
+
+
+ template<class T, class L> void TaskQueue<T, L>::completed(){
+ if(next){
+ if(!next->append(work)){
+ std::cout << "Warning: dropping task as next queue appears to have stopped." << std::endl;
+ }
+ }else{
+ delete work;
+ }
+ work = 0;
+ }
+
+ template<class T, class L> void TaskQueue<T, L>::complete(){
+ completed();
+ lock.acquire();
+ running = false;
+ if(stopped) lock.notify();
+ lock.release();
+ }
+
+ template<class T, class L> void TaskQueue<T, L>::stop(bool drain){
+ //prevent new tasks from being added
+ stopped = true;
+ //wait until no longer running
+ lock.acquire();
+ while(running && (drain && hasWork())){
+ lock.wait();
+ }
+ lock.release();
+ }
+
+ template<class T, class L> T* TaskQueue<T, L>::take(){
+ T* item = 0;
+ if(!queue.empty()){
+ item = queue.front();
+ queue.pop();
+ }
+ return item;
+ }
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/Thread.h b/cpp/common/concurrent/inc/Thread.h
new file mode 100644
index 0000000000..6bd2a379ce
--- /dev/null
+++ b/cpp/common/concurrent/inc/Thread.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Thread_
+#define _Thread_
+
+namespace qpid {
+namespace concurrent {
+
+ class Thread
+ {
+ public:
+ virtual ~Thread(){}
+ virtual void start() = 0;
+ virtual void join() = 0;
+ virtual void interrupt() = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/ThreadFactory.h b/cpp/common/concurrent/inc/ThreadFactory.h
new file mode 100644
index 0000000000..53be000ff3
--- /dev/null
+++ b/cpp/common/concurrent/inc/ThreadFactory.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ThreadFactory_
+#define _ThreadFactory_
+
+#include "Thread.h"
+#include "Runnable.h"
+
+namespace qpid {
+namespace concurrent {
+
+ class ThreadFactory
+ {
+ public:
+ virtual ~ThreadFactory(){}
+ virtual Thread* create(Runnable* runnable) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/ThreadFactoryImpl.h b/cpp/common/concurrent/inc/ThreadFactoryImpl.h
new file mode 100644
index 0000000000..a534b3c1e2
--- /dev/null
+++ b/cpp/common/concurrent/inc/ThreadFactoryImpl.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ThreadFactoryImpl_
+#define _ThreadFactoryImpl_
+
+
+#ifdef _USE_APR_IO_
+#include "APRThreadFactory.h"
+#else
+#include "LThreadFactory.h"
+#endif
+
+
+namespace qpid {
+namespace concurrent {
+
+
+#ifdef _USE_APR_IO_
+ class ThreadFactoryImpl : public virtual APRThreadFactory
+ {
+ public:
+ ThreadFactoryImpl(): APRThreadFactory() {};
+ virtual ~ThreadFactoryImpl() {};
+ };
+#else
+ class ThreadFactoryImpl : public virtual LThreadFactory
+ {
+ public:
+ ThreadFactoryImpl(): LThreadFactory() {};
+ virtual ~ThreadFactoryImpl() {};
+ };
+#endif
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/inc/ThreadPool.h b/cpp/common/concurrent/inc/ThreadPool.h
new file mode 100644
index 0000000000..679c889ff3
--- /dev/null
+++ b/cpp/common/concurrent/inc/ThreadPool.h
@@ -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.
+ *
+ */
+#ifndef _ThreadPool_
+#define _ThreadPool_
+
+#include "Thread.h"
+#include "Runnable.h"
+
+namespace qpid {
+namespace concurrent {
+
+ class ThreadPool
+ {
+ public:
+ virtual void start() = 0;
+ virtual void stop() = 0;
+ virtual void addTask(Runnable* runnable) = 0;
+ virtual ~ThreadPool(){}
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/concurrent/src/APRBase.cpp b/cpp/common/concurrent/src/APRBase.cpp
new file mode 100644
index 0000000000..f87ea9e25f
--- /dev/null
+++ b/cpp/common/concurrent/src/APRBase.cpp
@@ -0,0 +1,97 @@
+/*
+ *
+ * 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 "APRBase.h"
+#include "QpidError.h"
+
+using namespace qpid::concurrent;
+
+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();
+}
+
+void qpid::concurrent::check(apr_status_t status, const std::string& file, const int line){
+ if (status != APR_SUCCESS){
+ const int size = 50;
+ char tmp[size];
+ std::string msg(apr_strerror(status, tmp, size));
+ throw QpidError(APR_ERROR + ((int) status), msg, file, line);
+ }
+}
+
+std::string qpid::concurrent::get_desc(apr_status_t status){
+ const int size = 50;
+ char tmp[size];
+ std::string msg(apr_strerror(status, tmp, size));
+ return msg;
+}
+
diff --git a/cpp/common/concurrent/src/APRMonitor.cpp b/cpp/common/concurrent/src/APRMonitor.cpp
new file mode 100644
index 0000000000..428d76dff9
--- /dev/null
+++ b/cpp/common/concurrent/src/APRMonitor.cpp
@@ -0,0 +1,60 @@
+/*
+ *
+ * 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 "APRBase.h"
+#include "APRMonitor.h"
+#include <iostream>
+
+qpid::concurrent::APRMonitor::APRMonitor(){
+ APRBase::increment();
+ CHECK_APR_SUCCESS(apr_pool_create(&pool, NULL));
+ CHECK_APR_SUCCESS(apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, pool));
+ CHECK_APR_SUCCESS(apr_thread_cond_create(&condition, pool));
+}
+
+qpid::concurrent::APRMonitor::~APRMonitor(){
+ CHECK_APR_SUCCESS(apr_thread_cond_destroy(condition));
+ CHECK_APR_SUCCESS(apr_thread_mutex_destroy(mutex));
+ apr_pool_destroy(pool);
+ APRBase::decrement();
+}
+
+void qpid::concurrent::APRMonitor::wait(){
+ CHECK_APR_SUCCESS(apr_thread_cond_wait(condition, mutex));
+}
+
+
+void qpid::concurrent::APRMonitor::wait(u_int64_t time){
+ apr_status_t status = apr_thread_cond_timedwait(condition, mutex, time * 1000);
+ if(!status == APR_TIMEUP) CHECK_APR_SUCCESS(status);
+}
+
+void qpid::concurrent::APRMonitor::notify(){
+ CHECK_APR_SUCCESS(apr_thread_cond_signal(condition));
+}
+
+void qpid::concurrent::APRMonitor::notifyAll(){
+ CHECK_APR_SUCCESS(apr_thread_cond_broadcast(condition));
+}
+
+void qpid::concurrent::APRMonitor::acquire(){
+ CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
+}
+
+void qpid::concurrent::APRMonitor::release(){
+ CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex));
+}
diff --git a/cpp/common/concurrent/src/APRThread.cpp b/cpp/common/concurrent/src/APRThread.cpp
new file mode 100644
index 0000000000..4202fe81b6
--- /dev/null
+++ b/cpp/common/concurrent/src/APRThread.cpp
@@ -0,0 +1,50 @@
+/*
+ *
+ * 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 "APRBase.h"
+#include "APRThread.h"
+#include "apr_portable.h"
+
+using namespace qpid::concurrent;
+
+void* APR_THREAD_FUNC ExecRunnable(apr_thread_t* thread, void *data){
+ ((Runnable*) data)->run();
+ CHECK_APR_SUCCESS(apr_thread_exit(thread, APR_SUCCESS));
+ return NULL;
+}
+
+APRThread::APRThread(apr_pool_t* _pool, Runnable* _runnable) : pool(_pool), runnable(_runnable){}
+
+APRThread::~APRThread(){
+}
+
+void APRThread::start(){
+ CHECK_APR_SUCCESS(apr_thread_create(&runner, NULL, ExecRunnable,(void*) runnable, pool));
+}
+
+void APRThread::join(){
+ apr_status_t status;
+ CHECK_APR_SUCCESS(apr_thread_join(&status, runner));
+}
+
+void APRThread::interrupt(){
+ CHECK_APR_SUCCESS(apr_thread_exit(runner, APR_SUCCESS));
+}
+
+unsigned int qpid::concurrent::APRThread::currentThread(){
+ return apr_os_thread_current();
+}
diff --git a/cpp/common/concurrent/src/APRThreadFactory.cpp b/cpp/common/concurrent/src/APRThreadFactory.cpp
new file mode 100644
index 0000000000..9ba68e9e56
--- /dev/null
+++ b/cpp/common/concurrent/src/APRThreadFactory.cpp
@@ -0,0 +1,35 @@
+/*
+ *
+ * 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 "APRBase.h"
+#include "APRThreadFactory.h"
+
+using namespace qpid::concurrent;
+
+APRThreadFactory::APRThreadFactory(){
+ APRBase::increment();
+ CHECK_APR_SUCCESS(apr_pool_create(&pool, NULL));
+}
+
+APRThreadFactory::~APRThreadFactory(){
+ apr_pool_destroy(pool);
+ APRBase::decrement();
+}
+
+Thread* APRThreadFactory::create(Runnable* runnable){
+ return new APRThread(pool, runnable);
+}
diff --git a/cpp/common/concurrent/src/APRThreadPool.cpp b/cpp/common/concurrent/src/APRThreadPool.cpp
new file mode 100644
index 0000000000..e0fcb804e6
--- /dev/null
+++ b/cpp/common/concurrent/src/APRThreadPool.cpp
@@ -0,0 +1,85 @@
+/*
+ *
+ * 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 "APRThreadFactory.h"
+#include "APRThreadPool.h"
+#include "QpidError.h"
+#include <iostream>
+
+using namespace qpid::concurrent;
+
+APRThreadPool::APRThreadPool(int _size) : size(_size), factory(new APRThreadFactory()),
+ deleteFactory(true), running(false){
+ worker = new Worker(this);
+}
+
+APRThreadPool::APRThreadPool(int _size, ThreadFactory* _factory) : size(_size), factory(_factory),
+ deleteFactory(false), running(false){
+ worker = new Worker(this);
+}
+
+APRThreadPool::~APRThreadPool(){
+ if(deleteFactory) delete factory;
+}
+
+void APRThreadPool::addTask(Runnable* task){
+ lock.acquire();
+ tasks.push(task);
+ lock.notifyAll();
+ lock.release();
+}
+
+void APRThreadPool::runTask(){
+ lock.acquire();
+ while(tasks.empty()){
+ lock.wait();
+ }
+ Runnable* task = tasks.front();
+ tasks.pop();
+ lock.release();
+ try{
+ task->run();
+ }catch(qpid::QpidError error){
+ std::cout << "Error [" << error.code << "] " << error.msg << " (" << error.file << ":" << error.line << ")" << std::endl;
+ }
+}
+
+void APRThreadPool::start(){
+ if(!running){
+ running = true;
+ for(int i = 0; i < size; i++){
+ Thread* t = factory->create(worker);
+ t->start();
+ threads.push_back(t);
+ }
+ }
+}
+
+void APRThreadPool::stop(){
+ if(!running){
+ running = false;
+ lock.acquire();
+ lock.notifyAll();
+ lock.release();
+ for(int i = 0; i < size; i++){
+ threads[i]->join();
+ delete threads[i];
+ }
+ }
+}
+
+
diff --git a/cpp/common/error/inc/QpidError.h b/cpp/common/error/inc/QpidError.h
new file mode 100644
index 0000000000..a739b506c7
--- /dev/null
+++ b/cpp/common/error/inc/QpidError.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * 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>
+
+#ifndef __QpidError__
+#define __QpidError__
+
+namespace qpid {
+
+class QpidError{
+public:
+ const int code;
+ const std::string msg;
+ const std::string file;
+ const int line;
+
+ inline QpidError(int _code, const std::string& _msg, const std::string& _file, int _line) : code(_code), msg(_msg), file(_file), line(_line) {}
+ ~QpidError(){}
+
+};
+
+#define THROW_QPID_ERROR(A, B) throw QpidError(A, B, __FILE__, __LINE__)
+
+}
+
+#define PROTOCOL_ERROR 10000
+#define APR_ERROR 20000
+#define FRAMING_ERROR 30000
+#define CLIENT_ERROR 40000
+#define INTERNAL_ERROR 50000
+
+#endif
diff --git a/cpp/common/error/inc/QpidErrorIO.h b/cpp/common/error/inc/QpidErrorIO.h
new file mode 100644
index 0000000000..4f9bd3ce26
--- /dev/null
+++ b/cpp/common/error/inc/QpidErrorIO.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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 <ostream>
+
+std::ostream& operator <<(std::ostream& out, const QpidError& error)
+{
+ out << "Qpid Error [" << error.code << "] " << error.msg
+ << " (" << error.file << ":" << error.line << ")";
+ return out;
+}
+
+
diff --git a/cpp/common/framing/Makefile b/cpp/common/framing/Makefile
new file mode 100644
index 0000000000..1dfc286050
--- /dev/null
+++ b/cpp/common/framing/Makefile
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+.PHONY: all clean test
+
+all:
+ @$(MAKE) -C generated all
+
+test:
+ @$(MAKE) -C test all
+
+clean :
+ @$(MAKE) -C generated clean
+ @$(MAKE) -C test clean
+
diff --git a/cpp/common/framing/generated/Makefile b/cpp/common/framing/generated/Makefile
new file mode 100644
index 0000000000..12ec402760
--- /dev/null
+++ b/cpp/common/framing/generated/Makefile
@@ -0,0 +1,41 @@
+#
+# 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.
+#
+
+QPID_HOME = ../../../..
+include ${QPID_HOME}/cpp/options.mk
+
+STYLESHEET_DIR = stylesheets
+JAVA = java
+XSLTP = ${TOOLS_DIR}/saxon8.jar
+
+SPEC = ${SPEC_DIR}/amqp-8.0.xml
+STYLESHEETS = $(wildcard stylesheets/*.xsl)
+
+GENERATED_SOURCES=amqp_methods.cpp # Seed generation
+
+.PHONY: all clean
+
+all: ${GENERATED_SOURCES}
+
+clean :
+ -@rm -f *.cpp *.h
+
+${GENERATED_SOURCES}: ${STYLESHEETS} ${SPEC}
+ ${JAVA} -jar ${XSLTP} -o results.out ${SPEC} ${STYLESHEET_DIR}/code_gen.xsl
+ ${JAVA} -jar ${XSLTP} -o results.out ${SPEC} ${STYLESHEET_DIR}/framing.xsl
+
+-include $(GENERATED_SOURCES:.cpp=.d)
+
diff --git a/cpp/common/framing/generated/stylesheets/amqp_client.xsl b/cpp/common/framing/generated/stylesheets/amqp_client.xsl
new file mode 100644
index 0000000000..f0fa3d7890
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/amqp_client.xsl
@@ -0,0 +1,155 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+ <xsl:import href="code_utils.xsl"/>
+
+ <!--
+ ==================
+ Template: client_h
+ ==================
+ Client header file.
+ -->
+ <xsl:template match="amqp" mode="client_h">
+ <xsl:param name="domain-cpp-table"/>
+ <xsl:result-document href="AMQP_Client.h" format="textFormat">
+ <xsl:value-of select="amqp:copyright()"/>
+ <xsl:text>
+#ifndef _AMQP_Client_
+#define _AMQP_Client_
+
+#include "AMQP_ServerOperations.h"
+#include "FieldTable.h"
+#include "OutputHandler.h"
+
+namespace qpid {
+namespace framing {
+
+class AMQP_Client : virtual public AMQP_ServerOperations
+{
+ OutputHandler* out;
+
+ public:
+ AMQP_Client(OutputHandler* _out);
+ virtual ~AMQP_Client() {}&#xA;&#xA;</xsl:text>
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="amqp:cpp-class-name(@name)"/>
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/**&#xA;===== Class: </xsl:text><xsl:value-of select="$class"/><xsl:text> =====&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>&#xA;*/&#xA;</xsl:text>
+ </xsl:if>
+ <xsl:text> class </xsl:text><xsl:value-of select="$class"/><xsl:text> : virtual public AMQP_ServerOperations::</xsl:text><xsl:value-of select="$class"/><xsl:text>Handler
+ {
+ OutputHandler* out;
+
+ public:
+ /* Constructors and destructors */
+ </xsl:text><xsl:value-of select="$class"/><xsl:text>(OutputHandler* _out);
+ virtual ~</xsl:text><xsl:value-of select="$class"/><xsl:text>();
+
+ /* Protocol methods */&#xA;</xsl:text>
+ <xsl:for-each select="method">
+ <xsl:if test="chassis[@name='server']">
+ <xsl:variable name="method" select="amqp:cpp-name(@name)"/>
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/**&#xA;----- Method: </xsl:text><xsl:value-of select="$class"/><xsl:text>.</xsl:text><xsl:value-of select="$method"/><xsl:text> -----&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>&#xA;*/&#xA;</xsl:text>
+ </xsl:if>
+ <xsl:for-each select="rule">
+ <xsl:text>&#xA;/**&#xA;</xsl:text>
+ <xsl:text>Rule "</xsl:text><xsl:value-of select="@name"/><xsl:text>":&#xA;</xsl:text><xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>&#xA;*/&#xA;</xsl:text>
+ </xsl:for-each>
+ <xsl:text> virtual void </xsl:text><xsl:value-of select="$method"/>
+ <xsl:text>( u_int16_t channel</xsl:text><xsl:if test="field"><xsl:text>,&#xA; </xsl:text>
+ <xsl:for-each select="field">
+ <xsl:variable name="domain-cpp-type" select="amqp:cpp-lookup(@domain, $domain-cpp-table)"/>
+ <xsl:value-of select="concat($domain-cpp-type, amqp:cpp-arg-ref($domain-cpp-type), ' ', amqp:cpp-name(@name))"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:text> );&#xA;</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text> }; /* class </xsl:text><xsl:value-of select="$class"/><xsl:text> */&#xA;</xsl:text>
+ </xsl:for-each>
+ <xsl:text>}; /* class AMQP_Client */
+
+} /* namespace framing */
+} /* namespace qpid */
+
+#endif&#xA;</xsl:text>
+ </xsl:result-document>
+ </xsl:template>
+
+
+ <!--
+ ====================
+ Template: client_cpp
+ ====================
+ Client body.
+ -->
+ <xsl:template match="amqp" mode="client_cpp">
+ <xsl:param name="domain-cpp-table"/>
+ <xsl:result-document href="AMQP_Client.cpp" format="textFormat">
+ <xsl:value-of select="amqp:copyright()"/>
+ <xsl:text>
+
+#include "AMQP_Client.h"
+
+namespace qpid {
+namespace framing {
+
+AMQP_Client::AMQP_Client(OutputHandler* _out) :
+ out(_out)
+{
+}&#xA;&#xA;</xsl:text>
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="amqp:cpp-class-name(@name)"/>
+ <xsl:text>&#xA;/* ++++++++++ Class: </xsl:text><xsl:value-of select="$class"/><xsl:text> ++++++++++ */
+
+AMQP_Client::</xsl:text><xsl:value-of select="$class"/><xsl:text>::</xsl:text><xsl:value-of select="$class"/><xsl:text>(OutputHandler* _out) :
+ out(_out)
+{
+}
+
+AMQP_Client::</xsl:text><xsl:value-of select="$class"/><xsl:text>::~</xsl:text><xsl:value-of select="$class"/><xsl:text>() {}&#xA;&#xA;</xsl:text>
+ <xsl:for-each select="method">
+ <xsl:if test="chassis[@name='server']">
+ <xsl:text>void AMQP_Client::</xsl:text><xsl:value-of select="$class"/><xsl:text>::</xsl:text>
+ <xsl:value-of select="amqp:cpp-name(@name)"/><xsl:text>( u_int16_t channel</xsl:text><xsl:if test="field">
+ <xsl:text>,&#xA; </xsl:text>
+ <xsl:for-each select="field">
+ <xsl:variable name="domain-cpp-type" select="amqp:cpp-lookup(@domain, $domain-cpp-table)"/>
+ <xsl:value-of select="concat($domain-cpp-type, amqp:cpp-arg-ref($domain-cpp-type), ' ', amqp:cpp-name(@name))"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:text> )
+{
+ out->send( new AMQFrame( channel,
+ new </xsl:text><xsl:value-of select="concat($class, amqp:field-name(@name), 'Body')"/><xsl:text>( </xsl:text>
+ <xsl:for-each select="field">
+ <xsl:value-of select="amqp:cpp-name(@name)"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text> ) ) );
+}&#xA;&#xA;</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:for-each>
+ <xsl:text>
+
+} /* namespace framing */
+} /* namespace qpid */&#xA;</xsl:text>
+ </xsl:result-document>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/amqp_client_handler_impl.xsl b/cpp/common/framing/generated/stylesheets/amqp_client_handler_impl.xsl
new file mode 100644
index 0000000000..aa095eaf79
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/amqp_client_handler_impl.xsl
@@ -0,0 +1,187 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+ <xsl:import href="code_utils.xsl"/>
+
+ <!--
+ ===============================
+ Template: client_handler_impl_h
+ ===============================
+ Template to generate the AMQP_ServerHandlerImpl class header file.
+ -->
+ <xsl:template match="amqp" mode="client_handler_impl_h">
+ <xsl:param name="domain-cpp-table"/>
+ <xsl:result-document href="AMQP_ClientHandlerImpl.h" format="textFormat">
+ <xsl:value-of select="amqp:copyright()"/>
+ <xsl:text>
+#ifndef _AMQP_ClientHandlerImpl_
+#define _AMQP_ClientHandlerImpl_
+
+#include "AMQP_ClientOperations.h"
+#include "FieldTable.h"
+
+namespace qpid {
+namespace framing {
+
+class AMQP_ClientHandlerImpl : virtual public AMQP_ClientOperations
+{&#xA;</xsl:text>
+
+ <!-- List of pointers to each inner class instance -->
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="concat(amqp:cpp-class-name(@name), 'Handler')"/>
+ <xsl:text> AMQP_ClientOperations::</xsl:text><xsl:value-of select="$class"/><xsl:text>* </xsl:text>
+ <xsl:value-of select="$class"/><xsl:text>Ptr;&#xA;</xsl:text>
+ </xsl:for-each>
+ <xsl:text>
+ public:
+ AMQP_ClientHandlerImpl();
+ virtual ~AMQP_ClientHandlerImpl();&#xA;&#xA;</xsl:text>
+
+ <!-- List of functions to return pointer to each inner class instance -->
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="concat(amqp:cpp-class-name(@name), 'Handler')"/>
+ <xsl:text> inline AMQP_ClientOperations::</xsl:text>
+ <xsl:value-of select="$class"/><xsl:text>* get</xsl:text><xsl:value-of select="$class"/>
+ <xsl:text>() { return </xsl:text><xsl:value-of select="$class"/><xsl:text>Ptr; }&#xA;</xsl:text>
+ </xsl:for-each>
+ <xsl:text>&#xA;</xsl:text>
+
+ <!-- Inner classes -->
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="concat(amqp:cpp-class-name(@name), 'Handler')"/>
+
+ <!-- Inner class documentation & rules -->
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/**&#xA;</xsl:text>
+ <xsl:text>===== Class: </xsl:text><xsl:value-of select="$class"/><xsl:text>Impl =====&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>*/&#xA;</xsl:text>
+ </xsl:if>
+
+ <!-- Inner class definition -->
+ <xsl:text> class </xsl:text><xsl:value-of select="$class"/>
+ <xsl:text>Impl : virtual public AMQP_ClientOperations::</xsl:text><xsl:value-of select="$class"/>
+ <xsl:text>&#xA; {
+ public:
+ /* Constructors and destructors */
+ </xsl:text><xsl:value-of select="$class"/><xsl:text>Impl();
+ virtual ~</xsl:text><xsl:value-of select="$class"/><xsl:text>Impl();
+
+ /* Protocol methods */&#xA;</xsl:text>
+
+ <!-- Inner class methods (only if the chassis is set to "client") -->
+ <xsl:for-each select="method">
+ <xsl:if test="chassis[@name='client']">
+ <xsl:variable name="method" select="amqp:cpp-name(@name)"/>
+
+ <!-- Inner class method documentation & rules -->
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/**&#xA;</xsl:text>
+ <xsl:text>----- Method: </xsl:text><xsl:value-of select="$class"/>
+ <xsl:text>Impl.</xsl:text><xsl:value-of select="@name"/><xsl:text> -----&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>*/&#xA;</xsl:text>
+ </xsl:if>
+ <xsl:for-each select="rule">
+ <xsl:text>&#xA;/**&#xA;</xsl:text>
+ <xsl:text>Rule "</xsl:text><xsl:value-of select="@name"/><xsl:text>":&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>*/&#xA;</xsl:text>
+ </xsl:for-each>
+
+ <!-- Inner class method definition -->
+ <xsl:text>&#xA; virtual void </xsl:text><xsl:value-of select="$method"/>
+ <xsl:text>( u_int16_t channel</xsl:text>
+
+ <!-- Inner class method parameter definition -->
+ <xsl:if test="field">
+ <xsl:text>,&#xA; </xsl:text>
+ <xsl:for-each select="field">
+ <xsl:variable name="domain-cpp-type" select="amqp:cpp-lookup(@domain, $domain-cpp-table)"/>
+ <xsl:value-of select="concat($domain-cpp-type, amqp:cpp-arg-ref($domain-cpp-type), ' ', amqp:cpp-name(@name))"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:text> );&#xA;</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text>&#xA; }; /* class </xsl:text><xsl:value-of select="$class"/><xsl:text>Impl */&#xA;</xsl:text>
+ </xsl:for-each>
+ <xsl:text>&#xA;}; /* AMQP_ClientHandlerImpl */
+
+} /* namespace framing */
+} /* namespace qpid */
+
+#endif&#xA;</xsl:text>
+ </xsl:result-document>
+ </xsl:template>
+
+ <!--
+ =================================
+ Template: client_handler_impl_cpp
+ =================================
+ Template to generate the AMQP_ServerHandlerImpl class stubs.
+ -->
+ <xsl:template match="amqp" mode="client_handler_impl_cpp">
+ <xsl:param name="domain-cpp-table"/>
+ <xsl:result-document href="AMQP_ClientHandlerImpl.cpp" format="textFormat">
+ <xsl:value-of select="amqp:copyright()"/>
+ <xsl:text>
+#include "AMQP_ClientHandlerImpl.h"
+
+namespace qpid {
+namespace framing {
+
+AMQP_ClientHandlerImpl::AMQP_ClientHandlerImpl() :&#xA; </xsl:text>
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="amqp:cpp-class-name(@name)"/>
+ <xsl:value-of select="$class"/>
+ <xsl:text>HandlerPtr( new </xsl:text><xsl:value-of select="$class"/><xsl:text>HandlerImpl() )</xsl:text>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text>
+{
+}
+
+AMQP_ClientHandlerImpl::~AMQP_ClientHandlerImpl()
+{&#xA;</xsl:text>
+ <xsl:for-each select="class">
+ <xsl:text> delete </xsl:text><xsl:value-of select="amqp:cpp-class-name(@name)"/><xsl:text>HandlerPtr;&#xA;</xsl:text>
+ </xsl:for-each>}
+
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="amqp:cpp-class-name(@name)"/>
+ <xsl:text>&#xA;/* ===== Class: </xsl:text><xsl:value-of select="$class"/><xsl:text>HandlerImpl ===== */&#xA;&#xA;</xsl:text>
+ <xsl:text>AMQP_ClientHandlerImpl::</xsl:text><xsl:value-of select="$class"/><xsl:text>HandlerImpl::</xsl:text>
+ <xsl:value-of select="$class"/><xsl:text>HandlerImpl()&#xA;{&#xA;}&#xA;&#xA;</xsl:text>
+ <xsl:text>AMQP_ClientHandlerImpl::</xsl:text><xsl:value-of select="$class"/><xsl:text>HandlerImpl::~</xsl:text>
+ <xsl:value-of select="$class"/><xsl:text>HandlerImpl()&#xA;{&#xA;}&#xA;&#xA;</xsl:text>
+ <xsl:for-each select="method">
+ <xsl:if test="chassis[@name='client']">
+ <xsl:text>void AMQP_ClientHandlerImpl::</xsl:text><xsl:value-of select="$class"/><xsl:text>HandlerImpl::</xsl:text>
+ <xsl:value-of select="amqp:cpp-name(@name)"/><xsl:text>( u_int16_t channel</xsl:text>
+ <xsl:if test="field">
+ <xsl:text>,&#xA; </xsl:text>
+ <xsl:for-each select="field">
+ <xsl:variable name="domain-cpp-type" select="amqp:cpp-lookup(@domain, $domain-cpp-table)"/>
+ <xsl:value-of select="concat($domain-cpp-type, amqp:cpp-arg-ref($domain-cpp-type), ' ', amqp:cpp-name(@name))"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:if><xsl:text> )&#xA;{&#xA;}&#xA;&#xA;</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:for-each>
+ <xsl:text>
+
+} /* namespace framing */
+} /* namespace qpid */&#xA;&#xA;</xsl:text>
+ </xsl:result-document>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/amqp_client_operations.xsl b/cpp/common/framing/generated/stylesheets/amqp_client_operations.xsl
new file mode 100644
index 0000000000..234b7080ba
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/amqp_client_operations.xsl
@@ -0,0 +1,105 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+ <xsl:import href="code_utils.xsl"/>
+
+ <!--
+ =============================
+ Template: client-operations-h
+ =============================
+ Template to generate the AMQP_ClientHandler virtual class. This is the pure
+ virtual class from which the AMQP_Server and AMQP_ClientHandlerImpl classes
+ are derived.
+ -->
+ <xsl:template match="amqp" mode="client-operations-h">
+ <xsl:param name="domain-cpp-table"/>
+ <xsl:result-document href="AMQP_ClientOperations.h" format="textFormat">
+ <xsl:value-of select="amqp:copyright()"/>
+ <xsl:text>
+#ifndef _AMQP_ClientOperations_
+#define _AMQP_ClientOperations_
+
+#include "AMQP_Constants.h"
+#include "FieldTable.h"
+
+namespace qpid {
+namespace framing {
+
+class AMQP_ClientOperations
+{
+ public:
+ AMQP_ClientOperations() {}
+ virtual ~AMQP_ClientOperations() {}
+ inline u_int16_t getAmqpMajor() { return (u_int16_t)</xsl:text><xsl:value-of select="@major"/><xsl:text>; }
+ inline u_int16_t getAmqpMinor() { return (u_int16_t)</xsl:text><xsl:value-of select="@minor"/><xsl:text>; }&#xA;&#xA;</xsl:text>
+
+ <!-- Inner classes -->
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="concat(amqp:cpp-class-name(@name), 'Handler')"/>
+
+ <!-- Inner class documentation & rules -->
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/**&#xA;===== Class: </xsl:text><xsl:value-of select="$class"/><xsl:text> =====&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>*/&#xA;</xsl:text>
+ </xsl:if>
+
+ <!-- Inner class definition -->
+ <xsl:text> class </xsl:text><xsl:value-of select="$class"/><xsl:text>
+ {
+ public:
+ /* Constructors and destructors */
+ </xsl:text><xsl:value-of select="$class"/><xsl:text>() {}
+ virtual ~</xsl:text><xsl:value-of select="$class"/><xsl:text>() {}
+
+ /* Protocol methods */&#xA;</xsl:text>
+
+ <!-- Inner class methods (only if the chassis is set to "client") -->
+ <xsl:for-each select="method">
+ <xsl:if test="chassis[@name='client']">
+ <xsl:variable name="method" select="amqp:cpp-name(@name)"/>
+
+ <!-- Inner class method documentation & rules -->
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/**&#xA;----- Method: </xsl:text><xsl:value-of select="$class"/><xsl:text>.</xsl:text>
+ <xsl:value-of select="@name"/><xsl:text> -----&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>*/&#xA;</xsl:text>
+ </xsl:if>
+ <xsl:for-each select="rule">
+ <xsl:text>&#xA;/**&#xA;</xsl:text>
+ <xsl:text>Rule "</xsl:text><xsl:value-of select="@name"/><xsl:text>":&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>*/&#xA;</xsl:text>
+ </xsl:for-each>
+
+ <!-- Inner class method definition -->
+ <xsl:text> virtual void </xsl:text><xsl:value-of select="$method"/>
+ <xsl:text>( u_int16_t channel</xsl:text>
+
+ <!-- Inner class method parameter definition -->
+ <xsl:if test="field">
+ <xsl:text>,&#xA; </xsl:text>
+ <xsl:for-each select="field">
+ <xsl:variable name="domain-cpp-type" select="amqp:cpp-lookup(@domain, $domain-cpp-table)"/>
+ <xsl:value-of select="concat($domain-cpp-type, amqp:cpp-arg-ref($domain-cpp-type), ' ', amqp:cpp-name(@name))"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:text> ) = 0;&#xA;</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text>&#xA; }; /* class </xsl:text><xsl:value-of select="$class"/><xsl:text> */&#xA;</xsl:text>
+ </xsl:for-each>
+ <xsl:text>&#xA;}; /* class AMQP_ClientOperations */
+
+} /* namespace framing */
+} /* namespace qpid */
+
+#endif&#xA;</xsl:text>
+ </xsl:result-document>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/amqp_consts.xsl b/cpp/common/framing/generated/stylesheets/amqp_consts.xsl
new file mode 100644
index 0000000000..c1c927f941
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/amqp_consts.xsl
@@ -0,0 +1,77 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+ <xsl:import href="code_utils.xsl"/>
+ <xsl:output method="text" indent="yes" name="textFormat"/>
+
+ <xsl:template match="/">
+ <xsl:apply-templates select="amqp" mode="domain-table"/>
+ <xsl:apply-templates select="amqp" mode="domain-consts"/>
+ </xsl:template>
+
+ <!--
+ ======================
+ Template: domain-table
+ ======================
+ Generates the domain name to C++ type lookup table
+ which is required for later generation.
+ Format:
+ <domains>
+ <domain doamin-name="dname1" cpp-type="type1"/>
+ <domain doamin-name="dname2" cpp-type="type2"/>
+ ...
+ </domains>
+ -->
+ <xsl:template match="amqp" mode="domain-table">
+ <domains><xsl:text>&#xA;</xsl:text>
+ <xsl:for-each select="domain">
+ <xsl:text> </xsl:text><domain>
+ <xsl:attribute name="domain-name">
+ <xsl:value-of select="@name"/>
+ </xsl:attribute>
+ <xsl:attribute name="cpp-type">
+ <xsl:value-of select="amqp:cpp-type(@type)"/>
+ </xsl:attribute>
+ </domain><xsl:text>&#xA;</xsl:text>
+ </xsl:for-each>
+ </domains>
+ </xsl:template>
+
+ <!--
+ =======================
+ Template: domain-consts
+ =======================
+ Generates a header file (AMQP_Constants.h) containing definitions of
+ all the <constant> declarations in the AMQP XML specification.
+ -->
+ <xsl:template match="amqp" mode="domain-consts">
+ <xsl:result-document href="AMQP_Constants.h" format="textFormat">
+ <xsl:value-of select="amqp:copyright()"/>
+ <xsl:text>
+#ifndef _AMQP_Constants_
+#define _AMQP_Constants_
+
+#include "amqp_types.h"
+
+namespace qpid {
+namespace framing {
+
+/**** Constants ****/&#xA;&#xA;</xsl:text>
+ <xsl:for-each select="constant">
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/*&#xA;</xsl:text>
+ <xsl:value-of select="normalize-space(doc)"/>
+ <xsl:text>&#xA;*/&#xA;</xsl:text>
+ </xsl:if>
+ <xsl:text>const u_int16_t </xsl:text><xsl:value-of select="concat('AMQP_', upper-case(amqp:cpp-name(@name)), ' = ', @value)"/><xsl:text>;&#xA;</xsl:text>
+ </xsl:for-each>
+ <xsl:text>
+
+} /* namespace framing */
+} /* namespace qpid */
+
+#endif&#xA;</xsl:text>
+ </xsl:result-document>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/amqp_server.xsl b/cpp/common/framing/generated/stylesheets/amqp_server.xsl
new file mode 100644
index 0000000000..4ad29a4b95
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/amqp_server.xsl
@@ -0,0 +1,155 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+ <xsl:import href="code_utils.xsl"/>
+
+ <!--
+ ==================
+ Template: server_h
+ ==================
+ Server header file.
+ -->
+ <xsl:template match="amqp" mode="server_h">
+ <xsl:param name="domain-cpp-table"/>
+ <xsl:result-document href="AMQP_Server.h" format="textFormat">
+ <xsl:value-of select="amqp:copyright()"/>
+ <xsl:text>
+#ifndef _AMQP_Server_
+#define _AMQP_Server_
+
+#include "AMQP_ClientOperations.h"
+#include "FieldTable.h"
+#include "OutputHandler.h"
+
+namespace qpid {
+namespace framing {
+
+class AMQP_Server : virtual public AMQP_ClientOperations
+{
+ OutputHandler* out;
+
+ public:
+ AMQP_Server(OutputHandler* _out);
+ virtual ~AMQP_Server() {}&#xA;&#xA;</xsl:text>
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="amqp:cpp-class-name(@name)"/>
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/**&#xA;===== Class: </xsl:text><xsl:value-of select="$class"/><xsl:text> =====&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>&#xA;*/&#xA;</xsl:text>
+ </xsl:if>
+ <xsl:text> class </xsl:text><xsl:value-of select="$class"/><xsl:text> : virtual public AMQP_ClientOperations::</xsl:text><xsl:value-of select="$class"/><xsl:text>Handler
+ {
+ OutputHandler* out;
+
+ public:
+ /* Constructors and destructors */
+ </xsl:text><xsl:value-of select="$class"/><xsl:text>(OutputHandler* _out);
+ virtual ~</xsl:text><xsl:value-of select="$class"/><xsl:text>();
+
+ /* Protocol methods */&#xA;</xsl:text>
+ <xsl:for-each select="method">
+ <xsl:if test="chassis[@name='client']">
+ <xsl:variable name="method" select="amqp:cpp-name(@name)"/>
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/**&#xA;----- Method: </xsl:text><xsl:value-of select="$class"/><xsl:text>.</xsl:text><xsl:value-of select="$method"/><xsl:text> -----&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>&#xA;*/&#xA;</xsl:text>
+ </xsl:if>
+ <xsl:for-each select="rule">
+ <xsl:text>&#xA;/**&#xA;</xsl:text>
+ <xsl:text>Rule "</xsl:text><xsl:value-of select="@name"/><xsl:text>":&#xA;</xsl:text><xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>&#xA;*/&#xA;</xsl:text>
+ </xsl:for-each>
+ <xsl:text> virtual void </xsl:text><xsl:value-of select="$method"/>
+ <xsl:text>( u_int16_t channel</xsl:text><xsl:if test="field"><xsl:text>,&#xA; </xsl:text>
+ <xsl:for-each select="field">
+ <xsl:variable name="domain-cpp-type" select="amqp:cpp-lookup(@domain, $domain-cpp-table)"/>
+ <xsl:value-of select="concat($domain-cpp-type, amqp:cpp-arg-ref($domain-cpp-type), ' ', amqp:cpp-name(@name))"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:text> );&#xA;</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text> }; /* class </xsl:text><xsl:value-of select="$class"/><xsl:text> */&#xA;</xsl:text>
+ </xsl:for-each>
+ <xsl:text>}; /* class AMQP_Server */
+
+} /* namespace framing */
+} /* namespace qpid */
+
+#endif&#xA;</xsl:text>
+ </xsl:result-document>
+ </xsl:template>
+
+
+ <!--
+ ====================
+ Template: server_cpp
+ ====================
+ Server body.
+ -->
+ <xsl:template match="amqp" mode="server_cpp">
+ <xsl:param name="domain-cpp-table"/>
+ <xsl:result-document href="AMQP_Server.cpp" format="textFormat">
+ <xsl:value-of select="amqp:copyright()"/>
+ <xsl:text>
+
+#include "AMQP_Server.h"
+
+namespace qpid {
+namespace framing {
+
+AMQP_Server::AMQP_Server(OutputHandler* _out) :
+ out(_out)
+{
+}&#xA;&#xA;</xsl:text>
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="amqp:cpp-class-name(@name)"/>
+ <xsl:text>&#xA;/* ++++++++++ Class: </xsl:text><xsl:value-of select="$class"/><xsl:text> ++++++++++ */
+
+AMQP_Server::</xsl:text><xsl:value-of select="$class"/><xsl:text>::</xsl:text><xsl:value-of select="$class"/><xsl:text>(OutputHandler* _out) :
+ out(_out)
+{
+}
+
+AMQP_Server::</xsl:text><xsl:value-of select="$class"/><xsl:text>::~</xsl:text><xsl:value-of select="$class"/><xsl:text>() {}&#xA;&#xA;</xsl:text>
+ <xsl:for-each select="method">
+ <xsl:if test="chassis[@name='client']">
+ <xsl:text>void AMQP_Server::</xsl:text><xsl:value-of select="$class"/><xsl:text>::</xsl:text>
+ <xsl:value-of select="amqp:cpp-name(@name)"/><xsl:text>( u_int16_t channel</xsl:text><xsl:if test="field">
+ <xsl:text>,&#xA; </xsl:text>
+ <xsl:for-each select="field">
+ <xsl:variable name="domain-cpp-type" select="amqp:cpp-lookup(@domain, $domain-cpp-table)"/>
+ <xsl:value-of select="concat($domain-cpp-type, amqp:cpp-arg-ref($domain-cpp-type), ' ', amqp:cpp-name(@name))"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:text> )
+{
+ out->send( new AMQFrame( channel,
+ new </xsl:text><xsl:value-of select="concat($class, amqp:field-name(@name), 'Body')"/><xsl:text>( </xsl:text>
+ <xsl:for-each select="field">
+ <xsl:value-of select="amqp:cpp-name(@name)"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text> ) ) );
+}&#xA;&#xA;</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:for-each>
+ <xsl:text>
+
+} /* namespace framing */
+} /* namespace qpid */&#xA;</xsl:text>
+ </xsl:result-document>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/amqp_server_handler_impl.xsl b/cpp/common/framing/generated/stylesheets/amqp_server_handler_impl.xsl
new file mode 100644
index 0000000000..de879a5670
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/amqp_server_handler_impl.xsl
@@ -0,0 +1,187 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+ <xsl:import href="code_utils.xsl"/>
+
+ <!--
+ ===============================
+ Template: server_handler_impl_h
+ ===============================
+ Template to generate the AMQP_ServerHandlerImpl class header file.
+ -->
+ <xsl:template match="amqp" mode="server_handler_impl_h">
+ <xsl:param name="domain-cpp-table"/>
+ <xsl:result-document href="AMQP_ServerHandlerImpl.h" format="textFormat">
+ <xsl:value-of select="amqp:copyright()"/>
+ <xsl:text>
+#ifndef _AMQP_ServerHandlerImpl_
+#define _AMQP_ServerHandlerImpl_
+
+#include "AMQP_ServerOperations.h"
+#include "FieldTable.h"
+
+namespace qpid {
+namespace framing {
+
+class AMQP_ServerHandlerImpl : virtual public AMQP_ServerOperations
+{&#xA;</xsl:text>
+
+ <!-- List of pointers to each inner class instance -->
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="concat(amqp:cpp-class-name(@name), 'Handler')"/>
+ <xsl:text> AMQP_ServerOperations::</xsl:text><xsl:value-of select="$class"/><xsl:text>* </xsl:text>
+ <xsl:value-of select="$class"/><xsl:text>Ptr;&#xA;</xsl:text>
+ </xsl:for-each>
+ <xsl:text>
+ public:
+ AMQP_ServerHandlerImpl();
+ virtual ~AMQP_ServerHandlerImpl();&#xA;&#xA;</xsl:text>
+
+ <!-- List of functions to return pointer to each inner class instance -->
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="concat(amqp:cpp-class-name(@name), 'Handler')"/>
+ <xsl:text> virtual inline AMQP_ServerOperations::</xsl:text>
+ <xsl:value-of select="$class"/><xsl:text>* get</xsl:text><xsl:value-of select="$class"/>
+ <xsl:text>() { return </xsl:text><xsl:value-of select="$class"/><xsl:text>Ptr; }&#xA;</xsl:text>
+ </xsl:for-each>
+ <xsl:text>&#xA;</xsl:text>
+
+ <!-- Inner classes -->
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="concat(amqp:cpp-class-name(@name), 'Handler')"/>
+
+ <!-- Inner class documentation & rules -->
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/**&#xA;</xsl:text>
+ <xsl:text>===== Class: </xsl:text><xsl:value-of select="$class"/><xsl:text>Impl =====&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>*/&#xA;</xsl:text>
+ </xsl:if>
+
+ <!-- Inner class definition -->
+ <xsl:text> class </xsl:text><xsl:value-of select="$class"/>
+ <xsl:text>Impl : virtual public AMQP_ServerOperations::</xsl:text><xsl:value-of select="$class"/>
+ <xsl:text>&#xA; {
+ public:
+ /* Constructors and destructors */
+ </xsl:text><xsl:value-of select="$class"/><xsl:text>Impl();
+ virtual ~</xsl:text><xsl:value-of select="$class"/><xsl:text>Impl();
+
+ /* Protocol methods */&#xA;</xsl:text>
+
+ <!-- Inner class methods (only if the chassis is set to "server") -->
+ <xsl:for-each select="method">
+ <xsl:if test="chassis[@name='server']">
+ <xsl:variable name="method" select="amqp:cpp-name(@name)"/>
+
+ <!-- Inner class method documentation & rules -->
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/**&#xA;</xsl:text>
+ <xsl:text>----- Method: </xsl:text><xsl:value-of select="$class"/>
+ <xsl:text>Impl.</xsl:text><xsl:value-of select="@name"/><xsl:text> -----&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>*/&#xA;</xsl:text>
+ </xsl:if>
+ <xsl:for-each select="rule">
+ <xsl:text>&#xA;/**&#xA;</xsl:text>
+ <xsl:text>Rule "</xsl:text><xsl:value-of select="@name"/><xsl:text>":&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>*/&#xA;</xsl:text>
+ </xsl:for-each>
+
+ <!-- Inner class method definition -->
+ <xsl:text>&#xA; virtual void </xsl:text><xsl:value-of select="$method"/>
+ <xsl:text>( u_int16_t channel</xsl:text>
+
+ <!-- Inner class method parameter definition -->
+ <xsl:if test="field">
+ <xsl:text>,&#xA; </xsl:text>
+ <xsl:for-each select="field">
+ <xsl:variable name="domain-cpp-type" select="amqp:cpp-lookup(@domain, $domain-cpp-table)"/>
+ <xsl:value-of select="concat($domain-cpp-type, amqp:cpp-arg-ref($domain-cpp-type), ' ', amqp:cpp-name(@name))"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:text> );&#xA;</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text>&#xA; }; /* class </xsl:text><xsl:value-of select="$class"/><xsl:text>Impl */&#xA;</xsl:text>
+ </xsl:for-each>
+ <xsl:text>&#xA;}; /* AMQP_ServerHandlerImpl */
+
+} /* namespace framing */
+} /* namespace qpid */
+
+#endif&#xA;</xsl:text>
+ </xsl:result-document>
+ </xsl:template>
+
+ <!--
+ =================================
+ Template: server_handler_impl_cpp
+ =================================
+ Template to generate the AMQP_ServerHandlerImpl class stubs.
+ -->
+ <xsl:template match="amqp" mode="server_handler_impl_cpp">
+ <xsl:param name="domain-cpp-table"/>
+ <xsl:result-document href="AMQP_ServerHandlerImpl.cpp" format="textFormat">
+ <xsl:value-of select="amqp:copyright()"/>
+ <xsl:text>
+#include "AMQP_ServerHandlerImpl.h"
+
+namespace qpid {
+namespace framing {
+
+AMQP_ServerHandlerImpl::AMQP_ServerHandlerImpl() :&#xA; </xsl:text>
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="amqp:cpp-class-name(@name)"/>
+ <xsl:value-of select="$class"/>
+ <xsl:text>HandlerPtr( new </xsl:text><xsl:value-of select="$class"/><xsl:text>HandlerImpl() )</xsl:text>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text>
+{
+}
+
+AMQP_ServerHandlerImpl::~AMQP_ServerHandlerImpl()
+{&#xA;</xsl:text>
+ <xsl:for-each select="class">
+ <xsl:text> delete </xsl:text><xsl:value-of select="amqp:cpp-class-name(@name)"/><xsl:text>HandlerPtr;&#xA;</xsl:text>
+ </xsl:for-each>}
+
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="amqp:cpp-class-name(@name)"/>
+ <xsl:text>&#xA;/* ===== Class: </xsl:text><xsl:value-of select="$class"/><xsl:text>HandlerImpl ===== */&#xA;&#xA;</xsl:text>
+ <xsl:text>AMQP_ServerHandlerImpl::</xsl:text><xsl:value-of select="$class"/><xsl:text>HandlerImpl::</xsl:text>
+ <xsl:value-of select="$class"/><xsl:text>HandlerImpl()&#xA;{&#xA;}&#xA;&#xA;</xsl:text>
+ <xsl:text>AMQP_ServerHandlerImpl::</xsl:text><xsl:value-of select="$class"/><xsl:text>HandlerImpl::~</xsl:text>
+ <xsl:value-of select="$class"/><xsl:text>HandlerImpl()&#xA;{&#xA;}&#xA;&#xA;</xsl:text>
+ <xsl:for-each select="method">
+ <xsl:if test="chassis[@name='server']">
+ <xsl:text>void AMQP_ServerHandlerImpl::</xsl:text><xsl:value-of select="$class"/><xsl:text>HandlerImpl::</xsl:text>
+ <xsl:value-of select="amqp:cpp-name(@name)"/><xsl:text>( u_int16_t channel</xsl:text>
+ <xsl:if test="field">
+ <xsl:text>,&#xA; </xsl:text>
+ <xsl:for-each select="field">
+ <xsl:variable name="domain-cpp-type" select="amqp:cpp-lookup(@domain, $domain-cpp-table)"/>
+ <xsl:value-of select="concat($domain-cpp-type, amqp:cpp-arg-ref($domain-cpp-type), ' ', amqp:cpp-name(@name))"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:if><xsl:text> )&#xA;{&#xA;}&#xA;&#xA;</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:for-each>
+ <xsl:text>
+
+} /* namespace framing */
+} /* namespace qpid */&#xA;&#xA;</xsl:text>
+ </xsl:result-document>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/amqp_server_operations.xsl b/cpp/common/framing/generated/stylesheets/amqp_server_operations.xsl
new file mode 100644
index 0000000000..b42242e8fe
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/amqp_server_operations.xsl
@@ -0,0 +1,113 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+ <xsl:import href="code_utils.xsl"/>
+
+ <!--
+ =============================
+ Template: server-operations-h
+ =============================
+ Template to generate the AMQP_ServerHandler virtual class. This is the pure
+ virtual class from which the AMQP_Client and AMQP_ServerHandlerImpl classes
+ are derived.
+ -->
+ <xsl:template match="amqp" mode="server-operations-h">
+ <xsl:param name="domain-cpp-table"/>
+ <xsl:result-document href="AMQP_ServerOperations.h" format="textFormat">
+ <xsl:value-of select="amqp:copyright()"/>
+ <xsl:text>
+#ifndef _AMQP_ServerOperations_
+#define _AMQP_ServerOperations_
+
+#include "AMQP_Constants.h"
+#include "FieldTable.h"
+
+namespace qpid {
+namespace framing {
+
+class AMQP_ServerOperations
+{
+ public:
+ AMQP_ServerOperations() {}
+ virtual ~AMQP_ServerOperations() {}
+ inline u_int16_t getAmqpMajor() { return (u_int16_t)</xsl:text><xsl:value-of select="@major"/><xsl:text>; }
+ inline u_int16_t getAmqpMinor() { return (u_int16_t)</xsl:text><xsl:value-of select="@minor"/><xsl:text>; }&#xA;&#xA;</xsl:text>
+
+ <!-- Inner classes -->
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="concat(amqp:cpp-class-name(@name), 'Handler')"/>
+
+ <!-- Inner class documentation & rules -->
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/**&#xA;===== Class: </xsl:text><xsl:value-of select="$class"/><xsl:text> =====&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>*/&#xA;</xsl:text>
+ </xsl:if>
+
+ <!-- Inner class definition -->
+ <xsl:text> class </xsl:text><xsl:value-of select="$class"/><xsl:text>
+ {
+ public:
+ /* Constructors and destructors */
+ </xsl:text><xsl:value-of select="$class"/><xsl:text>() {}
+ virtual ~</xsl:text><xsl:value-of select="$class"/><xsl:text>() {}
+
+ /* Protocol methods */&#xA;</xsl:text>
+
+ <!-- Inner class methods (only if the chassis is set to "server") -->
+ <xsl:for-each select="method">
+ <xsl:if test="chassis[@name='server']">
+ <xsl:variable name="method" select="amqp:cpp-name(@name)"/>
+
+ <!-- Inner class method documentation & rules -->
+ <xsl:if test="doc">
+ <xsl:text>&#xA;/**&#xA;----- Method: </xsl:text><xsl:value-of select="$class"/><xsl:text>.</xsl:text>
+ <xsl:value-of select="@name"/><xsl:text> -----&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>*/&#xA;</xsl:text>
+ </xsl:if>
+ <xsl:for-each select="rule">/**
+ <xsl:text>&#xA;/**&#xA;</xsl:text>
+ <xsl:text>Rule "</xsl:text><xsl:value-of select="@name"/><xsl:text>":&#xA;</xsl:text>
+ <xsl:value-of select="amqp:process-docs(doc)"/>
+ <xsl:text>*/&#xA;</xsl:text>
+ </xsl:for-each>
+
+ <!-- Inner class method definition -->
+ <xsl:text> virtual void </xsl:text><xsl:value-of select="$method"/>
+ <xsl:text>( u_int16_t channel</xsl:text>
+
+ <!-- Inner class method parameter definition -->
+ <xsl:if test="field">
+ <xsl:text>,&#xA; </xsl:text>
+ <xsl:for-each select="field">
+ <xsl:variable name="domain-cpp-type" select="amqp:cpp-lookup(@domain, $domain-cpp-table)"/>
+ <xsl:value-of select="concat($domain-cpp-type, amqp:cpp-arg-ref($domain-cpp-type), ' ', amqp:cpp-name(@name))"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,&#xA; </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:text> ) = 0;&#xA;</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text> }; /* class </xsl:text><xsl:value-of select="$class"/><xsl:text> */&#xA;</xsl:text>
+ </xsl:for-each>
+
+ <xsl:for-each select="class">
+ <xsl:variable name="class" select="concat(amqp:cpp-class-name(@name), 'Handler')"/>
+ <xsl:text> virtual AMQP_ServerOperations::</xsl:text>
+ <xsl:value-of select="$class"/><xsl:text>* get</xsl:text><xsl:value-of select="$class"/>
+ <xsl:text>() = 0;</xsl:text>
+ </xsl:for-each>
+
+ <xsl:text>}; /* class AMQP_ServerOperations */
+
+} /* namespace framing */
+} /* namespace qpid */
+
+#endif&#xA;</xsl:text>
+ </xsl:result-document>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/code_gen.xsl b/cpp/common/framing/generated/stylesheets/code_gen.xsl
new file mode 100644
index 0000000000..5e9f4ef8f0
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/code_gen.xsl
@@ -0,0 +1,91 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+ <xsl:import href="convert_0.81.xsl"/>
+ <xsl:import href="amqp_consts.xsl"/>
+ <xsl:import href="amqp_server_operations.xsl"/>
+ <xsl:import href="amqp_client_operations.xsl"/>
+ <xsl:import href="amqp_server.xsl"/>
+ <xsl:import href="amqp_client.xsl"/>
+ <xsl:import href="amqp_server_handler_impl.xsl"/>
+ <xsl:import href="amqp_client_handler_impl.xsl"/>
+
+ <xsl:output method="text" indent="yes" name="textFormat"/>
+ <xsl:key name="domain-lookup" match="domains/domain" use="@domain-name"/>
+
+ <xsl:template match="/">
+
+ <!-- 0. Convert to 0.81 format -->
+ <!--
+ NOTE: The XML specification change from 0.8 to 0.81 is primarily a change to
+ the XML itself, not the protocol it represents. However, at the time of this
+ commit, the 0.81 specification has not been approved by the AMQP working group,
+ so this converter from the 0.8 format to the 0.81 format has been included as
+ a temporary measure. When the 0.81 format becomes official, then this conversion
+ should be removed, and all of the templates below will revert to select=".".
+
+ TODO: Remove this conversion when the new 0.81 spec is checked in.
+ -->
+ <xsl:variable name="format-v081">
+ <xsl:apply-templates mode="do-amqp" select="amqp"/>
+ </xsl:variable>
+ <!-- == Uncomment this to view output for debugging ==
+ <xsl:result-document href="convert_081.out">
+ <xsl:copy-of select="$format-v081"/>
+ </xsl:result-document>
+ -->
+
+ <!-- 1. Domain to C++ type lookup table -->
+ <xsl:variable name="domain-cpp-table">
+ <xsl:apply-templates mode="domain-table" select="$format-v081"/>
+ </xsl:variable>
+ <!-- == Uncomment this to view output for debugging ==
+ <xsl:result-document href="domain_cpp_table.out">
+ <xsl:copy-of select="$domain-cpp-table"/>
+ </xsl:result-document>
+ -->
+
+ <!-- 2. Constant declarations (AMQP_Constants.h) -->
+ <xsl:apply-templates mode="domain-consts" select="$format-v081"/>
+
+ <!-- 3. Client and server handler pure virtual classes -->
+ <xsl:apply-templates mode="server-operations-h" select="$format-v081">
+ <xsl:with-param name="domain-cpp-table" select="$domain-cpp-table"/>
+ </xsl:apply-templates>
+ <xsl:apply-templates mode="client-operations-h" select="$format-v081">
+ <xsl:with-param name="domain-cpp-table" select="$domain-cpp-table"/>
+ </xsl:apply-templates>
+
+ <!-- 4. Client and server output classes -->
+ <xsl:apply-templates mode="server_h" select="$format-v081">
+ <xsl:with-param name="domain-cpp-table" select="$domain-cpp-table"/>
+ </xsl:apply-templates>
+ <xsl:apply-templates mode="client_h" select="$format-v081">
+ <xsl:with-param name="domain-cpp-table" select="$domain-cpp-table"/>
+ </xsl:apply-templates>
+ <xsl:apply-templates mode="server_cpp" select="$format-v081">
+ <xsl:with-param name="domain-cpp-table" select="$domain-cpp-table"/>
+ </xsl:apply-templates>
+ <xsl:apply-templates mode="client_cpp" select="$format-v081">
+ <xsl:with-param name="domain-cpp-table" select="$domain-cpp-table"/>
+ </xsl:apply-templates>
+
+ <!-- 5. Client and server handler stub classes -->
+ <xsl:apply-templates mode="server_handler_impl_h" select="$format-v081">
+ <xsl:with-param name="domain-cpp-table" select="$domain-cpp-table"/>
+ </xsl:apply-templates>
+ <xsl:apply-templates mode="client_handler_impl_h" select="$format-v081">
+ <xsl:with-param name="domain-cpp-table" select="$domain-cpp-table"/>
+ </xsl:apply-templates>
+ <!-- TODO: Find a way to only run the .cpp stub generator when required, as
+ running this will overwrite any stub code in existance! -->
+ <xsl:apply-templates mode="server_handler_impl_cpp" select="$format-v081">
+ <xsl:with-param name="domain-cpp-table" select="$domain-cpp-table"/>
+ </xsl:apply-templates>
+ <xsl:apply-templates mode="client_handler_impl_cpp" select="$format-v081">
+ <xsl:with-param name="domain-cpp-table" select="$domain-cpp-table"/>
+ </xsl:apply-templates>
+
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/code_utils.xsl b/cpp/common/framing/generated/stylesheets/code_utils.xsl
new file mode 100644
index 0000000000..f4a0f6e5ce
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/code_utils.xsl
@@ -0,0 +1,210 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+ <!--
+ ========================
+ Function: amqp:copyright
+ ========================
+ Print out a standard Apache copyright notice and generated code warning.
+ -->
+ <xsl:function name="amqp:copyright">/**
+*
+* 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.
+*
+*/
+
+/**
+*
+* NOTE: This file is generated directly from the AMQP XML specification.
+* === DO NOT EDIT ===
+*
+*/&#xA;</xsl:function>
+
+ <!--
+ ==========================
+ Function: amqp:upper-first
+ ==========================
+ Convert the first character of the parameter to upper-case
+ -->
+ <xsl:function name="amqp:upper-first">
+ <xsl:param name="in"/>
+ <xsl:value-of select="concat(upper-case(substring($in, 1, 1)), substring($in, 2))"/>
+ </xsl:function>
+
+ <!--
+ ========================
+ Function: amqp:cpp-name-1
+ ========================
+ Convert parameter "name" to a valid C++ identifier, finding spaces and '-'s
+ in the parameter name and replacing them with '_' chars. Also check for C++
+ reserved words and prefix them with '_'. No capitalization is performed.
+ -->
+ <xsl:function name="amqp:cpp-name-1">
+ <xsl:param name="name"/>
+ <xsl:choose>
+ <!-- C++ reserved words. -->
+ <xsl:when test="$name='delete'">delete_</xsl:when>
+ <xsl:when test="$name='return'">return_</xsl:when>
+ <!-- Change unsuitable C++ identifier characters. -->
+ <xsl:otherwise><xsl:value-of select="translate($name, ' -', '__')"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:function>
+
+ <!--
+ =======================
+ Function: amqp:cpp-name
+ =======================
+ Convert parameter "name" to a valid, camel cased C++ name.
+ -->
+ <xsl:function name="amqp:cpp-name">
+ <xsl:param name="name"/>
+ <xsl:value-of select="amqp:cpp-name-1(amqp:camel-case($name))"/>
+ </xsl:function>
+
+ <!--
+ =============================
+ Function: amqp:cpp-class-name
+ =============================
+ Convert parameter "name" to a valid C++ identifier, finding spaces and '-'s
+ in the parameter name and replacing them with '_' chars. Also check for C++
+ reserved words and prefix them with '_'. First letter only is capitalized.
+ -->
+ <xsl:function name="amqp:cpp-class-name">
+ <xsl:param name="name"/>
+ <xsl:value-of select="amqp:upper-first(amqp:cpp-name($name))"/>
+ </xsl:function>
+
+ <!--
+ =========================
+ Function: amqp:camel-case
+ =========================
+ *** NOTE: Only works with *one* of either '-' or ' '. If a name contains 2 or
+ *** more of these characters, then this will break.
+ Convert parameter "name" to camel case, where words are separated by ' ' or '-'
+ -->
+ <xsl:function name="amqp:camel-case">
+ <xsl:param name="name"/>
+ <xsl:choose>
+ <xsl:when test="contains($name, ' ')">
+ <xsl:value-of select="concat(substring-before($name, ' '), amqp:upper-first(substring-after($name, ' ')))"/>
+ </xsl:when>
+ <xsl:when test="contains($name, '-')">
+ <xsl:value-of select="concat(substring-before($name, '-'), amqp:upper-first(substring-after($name, '-')))"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:function>
+
+ <!--
+ =========================
+ Function: amqp:field-name
+ =========================
+ Get a valid field name, processing spaces and '-'s where appropriate
+ -->
+ <xsl:function name="amqp:field-name">
+ <xsl:param name="name"/>
+ <xsl:value-of select="amqp:upper-first(amqp:camel-case($name))"/>
+ </xsl:function>
+
+ <!--
+ =======================
+ Function: amqp:cpp-type
+ =======================
+ Map the set of simple AMQP types to C++ types. Also map the AMQP table
+ domain to appropriate C++ class.
+ -->
+ <xsl:function name="amqp:cpp-type">
+ <xsl:param name="type"/>
+ <xsl:choose>
+ <!-- Simple AMQP domain types -->
+ <xsl:when test="$type='octet'">u_int8_t</xsl:when>
+ <xsl:when test="$type='short'">u_int16_t</xsl:when>
+ <xsl:when test="$type='shortstr'">string</xsl:when>
+ <xsl:when test="$type='longstr'">string</xsl:when>
+ <xsl:when test="$type='bit'">bool</xsl:when>
+ <xsl:when test="$type='long'">u_int32_t</xsl:when>
+ <xsl:when test="$type='longlong'">u_int64_t</xsl:when>
+ <xsl:when test="$type='timestamp'">u_int64_t</xsl:when>
+ <!-- AMQP structures -->
+ <xsl:when test="$type='table'">FieldTable</xsl:when>
+ <!-- Fallback: unknown type -->
+ <xsl:otherwise>unknown_type /* WARNING: undefined type */</xsl:otherwise>
+ </xsl:choose>
+ </xsl:function>
+
+ <!--
+ ==========================
+ Function: amqp:cpp-arg-ref
+ ==========================
+ Determines whether a C++ reference is required for an argument.
+ -->
+ <xsl:function name="amqp:cpp-arg-ref">
+ <xsl:param name="type"/>
+ <xsl:choose>
+ <xsl:when test="$type='string'">&amp;</xsl:when>
+ <xsl:when test="$type='FieldTable'">&amp;</xsl:when>
+ </xsl:choose>
+ </xsl:function>
+
+ <!--
+ =========================
+ Function: amqp:cpp-lookup
+ =========================
+ Template and function for looking up the cpp type from the domain name.
+ The template runs on a lookup table XML generated by the "domain_table"
+ template in amqp_domaintypes.xsl.
+ -->
+ <xsl:template match="/" mode="cpp-lookup">
+ <xsl:param name="domain-name"/>
+ <xsl:for-each select="key('domain-lookup', $domain-name)">
+ <xsl:value-of select="@cpp-type"/>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:function name="amqp:cpp-lookup">
+ <xsl:param name="domain-name"/>
+ <xsl:param name="domain-cpp-table"/>
+ <xsl:apply-templates mode="cpp-lookup" select="$domain-cpp-table">
+ <xsl:with-param name="domain-name" select="$domain-name"/>
+ </xsl:apply-templates>
+ </xsl:function>
+
+ <!--
+ =========================
+ Function: amqp:cpp-lookup
+ =========================
+ Template and function for processing the possibly multiple <doc> elements
+ within a node.
+ -->
+ <xsl:template match="doc" mode="process-doc-elts">
+ <xsl:for-each select=".">
+ <xsl:choose>
+ <xsl:when test=".[@type='grammar']"><xsl:value-of select="."/></xsl:when>
+ <xsl:when test=".[@type='scenario']"><xsl:value-of select="concat('&#xA;Test Scenario: ', normalize-space(.))"/></xsl:when>
+ <xsl:otherwise><xsl:value-of select="normalize-space(.)"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:function name="amqp:process-docs">
+ <xsl:param name="doc-elts"/>
+ <xsl:apply-templates mode="process-doc-elts" select="$doc-elts"/>
+ </xsl:function>
+
+
+</xsl:stylesheet>
+
diff --git a/cpp/common/framing/generated/stylesheets/convert_0.81.xsl b/cpp/common/framing/generated/stylesheets/convert_0.81.xsl
new file mode 100644
index 0000000000..9924f165da
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/convert_0.81.xsl
@@ -0,0 +1,407 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+<xsl:template match="/">
+ <xsl:apply-templates select="/" mode="do-amqp"/>
+</xsl:template>
+
+<!-- ======
+ <amqp>
+ ====== -->
+<xsl:template match="amqp" mode="do-amqp">
+
+<!-- <xsl:text>&#xA;</xsl:text> -->
+<xsl:element name= "amqp">
+<xsl:attribute name="major"><xsl:value-of select="@major"/></xsl:attribute>
+<xsl:attribute name="minor"><xsl:value-of select="@minor"/></xsl:attribute>
+<xsl:attribute name="port"><xsl:value-of select="@port"/></xsl:attribute>
+<xsl:attribute name="comment"><xsl:value-of select="@comment"/></xsl:attribute>
+<xsl:text>&#xA;</xsl:text>
+
+<!-- constant elements -->
+<xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:comment>
+ ====================
+ Constants
+ ====================
+ </xsl:comment><xsl:text>&#xA;</xsl:text>
+<xsl:text>&#xA;</xsl:text>
+<xsl:apply-templates select="constant" mode="do-constant">
+<xsl:with-param name="indent" select="' '"/>
+</xsl:apply-templates>
+
+<!-- domain elements -->
+<xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:comment>
+ ====================
+ Domains
+ ====================
+ </xsl:comment><xsl:text>&#xA;</xsl:text>
+<xsl:text>&#xA;</xsl:text>
+<xsl:apply-templates select="domain" mode="do-domain">
+<xsl:with-param name="indent" select="' '"/>
+</xsl:apply-templates>
+
+<!-- required elementary domain definition elements added into v0.81 -->
+<xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:comment> Elementary domains </xsl:comment><xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:element name="domain">
+ <xsl:attribute name="name">bit</xsl:attribute>
+ <xsl:attribute name="type">bit</xsl:attribute>
+ <xsl:attribute name="label">single bit</xsl:attribute>
+</xsl:element><xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:element name="domain">
+ <xsl:attribute name="name">octet</xsl:attribute>
+ <xsl:attribute name="type">octet</xsl:attribute>
+ <xsl:attribute name="label">single octet</xsl:attribute>
+</xsl:element><xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:element name="domain">
+ <xsl:attribute name="name">short</xsl:attribute>
+ <xsl:attribute name="type">short</xsl:attribute>
+ <xsl:attribute name="label">16-bit integer</xsl:attribute>
+</xsl:element><xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:element name="domain">
+ <xsl:attribute name="name">long</xsl:attribute>
+ <xsl:attribute name="type">long</xsl:attribute>
+ <xsl:attribute name="label">32-bit integer</xsl:attribute>
+</xsl:element><xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:element name="domain">
+ <xsl:attribute name="name">longlong</xsl:attribute>
+ <xsl:attribute name="type">longlong</xsl:attribute>
+ <xsl:attribute name="label">64-bit integer</xsl:attribute>
+</xsl:element><xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:element name="domain">
+ <xsl:attribute name="name">shortstr</xsl:attribute>
+ <xsl:attribute name="type">shortstr</xsl:attribute>
+ <xsl:attribute name="label">short string</xsl:attribute>
+</xsl:element><xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:element name="domain">
+ <xsl:attribute name="name">longstr</xsl:attribute>
+ <xsl:attribute name="type">longstr</xsl:attribute>
+ <xsl:attribute name="label">long string</xsl:attribute>
+</xsl:element><xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:element name="domain">
+ <xsl:attribute name="name">timestamp</xsl:attribute>
+ <xsl:attribute name="type">timestamp</xsl:attribute>
+ <xsl:attribute name="label">64-bit timestamp</xsl:attribute>
+</xsl:element><xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:element name="domain">
+ <xsl:attribute name="name">table</xsl:attribute>
+ <xsl:attribute name="type">table</xsl:attribute>
+ <xsl:attribute name="label">field table</xsl:attribute>
+</xsl:element><xsl:text>&#xA;</xsl:text>
+
+<!-- class elements -->
+<xsl:text>&#xA;</xsl:text>
+<xsl:text> </xsl:text><xsl:comment>
+ ====================
+ Classes
+ ====================
+ </xsl:comment><xsl:text>&#xA;</xsl:text>
+<xsl:apply-templates select="class" mode="do-class">
+<xsl:with-param name="indent" select="' '"/>
+</xsl:apply-templates>
+
+</xsl:element><!-- amqp -->
+<!-- <xsl:text>&#xA;</xsl:text> -->
+</xsl:template>
+
+<!-- ==========
+ <constant>
+ ========== -->
+<xsl:template match="constant" mode="do-constant">
+<xsl:param name="indent"/>
+<xsl:variable name="constant" select="translate(@name, ' ', '-')"/>
+
+<xsl:value-of select="$indent"/><xsl:element name="constant">
+<xsl:attribute name="name"><xsl:value-of select="$constant"/></xsl:attribute>
+<xsl:attribute name="value"><xsl:value-of select="@value"/></xsl:attribute>
+<xsl:if test="@class">
+<xsl:attribute name="class"><xsl:value-of select="translate(@class, ' ', '-')"/></xsl:attribute>
+</xsl:if>
+
+<!-- If there is content, place in child <doc> element -->
+<xsl:if test="string-length(.) > 0">
+<xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="$indent"/><xsl:text> </xsl:text><xsl:element name="doc"><xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="$indent"/><xsl:text> </xsl:text><xsl:value-of select="normalize-space(.)"/><xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="$indent"/><xsl:text> </xsl:text></xsl:element><xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="$indent"/>
+</xsl:if>
+
+</xsl:element><xsl:text>&#xA;</xsl:text>
+
+</xsl:template>
+
+<!-- ========
+ <domain>
+ ======== -->
+<xsl:template match="domain" mode="do-domain">
+<xsl:param name="indent"/>
+<xsl:variable name="domain" select="translate(@name, ' ', '-')"/>
+
+<xsl:value-of select="$indent"/><xsl:element name="domain">
+<xsl:attribute name="name"><xsl:value-of select="$domain"/></xsl:attribute>
+<xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute>
+<xsl:if test="doc|assert|rule"><xsl:text>&#xA;</xsl:text></xsl:if>
+
+<!-- doc elements -->
+<xsl:apply-templates select="doc" mode="do-doc">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+</xsl:apply-templates>
+
+<!-- assert elements -->
+<xsl:apply-templates select="assert" mode="do-assert">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+</xsl:apply-templates>
+
+<!-- rule elements -->
+<xsl:apply-templates select="rule" mode="do-rule">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+<xsl:with-param name="label" select="$domain"/>
+</xsl:apply-templates>
+
+<xsl:if test="doc|assert|rule"><xsl:value-of select="$indent"/></xsl:if></xsl:element><xsl:text>&#xA;</xsl:text>
+
+</xsl:template>
+
+<!-- ========
+ <class>
+ ======== -->
+
+<xsl:template match="class" mode="do-class">
+<xsl:param name="indent"/>
+<xsl:variable name="class" select="translate(@name, ' ', '-')"/>
+
+<!-- Ignore class test - removed from 0.81 -->
+<xsl:if test="not($class = 'test')">
+<xsl:text>&#xA;</xsl:text><xsl:value-of select="$indent"/><xsl:comment><xsl:value-of select="concat(' == Class: ', $class, ' == ')"/></xsl:comment><xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="$indent"/><xsl:element name="class">
+<xsl:attribute name="name"><xsl:value-of select="$class"/></xsl:attribute>
+<xsl:attribute name="handler"><xsl:value-of select="@handler"/></xsl:attribute>
+<xsl:attribute name="index"><xsl:value-of select="@index"/></xsl:attribute>
+<xsl:if test="doc|chassis|rule|field|method"><xsl:text>&#xA;</xsl:text></xsl:if>
+
+<!-- doc elements -->
+<xsl:apply-templates select="doc" mode="do-doc">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+<xsl:with-param name="label" select="$class"/>
+</xsl:apply-templates>
+
+<!-- chassis elements -->
+<xsl:apply-templates select="chassis" mode="do-chassis">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+</xsl:apply-templates>
+
+<!-- rule elements -->
+<xsl:apply-templates select="rule" mode="do-rule">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+<xsl:with-param name="label" select="$class"/>
+</xsl:apply-templates>
+
+<!-- field elements -->
+<xsl:apply-templates select="field" mode="do-field">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+<xsl:with-param name="label" select="$class"/>
+</xsl:apply-templates>
+
+<!-- method elements -->
+<xsl:apply-templates select="method" mode="do-method">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+<xsl:with-param name="label" select="$class"/>
+</xsl:apply-templates>
+
+<xsl:if test="doc|chassis|rule|field|method"><xsl:value-of select="$indent"/></xsl:if></xsl:element><xsl:text>&#xA;</xsl:text>
+</xsl:if>
+</xsl:template>
+
+<!-- ========
+ <method>
+ ======== -->
+
+<xsl:template match="method" mode="do-method">
+<xsl:param name="indent"/>
+<xsl:param name="label"/>
+<xsl:variable name="method" select="translate(@name, ' ', '-')"/>
+
+<xsl:text>&#xA;</xsl:text><xsl:value-of select="$indent"/><xsl:comment><xsl:value-of select="concat(' == Method: ', $label, '.', $method, ' == ')"/></xsl:comment><xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="$indent"/><xsl:element name="method">
+<xsl:attribute name="name"><xsl:value-of select="$method"/></xsl:attribute>
+<xsl:if test="@synchronous"><xsl:attribute name="synchronous"><xsl:value-of select="@synchronous"/></xsl:attribute></xsl:if>
+<xsl:attribute name="index"><xsl:value-of select="@index"/></xsl:attribute>
+<xsl:if test="doc|chassis|response|rule|field"><xsl:text>&#xA;</xsl:text></xsl:if>
+
+<!-- doc elements -->
+<xsl:apply-templates select="doc" mode="do-doc">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+<xsl:with-param name="label" select="concat($label, '.', $method)"/>
+</xsl:apply-templates>
+
+<!-- chassis and response elements -->
+<xsl:apply-templates select="chassis" mode="do-chassis">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+</xsl:apply-templates>
+<xsl:apply-templates select="response" mode="do-response">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+</xsl:apply-templates>
+
+<!-- rule elements -->
+<xsl:apply-templates select="rule" mode="do-rule">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+<xsl:with-param name="label" select="concat($label, '.', $method)"/>
+</xsl:apply-templates>
+
+<!-- field elements -->
+<xsl:apply-templates select="field" mode="do-field">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+<xsl:with-param name="label" select="concat($label, '.', $method)"/>
+</xsl:apply-templates>
+
+<xsl:if test="doc|chassis|response|rule|field"><xsl:value-of select="$indent"/></xsl:if></xsl:element><xsl:text>&#xA;</xsl:text>
+
+</xsl:template>
+
+<!-- ========
+ <field>
+ ======== -->
+
+<xsl:template match="field" mode="do-field">
+<xsl:param name="indent"/>
+<xsl:param name="label"/>
+<xsl:variable name="field" select="translate(@name, ' ', '-')"/>
+
+<xsl:value-of select="$indent"/><xsl:element name="field">
+<xsl:attribute name="name"><xsl:value-of select="$field"/></xsl:attribute>
+<xsl:if test="@type">
+<xsl:attribute name="domain"><xsl:value-of select="translate(@type, ' ', '-')"/></xsl:attribute>
+</xsl:if>
+<xsl:if test="@domain">
+<xsl:attribute name="domain"><xsl:value-of select="translate(@domain, ' ', '-')"/></xsl:attribute>
+</xsl:if>
+<xsl:if test="doc|rule|assert"><xsl:text>&#xA;</xsl:text></xsl:if>
+
+<!-- doc elements -->
+<xsl:apply-templates select="doc" mode="do-doc">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+<xsl:with-param name="label" select="concat($label, '.', $field)"/>
+</xsl:apply-templates>
+
+<!-- rule elements -->
+<xsl:apply-templates select="rule" mode="do-rule">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+<xsl:with-param name="label" select="concat($label, '.', $field)"/>
+</xsl:apply-templates>
+
+<!-- assert elements -->
+<xsl:apply-templates select="assert" mode="do-assert">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+</xsl:apply-templates>
+
+<xsl:if test="doc|rule|assert"><xsl:value-of select="$indent"/></xsl:if></xsl:element><xsl:text>&#xA;</xsl:text>
+
+</xsl:template>
+
+<!-- ========
+ <assert>
+ ======== -->
+<xsl:template match="assert" mode="do-assert">
+<xsl:param name="indent"/>
+
+<xsl:value-of select="$indent"/><xsl:element name="assert">
+<xsl:attribute name="check"><xsl:value-of select="@check"/></xsl:attribute>
+<xsl:if test="@value"><xsl:attribute name="value"><xsl:value-of select="@value"/></xsl:attribute></xsl:if>
+<xsl:if test="@rule"><xsl:attribute name="rule"><xsl:value-of select="@rule"/></xsl:attribute></xsl:if>
+
+<xsl:apply-templates select="doc" mode="do-doc">
+<xsl:with-param name="indent" select="concat($indent, ' ')"/>
+</xsl:apply-templates>
+
+</xsl:element><xsl:text>&#xA;</xsl:text>
+
+</xsl:template>
+
+<!-- ========
+ <rule>
+ ======== -->
+<xsl:template match="rule" mode="do-rule">
+<xsl:param name="indent"/>
+<xsl:param name="label"/>
+
+<xsl:value-of select="$indent"/><xsl:element name="rule">
+<xsl:attribute name="name">rule_<xsl:value-of select="$label"/>_<xsl:number format="01"/></xsl:attribute>
+
+<!-- If there is content, place in child <doc> element -->
+
+<xsl:if test="string-length(.) > 0">
+<xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="$indent"/><xsl:text> </xsl:text><xsl:element name="doc"><xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="$indent"/><xsl:text> </xsl:text><xsl:value-of select="normalize-space(.)"/><xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="$indent"/><xsl:text> </xsl:text></xsl:element><xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="$indent"/>
+</xsl:if>
+
+</xsl:element><xsl:text>&#xA;</xsl:text>
+
+</xsl:template>
+
+<!-- =========
+ <chassis>
+ ========= -->
+<xsl:template match="chassis" mode="do-chassis">
+<xsl:param name="indent"/>
+
+<xsl:value-of select="$indent"/><xsl:element name="chassis">
+<xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+<xsl:attribute name="implement"><xsl:value-of select="@implement"/></xsl:attribute>
+</xsl:element><xsl:text>&#xA;</xsl:text>
+
+</xsl:template>
+
+<!-- ==========
+ <response>
+ ========== -->
+<xsl:template match="response" mode="do-response">
+<xsl:param name="indent"/>
+
+<xsl:value-of select="$indent"/><xsl:element name="response">
+<xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+</xsl:element><xsl:text>&#xA;</xsl:text>
+
+</xsl:template>
+
+<!-- =====
+ <doc>
+ ===== -->
+<xsl:template match="doc" mode="do-doc">
+<xsl:param name="indent"/>
+<xsl:param name="label"/>
+
+<!-- Handle cases of <doc name="rule>...</doc>: turn them into <rule><doc>...</doc></rule> -->
+<xsl:if test="@name = 'rule'">
+<xsl:value-of select="$indent"/><xsl:element name="rule">
+<xsl:if test="@test"><xsl:attribute name="name"><xsl:value-of select="@test"/></xsl:attribute></xsl:if>
+<xsl:if test="not(@test)"><xsl:attribute name="name">doc_rule_<xsl:value-of select="$label"/>_<xsl:number format="01"/></xsl:attribute></xsl:if>
+<xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="concat($indent, ' ')"/><xsl:element name="doc"><xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="concat($indent, ' ')"/><xsl:text> </xsl:text><xsl:value-of select="normalize-space(.)"/><xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="concat($indent, ' ')"/></xsl:element><xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="$indent"/></xsl:element><xsl:text>&#xA;</xsl:text>
+</xsl:if>
+
+<!-- Normal <doc>...</doc> elements -->
+<xsl:if test="not(@name = 'rule')">
+<xsl:value-of select="$indent"/><xsl:element name="doc">
+<xsl:if test="@name = 'grammar'">
+<xsl:attribute name="type">grammar</xsl:attribute>
+<xsl:value-of select="$indent"/><xsl:text> </xsl:text><xsl:value-of select="."/>
+</xsl:if>
+<xsl:if test="not(@name = 'grammar')">
+<xsl:text>&#xA;</xsl:text>
+<xsl:value-of select="$indent"/><xsl:text> </xsl:text><xsl:value-of select="normalize-space(.)"/><xsl:text>&#xA;</xsl:text>
+</xsl:if>
+<xsl:value-of select="$indent"/></xsl:element><xsl:text>&#xA;</xsl:text>
+</xsl:if>
+
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/cpp.xsl b/cpp/common/framing/generated/stylesheets/cpp.xsl
new file mode 100644
index 0000000000..ae66f65745
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/cpp.xsl
@@ -0,0 +1,318 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+<!-- this class contains the templates for generating C++ source code for a given framing model -->
+
+<xsl:import href="utils.xsl"/>
+<xsl:output method="text" indent="yes" name="textFormat"/>
+
+<xsl:template match="/">
+ <xsl:apply-templates mode="generate-multi" select="frames"/>
+ <xsl:apply-templates mode="method-list-header" select="frames"/>
+ <xsl:apply-templates mode="method-list-source" select="frames"/>
+ <xsl:apply-templates mode="method-interface" select="frames"/>
+</xsl:template>
+
+<!-- processes all frames outputting the classes in a single stream -->
+<xsl:template match="frames" mode="generate-single">
+ <xsl:result-document href="amqp_methods.h" format="textFormat">
+#include "amqp_framing.h"
+ <xsl:for-each select="frame">
+ <xsl:call-template name="generate-class">
+ <xsl:with-param name="f" select="."/>
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:result-document>
+</xsl:template>
+
+<!-- generates seperate file for each class/frame -->
+<xsl:template match="frame" mode="generate-multi">
+ <xsl:variable name="uri" select="concat(@name, '.h')"/>
+ <xsl:result-document href="{$uri}" format="textFormat">
+#include "amqp_types.h"
+#include "AMQP_ServerOperations.h"
+#include "AMQMethodBody.h"
+#include "Buffer.h"
+#include "FieldTable.h"
+
+#ifndef _<xsl:value-of select="@name"/>_
+#define _<xsl:value-of select="@name"/>_
+
+namespace qpid {
+namespace framing {
+
+ <xsl:call-template name="generate-class">
+ <xsl:with-param name="f" select="."/>
+ </xsl:call-template>
+}
+}
+
+#endif
+
+</xsl:result-document>
+</xsl:template>
+
+
+<!-- main class generation template -->
+<xsl:template name="generate-class">
+ <xsl:param name="f"/>
+/**
+ * This class is autogenerated, do not modify. [From <xsl:value-of select="$f/parent::frames/@protocol"/>]
+ */
+class <xsl:value-of select="$f/@name"/> : virtual public AMQMethodBody
+{
+ <xsl:for-each select="$f/field">
+ <xsl:value-of select="@cpp-type"/>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="@name"/>;
+ </xsl:for-each>
+
+public:
+ typedef std::tr1::shared_ptr&lt;<xsl:value-of select="$f/@name"/>&gt; shared_ptr;
+
+ virtual ~<xsl:value-of select="$f/@name"/>() {}
+
+ <xsl:for-each select="$f/field">
+ inline <xsl:value-of select="concat(@cpp-arg-type, ' get', amqp:upper-first(@name), '() { return ', @name)"/>; }
+ </xsl:for-each>
+
+
+ inline void print(std::ostream&amp; out) const{
+ out &lt;&lt; "<xsl:value-of select="$f/@declaration_name"/>"
+ <xsl:for-each select="$f/field">
+ <xsl:text> &lt;&lt; ", </xsl:text>
+ <xsl:value-of select="@name"/>="&lt;&lt;
+ <xsl:value-of select="@name"/>
+ </xsl:for-each>
+ ;
+ }
+
+ inline u_int16_t amqpClassId() const {
+ return <xsl:value-of select="$f/@class-id"/>;
+ }
+
+ inline u_int16_t amqpMethodId() const {
+ return <xsl:value-of select="$f/@method-id"/>;
+ }
+
+ inline u_int32_t bodySize() const {
+ <xsl:choose>
+ <xsl:when test="$f/field">
+ return
+ <xsl:for-each select="$f/field">
+ <xsl:if test="position() != 1">+
+ </xsl:if>
+ <xsl:value-of select="amqp:field-length(.)"/>
+ </xsl:for-each>
+ ;
+ </xsl:when>
+ <xsl:otherwise>return 0;</xsl:otherwise>
+ </xsl:choose>
+ }
+
+ <xsl:if test="@server='true'">
+ inline void invoke(AMQP_ServerOperations&amp; target, u_int16_t channel) {
+ <xsl:if test="field">
+ <xsl:value-of select="concat('target.get', amqp:upper-first(parent::class/@name), 'Handler()->', @invocation_name, '(channel, ')"/>
+ <xsl:value-of select="$f/field/@name" separator=", "/>);
+ </xsl:if>
+ <xsl:if test="not(field)">
+ <xsl:value-of select="concat('target.get', amqp:upper-first(parent::class/@name), 'Handler()->', @invocation_name, '(channel)')"/>;
+ </xsl:if>
+ }
+ </xsl:if>
+
+ inline void encodeContent(Buffer&amp; buffer) const
+ {
+ <xsl:if test="$f/field[@type='bit']">
+ u_int8_t flags = 0;
+ <xsl:for-each select="$f/field[@type='bit']">
+ <xsl:value-of select="concat('flags |= ', @name,' &lt;&lt; (', @boolean-index, ' - 1)')"/>;
+ </xsl:for-each>
+ </xsl:if>
+ <xsl:for-each select="$f/field">
+ <xsl:if test="@type != 'bit'">
+ <xsl:value-of select="amqp:encoder(.)"/>;
+ </xsl:if>
+ <xsl:if test="@type = 'bit' and @boolean-index = 1">
+ <xsl:text>buffer.putOctet(flags)</xsl:text>;
+ </xsl:if>
+ </xsl:for-each>
+ }
+
+ inline void decodeContent(Buffer&amp; buffer)
+ {
+ <xsl:if test="$f/field[@type='bit']">
+ u_int8_t maxbit = <xsl:value-of select="$f/@bit-field-count"/>;
+ </xsl:if>
+ <xsl:for-each select="$f/field">
+ <xsl:choose>
+ <xsl:when test="@type = 'bit' and @boolean-index = 1">
+ <xsl:text>u_int8_t flags = buffer.getOctet()</xsl:text>;
+ <xsl:value-of select="amqp:decoder(.)"/>;
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="amqp:decoder(.)"/>;
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ }
+
+ <xsl:if test="$f/field">
+ <!-- only generate overloaded constructor if there are fields in this method -->
+ inline <xsl:value-of select="$f/@name"/>(<xsl:value-of select="$f/field/concat(@cpp-arg-type, ' _', @name)" separator=", "/>) : <xsl:value-of select="$f/field/concat(@name, '(_', @name, ')')" separator=", "/>
+ {
+ }
+ </xsl:if>
+
+ inline <xsl:value-of select="$f/@name"/>()
+ {
+ }
+};
+
+</xsl:template>
+
+<xsl:template match="frames" mode="method-list-header">
+<xsl:result-document href="amqp_methods.h" format="textFormat">
+/**
+ * This file is autogenerated, do not modify.
+ */
+
+#ifndef AMQ_METHODS_H
+#define AMQ_METHODS_H
+
+ <xsl:for-each select="class/frame">
+#include "<xsl:value-of select="@name"/>.h"
+ </xsl:for-each>
+
+namespace qpid {
+namespace framing {
+
+ <xsl:for-each select="class/frame">
+const <xsl:value-of select="concat(@name, ' ', @declaration_name)"/>;
+ </xsl:for-each>
+
+AMQMethodBody* createAMQMethodBody(u_int16_t classId, u_int16_t methodId);
+
+}
+}
+
+#endif
+</xsl:result-document>
+</xsl:template>
+
+<xsl:template match="frames" mode="method-list-source">
+ <xsl:result-document href="amqp_methods.cpp" format="textFormat">
+#include "amqp_methods.h"
+#include "QpidError.h"
+
+namespace qpid {
+namespace framing {
+/**
+ * This method is autogenerated, do not modify.
+ */
+AMQMethodBody* createAMQMethodBody(u_int16_t classId, u_int16_t methodId){
+ switch(classId * 1000 + methodId)
+ {
+ <xsl:for-each select="class/frame">
+ <xsl:text>case </xsl:text>
+ <xsl:value-of select="@class-id"/>
+ <xsl:text> * 1000 + </xsl:text>
+ <xsl:value-of select="@method-id"/>
+ <xsl:text>: return new </xsl:text>
+ <xsl:value-of select="@name"/>();
+ </xsl:for-each>
+ }
+ THROW_QPID_ERROR(FRAMING_ERROR, "Unknown method");
+}
+
+}
+}
+</xsl:result-document>
+</xsl:template>
+
+<xsl:template match="frames" mode="generate-interface">
+ <xsl:result-document href="AMQPServer.h" format="textFormat">
+#include "amqp_types.h"
+#include "FieldTable.h"
+
+#ifndef _AMQPServer_
+#define _AMQPServer_
+
+namespace qpid {
+namespace framing {
+
+class AMQPServer
+{
+ public:
+
+ <xsl:for-each select="class">
+ class <xsl:value-of select="concat(amqp:upper-first(@name), 'Handler')"/>{
+ public:
+ <xsl:for-each select="frame[@server='true']">
+ <xsl:if test="field">
+ virtual void <xsl:value-of select="@invocation_name"/>(u_int16_t channel, <xsl:value-of select="field/concat(@cpp-arg-type, ' ', @name)" separator=", "/>) = 0;
+ </xsl:if>
+ <xsl:if test="not(field)">
+ virtual void <xsl:value-of select="@invocation_name"/>(u_int16_t channel) = 0;
+ </xsl:if>
+ </xsl:for-each>
+ virtual ~<xsl:value-of select="concat(amqp:upper-first(@name), 'Handler')"/>(){}
+ };
+
+ virtual <xsl:value-of select="concat(amqp:upper-first(@name), 'Handler* get', amqp:upper-first(@name), 'Handler')"/>() = 0;
+
+ </xsl:for-each>
+ virtual ~AMQPServer(){}
+};
+
+}
+}
+
+#endif
+</xsl:result-document>
+
+ <xsl:result-document href="AMQPClient.h" format="textFormat">
+#include "amqp_types.h"
+#include "FieldTable.h"
+
+#ifndef _AMQPClient_
+#define _AMQPClient_
+
+namespace qpid {
+namespace framing {
+
+class AMQPClient
+{
+ public:
+
+ <xsl:for-each select="class">
+ class <xsl:value-of select="concat(amqp:upper-first(@name), 'Handler')"/>{
+ public:
+ <xsl:for-each select="frame[@client='true']">
+ <xsl:if test="field">
+ virtual void <xsl:value-of select="@invocation_name"/>(u_int16_t channel, <xsl:value-of select="field/concat(@cpp-arg-type, ' ', @name)" separator=", "/>) = 0;
+ </xsl:if>
+ <xsl:if test="not(field)">
+ virtual void <xsl:value-of select="@invocation_name"/>(u_int16_t channel) = 0;
+ </xsl:if>
+ </xsl:for-each>
+ virtual ~<xsl:value-of select="concat(amqp:upper-first(@name), 'Handler')"/>(){}
+ };
+
+ virtual <xsl:value-of select="concat(amqp:upper-first(@name), 'Handler* get', amqp:upper-first(@name), 'Handler')"/>() = 0;
+
+ </xsl:for-each>
+
+ virtual ~AMQPClient(){}
+};
+
+}
+}
+
+#endif
+</xsl:result-document>
+
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/framing.xsl b/cpp/common/framing/generated/stylesheets/framing.xsl
new file mode 100644
index 0000000000..c63e719a77
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/framing.xsl
@@ -0,0 +1,49 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+<xsl:import href="prepare1.xsl"/>
+<xsl:import href="prepare2.xsl"/>
+<xsl:import href="prepare3.xsl"/>
+<xsl:import href="cpp.xsl"/>
+
+<xsl:output indent="yes"/>
+<xsl:output method="text" indent="yes" name="textFormat"/>
+
+<xsl:template match="/">
+ <xsl:variable name="prepare1">
+ <xsl:apply-templates mode="prepare1" select="."/>
+ </xsl:variable>
+
+ <xsl:variable name="prepare2">
+ <xsl:apply-templates mode="prepare2" select="$prepare1"/>
+ </xsl:variable>
+
+ <xsl:variable name="model">
+ <xsl:apply-templates mode="prepare3" select="$prepare2"/>
+ </xsl:variable>
+
+ <xsl:apply-templates mode="generate-multi" select="$model"/>
+ <xsl:apply-templates mode="method-list-header" select="$model"/>
+ <xsl:apply-templates mode="method-list-source" select="$model"/>
+
+ <!-- these interfaces are now generated by the new scripts from kim -->
+ <!-- e.g. those of the form amqp-server/client-*.xsl -->
+ <!-- xsl:apply-templates mode="generate-interface" select="$model"/ -->
+
+ <!-- dump out the intermediary files for debugging -->
+ <!--
+ <xsl:result-document href="prepare1.out">
+ <xsl:copy-of select="$prepare1"/>
+ </xsl:result-document>
+
+ <xsl:result-document href="prepare2.out">
+ <xsl:copy-of select="$prepare2"/>
+ </xsl:result-document>
+
+ <xsl:result-document href="model.out">
+ <xsl:copy-of select="$model"/>
+ </xsl:result-document>
+ -->
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/prepare1.xsl b/cpp/common/framing/generated/stylesheets/prepare1.xsl
new file mode 100644
index 0000000000..2aeda89677
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/prepare1.xsl
@@ -0,0 +1,104 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+<xsl:import href="utils.xsl"/>
+
+<xsl:output indent="yes"/>
+<xsl:param name="asl_base"/>
+
+<!-- pre-process, phase 1 -->
+
+<xsl:template match="/">
+ <xsl:apply-templates select="protocol" mode="prepare1"/>
+</xsl:template>
+
+<xsl:template match="amqp" mode="prepare1">
+ <frames>
+ <xsl:attribute name="protocol">
+ <xsl:value-of select="@comment"/>
+ <xsl:text> (</xsl:text>
+ <xsl:text>major=</xsl:text><xsl:value-of select="@major"/>
+ <xsl:text>, minor=</xsl:text><xsl:value-of select="@minor"/>
+ <xsl:text>)</xsl:text>
+ </xsl:attribute>
+ <xsl:apply-templates mode="prepare1" select="inherit"/>
+ <xsl:apply-templates mode="prepare1" select="include"/>
+ <xsl:apply-templates mode="prepare1" select="domain"/>
+ <xsl:apply-templates mode="prepare1" select="class"/>
+ </frames>
+</xsl:template>
+
+<xsl:template match="include" mode="prepare1">
+ <xsl:if test="@filename != 'asl_constants.asl'">
+ <!-- skip asl_constants.asl, we don't need it and it is not well formed so causes error warnings -->
+ <xsl:apply-templates select="document(@filename)" mode="prepare1"/>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="inherit" mode="prepare1">
+ <xsl:variable name="ibase" select="concat('file:///', $asl_base, '/', @name, '.asl')"/>
+ <xsl:choose>
+ <xsl:when test="document($ibase)">
+ <xsl:apply-templates select="document($ibase)" mode="prepare1"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message>
+ Could not inherit from <xsl:value-of select="$ibase"/>; file not found.
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="class[@index]" mode="prepare1">
+<xsl:if test="not(@name = 'test')">
+ <class>
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+ <xsl:apply-templates select="method" mode="prepare1"/>
+ </class>
+</xsl:if>
+</xsl:template>
+
+<xsl:template match="method" mode="prepare1">
+ <xsl:if test="parent::class[@index]"><!-- there is a template class that has no index, which we want to skip -->
+ <frame>
+ <xsl:attribute name="name"><xsl:value-of select="amqp:class-name(parent::class/@name, @name)"/></xsl:attribute>
+ <xsl:attribute name="class-id"><xsl:value-of select="parent::class/@index"/></xsl:attribute>
+ <xsl:if test="@index">
+ <xsl:attribute name="method-id"><xsl:value-of select="@index"/></xsl:attribute>
+ </xsl:if>
+ <xsl:if test="not(@index)">
+ <xsl:attribute name="method-id"><xsl:number count="method"/></xsl:attribute>
+ </xsl:if>
+ <xsl:attribute name="invocation_name">
+ <xsl:value-of select="amqp:keyword-check(amqp:field-name(@name))"/>
+ </xsl:attribute>
+ <xsl:attribute name="declaration_name">
+ <xsl:value-of select="amqp:method-name(parent::class/@name, @name)"/>
+ </xsl:attribute>
+ <xsl:if test="chassis[@name='client']">
+ <xsl:attribute name="client">true</xsl:attribute>
+ </xsl:if>
+ <xsl:if test="chassis[@name='server']">
+ <xsl:attribute name="server">true</xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates select="field" mode="prepare1"/>
+ </frame>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="domain" mode="prepare1">
+ <domain>
+ <name><xsl:value-of select="@name"/></name>
+ <type><xsl:value-of select="@type"/></type>
+ </domain>
+</xsl:template>
+
+<xsl:template match="field" mode="prepare1">
+ <field>
+ <xsl:copy-of select="@name"/>
+ <xsl:copy-of select="@type"/>
+ <xsl:copy-of select="@domain"/>
+ </field>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/prepare2.xsl b/cpp/common/framing/generated/stylesheets/prepare2.xsl
new file mode 100644
index 0000000000..331319de57
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/prepare2.xsl
@@ -0,0 +1,54 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+<xsl:import href="utils.xsl"/>
+
+<xsl:output indent="yes"/>
+
+<!-- pre-process, phase 2 -->
+
+<xsl:key name="domain-lookup" match="domain" use="name"/>
+
+<xsl:template match="/">
+ <xsl:apply-templates mode="prepare2" select="frames"/>
+</xsl:template>
+
+<xsl:template match="field[@domain]" mode="prepare2">
+ <field>
+ <xsl:variable name="t1" select="key('domain-lookup', @domain)/type"/>
+ <xsl:attribute name="name"><xsl:value-of select="amqp:field-name(@name)"/></xsl:attribute>
+ <xsl:attribute name="type"><xsl:value-of select="$t1"/></xsl:attribute>
+ </field>
+</xsl:template>
+
+<xsl:template match="field[@type]" mode="prepare2">
+ <field>
+ <xsl:attribute name="name"><xsl:value-of select="amqp:field-name(@name)"/></xsl:attribute>
+ <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute>
+ </field>
+</xsl:template>
+
+<xsl:template match="frames" mode="prepare2">
+ <frames>
+ <xsl:copy-of select="@protocol"/>
+ <xsl:apply-templates mode="prepare2"/>
+ </frames>
+</xsl:template>
+
+<xsl:template match="class" mode="prepare2">
+ <class>
+ <xsl:copy-of select="@*"/>
+ <xsl:apply-templates mode="prepare2"/>
+ </class>
+</xsl:template>
+
+<xsl:template match="frame" mode="prepare2">
+ <xsl:element name="{name()}">
+ <xsl:copy-of select="@*"/>
+ <xsl:apply-templates mode="prepare2" select="field"/>
+ </xsl:element>
+</xsl:template>
+
+<xsl:template match="domain" mode="prepare2"></xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/prepare3.xsl b/cpp/common/framing/generated/stylesheets/prepare3.xsl
new file mode 100644
index 0000000000..27a4764e4f
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/prepare3.xsl
@@ -0,0 +1,54 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+<xsl:import href="utils.xsl"/>
+
+<xsl:output indent="yes"/>
+
+<!-- final preparation of the model -->
+
+<xsl:template match="/">
+ <xsl:apply-templates mode="prepare3"/>
+</xsl:template>
+
+<xsl:template match="frames" mode="prepare3">
+ <frames>
+ <xsl:copy-of select="@protocol"/>
+ <xsl:apply-templates mode="prepare3"/>
+ </frames>
+</xsl:template>
+
+<xsl:template match="class" mode="prepare3">
+ <class>
+ <xsl:copy-of select="@*"/>
+ <xsl:apply-templates mode="prepare3"/>
+ </class>
+</xsl:template>
+
+<xsl:template match="frame" mode="prepare3">
+ <xsl:element name="frame">
+ <xsl:copy-of select="@*"/>
+ <xsl:if test="field[@type='bit']">
+ <xsl:attribute name="has-bit-field">true</xsl:attribute>
+ <xsl:attribute name="bit-field-count"><xsl:value-of select="count(field[@type='bit'])"/></xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates mode="prepare3"/>
+ </xsl:element>
+</xsl:template>
+
+
+<xsl:template match="field" mode="prepare3">
+ <field>
+ <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute>
+ <!-- ensure the field name is processed to be a valid java name -->
+ <xsl:attribute name="name"><xsl:value-of select="amqp:field-name(@name)"/></xsl:attribute>
+ <!-- add some attributes to make code generation easier -->
+ <xsl:attribute name="cpp-type"><xsl:value-of select="amqp:cpp-type(@type)"/></xsl:attribute>
+ <xsl:attribute name="cpp-arg-type"><xsl:value-of select="amqp:cpp-arg-type(@type)"/></xsl:attribute>
+ <xsl:if test="@type='bit'">
+ <xsl:attribute name="boolean-index"><xsl:number count="field[@type='bit']"/></xsl:attribute>
+ </xsl:if>
+ </field>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/registry.xsl b/cpp/common/framing/generated/stylesheets/registry.xsl
new file mode 100644
index 0000000000..a818a0a871
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/registry.xsl
@@ -0,0 +1,12 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+<xsl:import href="java.xsl"/>
+
+<xsl:output method="text" indent="yes" name="textFormat"/>
+
+<xsl:template match="/">
+ <xsl:apply-templates mode="generate-registry" select="registries"/>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/generated/stylesheets/utils.xsl b/cpp/common/framing/generated/stylesheets/utils.xsl
new file mode 100644
index 0000000000..829d38433e
--- /dev/null
+++ b/cpp/common/framing/generated/stylesheets/utils.xsl
@@ -0,0 +1,194 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:amqp="http://amqp.org">
+
+<!-- This file contains functions that are used in the generation of the java classes for framing -->
+
+<!-- retrieve the java type of a given amq type -->
+<xsl:function name="amqp:cpp-type">
+ <xsl:param name="t"/>
+ <xsl:choose>
+ <xsl:when test="$t='octet'">u_int8_t</xsl:when>
+ <xsl:when test="$t='short'">u_int16_t</xsl:when>
+ <xsl:when test="$t='shortstr'">string</xsl:when>
+ <xsl:when test="$t='longstr'">string</xsl:when>
+ <xsl:when test="$t='bit'">bool</xsl:when>
+ <xsl:when test="$t='long'">u_int32_t</xsl:when>
+ <xsl:when test="$t='longlong'">u_int64_t</xsl:when>
+ <xsl:when test="$t='table'">FieldTable</xsl:when>
+ <xsl:otherwise>Object /*WARNING: undefined type*/</xsl:otherwise>
+ </xsl:choose>
+</xsl:function>
+<xsl:function name="amqp:cpp-arg-type">
+ <xsl:param name="t"/>
+ <xsl:choose>
+ <xsl:when test="$t='octet'">u_int8_t</xsl:when>
+ <xsl:when test="$t='short'">u_int16_t</xsl:when>
+ <xsl:when test="$t='shortstr'">string&amp;</xsl:when>
+ <xsl:when test="$t='longstr'">string&amp;</xsl:when>
+ <xsl:when test="$t='bit'">bool</xsl:when>
+ <xsl:when test="$t='long'">u_int32_t</xsl:when>
+ <xsl:when test="$t='longlong'">u_int64_t</xsl:when>
+ <xsl:when test="$t='table'">FieldTable&amp;</xsl:when>
+ <xsl:otherwise>Object /*WARNING: undefined type*/</xsl:otherwise>
+ </xsl:choose>
+</xsl:function>
+
+<!-- retrieve the code to get the field size of a given amq type -->
+<xsl:function name="amqp:field-length">
+ <xsl:param name="f"/>
+ <xsl:choose>
+ <xsl:when test="$f/@type='bit' and $f/@boolean-index=1">
+ <xsl:value-of select="concat('1 /*', $f/@name, '*/')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='bit' and $f/@boolean-index &gt; 1">
+ <xsl:value-of select="concat('0 /*', $f/@name, '*/')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='char'">
+ <xsl:value-of select="concat('1 /*', $f/@name, '*/')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='octet'">
+ <xsl:value-of select="concat('1 /*', $f/@name, '*/')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='short'">
+ <xsl:value-of select="concat('2 /*', $f/@name, '*/')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='long'">
+ <xsl:value-of select="concat('4 /*', $f/@name, '*/')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='longlong'">
+ <xsl:value-of select="concat('8 /*', $f/@name, '*/')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='shortstr'">
+ <xsl:value-of select="concat('1 + ', $f/@name, '.length()')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='longstr'">
+ <xsl:value-of select="concat('4 + ', $f/@name, '.length()')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='table'">
+ <xsl:value-of select="concat($f/@name, '.size()')"/>
+ </xsl:when>
+ <xsl:otherwise><xsl:text>/* WARNING: COULD NOT DETERMINE FIELD SIZE */</xsl:text></xsl:otherwise>
+ </xsl:choose>
+</xsl:function>
+
+<!-- retrieve the code to encode a field of a given amq type -->
+<!-- Note:
+ This method will not provide an encoder for a bit field.
+ Bit fields should be encoded together separately. -->
+
+<xsl:function name="amqp:encoder">
+ <xsl:param name="f"/>
+ <xsl:choose>
+ <xsl:when test="$f/@type='octet'">
+ <xsl:value-of select="concat('buffer.putOctet(', $f/@name, ')')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='short'">
+ <xsl:value-of select="concat('buffer.putShort(', $f/@name, ')')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='long'">
+ <xsl:value-of select="concat('buffer.putLong(', $f/@name, ')')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='longlong'">
+ <xsl:value-of select="concat('buffer.putLongLong(', $f/@name, ')')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='shortstr'">
+ <xsl:value-of select="concat('buffer.putShortString(', $f/@name, ')')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='longstr'">
+ <xsl:value-of select="concat('buffer.putLongString(', $f/@name, ')')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='table'">
+ <xsl:value-of select="concat('buffer.putFieldTable(', $f/@name, ')')"/>
+ </xsl:when>
+ <xsl:otherwise><xsl:text>/* WARNING: COULD NOT DETERMINE ENCODER */</xsl:text></xsl:otherwise>
+ </xsl:choose>
+</xsl:function>
+
+<!-- retrieve the code to decode a field of a given amq type -->
+<xsl:function name="amqp:decoder">
+ <xsl:param name="f"/>
+ <xsl:choose>
+ <xsl:when test="$f/@type='bit'">
+ <xsl:value-of select="concat($f/@name, ' = (1 &lt;&lt; (', $f/@boolean-index, ' - 1)) &amp; flags;')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='octet'">
+ <xsl:value-of select="concat($f/@name, ' = buffer.getOctet()')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='short'">
+ <xsl:value-of select="concat($f/@name, ' = buffer.getShort()')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='long'">
+ <xsl:value-of select="concat($f/@name, ' = buffer.getLong()')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='longlong'">
+ <xsl:value-of select="concat($f/@name, ' = buffer.getLongLong()')"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='shortstr'">
+ <xsl:value-of select="concat('buffer.getShortString(', $f/@name), ')'"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='longstr'">
+ <xsl:value-of select="concat('buffer.getLongString(', $f/@name), ')'"/>
+ </xsl:when>
+ <xsl:when test="$f/@type='table'">
+ <xsl:value-of select="concat('buffer.getFieldTable(', $f/@name, ')')"/>
+ </xsl:when>
+ <xsl:otherwise><xsl:text>/* WARNING: COULD NOT DETERMINE DECODER */</xsl:text></xsl:otherwise>
+ </xsl:choose>
+</xsl:function>
+
+<!-- create the class name for a frame, based on class and method (passed in) -->
+<xsl:function name="amqp:class-name">
+ <xsl:param name="class"/>
+ <xsl:param name="method"/>
+ <xsl:value-of select="concat(amqp:upper-first($class),amqp:upper-first(amqp:field-name($method)), 'Body')"/>
+</xsl:function>
+
+<!-- create the class name for a frame, based on class and method (passed in) -->
+<xsl:function name="amqp:method-name">
+ <xsl:param name="class"/>
+ <xsl:param name="method"/>
+ <xsl:value-of select="concat(translate($class, '- ', '__'), '_', translate($method, '- ', '__'))"/>
+</xsl:function>
+
+<!-- get a valid field name, processing spaces and '-'s where appropriate -->
+<xsl:function name="amqp:field-name">
+ <xsl:param name="name"/>
+ <xsl:choose>
+ <xsl:when test="contains($name, ' ')">
+ <xsl:value-of select="concat(substring-before($name, ' '), amqp:upper-first(substring-after($name, ' ')))"/>
+ </xsl:when>
+ <xsl:when test="contains($name, '-')">
+ <xsl:value-of select="concat(substring-before($name, '-'), amqp:upper-first(substring-after($name, '-')))"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:function>
+
+<!-- convert the first character of the input to upper-case -->
+<xsl:function name="amqp:upper-first">
+ <xsl:param name="in"/>
+ <xsl:value-of select="concat(upper-case(substring($in, 1, 1)), substring($in, 2))"/>
+</xsl:function>
+
+
+<xsl:function name="amqp:keyword-check">
+ <xsl:param name="in"/>
+ <xsl:choose>
+ <xsl:when test="contains($in, 'delete')">
+ <xsl:value-of select="concat($in, '_')"/>
+ </xsl:when>
+ <xsl:when test="contains($in, 'string')">
+ <xsl:value-of select="concat($in, '_')"/>
+ </xsl:when>
+ <xsl:when test="contains($in, 'return')">
+ <xsl:value-of select="concat($in, '_')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$in"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:function>
+
+</xsl:stylesheet>
diff --git a/cpp/common/framing/inc/AMQBody.h b/cpp/common/framing/inc/AMQBody.h
new file mode 100644
index 0000000000..d4b436c949
--- /dev/null
+++ b/cpp/common/framing/inc/AMQBody.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * 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.h"
+#include "amqp_types.h"
+#include "Buffer.h"
+
+#ifndef _AMQBody_
+#define _AMQBody_
+
+namespace qpid {
+ namespace framing {
+
+ class AMQBody
+ {
+ public:
+ typedef std::tr1::shared_ptr<AMQBody> shared_ptr;
+
+ virtual u_int32_t size() const = 0;
+ virtual u_int8_t type() const = 0;
+ virtual void encode(Buffer& buffer) const = 0;
+ virtual void decode(Buffer& buffer, u_int32_t size) = 0;
+ inline virtual ~AMQBody(){}
+ };
+
+ enum body_types {METHOD_BODY = 1, HEADER_BODY = 2, CONTENT_BODY = 3, HEARTBEAT_BODY = 8};
+
+ }
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/AMQContentBody.h b/cpp/common/framing/inc/AMQContentBody.h
new file mode 100644
index 0000000000..8e97c31edb
--- /dev/null
+++ b/cpp/common/framing/inc/AMQContentBody.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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_types.h"
+#include "AMQBody.h"
+#include "Buffer.h"
+
+#ifndef _AMQContentBody_
+#define _AMQContentBody_
+
+namespace qpid {
+namespace framing {
+
+class AMQContentBody : virtual public AMQBody
+{
+ string data;
+
+public:
+ typedef std::tr1::shared_ptr<AMQContentBody> shared_ptr;
+
+ AMQContentBody();
+ AMQContentBody(string& data);
+ inline virtual ~AMQContentBody(){}
+ inline u_int8_t type() const { return CONTENT_BODY; };
+ inline string& getData(){ return data; }
+ u_int32_t size() const;
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer, u_int32_t size);
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/AMQDataBlock.h b/cpp/common/framing/inc/AMQDataBlock.h
new file mode 100644
index 0000000000..6c47c78864
--- /dev/null
+++ b/cpp/common/framing/inc/AMQDataBlock.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * 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 "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 u_int32_t size() const = 0;
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/AMQFrame.h b/cpp/common/framing/inc/AMQFrame.h
new file mode 100644
index 0000000000..5656d20377
--- /dev/null
+++ b/cpp/common/framing/inc/AMQFrame.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * 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_methods.h"
+#include "amqp_types.h"
+#include "AMQBody.h"
+#include "AMQDataBlock.h"
+#include "AMQMethodBody.h"
+#include "AMQHeaderBody.h"
+#include "AMQContentBody.h"
+#include "AMQHeartbeatBody.h"
+#include "Buffer.h"
+
+#ifndef _AMQFrame_
+#define _AMQFrame_
+
+namespace qpid {
+ namespace framing {
+
+ class AMQFrame : virtual public AMQDataBlock
+ {
+ u_int16_t channel;
+ u_int8_t type;//used if the body is decoded separately from the 'head'
+ AMQBody::shared_ptr body;
+
+ public:
+ AMQFrame();
+ AMQFrame(u_int16_t channel, AMQBody* body);
+ AMQFrame(u_int16_t channel, AMQBody::shared_ptr& body);
+ virtual ~AMQFrame();
+ virtual void encode(Buffer& buffer);
+ virtual bool decode(Buffer& buffer);
+ virtual u_int32_t size() const;
+ u_int16_t getChannel();
+ AMQBody::shared_ptr& getBody();
+
+ u_int32_t decodeHead(Buffer& buffer);
+ void decodeBody(Buffer& buffer, uint32_t size);
+
+ friend std::ostream& operator<<(std::ostream& out, const AMQFrame& body);
+ };
+
+ }
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/AMQHeaderBody.h b/cpp/common/framing/inc/AMQHeaderBody.h
new file mode 100644
index 0000000000..369db8a9c8
--- /dev/null
+++ b/cpp/common/framing/inc/AMQHeaderBody.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * 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_types.h"
+#include "AMQBody.h"
+#include "Buffer.h"
+#include "HeaderProperties.h"
+
+#ifndef _AMQHeaderBody_
+#define _AMQHeaderBody_
+
+namespace qpid {
+namespace framing {
+
+class AMQHeaderBody : virtual public AMQBody
+{
+ HeaderProperties* properties;
+ u_int16_t weight;
+ u_int64_t contentSize;
+
+ void createProperties(int classId);
+public:
+ typedef std::tr1::shared_ptr<AMQHeaderBody> shared_ptr;
+
+ AMQHeaderBody(int classId);
+ AMQHeaderBody();
+ inline u_int8_t type() const { return HEADER_BODY; }
+ HeaderProperties* getProperties(){ return properties; }
+ inline u_int64_t getContentSize() const { return contentSize; }
+ inline void setContentSize(u_int64_t size) { contentSize = size; }
+ virtual ~AMQHeaderBody();
+ virtual u_int32_t size() const;
+ virtual void encode(Buffer& buffer) const;
+ virtual void decode(Buffer& buffer, u_int32_t size);
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/AMQHeartbeatBody.h b/cpp/common/framing/inc/AMQHeartbeatBody.h
new file mode 100644
index 0000000000..ca2def977a
--- /dev/null
+++ b/cpp/common/framing/inc/AMQHeartbeatBody.h
@@ -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 "amqp_types.h"
+#include "AMQBody.h"
+#include "Buffer.h"
+
+#ifndef _AMQHeartbeatBody_
+#define _AMQHeartbeatBody_
+
+namespace qpid {
+namespace framing {
+
+class AMQHeartbeatBody : virtual public AMQBody
+{
+public:
+ typedef std::tr1::shared_ptr<AMQHeartbeatBody> shared_ptr;
+
+ virtual ~AMQHeartbeatBody() {}
+ inline u_int32_t size() const { return 0; }
+ inline u_int8_t type() const { return HEARTBEAT_BODY; }
+ inline void encode(Buffer& buffer) const {}
+ inline void decode(Buffer& buffer, u_int32_t size) {}
+};
+
+}
+}
+
+#endif
diff --git a/cpp/common/framing/inc/AMQMethodBody.h b/cpp/common/framing/inc/AMQMethodBody.h
new file mode 100644
index 0000000000..59d5dd5212
--- /dev/null
+++ b/cpp/common/framing/inc/AMQMethodBody.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * 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 "amqp_types.h"
+#include "AMQBody.h"
+#include "Buffer.h"
+#include "AMQP_ServerOperations.h"
+
+#ifndef _AMQMethodBody_
+#define _AMQMethodBody_
+
+namespace qpid {
+namespace framing {
+
+class AMQMethodBody : virtual public AMQBody
+{
+public:
+ typedef std::tr1::shared_ptr<AMQMethodBody> shared_ptr;
+
+ inline u_int8_t type() const { return METHOD_BODY; }
+ inline u_int32_t size() const { return 4 + bodySize(); }
+ inline virtual ~AMQMethodBody(){}
+ virtual void print(std::ostream& out) const = 0;
+ virtual u_int16_t amqpMethodId() const = 0;
+ virtual u_int16_t amqpClassId() const = 0;
+ virtual void invoke(AMQP_ServerOperations& target, u_int16_t channel);
+ virtual void encodeContent(Buffer& buffer) const = 0;
+ virtual void decodeContent(Buffer& buffer) = 0;
+ virtual u_int32_t bodySize() const = 0;
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer, u_int32_t size);
+ bool match(AMQMethodBody* other) const;
+};
+
+std::ostream& operator<<(std::ostream& out, const AMQMethodBody& body);
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/BasicHeaderProperties.h b/cpp/common/framing/inc/BasicHeaderProperties.h
new file mode 100644
index 0000000000..8688a37bf9
--- /dev/null
+++ b/cpp/common/framing/inc/BasicHeaderProperties.h
@@ -0,0 +1,93 @@
+/*
+ *
+ * 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_types.h"
+#include "amqp_methods.h"
+#include "Buffer.h"
+#include "HeaderProperties.h"
+
+#ifndef _BasicHeaderProperties_
+#define _BasicHeaderProperties_
+
+namespace qpid {
+namespace framing {
+
+ //TODO: This could be easily generated from the spec
+ class BasicHeaderProperties : public HeaderProperties
+ {
+ string contentType;
+ string contentEncoding;
+ FieldTable headers;
+ u_int8_t deliveryMode;
+ u_int8_t priority;
+ string correlationId;
+ string replyTo;
+ string expiration;
+ string messageId;
+ u_int64_t timestamp;
+ string type;
+ string userId;
+ string appId;
+ string clusterId;
+
+ u_int16_t getFlags() const;
+
+ public:
+ BasicHeaderProperties();
+ virtual ~BasicHeaderProperties();
+ virtual u_int32_t size() const;
+ virtual void encode(Buffer& buffer) const;
+ virtual void decode(Buffer& buffer, u_int32_t size);
+
+ inline virtual u_int8_t classId(){ return BASIC; }
+
+ inline string& getContentType(){ return contentType; }
+ inline string& getContentEncoding(){ return contentEncoding; }
+ inline FieldTable& getHeaders(){ return headers; }
+ inline u_int8_t getDeliveryMode(){ return deliveryMode; }
+ inline u_int8_t getPriority(){ return priority; }
+ inline string& getCorrelationId(){return correlationId; }
+ inline string& getReplyTo(){ return replyTo; }
+ inline string& getExpiration(){ return expiration; }
+ inline string& getMessageId(){return messageId; }
+ inline u_int64_t getTimestamp(){ return timestamp; }
+ inline string& getType(){ return type; }
+ inline string& getUserId(){ return userId; }
+ inline string& getAppId(){ return appId; }
+ inline string& getClusterId(){ return clusterId; }
+
+ void inline setContentType(string& type){ contentType = type; }
+ void inline setContentEncoding(string& encoding){ contentEncoding = encoding; }
+ void inline setHeaders(FieldTable& headers){ this->headers = headers; }
+ void inline setDeliveryMode(u_int8_t mode){ deliveryMode = mode; }
+ void inline setPriority(u_int8_t priority){ this->priority = priority; }
+ void inline setCorrelationId(string& correlationId){ this->correlationId = correlationId; }
+ void inline setReplyTo(string& replyTo){ this->replyTo = replyTo;}
+ void inline setExpiration(string& expiration){ this->expiration = expiration; }
+ void inline setMessageId(string& messageId){ this->messageId = messageId; }
+ void inline setTimestamp(u_int64_t timestamp){ this->timestamp = timestamp; }
+ void inline setType(string& type){ this->type = type; }
+ void inline setUserId(string& userId){ this->userId = userId; }
+ void inline setAppId(string& appId){this->appId = appId; }
+ void inline setClusterId(string& clusterId){ this->clusterId = clusterId; }
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/BodyHandler.h b/cpp/common/framing/inc/BodyHandler.h
new file mode 100644
index 0000000000..f92ae66804
--- /dev/null
+++ b/cpp/common/framing/inc/BodyHandler.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * 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>
+
+#ifndef _BodyHandler_
+#define _BodyHandler_
+
+#include "AMQMethodBody.h"
+#include "AMQHeaderBody.h"
+#include "AMQContentBody.h"
+#include "AMQHeartbeatBody.h"
+
+namespace qpid {
+namespace framing {
+
+ class BodyHandler{
+ public:
+ virtual void handleMethod(AMQMethodBody::shared_ptr body) = 0;
+ virtual void handleHeader(AMQHeaderBody::shared_ptr body) = 0;
+ virtual void handleContent(AMQContentBody::shared_ptr body) = 0;
+ virtual void handleHeartbeat(AMQHeartbeatBody::shared_ptr body) = 0;
+
+ void handleBody(AMQBody::shared_ptr& body);
+ };
+
+ class UnknownBodyType{
+ public:
+ const u_int16_t type;
+ inline UnknownBodyType(u_int16_t _type) : type(_type){}
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/Buffer.h b/cpp/common/framing/inc/Buffer.h
new file mode 100644
index 0000000000..1ff4611f1f
--- /dev/null
+++ b/cpp/common/framing/inc/Buffer.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * 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_types.h"
+#include "FieldTable.h"
+
+#ifndef _Buffer_
+#define _Buffer_
+
+namespace qpid {
+namespace framing {
+
+class Buffer
+{
+ const int size;
+ char* data;
+ int position;
+ int limit;
+ int r_position;
+ int r_limit;
+
+public:
+
+ Buffer(int size);
+ ~Buffer();
+
+ void flip();
+ void clear();
+ void compact();
+ void record();
+ void restore();
+ int available();
+ char* start();
+ void move(int bytes);
+
+ void putOctet(u_int8_t i);
+ void putShort(u_int16_t i);
+ void putLong(u_int32_t i);
+ void putLongLong(u_int64_t i);
+
+ u_int8_t getOctet();
+ u_int16_t getShort();
+ u_int32_t getLong();
+ u_int64_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 putRawData(const string& s);
+ void getRawData(string& s, u_int32_t size);
+
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/FieldTable.h b/cpp/common/framing/inc/FieldTable.h
new file mode 100644
index 0000000000..cf935d3284
--- /dev/null
+++ b/cpp/common/framing/inc/FieldTable.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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 <vector>
+#include "amqp_types.h"
+
+#ifndef _FieldTable_
+#define _FieldTable_
+
+namespace qpid {
+namespace framing {
+
+ class NamedValue;
+ class Value;
+ class Buffer;
+
+ class FieldTable
+ {
+ std::vector<NamedValue*> values;
+ NamedValue* find(const std::string& name) const;
+
+ Value* getValue(const std::string& name) const;
+ void setValue(const std::string& name, Value* value);
+
+ public:
+ ~FieldTable();
+ u_int32_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, u_int64_t value);
+ void setTable(const std::string& name, const FieldTable& value);
+ //void setDecimal(string& name, xxx& value);
+ std::string getString(const std::string& name);
+ int getInt(const std::string& name);
+ u_int64_t getTimestamp(const std::string& name);
+ void getTable(const std::string& name, FieldTable& value);
+ //void getDecimal(string& name, xxx& value);
+
+ void encode(Buffer& buffer) const;
+ void decode(Buffer& buffer);
+
+ friend std::ostream& operator<<(std::ostream& out, const FieldTable& body);
+ };
+
+ class FieldNotFoundException{};
+ class UnknownFieldName : public FieldNotFoundException{};
+ class IncorrectFieldType : public FieldNotFoundException{};
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/HeaderProperties.h b/cpp/common/framing/inc/HeaderProperties.h
new file mode 100644
index 0000000000..f84345c203
--- /dev/null
+++ b/cpp/common/framing/inc/HeaderProperties.h
@@ -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 "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 u_int8_t classId() = 0;
+ virtual u_int32_t size() const = 0;
+ virtual void encode(Buffer& buffer) const = 0;
+ virtual void decode(Buffer& buffer, u_int32_t size) = 0;
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/InitiationHandler.h b/cpp/common/framing/inc/InitiationHandler.h
new file mode 100644
index 0000000000..2e8d1e652b
--- /dev/null
+++ b/cpp/common/framing/inc/InitiationHandler.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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>
+
+#ifndef _InitiationHandler_
+#define _InitiationHandler_
+
+#include "ProtocolInitiation.h"
+
+namespace qpid {
+namespace framing {
+
+ class InitiationHandler{
+ public:
+ virtual void initiated(ProtocolInitiation* header) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/InputHandler.h b/cpp/common/framing/inc/InputHandler.h
new file mode 100644
index 0000000000..2722cae0ed
--- /dev/null
+++ b/cpp/common/framing/inc/InputHandler.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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>
+
+#ifndef _InputHandler_
+#define _InputHandler_
+
+#include "AMQFrame.h"
+
+namespace qpid {
+namespace framing {
+
+ class InputHandler{
+ public:
+ virtual void received(AMQFrame* frame) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/NamedValue.h b/cpp/common/framing/inc/NamedValue.h
new file mode 100644
index 0000000000..729b5d08a7
--- /dev/null
+++ b/cpp/common/framing/inc/NamedValue.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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 <vector>
+#include "amqp_types.h"
+#include "Value.h"
+
+#ifndef _NamedValue_
+#define _NamedValue_
+
+namespace qpid {
+namespace framing {
+
+ class Buffer;
+
+ class NamedValue{
+ string name;
+ Value* value;
+ public:
+ NamedValue();
+ NamedValue(const string& name, Value* value);
+ ~NamedValue();
+ void encode(Buffer& buffer);
+ void decode(Buffer& buffer);
+ u_int32_t size() const;
+ inline const string& getName() const { return name; }
+ inline Value* getValue() const { return value; }
+ inline void setValue(Value* val) { value = val; }
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/OutputHandler.h b/cpp/common/framing/inc/OutputHandler.h
new file mode 100644
index 0000000000..7fe63660c3
--- /dev/null
+++ b/cpp/common/framing/inc/OutputHandler.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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>
+
+#ifndef _OutputHandler_
+#define _OutputHandler_
+
+#include "AMQFrame.h"
+
+namespace qpid {
+namespace framing {
+
+ class OutputHandler{
+ public:
+ virtual void send(AMQFrame* frame) = 0;
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/ProtocolInitiation.h b/cpp/common/framing/inc/ProtocolInitiation.h
new file mode 100644
index 0000000000..ab9734e6b3
--- /dev/null
+++ b/cpp/common/framing/inc/ProtocolInitiation.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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_types.h"
+#include "Buffer.h"
+#include "AMQDataBlock.h"
+
+#ifndef _ProtocolInitiation_
+#define _ProtocolInitiation_
+
+namespace qpid {
+namespace framing {
+
+class ProtocolInitiation : virtual public AMQDataBlock
+{
+ u_int8_t pmajor;
+ u_int8_t pminor;
+
+public:
+ ProtocolInitiation();
+ ProtocolInitiation(u_int8_t major, u_int8_t minor);
+ virtual ~ProtocolInitiation();
+ virtual void encode(Buffer& buffer);
+ virtual bool decode(Buffer& buffer);
+ inline virtual u_int32_t size() const { return 8; }
+ inline u_int8_t getMajor(){ return pmajor; }
+ inline u_int8_t getMinor(){ return pminor; }
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/Value.h b/cpp/common/framing/inc/Value.h
new file mode 100644
index 0000000000..e3d2a2c1d6
--- /dev/null
+++ b/cpp/common/framing/inc/Value.h
@@ -0,0 +1,109 @@
+/*
+ *
+ * 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 <vector>
+#include "amqp_types.h"
+#include "FieldTable.h"
+
+#ifndef _Value_
+#define _Value_
+
+namespace qpid {
+namespace framing {
+
+ class Buffer;
+
+ class Value{
+ public:
+ inline virtual ~Value(){}
+ virtual u_int32_t size() const = 0;
+ virtual char getType() const = 0;
+ virtual void encode(Buffer& buffer) = 0;
+ virtual void decode(Buffer& buffer) = 0;
+ };
+
+ class StringValue : public virtual Value{
+ string value;
+
+ public:
+ inline StringValue(const string& v) : value(v){}
+ inline StringValue(){}
+ inline string getValue(){ return value; }
+ ~StringValue(){}
+ inline virtual u_int32_t size() const { return 4 + value.length(); }
+ inline virtual char getType() const { return 'S'; }
+ virtual void encode(Buffer& buffer);
+ virtual void decode(Buffer& buffer);
+ };
+
+ class IntegerValue : public virtual Value{
+ int value;
+ public:
+ inline IntegerValue(int v) : value(v){}
+ inline IntegerValue(){}
+ inline int getValue(){ return value; }
+ ~IntegerValue(){}
+ inline virtual u_int32_t size() const { return 4; }
+ inline virtual char getType() const { return 'I'; }
+ virtual void encode(Buffer& buffer);
+ virtual void decode(Buffer& buffer);
+ };
+
+ class TimeValue : public virtual Value{
+ u_int64_t value;
+ public:
+ inline TimeValue(int v) : value(v){}
+ inline TimeValue(){}
+ inline u_int64_t getValue(){ return value; }
+ ~TimeValue(){}
+ inline virtual u_int32_t size() const { return 8; }
+ inline virtual char getType() const { return 'T'; }
+ virtual void encode(Buffer& buffer);
+ virtual void decode(Buffer& buffer);
+ };
+
+ class DecimalValue : public virtual Value{
+ u_int8_t decimals;
+ u_int32_t value;
+ public:
+ inline DecimalValue(int v) : value(v){}
+ inline DecimalValue(){}
+ ~DecimalValue(){}
+ inline virtual u_int32_t size() const { return 5; }
+ inline virtual char getType() const { return 'D'; }
+ virtual void encode(Buffer& buffer);
+ virtual void decode(Buffer& buffer);
+ };
+
+ class FieldTableValue : public virtual Value{
+ FieldTable value;
+ public:
+ inline FieldTableValue(const FieldTable& v) : value(v){}
+ inline FieldTableValue(){}
+ inline FieldTable getValue(){ return value; }
+ ~FieldTableValue(){}
+ inline virtual u_int32_t size() const { return 4 + value.size(); }
+ inline virtual char getType() const { return 'F'; }
+ virtual void encode(Buffer& buffer);
+ virtual void decode(Buffer& buffer);
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/common/framing/inc/amqp_framing.h b/cpp/common/framing/inc/amqp_framing.h
new file mode 100644
index 0000000000..adb0045ee5
--- /dev/null
+++ b/cpp/common/framing/inc/amqp_framing.h
@@ -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 "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_methods.h"
+#include "InputHandler.h"
+#include "OutputHandler.h"
+#include "InitiationHandler.h"
+#include "ProtocolInitiation.h"
+#include "BasicHeaderProperties.h"
diff --git a/cpp/common/framing/inc/amqp_types.h b/cpp/common/framing/inc/amqp_types.h
new file mode 100644
index 0000000000..6f8ef0862a
--- /dev/null
+++ b/cpp/common/framing/inc/amqp_types.h
@@ -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 <string>
+#ifdef _WINDOWS
+#include "windows.h"
+typedef unsigned char u_int8_t;
+typedef unsigned short u_int16_t;
+typedef unsigned int u_int32_t;
+typedef unsigned __int64 u_int64_t;
+#endif
+#ifndef _WINDOWS
+#include "sys/types.h"
+#endif
+
+#ifndef AMQP_TYPES_H
+#define AMQP_TYPES_H
+
+
+typedef std::string string;
+
+#endif
diff --git a/cpp/common/framing/src/AMQContentBody.cpp b/cpp/common/framing/src/AMQContentBody.cpp
new file mode 100644
index 0000000000..c8aadc8108
--- /dev/null
+++ b/cpp/common/framing/src/AMQContentBody.cpp
@@ -0,0 +1,35 @@
+/*
+ *
+ * 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 "AMQContentBody.h"
+
+qpid::framing::AMQContentBody::AMQContentBody(){
+}
+
+qpid::framing::AMQContentBody::AMQContentBody(string& _data) : data(_data){
+}
+
+u_int32_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, u_int32_t size){
+ buffer.getRawData(data, size);
+}
+
diff --git a/cpp/common/framing/src/AMQFrame.cpp b/cpp/common/framing/src/AMQFrame.cpp
new file mode 100644
index 0000000000..70f71010ff
--- /dev/null
+++ b/cpp/common/framing/src/AMQFrame.cpp
@@ -0,0 +1,147 @@
+/*
+ *
+ * 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 "QpidError.h"
+
+using namespace qpid::framing;
+
+AMQFrame::AMQFrame(){}
+
+AMQFrame::AMQFrame(u_int16_t _channel, AMQBody* _body) : channel(_channel), body(_body){}
+
+AMQFrame::AMQFrame(u_int16_t _channel, AMQBody::shared_ptr& _body) : channel(_channel), body(_body){}
+
+AMQFrame::~AMQFrame(){
+}
+
+u_int16_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);
+}
+
+AMQBody::shared_ptr createMethodBody(Buffer& buffer){
+ u_int16_t classId = buffer.getShort();
+ u_int16_t methodId = buffer.getShort();
+ AMQBody::shared_ptr body(createAMQMethodBody(classId, methodId));
+ return body;
+}
+
+u_int32_t AMQFrame::size() const{
+ if(!body.get()) THROW_QPID_ERROR(INTERNAL_ERROR, "Attempt to get size of frame with no body set!");
+ 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();
+ u_int8_t type = buffer.getOctet();
+ channel = buffer.getShort();
+ u_int32_t size = buffer.getLong();
+ if(buffer.available() < size + 1){
+ buffer.restore();
+ return false;
+ }
+ switch(type)
+ {
+ case METHOD_BODY:
+ body = createMethodBody(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:
+ string msg("Unknown body type: ");
+ msg += type;
+ THROW_QPID_ERROR(FRAMING_ERROR, msg);
+ }
+ body->decode(buffer, size);
+ u_int8_t end = buffer.getOctet();
+ if(end != 0xCE) THROW_QPID_ERROR(FRAMING_ERROR, "Frame end not found");
+ return true;
+}
+
+u_int32_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 = createMethodBody(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:
+ string msg("Unknown body type: ");
+ msg += type;
+ THROW_QPID_ERROR(FRAMING_ERROR, msg);
+ }
+ body->decode(buffer, size);
+}
+
+std::ostream& qpid::framing::operator<<(std::ostream& out, const AMQFrame& t){
+ out << "Frame[channel=" << t.channel << "; ";
+ if(t.body.get() == 0){
+ out << "empty";
+ }else if(t.body->type() == METHOD_BODY){
+ (dynamic_cast<AMQMethodBody*>(t.body.get()))->print(out);
+ }else if(t.body->type() == HEADER_BODY){
+ out << "header, content_size=" <<
+ (dynamic_cast<AMQHeaderBody*>(t.body.get()))->getContentSize()
+ << " (" << t.body->size() << " bytes)";
+ }else if(t.body->type() == CONTENT_BODY){
+ out << "content (" << t.body->size() << " bytes)";
+ }else if(t.body->type() == HEARTBEAT_BODY){
+ out << "heartbeat";
+ }else{
+ out << "unknown type, " << t.body->type();
+ }
+ out << "]";
+ return out;
+}
+
diff --git a/cpp/common/framing/src/AMQHeaderBody.cpp b/cpp/common/framing/src/AMQHeaderBody.cpp
new file mode 100644
index 0000000000..4bf1626a8a
--- /dev/null
+++ b/cpp/common/framing/src/AMQHeaderBody.cpp
@@ -0,0 +1,60 @@
+/*
+ *
+ * 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 "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;
+}
+
+u_int32_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, u_int32_t size){
+ u_int16_t classId = buffer.getShort();
+ weight = buffer.getShort();
+ contentSize = buffer.getLongLong();
+ createProperties(classId);
+ properties->decode(buffer, size - 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");
+ }
+}
diff --git a/cpp/common/framing/src/AMQMethodBody.cpp b/cpp/common/framing/src/AMQMethodBody.cpp
new file mode 100644
index 0000000000..73862bb2bf
--- /dev/null
+++ b/cpp/common/framing/src/AMQMethodBody.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 "AMQMethodBody.h"
+#include "QpidError.h"
+
+void qpid::framing::AMQMethodBody::encode(Buffer& buffer) const{
+ buffer.putShort(amqpClassId());
+ buffer.putShort(amqpMethodId());
+ encodeContent(buffer);
+}
+
+void qpid::framing::AMQMethodBody::decode(Buffer& buffer, u_int32_t size){
+ decodeContent(buffer);
+}
+
+bool qpid::framing::AMQMethodBody::match(AMQMethodBody* other) const{
+ return other != 0 && other->amqpClassId() == amqpClassId() && other->amqpMethodId() == amqpMethodId();
+}
+
+void qpid::framing::AMQMethodBody::invoke(AMQP_ServerOperations& target, u_int16_t channel){
+ THROW_QPID_ERROR(PROTOCOL_ERROR, "Method not supported by AMQP Server.");
+}
+
+
+std::ostream& qpid::framing::operator<<(std::ostream& out, const AMQMethodBody& m){
+ m.print(out);
+ return out;
+}
diff --git a/cpp/common/framing/src/BasicHeaderProperties.cpp b/cpp/common/framing/src/BasicHeaderProperties.cpp
new file mode 100644
index 0000000000..4219d33a8f
--- /dev/null
+++ b/cpp/common/framing/src/BasicHeaderProperties.cpp
@@ -0,0 +1,102 @@
+/*
+ *
+ * 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 "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(){}
+
+u_int32_t qpid::framing::BasicHeaderProperties::size() const{
+ u_int32_t size = 2;//flags
+ if(contentType.length() > 0) size += contentType.length() + 1;
+ if(contentEncoding.length() > 0) size += contentEncoding.length() + 1;
+ if(headers.count() > 0) size += headers.size();
+ if(deliveryMode != 0) size += 1;
+ if(priority != 0) size += 1;
+ if(correlationId.length() > 0) size += correlationId.length() + 1;
+ if(replyTo.length() > 0) size += replyTo.length() + 1;
+ if(expiration.length() > 0) size += expiration.length() + 1;
+ if(messageId.length() > 0) size += messageId.length() + 1;
+ if(timestamp != 0) size += 8;
+ if(type.length() > 0) size += type.length() + 1;
+ if(userId.length() > 0) size += userId.length() + 1;
+ if(appId.length() > 0) size += appId.length() + 1;
+ if(clusterId.length() > 0) size += clusterId.length() + 1;
+
+ return size;
+}
+
+void qpid::framing::BasicHeaderProperties::encode(qpid::framing::Buffer& buffer) const{
+ u_int16_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, u_int32_t size){
+ u_int16_t flags = buffer.getShort();
+ int shift = 15;
+ 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);
+}
+
+u_int16_t qpid::framing::BasicHeaderProperties::getFlags() const{
+ u_int16_t flags(0);
+ int shift = 15;
+ 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/common/framing/src/BodyHandler.cpp b/cpp/common/framing/src/BodyHandler.cpp
new file mode 100644
index 0000000000..4e4e2e02f7
--- /dev/null
+++ b/cpp/common/framing/src/BodyHandler.cpp
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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.h"
+#include "BodyHandler.h"
+
+using namespace qpid::framing;
+using namespace std::tr1;
+
+void BodyHandler::handleBody(AMQBody::shared_ptr& body){
+
+ switch(body->type())
+ {
+
+ case METHOD_BODY:
+ handleMethod(dynamic_pointer_cast<AMQMethodBody, AMQBody>(body));
+ break;
+
+ case HEADER_BODY:
+ handleHeader(dynamic_pointer_cast<AMQHeaderBody, AMQBody>(body));
+ break;
+
+ case CONTENT_BODY:
+ handleContent(dynamic_pointer_cast<AMQContentBody, AMQBody>(body));
+ break;
+
+ case HEARTBEAT_BODY:
+ handleHeartbeat(dynamic_pointer_cast<AMQHeartbeatBody, AMQBody>(body));
+ break;
+
+ default:
+ throw UnknownBodyType(body->type());
+ }
+
+}
diff --git a/cpp/common/framing/src/Buffer.cpp b/cpp/common/framing/src/Buffer.cpp
new file mode 100644
index 0000000000..5264491980
--- /dev/null
+++ b/cpp/common/framing/src/Buffer.cpp
@@ -0,0 +1,167 @@
+/*
+ *
+ * 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 "Buffer.h"
+
+qpid::framing::Buffer::Buffer(int _size) : size(_size), position(0), limit(_size){
+ data = new char[size];
+}
+
+qpid::framing::Buffer::~Buffer(){
+ 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(){
+ int 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;
+}
+
+int qpid::framing::Buffer::available(){
+ return limit - position;
+}
+
+char* qpid::framing::Buffer::start(){
+ return data + position;
+}
+
+void qpid::framing::Buffer::move(int bytes){
+ position += bytes;
+}
+
+void qpid::framing::Buffer::putOctet(u_int8_t i){
+ data[position++] = i;
+}
+
+void qpid::framing::Buffer::putShort(u_int16_t i){
+ u_int16_t b = i;
+ data[position++] = (u_int8_t) (0xFF & (b >> 8));
+ data[position++] = (u_int8_t) (0xFF & b);
+}
+
+void qpid::framing::Buffer::putLong(u_int32_t i){
+ u_int32_t b = i;
+ data[position++] = (u_int8_t) (0xFF & (b >> 24));
+ data[position++] = (u_int8_t) (0xFF & (b >> 16));
+ data[position++] = (u_int8_t) (0xFF & (b >> 8));
+ data[position++] = (u_int8_t) (0xFF & b);
+}
+
+void qpid::framing::Buffer::putLongLong(u_int64_t i){
+ u_int32_t hi = i >> 32;
+ u_int32_t lo = i;
+ putLong(hi);
+ putLong(lo);
+}
+
+u_int8_t qpid::framing::Buffer::getOctet(){
+ return (u_int8_t) data[position++];
+}
+
+u_int16_t qpid::framing::Buffer::getShort(){
+ u_int16_t hi = (unsigned char) data[position++];
+ hi = hi << 8;
+ hi |= (unsigned char) data[position++];
+ return hi;
+}
+
+u_int32_t qpid::framing::Buffer::getLong(){
+ u_int32_t a = (unsigned char) data[position++];
+ u_int32_t b = (unsigned char) data[position++];
+ u_int32_t c = (unsigned char) data[position++];
+ u_int32_t d = (unsigned char) data[position++];
+ a = a << 24;
+ a |= b << 16;
+ a |= c << 8;
+ a |= d;
+ return a;
+}
+
+u_int64_t qpid::framing::Buffer::getLongLong(){
+ u_int64_t hi = getLong();
+ u_int64_t lo = getLong();
+ hi = hi << 32;
+ return hi | lo;
+}
+
+
+void qpid::framing::Buffer::putShortString(const string& s){
+ u_int8_t size = s.length();
+ putOctet(size);
+ s.copy(data + position, size);
+ position += size;
+}
+
+void qpid::framing::Buffer::putLongString(const string& s){
+ u_int32_t size = s.length();
+ putLong(size);
+ s.copy(data + position, size);
+ position += size;
+}
+
+void qpid::framing::Buffer::getShortString(string& s){
+ u_int8_t size = getOctet();
+ s.assign(data + position, size);
+ position += size;
+}
+
+void qpid::framing::Buffer::getLongString(string& s){
+ u_int32_t size = getLong();
+ s.assign(data + position, size);
+ position += size;
+}
+
+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::putRawData(const string& s){
+ u_int32_t size = s.length();
+ s.copy(data + position, size);
+ position += size;
+}
+
+void qpid::framing::Buffer::getRawData(string& s, u_int32_t size){
+ s.assign(data + position, size);
+ position += size;
+}
diff --git a/cpp/common/framing/src/FieldTable.cpp b/cpp/common/framing/src/FieldTable.cpp
new file mode 100644
index 0000000000..048cefa83c
--- /dev/null
+++ b/cpp/common/framing/src/FieldTable.cpp
@@ -0,0 +1,127 @@
+/*
+ *
+ * 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 "FieldTable.h"
+#include "NamedValue.h"
+#include "QpidError.h"
+#include "Buffer.h"
+#include "Value.h"
+
+qpid::framing::FieldTable::~FieldTable(){
+ int count(values.size());
+ for(int i = 0; i < count; i++){
+ delete values[i];
+ }
+}
+
+u_int32_t qpid::framing::FieldTable::size() const {
+ u_int32_t size(4);
+ int count(values.size());
+ for(int i = 0; i < count; i++){
+ size += values[i]->size();
+ }
+ return size;
+}
+
+int qpid::framing::FieldTable::count() const {
+ return values.size();
+}
+
+std::ostream& qpid::framing::operator<<(std::ostream& out, const FieldTable& t){
+ out << "field_table{}";
+ return out;
+}
+
+void qpid::framing::FieldTable::setString(const std::string& name, const std::string& value){
+ setValue(name, new StringValue(value));
+}
+
+void qpid::framing::FieldTable::setInt(const std::string& name, int value){
+ setValue(name, new IntegerValue(value));
+}
+
+void qpid::framing::FieldTable::setTimestamp(const std::string& name, u_int64_t value){
+ setValue(name, new TimeValue(value));
+}
+
+void qpid::framing::FieldTable::setTable(const std::string& name, const FieldTable& value){
+ setValue(name, new FieldTableValue(value));
+}
+
+std::string qpid::framing::FieldTable::getString(const std::string& name){
+ StringValue* val = dynamic_cast<StringValue*>(getValue(name));
+ return (val == 0 ? "" : val->getValue());
+}
+
+int qpid::framing::FieldTable::getInt(const std::string& name){
+ IntegerValue* val = dynamic_cast<IntegerValue*>(getValue(name));
+ return (val == 0 ? 0 : val->getValue());
+}
+
+u_int64_t qpid::framing::FieldTable::getTimestamp(const std::string& name){
+ TimeValue* val = dynamic_cast<TimeValue*>(getValue(name));
+ return (val == 0 ? 0 : val->getValue());
+}
+
+void qpid::framing::FieldTable::getTable(const std::string& name, FieldTable& value){
+ FieldTableValue* val = dynamic_cast<FieldTableValue*>(getValue(name));
+ if(val != 0) value = val->getValue();
+}
+
+qpid::framing::NamedValue* qpid::framing::FieldTable::find(const std::string& name) const{
+ int count(values.size());
+ for(int i = 0; i < count; i++){
+ if(values[i]->getName() == name) return values[i];
+ }
+ return 0;
+}
+
+qpid::framing::Value* qpid::framing::FieldTable::getValue(const std::string& name) const{
+ NamedValue* val = find(name);
+ return val == 0 ? 0 : val->getValue();
+}
+
+void qpid::framing::FieldTable::setValue(const std::string& name, Value* value){
+ NamedValue* val = find(name);
+ if(val == 0){
+ val = new NamedValue(name, value);
+ values.push_back(val);
+ }else{
+ Value* old = val->getValue();
+ if(old != 0) delete old;
+ val->setValue(value);
+ }
+}
+
+void qpid::framing::FieldTable::encode(Buffer& buffer) const{
+ buffer.putLong(size() - 4);
+ int count(values.size());
+ for(int i = 0; i < count; i++){
+ values[i]->encode(buffer);
+ }
+}
+
+void qpid::framing::FieldTable::decode(Buffer& buffer){
+ u_int32_t size = buffer.getLong();
+ int leftover = buffer.available() - size;
+
+ while(buffer.available() > leftover){
+ NamedValue* value = new NamedValue();
+ value->decode(buffer);
+ values.push_back(value);
+ }
+}
diff --git a/cpp/common/framing/src/NamedValue.cpp b/cpp/common/framing/src/NamedValue.cpp
new file mode 100644
index 0000000000..e80aea433c
--- /dev/null
+++ b/cpp/common/framing/src/NamedValue.cpp
@@ -0,0 +1,67 @@
+/*
+ *
+ * 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 "NamedValue.h"
+#include "QpidError.h"
+#include "Buffer.h"
+#include "FieldTable.h"
+
+qpid::framing::NamedValue::NamedValue() : value(0){}
+
+qpid::framing::NamedValue::NamedValue(const string& n, Value* v) : name(n), value(v){}
+
+qpid::framing::NamedValue::~NamedValue(){
+ if(value != 0){
+ delete value;
+ }
+}
+
+u_int32_t qpid::framing::NamedValue::size() const{
+ return value ? 1/*size of name*/ + name.length() + 1/*type char*/ + value->size() : 0;
+}
+
+void qpid::framing::NamedValue::encode(Buffer& buffer){
+ buffer.putShortString(name);
+ u_int8_t type = value->getType();
+ buffer.putOctet(type);
+ value->encode(buffer);
+}
+
+void qpid::framing::NamedValue::decode(Buffer& buffer){
+ buffer.getShortString(name);
+ u_int8_t type = buffer.getOctet();
+ switch(type){
+ case 'S':
+ value = new StringValue();
+ break;
+ case 'I':
+ value = new IntegerValue();
+ break;
+ case 'D':
+ value = new DecimalValue();
+ break;
+ case 'T':
+ value = new TimeValue();
+ break;
+ case 'F':
+ value = new FieldTableValue();
+ break;
+ default:
+ THROW_QPID_ERROR(FRAMING_ERROR, "Unknown field table value type");
+ }
+ value->decode(buffer);
+}
diff --git a/cpp/common/framing/src/ProtocolInitiation.cpp b/cpp/common/framing/src/ProtocolInitiation.cpp
new file mode 100644
index 0000000000..6806d73b55
--- /dev/null
+++ b/cpp/common/framing/src/ProtocolInitiation.cpp
@@ -0,0 +1,53 @@
+/*
+ *
+ * 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 "ProtocolInitiation.h"
+
+qpid::framing::ProtocolInitiation::ProtocolInitiation(){}
+
+qpid::framing::ProtocolInitiation::ProtocolInitiation(u_int8_t _major, u_int8_t _minor) : pmajor(_major), pminor(_minor){}
+
+qpid::framing::ProtocolInitiation::~ProtocolInitiation(){}
+
+void qpid::framing::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(pmajor);
+ buffer.putOctet(pminor);
+}
+
+bool qpid::framing::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
+ pmajor = buffer.getOctet();
+ pminor = 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
diff --git a/cpp/common/framing/src/Value.cpp b/cpp/common/framing/src/Value.cpp
new file mode 100644
index 0000000000..240b086696
--- /dev/null
+++ b/cpp/common/framing/src/Value.cpp
@@ -0,0 +1,57 @@
+/*
+ *
+ * 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 "Value.h"
+#include "Buffer.h"
+#include "FieldTable.h"
+
+void qpid::framing::StringValue::encode(Buffer& buffer){
+ buffer.putLongString(value);
+}
+void qpid::framing::StringValue::decode(Buffer& buffer){
+ buffer.getLongString(value);
+}
+
+void qpid::framing::IntegerValue::encode(Buffer& buffer){
+ buffer.putLong((u_int32_t) value);
+}
+void qpid::framing::IntegerValue::decode(Buffer& buffer){
+ value = buffer.getLong();
+}
+
+void qpid::framing::TimeValue::encode(Buffer& buffer){
+ buffer.putLongLong(value);
+}
+void qpid::framing::TimeValue::decode(Buffer& buffer){
+ value = buffer.getLongLong();
+}
+
+void qpid::framing::DecimalValue::encode(Buffer& buffer){
+ buffer.putOctet(decimals);
+ buffer.putLong(value);
+}
+void qpid::framing::DecimalValue::decode(Buffer& buffer){
+ decimals = buffer.getOctet();
+ value = buffer.getLong();
+}
+
+void qpid::framing::FieldTableValue::encode(Buffer& buffer){
+ buffer.putFieldTable(value);
+}
+void qpid::framing::FieldTableValue::decode(Buffer& buffer){
+ buffer.getFieldTable(value);
+}
diff --git a/cpp/common/framing/test/BodyHandlerTest.cpp b/cpp/common/framing/test/BodyHandlerTest.cpp
new file mode 100644
index 0000000000..94038d9a6c
--- /dev/null
+++ b/cpp/common/framing/test/BodyHandlerTest.cpp
@@ -0,0 +1,107 @@
+/*
+ *
+ * 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 "amqp_framing.h"
+#include <cppunit/TestCase.h>
+#include <cppunit/TextTestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+using namespace qpid::framing;
+
+class BodyHandlerTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(BodyHandlerTest);
+ CPPUNIT_TEST(testMethod);
+ CPPUNIT_TEST(testHeader);
+ CPPUNIT_TEST(testContent);
+ CPPUNIT_TEST(testHeartbeat);
+ CPPUNIT_TEST_SUITE_END();
+private:
+
+ class TestBodyHandler : public BodyHandler{
+ AMQMethodBody* const method;
+ AMQHeaderBody* const header;
+ AMQContentBody* const content;
+ AMQHeartbeatBody* const heartbeat;
+
+ public:
+
+ TestBodyHandler(AMQMethodBody* _method) : method(_method), header(0), content(0), heartbeat(0){}
+ TestBodyHandler(AMQHeaderBody* _header) : method(0), header(_header), content(0), heartbeat(0){}
+ TestBodyHandler(AMQContentBody* _content) : method(0), header(0), content(_content), heartbeat(0){}
+ TestBodyHandler(AMQHeartbeatBody* _heartbeat) : method(0), header(0), content(0), heartbeat(_heartbeat){}
+
+ virtual void handleMethod(AMQMethodBody::shared_ptr body){
+ CPPUNIT_ASSERT(method);
+ CPPUNIT_ASSERT_EQUAL(method, body.get());
+ }
+ virtual void handleHeader(AMQHeaderBody::shared_ptr body){
+ CPPUNIT_ASSERT(header);
+ CPPUNIT_ASSERT_EQUAL(header, body.get());
+ }
+ virtual void handleContent(AMQContentBody::shared_ptr body){
+ CPPUNIT_ASSERT(content);
+ CPPUNIT_ASSERT_EQUAL(content, body.get());
+ }
+ virtual void handleHeartbeat(AMQHeartbeatBody::shared_ptr body){
+ CPPUNIT_ASSERT(heartbeat);
+ CPPUNIT_ASSERT_EQUAL(heartbeat, body.get());
+ }
+ };
+
+public:
+
+ void testMethod()
+ {
+ AMQMethodBody* method = new QueueDeclareBody();
+ AMQFrame frame(0, method);
+ TestBodyHandler handler(method);
+ handler.handleBody(frame.getBody());
+ }
+
+ void testHeader()
+ {
+ AMQHeaderBody* header = new AMQHeaderBody();
+ AMQFrame frame(0, header);
+ TestBodyHandler handler(header);
+ handler.handleBody(frame.getBody());
+ }
+
+ void testContent()
+ {
+ AMQContentBody* content = new AMQContentBody();
+ AMQFrame frame(0, content);
+ TestBodyHandler handler(content);
+ handler.handleBody(frame.getBody());
+ }
+
+ void testHeartbeat()
+ {
+ AMQHeartbeatBody* heartbeat = new AMQHeartbeatBody();
+ AMQFrame frame(0, heartbeat);
+ TestBodyHandler handler(heartbeat);
+ handler.handleBody(frame.getBody());
+ }
+};
+
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(BodyHandlerTest);
+
diff --git a/cpp/common/framing/test/Makefile b/cpp/common/framing/test/Makefile
new file mode 100644
index 0000000000..487b8d537b
--- /dev/null
+++ b/cpp/common/framing/test/Makefile
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+QPID_HOME = ../../../..
+LDLIBS=-lapr-1 -lcppunit $(COMMON_LIB)
+INCLUDES=$(TEST_INCLUDES) -I ../generated
+include ${QPID_HOME}/cpp/test_plugins.mk
+
diff --git a/cpp/common/framing/test/field_table_test.cpp b/cpp/common/framing/test/field_table_test.cpp
new file mode 100644
index 0000000000..48332e05bc
--- /dev/null
+++ b/cpp/common/framing/test/field_table_test.cpp
@@ -0,0 +1,55 @@
+/*
+ *
+ * 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 "amqp_framing.h"
+#include <cppunit/TestCase.h>
+#include <cppunit/TextTestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+using namespace qpid::framing;
+
+class FieldTableTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(FieldTableTest);
+ CPPUNIT_TEST(testMe);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ void testMe()
+ {
+ FieldTable ft;
+ ft.setString("A", "BCDE");
+ CPPUNIT_ASSERT_EQUAL(std::string("BCDE"), ft.getString("A"));
+
+ Buffer buffer(100);
+ buffer.putFieldTable(ft);
+ buffer.flip();
+ FieldTable ft2;
+ buffer.getFieldTable(ft2);
+ CPPUNIT_ASSERT_EQUAL(std::string("BCDE"), ft2.getString("A"));
+
+ }
+};
+
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(FieldTableTest);
+
diff --git a/cpp/common/framing/test/framing_test.cpp b/cpp/common/framing/test/framing_test.cpp
new file mode 100644
index 0000000000..1978c2cbed
--- /dev/null
+++ b/cpp/common/framing/test/framing_test.cpp
@@ -0,0 +1,147 @@
+/*
+ *
+ * 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_framing.h"
+#include "ConnectionRedirectBody.h"
+#include <iostream>
+#include <sstream>
+#include <cppunit/TestCase.h>
+#include <cppunit/TextTestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+#include <typeinfo>
+
+using namespace qpid::framing;
+
+// TODO aconway 2006-09-12: Why do we need explicit qpid::framing:: below?
+
+template <class T>
+std::string tostring(const T& x)
+{
+ std::ostringstream out;
+ out << x;
+ return out.str();
+}
+
+class FramingTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(FramingTest);
+ CPPUNIT_TEST(testBasicQosBody);
+ CPPUNIT_TEST(testConnectionSecureBody);
+ CPPUNIT_TEST(testConnectionRedirectBody);
+ CPPUNIT_TEST(testAccessRequestBody);
+ CPPUNIT_TEST(testBasicConsumeBody);
+ CPPUNIT_TEST(ConnectionRedirectBody);
+ CPPUNIT_TEST(BasicConsumeOkBody);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ Buffer buffer;
+
+ public:
+
+ FramingTest() : buffer(100) {}
+
+ void testBasicQosBody()
+ {
+ BasicQosBody in(0xCAFEBABE, 0xABBA, true);
+ in.encodeContent(buffer);
+ buffer.flip();
+ BasicQosBody out;
+ out.decodeContent(buffer);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+ void testConnectionSecureBody()
+ {
+ std::string s = "security credential";
+ ConnectionSecureBody in(s);
+ in.encodeContent(buffer);
+ buffer.flip();
+ ConnectionSecureBody out;
+ out.decodeContent(buffer);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+ void testConnectionRedirectBody()
+ {
+ std::string a = "hostA";
+ std::string b = "hostB";
+ qpid::framing::ConnectionRedirectBody in(a, b);
+ in.encodeContent(buffer);
+ buffer.flip();
+ qpid::framing::ConnectionRedirectBody out;
+ out.decodeContent(buffer);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+ void testAccessRequestBody()
+ {
+ std::string s = "text";
+ AccessRequestBody in(s, true, false, true, false, true);
+ in.encodeContent(buffer);
+ buffer.flip();
+ AccessRequestBody out;
+ out.decodeContent(buffer);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+ void testBasicConsumeBody()
+ {
+ std::string q = "queue";
+ std::string t = "tag";
+ BasicConsumeBody in(0, q, t, false, true, false, false);
+ in.encodeContent(buffer);
+ buffer.flip();
+ BasicConsumeBody out;
+ out.decodeContent(buffer);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+
+ void ConnectionRedirectBody()
+ {
+ std::string a = "hostA";
+ std::string b = "hostB";
+ AMQFrame in(999, new qpid::framing::ConnectionRedirectBody(a, b));
+ in.encode(buffer);
+ buffer.flip();
+ AMQFrame out;
+ out.decode(buffer);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+
+ void BasicConsumeOkBody()
+ {
+ std::string s = "hostA";
+ AMQFrame in(999, new qpid::framing::BasicConsumeOkBody(s));
+ in.encode(buffer);
+ buffer.flip();
+ AMQFrame out;
+ for(int i = 0; i < 5; i++){
+ out.decode(buffer);
+ CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out));
+ }
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(FramingTest);
+
+
+
diff --git a/cpp/common/framing/test/header_test.cpp b/cpp/common/framing/test/header_test.cpp
new file mode 100644
index 0000000000..0ff6d47d57
--- /dev/null
+++ b/cpp/common/framing/test/header_test.cpp
@@ -0,0 +1,144 @@
+/*
+ *
+ * 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 "amqp_framing.h"
+#include <cppunit/TestCase.h>
+#include <cppunit/TextTestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+using namespace qpid::framing;
+
+class HeaderTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(HeaderTest);
+ CPPUNIT_TEST(testGenericProperties);
+ CPPUNIT_TEST(testAllSpecificProperties);
+ CPPUNIT_TEST(testSomeSpecificProperties);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+
+ // TODO aconway 2006-09-12: Need more detailed tests,
+ // need tests to assert something!
+ //
+ void testGenericProperties()
+ {
+ AMQHeaderBody body(BASIC);
+ dynamic_cast<BasicHeaderProperties*>(body.getProperties())->getHeaders().setString("A", "BCDE");
+ Buffer buffer(100);
+
+ body.encode(buffer);
+ buffer.flip();
+ AMQHeaderBody body2;
+ body2.decode(buffer, body.size());
+ BasicHeaderProperties* props =
+ dynamic_cast<BasicHeaderProperties*>(body2.getProperties());
+ CPPUNIT_ASSERT_EQUAL(std::string("BCDE"),
+ props->getHeaders().getString("A"));
+ }
+
+ void testAllSpecificProperties(){
+ string contentType("text/html");
+ string contentEncoding("UTF8");
+ u_int8_t deliveryMode(2);
+ u_int8_t priority(3);
+ string correlationId("abc");
+ string replyTo("no-address");
+ string expiration("why is this a string?");
+ string messageId("xyz");
+ u_int64_t timestamp(0xabcd);
+ string type("eh?");
+ string userId("guest");
+ string appId("just testing");
+ string clusterId("no clustering required");
+
+ AMQHeaderBody body(BASIC);
+ BasicHeaderProperties* properties =
+ dynamic_cast<BasicHeaderProperties*>(body.getProperties());
+ properties->setContentType(contentType);
+ properties->getHeaders().setString("A", "BCDE");
+ properties->setDeliveryMode(deliveryMode);
+ properties->setPriority(priority);
+ properties->setCorrelationId(correlationId);
+ properties->setReplyTo(replyTo);
+ properties->setExpiration(expiration);
+ properties->setMessageId(messageId);
+ properties->setTimestamp(timestamp);
+ properties->setType(type);
+ properties->setUserId(userId);
+ properties->setAppId(appId);
+ properties->setClusterId(clusterId);
+
+ Buffer buffer(10000);
+ body.encode(buffer);
+ buffer.flip();
+ AMQHeaderBody temp;
+ temp.decode(buffer, body.size());
+ properties = dynamic_cast<BasicHeaderProperties*>(temp.getProperties());
+
+ CPPUNIT_ASSERT_EQUAL(contentType, properties->getContentType());
+ CPPUNIT_ASSERT_EQUAL(std::string("BCDE"), properties->getHeaders().getString("A"));
+ CPPUNIT_ASSERT_EQUAL(deliveryMode, properties->getDeliveryMode());
+ CPPUNIT_ASSERT_EQUAL(priority, properties->getPriority());
+ CPPUNIT_ASSERT_EQUAL(correlationId, properties->getCorrelationId());
+ CPPUNIT_ASSERT_EQUAL(replyTo, properties->getReplyTo());
+ CPPUNIT_ASSERT_EQUAL(expiration, properties->getExpiration());
+ CPPUNIT_ASSERT_EQUAL(messageId, properties->getMessageId());
+ CPPUNIT_ASSERT_EQUAL(timestamp, properties->getTimestamp());
+ CPPUNIT_ASSERT_EQUAL(type, properties->getType());
+ CPPUNIT_ASSERT_EQUAL(userId, properties->getUserId());
+ CPPUNIT_ASSERT_EQUAL(appId, properties->getAppId());
+ CPPUNIT_ASSERT_EQUAL(clusterId, properties->getClusterId());
+ }
+
+ void testSomeSpecificProperties(){
+ string contentType("application/octet-stream");
+ u_int8_t deliveryMode(5);
+ u_int8_t priority(6);
+ string expiration("Z");
+ u_int64_t timestamp(0xabe4a34a);
+
+ AMQHeaderBody body(BASIC);
+ BasicHeaderProperties* properties =
+ dynamic_cast<BasicHeaderProperties*>(body.getProperties());
+ properties->setContentType(contentType);
+ properties->setDeliveryMode(deliveryMode);
+ properties->setPriority(priority);
+ properties->setExpiration(expiration);
+ properties->setTimestamp(timestamp);
+
+ Buffer buffer(100);
+ body.encode(buffer);
+ buffer.flip();
+ AMQHeaderBody temp;
+ temp.decode(buffer, body.size());
+ properties = dynamic_cast<BasicHeaderProperties*>(temp.getProperties());
+
+ CPPUNIT_ASSERT_EQUAL(contentType, properties->getContentType());
+ CPPUNIT_ASSERT_EQUAL((int) deliveryMode, (int) properties->getDeliveryMode());
+ CPPUNIT_ASSERT_EQUAL((int) priority, (int) properties->getPriority());
+ CPPUNIT_ASSERT_EQUAL(expiration, properties->getExpiration());
+ CPPUNIT_ASSERT_EQUAL(timestamp, properties->getTimestamp());
+ }
+};
+
+// Make this test suite a plugin.
+CPPUNIT_PLUGIN_IMPLEMENT();
+CPPUNIT_TEST_SUITE_REGISTRATION(HeaderTest);
+
diff --git a/cpp/common/io/Makefile b/cpp/common/io/Makefile
new file mode 100644
index 0000000000..e94e802afa
--- /dev/null
+++ b/cpp/common/io/Makefile
@@ -0,0 +1,35 @@
+ #
+ # 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.
+ #
+
+QPID_HOME = ../../..
+include ${QPID_HOME}/cpp/options.mk
+
+# Compiler flags
+CXXFLAGS = ${DEBUG} ${OPT} -MMD -I inc -I ../concurrent/inc -I ../error/inc -I ../framing/inc -I ../framing/generated -I ${APR_HOME}/include/apr-1/
+
+SOURCES := $(wildcard src/*.cpp)
+OBJECTS := $(subst .cpp,.o,$(SOURCES))
+DEPS := $(subst .cpp,.d,$(SOURCES))
+
+.PHONY: all clean
+
+all: ${OBJECTS}
+
+-include $(DEPS)
+
+clean :
+ -@rm -f ${OBJECTS} src/*.d
+
diff --git a/cpp/common/io/inc/APRConnector.h b/cpp/common/io/inc/APRConnector.h
new file mode 100644
index 0000000000..c292c4d7e0
--- /dev/null
+++ b/cpp/common/io/inc/APRConnector.h
@@ -0,0 +1,95 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _APRConnector_
+#define _APRConnector_
+
+#include "apr_network_io.h"
+#include "apr_time.h"
+
+#include "InputHandler.h"
+#include "OutputHandler.h"
+#include "InitiationHandler.h"
+#include "ProtocolInitiation.h"
+#include "ShutdownHandler.h"
+#include "Thread.h"
+#include "ThreadFactory.h"
+#include "Connector.h"
+#include "APRMonitor.h"
+
+namespace qpid {
+namespace io {
+
+ class APRConnector : public virtual qpid::framing::OutputHandler,
+ public virtual Connector,
+ private virtual qpid::concurrent::Runnable
+ {
+ const bool debug;
+ const int receive_buffer_size;
+ const int send_buffer_size;
+
+ bool closed;
+
+ apr_time_t lastIn;
+ apr_time_t lastOut;
+ apr_interval_time_t timeout;
+ u_int32_t idleIn;
+ u_int32_t idleOut;
+
+ TimeoutHandler* timeoutHandler;
+ ShutdownHandler* shutdownHandler;
+ qpid::framing::InputHandler* input;
+ qpid::framing::InitiationHandler* initialiser;
+ qpid::framing::OutputHandler* output;
+
+ qpid::framing::Buffer inbuf;
+ qpid::framing::Buffer outbuf;
+
+ qpid::concurrent::APRMonitor* writeLock;
+ qpid::concurrent::ThreadFactory* threadFactory;
+ qpid::concurrent::Thread* receiver;
+
+ apr_pool_t* pool;
+ apr_socket_t* socket;
+
+ void checkIdle(apr_status_t status);
+ void writeBlock(qpid::framing::AMQDataBlock* data);
+ void writeToSocket(char* data, int available);
+ void setSocketTimeout();
+
+ void run();
+
+ public:
+ APRConnector(bool debug = false, u_int32_t buffer_size = 1024);
+ virtual ~APRConnector();
+ virtual void connect(const std::string& host, int port);
+ virtual void init(qpid::framing::ProtocolInitiation* header);
+ virtual void close();
+ virtual void setInputHandler(qpid::framing::InputHandler* handler);
+ virtual void setTimeoutHandler(TimeoutHandler* handler);
+ virtual void setShutdownHandler(ShutdownHandler* handler);
+ virtual qpid::framing::OutputHandler* getOutputHandler();
+ virtual void send(qpid::framing::AMQFrame* frame);
+ virtual void setReadTimeout(u_int16_t timeout);
+ virtual void setWriteTimeout(u_int16_t timeout);
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/APRIOProcessor.h b/cpp/common/io/inc/APRIOProcessor.h
new file mode 100644
index 0000000000..de0d67a9c4
--- /dev/null
+++ b/cpp/common/io/inc/APRIOProcessor.h
@@ -0,0 +1,86 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _APRIOProcessor_
+#define _APRIOProcessor_
+
+#include "apr_poll.h"
+#include <queue>
+#include <iostream>
+#include "APRMonitor.h"
+#include "APRThread.h"
+#include "IOSession.h"
+#include "Runnable.h"
+
+namespace qpid {
+namespace io {
+
+ /**
+ * Manages non-blocking io through the APR polling
+ * routines. Interacts with the actual io tasks to be performed
+ * through the IOSession interface, an implementing instance of
+ * which must be set as the client_data of the apr_pollfd_t
+ * structures registered.
+ */
+ class APRIOProcessor : private virtual qpid::concurrent::Runnable
+ {
+ const int size;
+ const apr_interval_time_t timeout;
+ apr_pollset_t* pollset;
+ int count;
+ qpid::concurrent::APRThread thread;
+ qpid::concurrent::APRMonitor lock;
+ volatile bool stopped;
+
+ void poll();
+ virtual void run();
+
+ public:
+ APRIOProcessor(apr_pool_t* pool, int size, int timeout);
+ /**
+ * Add the fd to the poll set. Relies on the client_data being
+ * an instance implementing IOSession, through which the write
+ * and read operations will be performed when readiness is
+ * indicated by the poll response.
+ */
+ void add(apr_pollfd_t* const fd);
+ /**
+ * Remove the fd from the poll set.
+ */
+ void remove(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();
+
+ ~APRIOProcessor();
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/APRSocket.h b/cpp/common/io/inc/APRSocket.h
new file mode 100644
index 0000000000..610cf0e175
--- /dev/null
+++ b/cpp/common/io/inc/APRSocket.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _APRSocket_
+#define _APRSocket_
+
+#include "apr_network_io.h"
+#include "Buffer.h"
+
+namespace qpid {
+namespace io {
+
+ 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();
+ u_int8_t read();
+ ~APRSocket();
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/Acceptor.h b/cpp/common/io/inc/Acceptor.h
new file mode 100644
index 0000000000..5c690c546f
--- /dev/null
+++ b/cpp/common/io/inc/Acceptor.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Acceptor_
+#define _Acceptor_
+
+#include "SessionHandlerFactory.h"
+
+
+namespace qpid {
+namespace io {
+
+ class Acceptor
+ {
+ public:
+ virtual void bind(int port, SessionHandlerFactory* factory) = 0;
+ virtual ~Acceptor(){}
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/BlockingAPRAcceptor.h b/cpp/common/io/inc/BlockingAPRAcceptor.h
new file mode 100644
index 0000000000..b77371b02e
--- /dev/null
+++ b/cpp/common/io/inc/BlockingAPRAcceptor.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _BlockingAPRAcceptor_
+#define _BlockingAPRAcceptor_
+
+#include <vector>
+#include "apr_network_io.h"
+#include "apr_poll.h"
+#include "apr_time.h"
+
+#include "Acceptor.h"
+#include "APRMonitor.h"
+#include "BlockingAPRSessionContext.h"
+#include "Runnable.h"
+#include "SessionContext.h"
+#include "SessionHandlerFactory.h"
+#include "Thread.h"
+#include "ThreadFactory.h"
+#include "ThreadPool.h"
+
+namespace qpid {
+namespace io {
+
+ class BlockingAPRAcceptor : public virtual Acceptor
+ {
+ typedef std::vector<BlockingAPRSessionContext*>::iterator iterator;
+
+ const bool debug;
+ apr_pool_t* apr_pool;
+ qpid::concurrent::ThreadFactory* threadFactory;
+ std::vector<BlockingAPRSessionContext*> sessions;
+ apr_socket_t* socket;
+ const int connectionBacklog;
+ volatile bool running;
+
+ public:
+ BlockingAPRAcceptor(bool debug = false, int connectionBacklog = 10);
+ virtual void bind(int port, SessionHandlerFactory* factory);
+ virtual ~BlockingAPRAcceptor();
+ void closed(BlockingAPRSessionContext* session);
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/BlockingAPRSessionContext.h b/cpp/common/io/inc/BlockingAPRSessionContext.h
new file mode 100644
index 0000000000..038ebd6662
--- /dev/null
+++ b/cpp/common/io/inc/BlockingAPRSessionContext.h
@@ -0,0 +1,94 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _BlockingAPRSessionContext_
+#define _BlockingAPRSessionContext_
+
+#include <queue>
+#include <vector>
+
+#include "apr_network_io.h"
+#include "apr_time.h"
+
+#include "AMQFrame.h"
+#include "APRMonitor.h"
+#include "Buffer.h"
+#include "Runnable.h"
+#include "SessionContext.h"
+#include "SessionHandler.h"
+#include "SessionHandlerFactory.h"
+#include "ShutdownHandler.h"
+#include "Thread.h"
+#include "ThreadFactory.h"
+
+namespace qpid {
+namespace io {
+
+ class BlockingAPRAcceptor;
+
+ class BlockingAPRSessionContext : public virtual SessionContext
+ {
+ class Reader : public virtual qpid::concurrent::Runnable{
+ BlockingAPRSessionContext* parent;
+ public:
+ inline Reader(BlockingAPRSessionContext* p) : parent(p){}
+ inline virtual void run(){ parent->read(); }
+ inline virtual ~Reader(){}
+ };
+
+ class Writer : public virtual qpid::concurrent::Runnable{
+ BlockingAPRSessionContext* parent;
+ public:
+ inline Writer(BlockingAPRSessionContext* p) : parent(p){}
+ inline virtual void run(){ parent->write(); }
+ inline virtual ~Writer(){}
+ };
+
+ apr_socket_t* socket;
+ const bool debug;
+ SessionHandler* handler;
+ BlockingAPRAcceptor* acceptor;
+ std::queue<qpid::framing::AMQFrame*> outframes;
+ qpid::framing::Buffer inbuf;
+ qpid::framing::Buffer outbuf;
+ qpid::concurrent::APRMonitor outlock;
+ Reader* reader;
+ Writer* writer;
+ qpid::concurrent::Thread* rThread;
+ qpid::concurrent::Thread* wThread;
+
+ volatile bool closed;
+
+ void read();
+ void write();
+ public:
+ BlockingAPRSessionContext(apr_socket_t* socket,
+ qpid::concurrent::ThreadFactory* factory,
+ BlockingAPRAcceptor* acceptor,
+ bool debug = false);
+ ~BlockingAPRSessionContext();
+ virtual void send(qpid::framing::AMQFrame* frame);
+ virtual void close();
+ void shutdown();
+ void init(SessionHandler* handler);
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/Connector.h b/cpp/common/io/inc/Connector.h
new file mode 100644
index 0000000000..52684329f1
--- /dev/null
+++ b/cpp/common/io/inc/Connector.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _Connector_
+#define _Connector_
+
+#include "InputHandler.h"
+#include "OutputHandler.h"
+#include "InitiationHandler.h"
+#include "ProtocolInitiation.h"
+#include "ShutdownHandler.h"
+#include "TimeoutHandler.h"
+
+namespace qpid {
+namespace io {
+
+ class Connector
+ {
+ public:
+ virtual void connect(const std::string& host, int port) = 0;
+ virtual void init(qpid::framing::ProtocolInitiation* header) = 0;
+ virtual void close() = 0;
+ virtual void setInputHandler(qpid::framing::InputHandler* handler) = 0;
+ virtual void setTimeoutHandler(TimeoutHandler* handler) = 0;
+ virtual void setShutdownHandler(ShutdownHandler* handler) = 0;
+ virtual qpid::framing::OutputHandler* getOutputHandler() = 0;
+ /**
+ * Set the timeout for reads, in secs.
+ */
+ virtual void setReadTimeout(u_int16_t timeout) = 0;
+ /**
+ * Set the timeout for writes, in secs.
+ */
+ virtual void setWriteTimeout(u_int16_t timeout) = 0;
+ virtual ~Connector(){}
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/ConnectorImpl.h b/cpp/common/io/inc/ConnectorImpl.h
new file mode 100644
index 0000000000..242f3aed49
--- /dev/null
+++ b/cpp/common/io/inc/ConnectorImpl.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _APRConnectorImpl_
+#define _APRConnectorImpl_
+
+#ifdef _USE_APR_IO_
+#include "APRConnector.h"
+#else
+#include "LConnector.h"
+#endif
+
+namespace qpid {
+namespace io {
+
+#ifdef _USE_APR_IO_
+ class ConnectorImpl : public virtual APRConnector
+ {
+
+ public:
+ ConnectorImpl(bool debug = false, u_int32_t buffer_size = 1024):APRConnector(debug,buffer_size){};
+ virtual ~ConnectorImpl(){};
+ };
+#else
+ class ConnectorImpl : public virtual LConnector
+ {
+
+ public:
+ ConnectorImpl(bool debug = false, u_int32_t buffer_size = 1024):LConnector(debug, buffer_size){};
+ virtual ~ConnectorImpl(){};
+ };
+
+#endif
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/IOSession.h b/cpp/common/io/inc/IOSession.h
new file mode 100644
index 0000000000..45e84d29b1
--- /dev/null
+++ b/cpp/common/io/inc/IOSession.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _IOSession_
+#define _IOSession_
+
+namespace qpid {
+namespace io {
+
+ class IOSession
+ {
+ public:
+ virtual void read() = 0;
+ virtual void write() = 0;
+ virtual ~IOSession(){}
+ };
+
+
+ class IOSessionHolder
+ {
+ IOSession* session;
+ public:
+ IOSessionHolder(IOSession* _session) : session(_session) {}
+ void read(){ session->read(); }
+ void write(){ session->write(); }
+ };
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/LConnector.h b/cpp/common/io/inc/LConnector.h
new file mode 100644
index 0000000000..59d95a6b57
--- /dev/null
+++ b/cpp/common/io/inc/LConnector.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _LConnector_
+#define _LConnector_
+
+
+#include "InputHandler.h"
+#include "OutputHandler.h"
+#include "InitiationHandler.h"
+#include "ProtocolInitiation.h"
+#include "Thread.h"
+#include "ThreadFactory.h"
+#include "Connector.h"
+
+namespace qpid {
+namespace io {
+
+ class LConnector : public virtual qpid::framing::OutputHandler,
+ public virtual Connector,
+ private virtual qpid::concurrent::Runnable
+ {
+
+ public:
+ LConnector(bool debug = false, u_int32_t buffer_size = 1024){};
+ virtual ~LConnector(){};
+
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/LFAcceptor.h b/cpp/common/io/inc/LFAcceptor.h
new file mode 100644
index 0000000000..314f811827
--- /dev/null
+++ b/cpp/common/io/inc/LFAcceptor.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _LFAcceptor_
+#define _LFAcceptor_
+
+#include <vector>
+#include "apr_network_io.h"
+#include "apr_poll.h"
+#include "apr_time.h"
+
+#include "Acceptor.h"
+#include "APRMonitor.h"
+#include "APRThreadFactory.h"
+#include "APRThreadPool.h"
+#include "LFProcessor.h"
+#include "LFSessionContext.h"
+#include "Runnable.h"
+#include "SessionContext.h"
+#include "SessionHandlerFactory.h"
+#include "Thread.h"
+
+namespace qpid {
+namespace io {
+
+ class LFAcceptor : public virtual Acceptor
+ {
+ class APRPool{
+ public:
+ apr_pool_t* pool;
+ APRPool();
+ ~APRPool();
+ };
+
+ APRPool aprPool;
+ LFProcessor processor;
+
+ const int max_connections_per_processor;
+ const bool debug;
+ const int connectionBacklog;
+
+ volatile bool running;
+
+ public:
+ LFAcceptor(bool debug = false,
+ int connectionBacklog = 10,
+ int worker_threads = 5,
+ int max_connections_per_processor = 500);
+ virtual void bind(int port, SessionHandlerFactory* factory);
+ virtual ~LFAcceptor();
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/LFProcessor.h b/cpp/common/io/inc/LFProcessor.h
new file mode 100644
index 0000000000..7d99d51943
--- /dev/null
+++ b/cpp/common/io/inc/LFProcessor.h
@@ -0,0 +1,116 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _LFProcessor_
+#define _LFProcessor_
+
+#include "apr_poll.h"
+#include <iostream>
+#include <vector>
+#include "APRMonitor.h"
+#include "APRThreadFactory.h"
+#include "IOSession.h"
+#include "Runnable.h"
+
+namespace qpid {
+namespace io {
+
+ 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::concurrent::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;
+ qpid::concurrent::Thread** const workers;
+ qpid::concurrent::APRMonitor leadLock;
+ qpid::concurrent::APRMonitor countLock;
+ qpid::concurrent::APRThreadFactory factory;
+ std::vector<LFSessionContext*> sessions;
+ bool hasLeader;
+ 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();
+
+ ~LFProcessor();
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/LFSessionContext.h b/cpp/common/io/inc/LFSessionContext.h
new file mode 100644
index 0000000000..ef6a0d07b0
--- /dev/null
+++ b/cpp/common/io/inc/LFSessionContext.h
@@ -0,0 +1,89 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _LFSessionContext_
+#define _LFSessionContext_
+
+#include <queue>
+
+#include "apr_network_io.h"
+#include "apr_poll.h"
+#include "apr_time.h"
+
+#include "AMQFrame.h"
+#include "APRMonitor.h"
+#include "APRSocket.h"
+#include "Buffer.h"
+#include "IOSession.h"
+#include "LFProcessor.h"
+#include "SessionContext.h"
+#include "SessionHandler.h"
+
+namespace qpid {
+namespace io {
+
+
+ class LFSessionContext : public virtual SessionContext, public virtual IOSession
+ {
+ const bool debug;
+ APRSocket socket;
+ bool initiated;
+
+ qpid::framing::Buffer in;
+ qpid::framing::Buffer out;
+
+ SessionHandler* handler;
+ LFProcessor* const processor;
+
+ apr_pollfd_t fd;
+
+ std::queue<qpid::framing::AMQFrame*> framesToWrite;
+ qpid::concurrent::APRMonitor writeLock;
+
+ bool processing;
+ bool closing;
+
+ //these are just for debug, as a crude way of detecting concurrent access
+ volatile unsigned int reading;
+ volatile unsigned int writing;
+
+ static qpid::concurrent::APRMonitor 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);
+ ~LFSessionContext();
+ virtual void send(qpid::framing::AMQFrame* frame);
+ virtual void close();
+ virtual void read();
+ virtual void write();
+ void init(SessionHandler* 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/common/io/inc/SessionContext.h b/cpp/common/io/inc/SessionContext.h
new file mode 100644
index 0000000000..f223a70daa
--- /dev/null
+++ b/cpp/common/io/inc/SessionContext.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _SessionContext_
+#define _SessionContext_
+
+#include "OutputHandler.h"
+
+namespace qpid {
+namespace io {
+
+ class SessionContext : public virtual qpid::framing::OutputHandler
+ {
+ public:
+ virtual void close() = 0;
+ virtual ~SessionContext(){}
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/SessionHandler.h b/cpp/common/io/inc/SessionHandler.h
new file mode 100644
index 0000000000..21a992ab65
--- /dev/null
+++ b/cpp/common/io/inc/SessionHandler.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _SessionHandler_
+#define _SessionHandler_
+
+#include "InputHandler.h"
+#include "InitiationHandler.h"
+#include "ProtocolInitiation.h"
+#include "TimeoutHandler.h"
+
+namespace qpid {
+namespace io {
+
+ class SessionHandler : public virtual qpid::framing::InitiationHandler,
+ public virtual qpid::framing::InputHandler,
+ public virtual TimeoutHandler
+ {
+ public:
+ virtual void closed() = 0;
+ virtual ~SessionHandler(){}
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/SessionHandlerFactory.h b/cpp/common/io/inc/SessionHandlerFactory.h
new file mode 100644
index 0000000000..67d968b72e
--- /dev/null
+++ b/cpp/common/io/inc/SessionHandlerFactory.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _SessionHandlerFactory_
+#define _SessionHandlerFactory_
+
+#include "SessionContext.h"
+#include "SessionHandler.h"
+
+namespace qpid {
+namespace io {
+
+ class SessionHandlerFactory
+ {
+ public:
+ virtual SessionHandler* create(SessionContext* ctxt) = 0;
+ virtual ~SessionHandlerFactory(){}
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/SessionManager.h b/cpp/common/io/inc/SessionManager.h
new file mode 100644
index 0000000000..30c5208532
--- /dev/null
+++ b/cpp/common/io/inc/SessionManager.h
@@ -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.
+ *
+ */
+#ifndef _SessionManager_
+#define _SessionManager_
+
+#include "SessionContext.h"
+#include "SessionHandler.h"
+
+namespace qpid {
+namespace io {
+
+ class SessionManager
+ {
+ public:
+ virtual SessionHandler* init(SessionContext* ctxt) = 0;
+ virtual void close(SessionContext* ctxt) = 0;
+ virtual void updateInterest(SessionContext* ctxt, bool read, bool write) = 0;
+ virtual ~SessionManager(){}
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/inc/ShutdownHandler.h b/cpp/common/io/inc/ShutdownHandler.h
new file mode 100644
index 0000000000..186d9eeca4
--- /dev/null
+++ b/cpp/common/io/inc/ShutdownHandler.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _ShutdownHandler_
+#define _ShutdownHandler_
+
+namespace qpid {
+namespace io {
+
+ class ShutdownHandler
+ {
+ public:
+ virtual void shutdown() = 0;
+ virtual ~ShutdownHandler(){}
+ };
+
+}
+}
+
+#endif
diff --git a/cpp/common/io/inc/TimeoutHandler.h b/cpp/common/io/inc/TimeoutHandler.h
new file mode 100644
index 0000000000..c92220fd6e
--- /dev/null
+++ b/cpp/common/io/inc/TimeoutHandler.h
@@ -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.
+ *
+ */
+#ifndef _TimeoutHandler_
+#define _TimeoutHandler_
+
+namespace qpid {
+namespace io {
+
+ class TimeoutHandler
+ {
+ public:
+ virtual void idleOut() = 0;
+ virtual void idleIn() = 0;
+ virtual ~TimeoutHandler(){}
+ };
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/io/src/APRConnector.cpp b/cpp/common/io/src/APRConnector.cpp
new file mode 100644
index 0000000000..0e022a8c73
--- /dev/null
+++ b/cpp/common/io/src/APRConnector.cpp
@@ -0,0 +1,198 @@
+/*
+ *
+ * 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 "APRBase.h"
+#include "APRConnector.h"
+#include "APRThreadFactory.h"
+#include "QpidError.h"
+
+using namespace qpid::io;
+using namespace qpid::concurrent;
+using namespace qpid::framing;
+using qpid::QpidError;
+
+APRConnector::APRConnector(bool _debug, u_int32_t buffer_size) : closed(true), debug(_debug),
+ idleIn(0), idleOut(0), timeout(0),
+ timeoutHandler(0),
+ shutdownHandler(0),
+ lastIn(0), lastOut(0),
+ receive_buffer_size(buffer_size),
+ send_buffer_size(buffer_size),
+ inbuf(receive_buffer_size),
+ outbuf(send_buffer_size){
+
+ APRBase::increment();
+
+ CHECK_APR_SUCCESS(apr_pool_create(&pool, NULL));
+ CHECK_APR_SUCCESS(apr_socket_create(&socket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, pool));
+
+ threadFactory = new APRThreadFactory();
+ writeLock = new APRMonitor();
+}
+
+APRConnector::~APRConnector(){
+ delete receiver;
+ delete writeLock;
+ delete threadFactory;
+ apr_pool_destroy(pool);
+
+ APRBase::decrement();
+}
+
+void APRConnector::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, pool));
+ CHECK_APR_SUCCESS(apr_socket_connect(socket, address));
+ closed = false;
+
+ receiver = threadFactory->create(this);
+ receiver->start();
+}
+
+void APRConnector::init(ProtocolInitiation* header){
+ writeBlock(header);
+ delete header;
+}
+
+void APRConnector::close(){
+ closed = true;
+ CHECK_APR_SUCCESS(apr_socket_close(socket));
+ receiver->join();
+}
+
+void APRConnector::setInputHandler(InputHandler* handler){
+ input = handler;
+}
+
+void APRConnector::setShutdownHandler(ShutdownHandler* handler){
+ shutdownHandler = handler;
+}
+
+OutputHandler* APRConnector::getOutputHandler(){
+ return this;
+}
+
+void APRConnector::send(AMQFrame* frame){
+ writeBlock(frame);
+ if(debug) std::cout << "SENT: " << *frame << std::endl;
+ delete frame;
+}
+
+void APRConnector::writeBlock(AMQDataBlock* data){
+ writeLock->acquire();
+ data->encode(outbuf);
+
+ //transfer data to wire
+ outbuf.flip();
+ writeToSocket(outbuf.start(), outbuf.available());
+ outbuf.clear();
+ writeLock->release();
+}
+
+void APRConnector::writeToSocket(char* data, int available){
+ apr_size_t bytes(available);
+ apr_size_t written(0);
+ while(written < available && !closed){
+ apr_status_t status = apr_socket_send(socket, data + written, &bytes);
+ if(status == APR_TIMEUP){
+ std::cout << "Write request timed out." << std::endl;
+ }
+ if(bytes == 0){
+ std::cout << "Write request wrote 0 bytes." << std::endl;
+ }
+ lastOut = apr_time_as_msec(apr_time_now());
+ written += bytes;
+ bytes = available - written;
+ }
+}
+
+void APRConnector::checkIdle(apr_status_t status){
+ if(timeoutHandler){
+ apr_time_t now = apr_time_as_msec(apr_time_now());
+ if(APR_STATUS_IS_TIMEUP(status)){
+ if(idleIn && (now - lastIn > idleIn)){
+ timeoutHandler->idleIn();
+ }
+ }else if(APR_STATUS_IS_EOF(status)){
+ closed = true;
+ CHECK_APR_SUCCESS(apr_socket_close(socket));
+ if(shutdownHandler) shutdownHandler->shutdown();
+ }else{
+ lastIn = now;
+ }
+ if(idleOut && (now - lastOut > idleOut)){
+ timeoutHandler->idleOut();
+ }
+ }
+}
+
+void APRConnector::setReadTimeout(u_int16_t t){
+ idleIn = t * 1000;//t is in secs
+ if(idleIn && (!timeout || idleIn < timeout)){
+ timeout = idleIn;
+ setSocketTimeout();
+ }
+
+}
+
+void APRConnector::setWriteTimeout(u_int16_t t){
+ idleOut = t * 1000;//t is in secs
+ if(idleOut && (!timeout || idleOut < timeout)){
+ timeout = idleOut;
+ setSocketTimeout();
+ }
+}
+
+void APRConnector::setSocketTimeout(){
+ //interval is in microseconds, timeout in milliseconds
+ //want the interval to be a bit shorter than the timeout, hence multiply
+ //by 800 rather than 1000.
+ apr_interval_time_t interval(timeout * 800);
+ apr_socket_timeout_set(socket, interval);
+}
+
+void APRConnector::setTimeoutHandler(TimeoutHandler* handler){
+ timeoutHandler = handler;
+}
+
+void APRConnector::run(){
+ try{
+ while(!closed){
+ apr_size_t bytes(inbuf.available());
+ if(bytes < 1){
+ THROW_QPID_ERROR(INTERNAL_ERROR, "Frame exceeds buffer size.");
+ }
+ checkIdle(apr_socket_recv(socket, inbuf.start(), &bytes));
+
+ if(bytes > 0){
+ inbuf.move(bytes);
+ inbuf.flip();//position = 0, limit = total data read
+
+ AMQFrame frame;
+ 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(QpidError error){
+ std::cout << "Error [" << error.code << "] " << error.msg << " (" << error.file << ":" << error.line << ")" << std::endl;
+ }
+}
diff --git a/cpp/common/io/src/APRIOProcessor.cpp b/cpp/common/io/src/APRIOProcessor.cpp
new file mode 100644
index 0000000000..d630f2f315
--- /dev/null
+++ b/cpp/common/io/src/APRIOProcessor.cpp
@@ -0,0 +1,100 @@
+/*
+ *
+ * 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 "APRIOProcessor.h"
+#include "APRBase.h"
+#include "QpidError.h"
+
+using namespace qpid::io;
+using namespace qpid::concurrent;
+
+APRIOProcessor::APRIOProcessor(apr_pool_t* pool, int _size, int _timeout) : size(_size),
+ timeout(_timeout),
+ count(0),
+ thread(pool, this),
+ stopped(false){
+
+ CHECK_APR_SUCCESS(apr_pollset_create(&pollset, size, pool, APR_POLLSET_THREADSAFE));
+ thread.start();
+}
+
+void APRIOProcessor::add(apr_pollfd_t* const fd){
+ CHECK_APR_SUCCESS(apr_pollset_add(pollset, fd));
+ lock.acquire();
+ if(!count++) lock.notify();
+ lock.release();
+}
+
+void APRIOProcessor::remove(apr_pollfd_t* const fd){
+ CHECK_APR_SUCCESS(apr_pollset_remove(pollset, fd));
+ lock.acquire();
+ count--;
+ lock.release();
+}
+
+bool APRIOProcessor::full(){
+ lock.acquire();
+ bool full = count == size;
+ lock.release();
+ return full;
+}
+
+bool APRIOProcessor::empty(){
+ lock.acquire();
+ bool empty = count == 0;
+ lock.release();
+ return empty;
+}
+
+void APRIOProcessor::poll(){
+ try{
+ int signalledCount;
+ const apr_pollfd_t* signalledFDs;
+ apr_status_t status = apr_pollset_poll(pollset, timeout, &signalledCount, &signalledFDs);
+ if(status == APR_SUCCESS){
+ for(int i = 0; i < signalledCount; i++){
+ IOSessionHolder* session = reinterpret_cast<IOSessionHolder*>(signalledFDs[i].client_data);
+ if(signalledFDs[i].rtnevents & APR_POLLIN) session->read();
+ if(signalledFDs[i].rtnevents & APR_POLLOUT) session->write();
+ }
+ }
+ }catch(qpid::QpidError error){
+ std::cout << "Error [" << error.code << "] " << error.msg << " (" << error.file << ":" << error.line << ")" << std::endl;
+ }
+
+}
+
+void APRIOProcessor::run(){
+ while(!stopped){
+ lock.acquire();
+ while(count == 0) lock.wait();
+ lock.release();
+ poll();
+ }
+}
+
+void APRIOProcessor::stop(){
+ lock.acquire();
+ stopped = true;
+ lock.notify();
+ lock.release();
+}
+
+APRIOProcessor::~APRIOProcessor(){
+ CHECK_APR_SUCCESS(apr_pollset_destroy(pollset));
+}
+
diff --git a/cpp/common/io/src/APRSocket.cpp b/cpp/common/io/src/APRSocket.cpp
new file mode 100644
index 0000000000..32861ea442
--- /dev/null
+++ b/cpp/common/io/src/APRSocket.cpp
@@ -0,0 +1,76 @@
+/*
+ *
+ * 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 "APRBase.h"
+#include "APRSocket.h"
+
+#include <iostream>
+
+using namespace qpid::io;
+using namespace qpid::framing;
+using namespace qpid::concurrent;
+
+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_status_t s = 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(){
+ return !closed;
+}
+
+u_int8_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/common/io/src/BlockingAPRAcceptor.cpp b/cpp/common/io/src/BlockingAPRAcceptor.cpp
new file mode 100644
index 0000000000..380318bcfa
--- /dev/null
+++ b/cpp/common/io/src/BlockingAPRAcceptor.cpp
@@ -0,0 +1,81 @@
+/*
+ *
+ * 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 "BlockingAPRAcceptor.h"
+#include "APRBase.h"
+#include "APRThreadFactory.h"
+
+using namespace qpid::concurrent;
+using namespace qpid::framing;
+using namespace qpid::io;
+
+BlockingAPRAcceptor::BlockingAPRAcceptor(bool _debug, int c) : connectionBacklog(c),
+ threadFactory(new APRThreadFactory()),
+ debug(_debug){
+
+ APRBase::increment();
+ CHECK_APR_SUCCESS(apr_pool_create(&apr_pool, NULL));
+}
+
+void BlockingAPRAcceptor::bind(int port, SessionHandlerFactory* factory){
+ apr_sockaddr_t* address;
+ CHECK_APR_SUCCESS(apr_sockaddr_info_get(&address, APR_ANYADDR, APR_UNSPEC, port, APR_IPV4_ADDR_OK, apr_pool));
+ CHECK_APR_SUCCESS(apr_socket_create(&socket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, apr_pool));
+ CHECK_APR_SUCCESS(apr_socket_bind(socket, address));
+ CHECK_APR_SUCCESS(apr_socket_listen(socket, connectionBacklog));
+ running = true;
+ std::cout << "Listening on port " << port << "..." << std::endl;
+ while(running){
+ apr_socket_t* client;
+ apr_status_t status = apr_socket_accept(&client, socket, apr_pool);
+ if(status == APR_SUCCESS){
+ //configure socket:
+ CHECK_APR_SUCCESS(apr_socket_timeout_set(client, 1000000/* i.e. 1 sec*/));
+ 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));
+
+ BlockingAPRSessionContext* session = new BlockingAPRSessionContext(client, threadFactory, this, debug);
+ session->init(factory->create(session));
+ sessions.push_back(session);
+ }else{
+ running = false;
+ if(status != APR_EINTR){
+ std::cout << "ERROR: " << get_desc(status) << std::endl;
+ }
+ }
+ }
+ for(iterator i = sessions.begin(); i < sessions.end(); i++){
+ (*i)->shutdown();
+ }
+
+ CHECK_APR_SUCCESS(apr_socket_close(socket));
+}
+
+BlockingAPRAcceptor::~BlockingAPRAcceptor(){
+ delete threadFactory;
+ apr_pool_destroy(apr_pool);
+ APRBase::decrement();
+}
+
+
+void BlockingAPRAcceptor::closed(BlockingAPRSessionContext* session){
+ sessions.erase(find(sessions.begin(), sessions.end(), session));
+ delete this;
+}
+
diff --git a/cpp/common/io/src/BlockingAPRSessionContext.cpp b/cpp/common/io/src/BlockingAPRSessionContext.cpp
new file mode 100644
index 0000000000..99352c90d5
--- /dev/null
+++ b/cpp/common/io/src/BlockingAPRSessionContext.cpp
@@ -0,0 +1,177 @@
+/*
+ *
+ * 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 "BlockingAPRSessionContext.h"
+#include "BlockingAPRAcceptor.h"
+#include "APRBase.h"
+#include "QpidError.h"
+
+using namespace qpid::concurrent;
+using namespace qpid::framing;
+using namespace qpid::io;
+
+
+BlockingAPRSessionContext::BlockingAPRSessionContext(apr_socket_t* _socket,
+ ThreadFactory* factory,
+ BlockingAPRAcceptor* _acceptor,
+ bool _debug)
+ : socket(_socket),
+ debug(_debug),
+ inbuf(65536),
+ outbuf(65536),
+ handler(0),
+ acceptor(_acceptor),
+ closed(false){
+
+ reader = new Reader(this);
+ writer = new Writer(this);
+
+ rThread = factory->create(reader);
+ wThread = factory->create(writer);
+}
+
+BlockingAPRSessionContext::~BlockingAPRSessionContext(){
+ delete reader;
+ delete writer;
+
+ delete rThread;
+ delete wThread;
+
+ delete handler;
+}
+
+void BlockingAPRSessionContext::read(){
+ try{
+ bool initiated(false);
+ while(!closed){
+ apr_size_t bytes(inbuf.available());
+ if(bytes < 1){
+ THROW_QPID_ERROR(INTERNAL_ERROR, "Frame exceeds buffer size.");
+ }
+ apr_status_t s = apr_socket_recv(socket, inbuf.start(), &bytes);
+ if(APR_STATUS_IS_TIMEUP(s)){
+ //timed out, check closed on loop
+ }else if(APR_STATUS_IS_EOF(s) || bytes == 0){
+ closed = true;
+ }else{
+ inbuf.move(bytes);
+ inbuf.flip();
+
+ if(!initiated){
+ ProtocolInitiation* init = new ProtocolInitiation();
+ if(init->decode(inbuf)){
+ handler->initiated(init);
+ if(debug) std::cout << "RECV: [" << &socket << "]: Initialised " << std::endl;
+ initiated = true;
+ }
+ }else{
+ AMQFrame frame;
+ while(frame.decode(inbuf)){
+ if(debug) std::cout << "RECV: [" << &socket << "]:" << frame << std::endl;
+ handler->received(&frame);
+ }
+ }
+ //need to compact buffer to preserve any 'extra' data
+ inbuf.compact();
+ }
+ }
+
+ //close socket
+ }catch(qpid::QpidError error){
+ std::cout << "Error [" << error.code << "] " << error.msg << " (" << error.file << ":" << error.line << ")" << std::endl;
+ }
+}
+
+void BlockingAPRSessionContext::write(){
+ while(!closed){
+ //get next frame
+ outlock.acquire();
+ while(outframes.empty() && !closed){
+ outlock.wait();
+ }
+ if(!closed){
+ AMQFrame* frame = outframes.front();
+ outframes.pop();
+ outlock.release();
+
+ //encode
+ frame->encode(outbuf);
+ if(debug) std::cout << "SENT [" << &socket << "]:" << *frame << std::endl;
+ delete frame;
+ outbuf.flip();
+
+ //write from outbuf to socket
+ char* data = outbuf.start();
+ const int available = outbuf.available();
+ int written = 0;
+ apr_size_t bytes = available;
+ while(available > written){
+ apr_status_t s = apr_socket_send(socket, data + written, &bytes);
+ written += bytes;
+ bytes = available - written;
+ }
+ outbuf.clear();
+ }else{
+ outlock.release();
+ }
+ }
+}
+
+void BlockingAPRSessionContext::send(AMQFrame* frame){
+ if(!closed){
+ outlock.acquire();
+ bool was_empty(outframes.empty());
+ outframes.push(frame);
+ if(was_empty){
+ outlock.notify();
+ }
+ outlock.release();
+ }else{
+ std::cout << "WARNING: Session closed[" << &socket << "], dropping frame. " << &frame << std::endl;
+ }
+}
+
+void BlockingAPRSessionContext::init(SessionHandler* handler){
+ this->handler = handler;
+ //start the threads
+ rThread->start();
+ wThread->start();
+}
+
+void BlockingAPRSessionContext::close(){
+ closed = true;
+ wThread->join();
+ CHECK_APR_SUCCESS(apr_socket_close(socket));
+ if(debug) std::cout << "RECV: [" << &socket << "]: Closed " << std::endl;
+ handler->closed();
+ acceptor->closed(this);
+ delete this;
+}
+
+void BlockingAPRSessionContext::shutdown(){
+ closed = true;
+ outlock.acquire();
+ outlock.notify();
+ outlock.release();
+
+ wThread->join();
+ CHECK_APR_SUCCESS(apr_socket_close(socket));
+ rThread->join();
+ handler->closed();
+ delete this;
+}
diff --git a/cpp/common/io/src/LFAcceptor.cpp b/cpp/common/io/src/LFAcceptor.cpp
new file mode 100644
index 0000000000..6653e926db
--- /dev/null
+++ b/cpp/common/io/src/LFAcceptor.cpp
@@ -0,0 +1,80 @@
+/*
+ *
+ * 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 "LFAcceptor.h"
+#include "APRBase.h"
+
+using namespace qpid::concurrent;
+using namespace qpid::io;
+
+LFAcceptor::LFAcceptor(bool _debug, int c, int worker_threads, int m) : processor(aprPool.pool, worker_threads, 1000, 5000000),
+ connectionBacklog(c),
+ max_connections_per_processor(m),
+ debug(_debug){
+
+}
+
+
+void LFAcceptor::bind(int port, SessionHandlerFactory* factory){
+ apr_socket_t* socket;
+ apr_sockaddr_t* address;
+ CHECK_APR_SUCCESS(apr_sockaddr_info_get(&address, APR_ANYADDR, APR_UNSPEC, port, APR_IPV4_ADDR_OK, aprPool.pool));
+ CHECK_APR_SUCCESS(apr_socket_create(&socket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, aprPool.pool));
+ 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, connectionBacklog));
+ running = true;
+ processor.start();
+
+ std::cout << "Listening on port " << port << "..." << std::endl;
+ while(running){
+ apr_socket_t* client;
+ apr_status_t status = apr_socket_accept(&client, socket, aprPool.pool);
+ 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.pool, client, &processor, debug);
+ session->init(factory->create(session));
+ }else{
+ running = false;
+ if(status != APR_EINTR){
+ std::cout << "ERROR: " << get_desc(status) << std::endl;
+ }
+ }
+ }
+
+ processor.stop();
+ CHECK_APR_SUCCESS(apr_socket_close(socket));
+}
+
+
+LFAcceptor::~LFAcceptor(){
+}
+
+LFAcceptor::APRPool::APRPool(){
+ APRBase::increment();
+ CHECK_APR_SUCCESS(apr_pool_create(&pool, NULL));
+}
+
+LFAcceptor::APRPool::~APRPool(){
+ apr_pool_destroy(pool);
+ APRBase::decrement();
+}
diff --git a/cpp/common/io/src/LFProcessor.cpp b/cpp/common/io/src/LFProcessor.cpp
new file mode 100644
index 0000000000..8ef3543b8f
--- /dev/null
+++ b/cpp/common/io/src/LFProcessor.cpp
@@ -0,0 +1,191 @@
+/*
+ *
+ * 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 "LFProcessor.h"
+#include "APRBase.h"
+#include "LFSessionContext.h"
+#include "QpidError.h"
+#include <sstream>
+
+using namespace qpid::io;
+using namespace qpid::concurrent;
+using qpid::QpidError;
+
+LFProcessor::LFProcessor(apr_pool_t* pool, int _workers, int _size, int _timeout) : size(_size),
+ timeout(_timeout),
+ signalledCount(0),
+ current(0),
+ count(0),
+ hasLeader(false),
+ workerCount(_workers),
+ workers(new Thread*[_workers]),
+ stopped(false){
+
+ CHECK_APR_SUCCESS(apr_pollset_create(&pollset, size, pool, APR_POLLSET_THREADSAFE));
+ //create & start the required number of threads
+ for(int i = 0; i < workerCount; i++){
+ workers[i] = factory.create(this);
+ }
+}
+
+
+LFProcessor::~LFProcessor(){
+ for(int i = 0; i < workerCount; i++){
+ delete workers[i];
+ }
+ delete[] workers;
+ CHECK_APR_SUCCESS(apr_pollset_destroy(pollset));
+}
+
+void LFProcessor::start(){
+ for(int i = 0; i < workerCount; i++){
+ workers[i]->start();
+ }
+}
+
+void LFProcessor::add(const apr_pollfd_t* const fd){
+ CHECK_APR_SUCCESS(apr_pollset_add(pollset, fd));
+ countLock.acquire();
+ sessions.push_back(reinterpret_cast<LFSessionContext*>(fd->client_data));
+ count++;
+ countLock.release();
+}
+
+void LFProcessor::remove(const apr_pollfd_t* const fd){
+ CHECK_APR_SUCCESS(apr_pollset_remove(pollset, fd));
+ countLock.acquire();
+ sessions.erase(find(sessions.begin(), sessions.end(), reinterpret_cast<LFSessionContext*>(fd->client_data)));
+ count--;
+ countLock.release();
+}
+
+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(){
+ countLock.acquire();
+ bool full = count == size;
+ countLock.release();
+ return full;
+}
+
+bool LFProcessor::empty(){
+ countLock.acquire();
+ bool empty = count == 0;
+ countLock.release();
+ return empty;
+}
+
+void LFProcessor::poll(){
+ apr_status_t status;
+ do{
+ current = 0;
+ if(!stopped){
+ status = apr_pollset_poll(pollset, timeout, &signalledCount, &signalledFDs);
+ }
+ }while(status != APR_SUCCESS && !stopped);
+}
+
+void LFProcessor::run(){
+ try{
+ while(!stopped){
+ leadLock.acquire();
+ waitToLead();
+ if(!stopped){
+ const apr_pollfd_t* evt = getNextEvent();
+ if(evt){
+ LFSessionContext* session = reinterpret_cast<LFSessionContext*>(evt->client_data);
+ session->startProcessing();
+
+ relinquishLead();
+ leadLock.release();
+
+ //process event:
+ if(evt->rtnevents & APR_POLLIN) session->read();
+ if(evt->rtnevents & APR_POLLOUT) session->write();
+
+ if(session->isClosed()){
+ session->handleClose();
+ countLock.acquire();
+ sessions.erase(find(sessions.begin(), sessions.end(), session));
+ count--;
+ countLock.release();
+ }else{
+ session->stopProcessing();
+ }
+
+ }else{
+ leadLock.release();
+ }
+ }else{
+ leadLock.release();
+ }
+ }
+ }catch(QpidError error){
+ std::cout << "Error [" << error.code << "] " << error.msg << " (" << error.file << ":" << error.line << ")" << 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;
+ leadLock.acquire();
+ leadLock.notifyAll();
+ leadLock.release();
+
+ 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/common/io/src/LFSessionContext.cpp b/cpp/common/io/src/LFSessionContext.cpp
new file mode 100644
index 0000000000..d786cb5e98
--- /dev/null
+++ b/cpp/common/io/src/LFSessionContext.cpp
@@ -0,0 +1,187 @@
+/*
+ *
+ * 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 "LFSessionContext.h"
+#include "APRBase.h"
+#include "QpidError.h"
+#include <assert.h>
+
+using namespace qpid::concurrent;
+using namespace qpid::io;
+using namespace qpid::framing;
+
+LFSessionContext::LFSessionContext(apr_pool_t* _pool, apr_socket_t* _socket,
+ LFProcessor* const _processor,
+ bool _debug) : socket(_socket),
+ processor(_processor),
+ initiated(false),
+ processing(false),
+ closing(false),
+ in(32768),
+ out(32768),
+ reading(0),
+ writing(0),
+ debug(_debug){
+
+ 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(){
+ assert(!reading); // No concurrent read.
+ reading = APRThread::currentThread();
+
+ socket.read(in);
+ in.flip();
+ if(initiated){
+ AMQFrame frame;
+ while(frame.decode(in)){
+ if(debug) log("RECV", &frame);
+ handler->received(&frame);
+ }
+ }else{
+ ProtocolInitiation init;
+ if(init.decode(in)){
+ handler->initiated(&init);
+ initiated = true;
+ if(debug) std::cout << "INIT [" << &socket << "]" << std::endl;
+ }
+ }
+ in.compact();
+
+ reading = 0;
+}
+
+void LFSessionContext::write(){
+ assert(!writing); // No concurrent writes.
+ writing = APRThread::currentThread();
+
+ bool done = isClosed();
+ while(!done){
+ if(out.available() > 0){
+ socket.write(out);
+ if(out.available() > 0){
+ writing = 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?
+ writeLock.acquire();
+ 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;
+
+ writing = 0;
+
+ if(closing){
+ socket.close();
+ }
+ }
+ writeLock.release();
+ }
+ }
+}
+
+void LFSessionContext::send(AMQFrame* frame){
+ writeLock.acquire();
+ if(!closing){
+ framesToWrite.push(frame);
+ if(!(fd.reqevents & APR_POLLOUT)){
+ fd.reqevents |= APR_POLLOUT;
+ if(!processing){
+ processor->update(&fd);
+ }
+ }
+ }
+ writeLock.release();
+}
+
+void LFSessionContext::startProcessing(){
+ writeLock.acquire();
+ processing = true;
+ processor->deactivate(&fd);
+ writeLock.release();
+}
+
+void LFSessionContext::stopProcessing(){
+ writeLock.acquire();
+ processor->reactivate(&fd);
+ processing = false;
+ writeLock.release();
+}
+
+void LFSessionContext::close(){
+ closing = true;
+ writeLock.acquire();
+ if(!processing){
+ //allow pending frames to be written to socket
+ fd.reqevents = APR_POLLOUT;
+ processor->update(&fd);
+ }
+ writeLock.release();
+}
+
+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(SessionHandler* handler){
+ this->handler = handler;
+ processor->add(&fd);
+}
+
+void LFSessionContext::log(const std::string& desc, AMQFrame* const frame){
+ logLock.acquire();
+ std::cout << desc << " [" << &socket << "]: " << *frame << std::endl;
+ logLock.release();
+}
+
+APRMonitor LFSessionContext::logLock;
diff --git a/cpp/common/utils/inc/logger.h b/cpp/common/utils/inc/logger.h
new file mode 100644
index 0000000000..8a57854476
--- /dev/null
+++ b/cpp/common/utils/inc/logger.h
@@ -0,0 +1,82 @@
+/*
+ *
+ * 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.
+ *
+ */
+/*********************************************************************
+*
+* NOTE: This is a lightweight logging class intended for debugging and
+* verification purposes only.
+*
+* DO NOT USE FOR PRODUCT DEVELOPMENT - Rather, use an agreed upon
+* established logging class (such as Apache's log4cxx) for product
+* development purposes.
+*
+*********************************************************************/
+
+#ifndef __LOGGER__
+#define __LOGGER__
+
+#include <fstream>
+#include <iostream>
+
+namespace qpid {
+namespace utils {
+
+class Logger : public std::ofstream
+{
+ private:
+ bool echo_flag;
+ bool timestamp_flag;
+ bool eol_flag;
+ char buff[128]; // Buffer for writing formatted strings
+
+ void write_timestamp();
+
+ public:
+ Logger(const char* filename, const bool append);
+ Logger(std::string& filename, const bool append);
+ ~Logger();
+
+ bool getEchoFlag() {return echo_flag;}
+ bool setEchoFlag(const bool _echo_flag) {echo_flag = _echo_flag;}
+ bool getTimestampFlag() {return timestamp_flag;}
+ bool setTimestampFlag(const bool _timestamp_flag) {timestamp_flag = _timestamp_flag;}
+
+ void log(const char* message);
+ void log(const char* message, const bool echo);
+ void log(const char* message, const bool echo, const bool timestamp);
+
+ Logger& operator<< (bool b);
+ Logger& operator<< (const short s);
+ Logger& operator<< (const unsigned short us);
+ Logger& operator<< (const int i);
+ Logger& operator<< (const unsigned int ui);
+ Logger& operator<< (const long l);
+ Logger& operator<< (const unsigned long ul);
+ Logger& operator<< (const long long l);
+ Logger& operator<< (const unsigned long long ul);
+ Logger& operator<< (const float f);
+ Logger& operator<< (const double d);
+ Logger& operator<< (const long double ld);
+ Logger& operator<< (const char* cstr);
+ Logger& operator<< (const std::string& str);
+};
+
+}
+}
+
+
+#endif
diff --git a/cpp/common/utils/inc/memory.h b/cpp/common/utils/inc/memory.h
new file mode 100644
index 0000000000..2d65877adb
--- /dev/null
+++ b/cpp/common/utils/inc/memory.h
@@ -0,0 +1,17 @@
+#ifndef __UTIL_MEMORY__
+#define __UTIL_MEMORY__
+
+#if __GNUC__ < 4
+ #include "boost/shared_ptr.hpp"
+ namespace std {
+ namespace tr1 {
+ using boost::shared_ptr;
+ using boost::dynamic_pointer_cast;
+ using boost::static_pointer_cast;
+ }
+ }
+#else
+ #include <tr1/memory>
+#endif
+#endif
+
diff --git a/cpp/common/utils/src/Makefile b/cpp/common/utils/src/Makefile
new file mode 100644
index 0000000000..0185ab9975
--- /dev/null
+++ b/cpp/common/utils/src/Makefile
@@ -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.
+ #
+##### Options #####
+QPID_HOME = ../../../..
+
+include ${QPID_HOME}/cpp/options.mk
+
+##### Compiler flags #####
+CXXFLAGS = -I ../inc -I ${APR_HOME}/include/apr-1/
+
+##### Targets #####
+# Add additional source files to SOURCE LIST to include them in the build.
+COMMON_SOURCE_LIST = logger.cpp
+
+COMMON_OBJ_LIST = $(COMMON_SOURCE_LIST:.cpp=.o)
+LOGGER_TEST_EXE = logger_test
+
+
+.PHONY: all clean
+
+all: $(LOGGER_TEST_EXE)
+
+$(LOGGER_TEST_EXE) : $(COMMON_OBJ_LIST) $(LOGGER_TEST_EXE).o
+ $(CXX) -o $@ $^ -l apr-1 -L /usr/local/apr/lib/
+
+clean:
+ -@rm -f $(LOGGER_TEST_EXE) $(LOGGER_TEST_EXE).o $(COMMON_OBJ_LIST) test_log.txt *~ ../inc/*~
diff --git a/cpp/common/utils/src/logger.cpp b/cpp/common/utils/src/logger.cpp
new file mode 100644
index 0000000000..603fa6574e
--- /dev/null
+++ b/cpp/common/utils/src/logger.cpp
@@ -0,0 +1,209 @@
+/*
+ *
+ * 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.
+ *
+ */
+/*********************************************************************
+*
+* NOTE: This is a lightweight logging class intended for debugging and
+* verification purposes only.
+*
+* DO NOT USE FOR PRODUCT DEVELOPMENT - Rather, use an agreed upon
+* established logging class (such as Apache's log4cxx) for product
+* development purposes.
+*
+*********************************************************************/
+
+#include <iostream>
+#include <ostream>
+#include <string.h>
+#include "apr_time.h"
+#include "logger.h"
+
+namespace qpid {
+namespace utils {
+
+Logger::Logger(const char* filename, const bool append):
+ std::ofstream(filename, append ? std::ios::app : std::ios::out)
+{
+ echo_flag = false;
+ timestamp_flag = true;
+ eol_flag = true;
+}
+
+Logger::Logger(std::string& filename, const bool append):
+ std::ofstream(filename.c_str(), append ? std::ios::app : std::ios::out)
+{
+ echo_flag = false;
+ timestamp_flag = true;
+ eol_flag = true;
+}
+
+Logger::~Logger()
+{
+ close();
+}
+
+void Logger::write_timestamp()
+{
+ int len;
+ apr_time_exp_t now;
+ apr_time_exp_lt(&now, apr_time_now());
+ sprintf(buff, "%4d/%02d/%02d %02d:%02d:%02d.%06d : ", 1900+now.tm_year, now.tm_mon,
+ now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec, now.tm_usec);
+ write(buff, strlen(buff));
+}
+
+
+void Logger::log(const char* message)
+{
+ if (timestamp_flag && eol_flag)
+ {
+ eol_flag = false;
+ write_timestamp();
+ }
+ write(message, strlen(message));
+ if (echo_flag)
+ std::cout << message;
+ if (strchr(message, '\n'))
+ eol_flag = true;
+}
+
+void Logger::log(const char* message, const bool echo)
+{
+ if (timestamp_flag && eol_flag)
+ {
+ eol_flag = false;
+ write_timestamp();
+ }
+ write(message, strlen(message));
+ if (echo)
+ std::cout << message;
+ if (strchr(message, '\n'))
+ eol_flag = true;
+}
+
+void Logger::log(const char* message, const bool echo, const bool timestamp)
+{
+ if (timestamp && eol_flag)
+ {
+ eol_flag = false;
+ write_timestamp();
+ }
+ write(message, strlen(message));
+ if (echo)
+ std::cout << message;
+ if (strchr(message, '\n'))
+ eol_flag = true;
+}
+
+Logger& Logger::operator<< (const bool b)
+{
+ log(b ? "true" : "false");
+ return *this;
+}
+
+Logger& Logger::operator<< (const short s)
+{
+ sprintf(buff, "%d", s);
+ log(buff);
+ return *this;
+}
+
+Logger& Logger::operator<< (const unsigned short us)
+{
+ sprintf(buff, "%u", us);
+ log(buff);
+ return *this;
+}
+
+Logger& Logger::operator<< (const int i)
+{
+ sprintf(buff, "%d", i);
+ log(buff);
+ return *this;
+}
+
+Logger& Logger::operator<< (const unsigned int ui)
+{
+ sprintf(buff, "%u", ui);
+ log(buff);
+ return *this;
+}
+
+Logger& Logger::operator<< (const long l)
+{
+ sprintf(buff, "%ld", l);
+ log(buff);
+ return *this;
+}
+
+Logger& Logger::operator<< (const unsigned long ul)
+{
+ sprintf(buff, "%lu", ul);
+ log(buff);
+ return *this;
+}
+
+Logger& Logger::operator<< (const long long l)
+{
+ sprintf(buff, "%ld", l);
+ log(buff);
+ return *this;
+}
+
+Logger& Logger::operator<< (const unsigned long long ul)
+{
+ sprintf(buff, "%lu", ul);
+ log(buff);
+ return *this;
+}
+
+Logger& Logger::operator<< (const float f)
+{
+ sprintf(buff, "%f", f);
+ log(buff);
+ return *this;
+}
+
+Logger& Logger::operator<< (const double d)
+{
+ sprintf(buff, "%lf", d);
+ log(buff);
+ return *this;
+}
+
+Logger& Logger::operator<< (const long double ld)
+{
+ sprintf(buff, "%Lf", ld);
+ log(buff);
+ return *this;
+}
+
+Logger& Logger::operator<< (const char* cstr)
+{
+ log(cstr);
+ return *this;
+}
+
+Logger& Logger::operator<< (const std::string& str)
+{
+ log(str.c_str());
+ return *this;
+}
+
+}
+}
+
diff --git a/cpp/common/utils/src/logger_test.cpp b/cpp/common/utils/src/logger_test.cpp
new file mode 100644
index 0000000000..1866af9fbb
--- /dev/null
+++ b/cpp/common/utils/src/logger_test.cpp
@@ -0,0 +1,78 @@
+/*
+ *
+ * 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 <string>
+#include "logger.h"
+
+using namespace qpid::utils;
+
+void run_sequence(Logger& log)
+{
+ bool b = true;
+ short s = -5;
+ unsigned short us = 12;
+ int i = -2345;
+ unsigned int ui = 34567;
+ long l = -12345678;
+ unsigned long ul = 23456789;
+ long long ll = -1234567890;
+ unsigned long long ull = 1234567890;
+ float f = -123.45678;
+ double d = 123.45678901;
+ long double ld = 23456.789012345678;
+ char* cstr = "This is a test C string.";
+ char* cr = "\n";
+ std::string str("This is a test std::string");
+ log << "bool = " << b << cr;
+ log << "short = " << s << cr;
+ log << "unsigned sort = " << us << cr;
+ log << "int = " << i << cr;
+ log << "unsigned int = " << ui << cr;
+ log << "long = " << l << cr;
+ log << "unsigned long = " << ul << cr;
+ log << "long long = " << ll << cr;
+ log << "unsigned long long = " << ull << cr;
+ log << "float = " << f << cr;
+ log << "double = " << d << cr;
+ log << "long double = " << ld << cr;
+ log << "char* = " << cstr << cr;
+ log << "std::string = " << str << cr;
+ log << "String 1\n";
+ log << "String 2\n" << "String 3 " << "String 4\n";
+ log << "Literal bool = " << false << cr;
+ log << "Literal unsigned int = " << 15 << cr;
+ log << "Literal double = " << (double)15 << cr;
+}
+
+int main(int argc, char** argv)
+{
+ Logger log("test_log.txt", false);
+ std::cout << "****** Initial state (echo off, timestamp on)" << std::endl;
+ run_sequence(log);
+ std::cout << std::endl << "****** (echo off, timestamp off)" << std::endl;
+ log.setTimestampFlag(false);
+ run_sequence(log);
+ std::cout << std::endl << "****** (echo on, timestamp on)" << std::endl;
+ log.setEchoFlag(true);
+ log.setTimestampFlag(true);
+ run_sequence(log);
+ std::cout << std::endl << "****** (echo on, timestamp off)" << std::endl;
+ log.setTimestampFlag(false);
+ run_sequence(log);
+ return 0;
+}
diff --git a/cpp/doxygen/Makefile b/cpp/doxygen/Makefile
new file mode 100644
index 0000000000..187fe698a0
--- /dev/null
+++ b/cpp/doxygen/Makefile
@@ -0,0 +1,23 @@
+ #
+ # 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.
+ #
+
+.PHONY: all
+
+all:
+ doxygen doxygen.cfg
+
+clean:
+ rm -rf html
diff --git a/cpp/doxygen/doxygen.cfg b/cpp/doxygen/doxygen.cfg
new file mode 100644
index 0000000000..d31c1bb134
--- /dev/null
+++ b/cpp/doxygen/doxygen.cfg
@@ -0,0 +1,1238 @@
+# NB: requires doxygen and graphviz - install with yum.
+
+# Doxyfile 1.4.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = Qpid
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 0
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = YES
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ..
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+
+
+FILE_PATTERNS = *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = YES
diff --git a/cpp/options.mk b/cpp/options.mk
new file mode 100644
index 0000000000..a1dfd695a7
--- /dev/null
+++ b/cpp/options.mk
@@ -0,0 +1,54 @@
+ #l
+ # 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.
+ #
+
+# Directories
+SPEC_DIR = ${QPID_HOME}/specs
+QPID_CPP_HOME = ${QPID_HOME}/cpp
+COMMON_HOME = ${QPID_CPP_HOME}/common
+TOOLS_DIR = ${QPID_CPP_HOME}/tools
+LIB_DIR = ${QPID_CPP_HOME}/lib
+BIN_DIR = ${QPID_CPP_HOME}/bin
+APR_HOME= /usr
+BOOST_HOME= /usr
+CPPUNIT_HOME= /usr
+
+# Compile flags
+DEBUG = -g
+# _USE_APR_IO_ set when APR IO build is desired.
+OPT = -D _USE_APR_IO_ #-O3
+APR_INCLUDES=-I ${APR_HOME}/include/apr-1/
+BOOST_INCLUDES=-I ${BOOST_HOME}/include/boost-1_33_1
+CPPUNIT_INCLUDES=-I ${CPPUNIT_HOME}/include
+COMMON_INCLUDES = -I ${COMMON_HOME}/framing/inc -I ${COMMON_HOME}/framing/generated -I ${COMMON_HOME}/concurrent/inc -I ${COMMON_HOME}/io/inc -I ${COMMON_HOME}/error/inc -I $(COMMON_HOME)/utils/inc ${APR_INCLUDES} ${BOOST_INCLUDES} ${CPPUNIT_INCLUDES}
+SRC_INCLUDES = $(COMMON_INCLUDES) -I inc
+TEST_INCLUDES = $(COMMON_INCLUDES) -I ../inc
+INCLUDES=$(SRC_INCLUDES) # Default to src
+CXXFLAGS = $(DEBUG) $(OPT) -MMD -fpic $(INCLUDES)
+
+# TODO aconway 2006-09-12: This is not something we want in a release
+# but it's useful for development.
+RPATH= -Wl,-rpath,$(CURDIR)/$(LIB_DIR)
+
+# General link flags
+LDFLAGS= -L $(LIB_DIR) -L ${APR_HOME}/lib -L ${BOOST_HOME}/lib -L ${CPPUNIT_HOME}/lib $(RPATH)
+
+# Libraries and executables. Use absolute paths so exes can find
+# libs wherever they are run. TODO: Proper library management.
+BROKER=$(BIN_DIR)/qpidd
+BROKER_LIB=$(CURDIR)/$(LIB_DIR)/libqpid_broker.so.1.0
+COMMON_LIB=$(CURDIR)/$(LIB_DIR)/libqpid_common.so.1.0
+CLIENT_LIB=$(CURDIR)/$(LIB_DIR)/libqpid_client.so.1.0
+
diff --git a/cpp/test_plugins.mk b/cpp/test_plugins.mk
new file mode 100644
index 0000000000..abac186954
--- /dev/null
+++ b/cpp/test_plugins.mk
@@ -0,0 +1,42 @@
+#
+# 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.
+#
+
+
+#
+# Standard make fragment for building test plugins in a directory.
+#
+
+include ${QPID_HOME}/cpp/options.mk
+
+SOURCES := $(wildcard *.cpp)
+TESTS := $(SOURCES:.cpp=.so)
+DEPS= $(SOURCES:.cpp=.d)
+
+INCLUDES = $(TEST_INCLUDES)
+
+.PHONY: all clean
+
+all: $(TESTS)
+
+clean:
+ -@rm -f $(TESTS) $(DEPS)
+
+# Rule to build test plugins from .cpp files.
+%.so: %.cpp
+ $(CXX) -shared -o $@ $< $(CXXFLAGS) $(LDFLAGS) $(LDLIBS)
+
+# Dependencies
+-include $(DEPS)
diff --git a/cpp/tools/saxon8.jar b/cpp/tools/saxon8.jar
new file mode 100644
index 0000000000..197ce75c5b
--- /dev/null
+++ b/cpp/tools/saxon8.jar
Binary files differ