diff options
author | Alan Conway <aconway@apache.org> | 2007-03-21 01:26:37 +0000 |
---|---|---|
committer | Alan Conway <aconway@apache.org> | 2007-03-21 01:26:37 +0000 |
commit | 1fb29f138da337b2b318355477b271dcf2fa13ca (patch) | |
tree | 2da3d26e35031c6e7b2587b77bc1d2a9460a9a9c | |
parent | 7ee9b2a933020efadcba42d6200a786321695507 (diff) | |
download | qpid-python-1fb29f138da337b2b318355477b271dcf2fa13ca.tar.gz |
* cpp-0-9: svn copy of 0-9 branch cpp, will rename to cpp on next update.
* cpp-0-9/gentools: independent copy of gentools for cpp.
Temporary measure till /java and /gentools are at 0-9
* python/tests_0-9: tests from 0-9 branch.
* python/qpid/testlib.py: Use tests_0-9 with 0-9 spec (default is still 0-8)
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@520690 13f79535-47bb-0310-9956-ffa450edef68
370 files changed, 69732 insertions, 6 deletions
diff --git a/qpid/cpp-0-9/DESIGN b/qpid/cpp-0-9/DESIGN new file mode 100644 index 0000000000..7e9ba6755c --- /dev/null +++ b/qpid/cpp-0-9/DESIGN @@ -0,0 +1,79 @@ +Qpid C++ AMQP implementation +============================= + += Project layout = + +For Build system design see comment at start of Makefile. + +Project contains: + * Client library (lib/libqpid_client): src/qpid/client + * Broker library (lib/libqpid_broker): src/qpid/broker + * Common classes + * src/qpid/concurrent: concurrecy + * src/qpid/framing: wire encoding/decoding + * src/qpid/io: reading/writing + * src/qpid/Exception.cpp, QpidError.cpp: Exception classes. + * Qpid Daemon (bin/qpidd): src/qpidd.cpp + +Unit tests in test/unit: each *Test.cpp builds a CppUnit plugin. + +Client tests in test/client: each *.cpp builds a test executable. + +Test utilities: test/include + += 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/qpid/cpp-0-9/LICENSE b/qpid/cpp-0-9/LICENSE new file mode 100644 index 0000000000..6b0b1270ff --- /dev/null +++ b/qpid/cpp-0-9/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + diff --git a/qpid/cpp-0-9/Makefile.am b/qpid/cpp-0-9/Makefile.am new file mode 100644 index 0000000000..112cd5dd59 --- /dev/null +++ b/qpid/cpp-0-9/Makefile.am @@ -0,0 +1,26 @@ +AUTOMAKE_OPTIONS = 1.9.2 foreign +ACLOCAL_AMFLAGS = -I m4 + +EXTRA_DIST = \ + LICENSE NOTICE README \ + etc/qpidd \ + $(PACKAGE).spec \ + $(PACKAGE).spec.in + +SUBDIRS = gen lib src docs/api docs/man rpm tests + +# Update libtool, if needed. +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck + +# This cannot be done by AC_CONFIG_FILES, because automake's +# make distcheck target does not like auto-generated files +# being included in the distributed archive. +qpidc.spec: %: %.in + sed 's/@''PACKAGE@/@PACKAGE@/;s/@''VERSION@/@VERSION@/' $< > $@-tmp + mv $@-tmp $@ +MAINTAINERCLEANFILES = $(PACKAGE).spec + +.PHONY: rpm srpm +rpm srpm: + cd rpm && $(MAKE) $(MAKEFLAGS_AM) $@ diff --git a/qpid/cpp-0-9/NOTICE b/qpid/cpp-0-9/NOTICE new file mode 100644 index 0000000000..1e7859909a --- /dev/null +++ b/qpid/cpp-0-9/NOTICE @@ -0,0 +1,21 @@ +========================================================================= +== NOTICE file corresponding to the section 4 d of == +== the Apache License, Version 2.0, == +== in this case for the Apache Qpid distribution. == +========================================================================= + +This product includes software developed by the Apache Software Foundation +(http://www.apache.org/). + +Please read the LICENSE file present in the root directory of this +distribution. + + +Aside from contributions to the Apache Qpid project, this software also +includes (binary only): + + - None. + + + + diff --git a/qpid/cpp-0-9/README b/qpid/cpp-0-9/README new file mode 100644 index 0000000000..83e9d6ed5e --- /dev/null +++ b/qpid/cpp-0-9/README @@ -0,0 +1,274 @@ += Qpid C++ = + +Qpid C++ is a C++ implementation of the AMQP protcol described at + http://amqp.org/ + +The Qpid project also provides Java, Ruby and Python implementations. + +For additional software or information on the Qpid project go to: + http://incubator.apache.org/qpid/index.html + + +Available documentation: + qpidd(1) man page - how to run the broker daemon. + html/index.html - C++ client API. + +Note the daemon and client API can be installed separately. + +This README describes how to build the Qpid C++ broker and client, either +from a checkout of the source or from a source distribution. + +== Prerequisites == + +We prefer to avoid spending time accommodating older versions of these +packages, so please make sure that you have the latest stable versions. +Known version numbers for a succesfull build are given in brackets, take +these as a recommended minimum version. Older unix versions, for example, +Redhat Linux 3, will almost certainly require some packages to be upgraded. + +Qpid can be built using the gcc compiler: + + # gcc <http://gcc.gnu.org/> (3.2.3) + +Qpid is compiled against libraries: + + * apr <http://apr.apache.org> (1.2.7) + * boost <http://www.boost.org> (1.33.1) + * cppunit <http://cppunit.sourceforge.net> (1.11.4) + +Using tools: + + * boost-jam <http://boost.sourceforge.net/> (3.1.13) + * GNU make <http://www.gnu.org/software/make/> (3.8.0) + * autoconf <http://www.gnu.org/software/autoconf/> (2.61) + * automake <http://www.gnu.org/software/automake/> (1.9.6) + * help2man <http://www.gnu.org/software/help2man/> (1.36.4) + * libtool <http://www.gnu.org/software/libtool/> (1.5.22) + * pkgconfig <http://pkgconfig.freedesktop.org/wiki/> (0.21) + * doxygen <ftp://ftp.stack.nl/pub/users/dimitri/> (1.5.1) + * graphviz <http://www.graphviz.org/> (2.12) + * JDK 5.0 <http://java.sun.com/j2se/1.5.0/> (1.5.0.11) + +=== Optional tools === + +Building from a source distribution does not require: + + * autoconf + * automake + * JDK 5.0 + +Building without testing does not require: + + * cppunit + +Building without documentaion does not require: + + * help2man + * doxygen + * graphviz + +=== Installing as root === + +On linux most packages can be installed using your distribution's package +management tool. For example on Fedora: + + # yum install apr apr-devel boost boost-devel cppunit cppunit-devel + # yum install pkgconfig doxygen graphviz help2man + + +Follow the manual installation instruction below for any packages not +available through yum. + +=== Building and installing packages manually or as non-root user === + +Required dependencies can be installed and built from source distributions. +It is recommended that you create a directory to install them to, for example, +~/qpid-tools. To build and install the dependency pakcages: + + 1. Unzip and untar them and cd to the untared directory. + 2. do: + # ./configure --prefix=~/qpid-tools + # make install + + The exceptions to this are boost and JDK 5.0. + To build the boost library: + + 1. Unpack boost-jam. + 2. Add bjam in the unpacked directory to your path. + 3. Unpack boost and cd to the boost untarred directory. + 4. do: + + # bjam -sTOOLS=gcc --prefix=~/qpid-tools + +To install JDK 5.0 download and run its install script, or whatever +alternative instructions may be on the sun website. + +Ensure that all the build tools are available on your path, when they are +manually installed to non-standard locations. For example: + + # export PATH=~/qpid-tools/bin:$PATH + +Ensure that pkg-config is set up correctly. For example: + + # export PKG_CONFIG_PATH=~/qpid-tools/lib/pkgconfig:/usr/local/pkgconfig + # export PKG_CONFIG=~/qpid-tools/bin/pkg-config + +Ensure that the boost libraries are made available on the gcc library path. +For example: + + # export CXXFLAGS=-I~/qpid-tools/include/boost-1_33_1 + +Ensure that JDK 5.0 has its home location set up correctly and is added to +the path. For example: + + # export PATH=~/jdk1.5.0_11/bin:$PATH + +== Building from a source distribution. == + +In the distribution directory + +Build and install with: + + # ./configure --prefix=<install_location> + # make all + # make install + +To build and test everything: + + # make + # make check + +This builds in the source tree. You can have multiple builds in the +same working copy with different configuration. For example you can do +the following to build twice, once for debug, the other with +optimization: + + # make distclean + # mkdir .build-dbg .build-opt + # (cd .build-opt ../configure --prefix=/tmp/x && make && make check) + # (cd .build-dbg ../configure CXXFLAGS=-g --prefix=/tmp/x \ + && make && make check) + + +== For Qpid developers: building a repository working copy == + +=== Installing the latest autotools === + +If you don't have sufficiently up-to-date autotools you can get the +latest by running run the script qpid-autotools-install. + +1. Decide where you would like to install the tools. It should be in a + local directory so that you do not need root privileges. (Suggest + $HOME/qpid-tools.) Create an empty directory. +2. Modify your environment variable PATH to ensure that the bin directory + within this directory comes first in the PATH string: + PATH=$HOME/qpid-tools/bin:$PATH +3. Set PKG_CONFIG_PATH=$HOME/qpid-tools/lib/pkgconfig:/usr/lib/pkgconfig + (or if it already exists, make sure that the above path to your + qpid-tools directory is first). +4. Run the install utility from the cpp directory: + ./qpid-autotools-install --prefix=$HOME/qpid-tools --skip-check + (Note that --prefix will only accept an absolute path, so don't use + ~/qpid-tools.) The utility will download, compile and install the + required tools into the qpid-tools directory (this may take a little + time). Watch for any notices about paths at the end of the install - + this means that your environment is not correct - see steps 2 and 3 + above. + NOTE: If you omit the --skip-check option, the check of the build + can add up to an hour to what is normally a few minutes of install + time. +5. Perform a check: from the command-line run "which automake" and + ensure that it finds the automake in your qpid-tools directory. If not, + check that the build completed normally and your environment. +6. (Optional) If having the build artifacts lying around bothers you, delete + the (hidden) build directory cpp/.build-auto-tools. + +To see help, run ./qpid-autotools-install --help. + +=== Building a checkout === +To get the source code from the subversion repository (trunk) do: + + # svn checkout https://svn.apache.org/repos/asf/incubator/qpid/trunk/ . + +To build a fresh checkout: + +Cd to qpid/cpp subdirectory. Before running make on a fresh checkout do: + + # ./bootstrap + +This generates config, makefiles and the like - check the script for +details. You only need to do this once, "make" will keep everything up +to date thereafter (including re-generating configuration & Makefiles +if the automake templates change etc.) + +If you are developing code yourself, or if you want to help +us keep the code as tight and robust as possible, consider enabling +the use of valgrind. If you configure like this: + + # ./configure --enable-valgrind + +That will arrange (assuming you have valgrind installed) for "make check" +to run tests via valgrind. That makes the tests run more slowly, but +helps detect certain types of bugs, as well as memory leaks. If you run +"make check" and valgrind detects a leak that is not listed as being +"ignorable-for-now", the test script in question will fail. However, +recording whether a leak is ignorable is not easy, when the stack +signature, libraries, compiler, O/S, architecture, etc., may all vary, +so if you see a new leak, try to figure out if it's one you can fix +before adding it to the list. + +Now follow instruction for building from a source distribution. + +=== Portability === + +All system calls are abstracted by classes under lib/common/sys. This +provides an object-oriented C++ API and contains platform-specific +code. + +These wrappers are mainly inline by-value classes so they impose no +run-time penalty compared do direct system calls. + +Initially we will have a full linux implementation and a portable +implementation sufficient for the client using the APR portability +library. The implementations may change in future but the interface +for qpid code outside the qpid/sys namespace should remain stable. + +=== 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. + +NOTE: If foobar.so is a test plugin in the current directory then +surprisingly this will fail with "can't load plugin": + # DllPluginTester foobar.so + +Instead you need to say: + # DllPluginTester ./foobar.so + +Reason: DllPluginTester uses dlopen() which only searches for shlibs +in the standard places unless the filename contains a "/". In that +case it just tries to open the filename. + +=== 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 +This README describes how to build the Qpid C++ broker and client, either +from a checkout of the source or from a source distribution. diff --git a/qpid/cpp-0-9/bootstrap b/qpid/cpp-0-9/bootstrap new file mode 100755 index 0000000000..4fbce77e3f --- /dev/null +++ b/qpid/cpp-0-9/bootstrap @@ -0,0 +1,39 @@ +#!/bin/sh +set -e +aclocal -I m4 +autoheader +libtoolize --automake + +# These are needed only if you don't already have the gen/*.{h,cpp} files. +: ${JAVA=java} +: ${JAVAC=javac} +export JAVA JAVAC + +# If we're building in the qpid tree, we can generate +# some Makefile snippets: + +if test -d ../specs; then + # Transform gen/Makefile.am, removing automake-constructs and the + # contents of the sole automake-else clause (the warning), then + # use the result to run the rules that create gen-src.mk, a file + # that must be created before we run automake. + (cd gen && rm -f gen-src.mk + perl -ne '/warning:|^(if|else|endif|include)\b/ or print' Makefile.am \ + | make -f - srcdir=. gen-src.mk > /dev/null ) +fi + +# Generate (for automake) lots of repetitive parts of tests/Makefile.am. +(cd tests && rm -f gen.mk + perl -ne '/^include / or print' Makefile.am \ + | make -f - abs_srcdir=`dirname $(pwd)` gen.mk > /dev/null ) + +automake +autoconf + + +if [ "$1" = "-build" -o "$1" = "--build" ] ; then + shift + ./configure "$@" + make + make check +fi diff --git a/qpid/cpp-0-9/build-aux/compile b/qpid/cpp-0-9/build-aux/compile new file mode 100755 index 0000000000..1b1d232169 --- /dev/null +++ b/qpid/cpp-0-9/build-aux/compile @@ -0,0 +1,142 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. +# Written by Tom Tromey <tromey@cygnus.com>. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to <bug-automake@gnu.org> or send patches to +# <automake-patches@gnu.org>. + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to <bug-automake@gnu.org>. +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/qpid/cpp-0-9/build-aux/config.guess b/qpid/cpp-0-9/build-aux/config.guess new file mode 100755 index 0000000000..c93201a4d2 --- /dev/null +++ b/qpid/cpp-0-9/build-aux/config.guess @@ -0,0 +1,1501 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +# Inc. + +timestamp='2006-11-08' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner <per@bothner.com>. +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + x86:Interix*:[3456]*) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T:Interix*:[3456]* | authenticamd:Interix*:[3456]*) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <features.h> + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include <sys/param.h> +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 <<EOF +$0: unable to guess system type + +This script, last modified $timestamp, has failed to recognize +the operating system you are using. It is advised that you +download the most up to date version of the config scripts from + + http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess +and + http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub + +If the version you run ($0) is already up to date, please +send the following data and any information you think might be +pertinent to <config-patches@gnu.org> in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/qpid/cpp-0-9/build-aux/config.rpath b/qpid/cpp-0-9/build-aux/config.rpath new file mode 100755 index 0000000000..c492a93b66 --- /dev/null +++ b/qpid/cpp-0-9/build-aux/config.rpath @@ -0,0 +1,614 @@ +#! /bin/sh +# Output a system dependent set of variables, describing how to set the +# run time search path of shared libraries in an executable. +# +# Copyright 1996-2006 Free Software Foundation, Inc. +# Taken from GNU libtool, 2001 +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld +# should be set by the caller. +# +# The set of defined variables is at the end of this script. + +# Known limitations: +# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer +# than 256 bytes, otherwise the compiler driver will dump core. The only +# known workaround is to choose shorter directory names for the build +# directory and/or the installation directory. + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +shrext=.so + +host="$1" +host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +# Code taken from libtool.m4's _LT_CC_BASENAME. + +for cc_temp in $CC""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` + +# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC. + +wl= +if test "$GCC" = yes; then + wl='-Wl,' +else + case "$host_os" in + aix*) + wl='-Wl,' + ;; + darwin*) + case $cc_basename in + xlc*) + wl='-Wl,' + ;; + esac + ;; + mingw* | pw32* | os2*) + ;; + hpux9* | hpux10* | hpux11*) + wl='-Wl,' + ;; + irix5* | irix6* | nonstopux*) + wl='-Wl,' + ;; + newsos6) + ;; + linux*) + case $cc_basename in + icc* | ecc*) + wl='-Wl,' + ;; + pgcc | pgf77 | pgf90) + wl='-Wl,' + ;; + ccc*) + wl='-Wl,' + ;; + como) + wl='-lopt=' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + wl='-Wl,' + ;; + esac + ;; + esac + ;; + osf3* | osf4* | osf5*) + wl='-Wl,' + ;; + sco3.2v5*) + ;; + solaris*) + wl='-Wl,' + ;; + sunos4*) + wl='-Qoption ld ' + ;; + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + wl='-Wl,' + ;; + sysv4*MP*) + ;; + unicos*) + wl='-Wl,' + ;; + uts4*) + ;; + esac +fi + +# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS. + +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no + +case "$host_os" in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + # Unlike libtool, we use -rpath here, not --rpath, since the documented + # option of GNU ld is called -rpath, not --rpath. + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + case "$host_os" in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we cannot use + # them. + ld_shlibs=no + ;; + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + cygwin* | mingw* | pw32*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + interix3*) + hardcode_direct=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + netbsd*) + ;; + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + else + ld_shlibs=no + fi + ;; + esac + ;; + sunos4*) + hardcode_direct=yes + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + esac + if test "$ld_shlibs" = no; then + hardcode_libdir_flag_spec= + fi +else + case "$host_os" in + aix3*) + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + else + aix_use_runtimelinking=no + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + fi + hardcode_direct=yes + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + fi + # Begin _LT_AC_SYS_LIBPATH_AIX. + echo 'int main () { return 0; }' > conftest.c + ${CC} ${LDFLAGS} conftest.c -o conftest + aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + fi + if test -z "$aix_libpath"; then + aix_libpath="/usr/lib:/lib" + fi + rm -f conftest.c conftest + # End _LT_AC_SYS_LIBPATH_AIX. + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + else + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + fi + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + libext=lib + ;; + darwin* | rhapsody*) + hardcode_direct=no + if test "$GCC" = yes ; then + : + else + case $cc_basename in + xlc*) + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + freebsd1*) + ld_shlibs=no + ;; + freebsd2.2*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + freebsd2*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + hpux9*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + hpux10*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + hpux11*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + ;; + *) + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + irix5* | irix6* | nonstopux*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + netbsd*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + newsos6) + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + openbsd*) + hardcode_direct=yes + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + osf3*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + osf4* | osf5*) + if test "$GCC" = yes; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + # Both cc and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + solaris*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + sunos4*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + sysv4) + case $host_vendor in + sni) + hardcode_direct=yes # is this really true??? + ;; + siemens) + hardcode_direct=no + ;; + motorola) + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + ;; + sysv4.3*) + ;; + sysv4*MP*) + if test -d /usr/nec; then + ld_shlibs=yes + fi + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) + ;; + sysv5* | sco3.2v5* | sco5v6*) + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + ;; + uts4*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + *) + ld_shlibs=no + ;; + esac +fi + +# Check dynamic linker characteristics +# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER. +libname_spec='lib$name' +case "$host_os" in + aix3*) + ;; + aix4* | aix5*) + ;; + amigaos*) + ;; + beos*) + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32*) + shrext=.dll + ;; + darwin* | rhapsody*) + shrext=.dylib + ;; + dgux*) + ;; + freebsd1*) + ;; + kfreebsd*-gnu) + ;; + freebsd* | dragonfly*) + ;; + gnu*) + ;; + hpux9* | hpux10* | hpux11*) + case $host_cpu in + ia64*) + shrext=.so + ;; + hppa*64*) + shrext=.sl + ;; + *) + shrext=.sl + ;; + esac + ;; + interix3*) + ;; + irix5* | irix6* | nonstopux*) + case "$host_os" in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; + *) libsuff= shlibsuff= ;; + esac + ;; + esac + ;; + linux*oldld* | linux*aout* | linux*coff*) + ;; + linux*) + ;; + knetbsd*-gnu) + ;; + netbsd*) + ;; + newsos6) + ;; + nto-qnx*) + ;; + openbsd*) + ;; + os2*) + libname_spec='$name' + shrext=.dll + ;; + osf3* | osf4* | osf5*) + ;; + solaris*) + ;; + sunos4*) + ;; + sysv4 | sysv4.3*) + ;; + sysv4*MP*) + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + ;; + uts4*) + ;; +esac + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` +shlibext=`echo "$shrext" | sed -e 's,^\.,,'` +escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` + +LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF + +# How to pass a linker flag through the compiler. +wl="$escaped_wl" + +# Static library suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally "so"). +shlibext="$shlibext" + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="$hardcode_libdir_separator" + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct="$hardcode_direct" + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L="$hardcode_minus_L" + +EOF diff --git a/qpid/cpp-0-9/build-aux/config.sub b/qpid/cpp-0-9/build-aux/config.sub new file mode 100755 index 0000000000..7ccee73057 --- /dev/null +++ b/qpid/cpp-0-9/build-aux/config.sub @@ -0,0 +1,1619 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +# Inc. + +timestamp='2006-11-07' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/qpid/cpp-0-9/build-aux/depcomp b/qpid/cpp-0-9/build-aux/depcomp new file mode 100755 index 0000000000..ca5ea4e1ef --- /dev/null +++ b/qpid/cpp-0-9/build-aux/depcomp @@ -0,0 +1,584 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2006-10-15.18 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006 Free Software +# Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>. + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to <bug-automake@gnu.org>. +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add `dependent.h:' lines. + sed -ne '2,${; s/^ *//; s/ \\*$//; s/$/:/; p;}' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/qpid/cpp-0-9/build-aux/install-sh b/qpid/cpp-0-9/build-aux/install-sh new file mode 100755 index 0000000000..4fbbae7b7f --- /dev/null +++ b/qpid/cpp-0-9/build-aux/install-sh @@ -0,0 +1,507 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2006-10-14.15 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +posix_glob= +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chmodcmd=$chmodprog +chowncmd= +chgrpcmd= +stripcmd= +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src= +dst= +dir_arg= +dstarg= +no_target_directory= + +usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: +-c (ignored) +-d create directories instead of installing files. +-g GROUP $chgrpprog installed files to GROUP. +-m MODE $chmodprog installed files to MODE. +-o USER $chownprog installed files to USER. +-s $stripprog installed files. +-t DIRECTORY install into DIRECTORY. +-T report an error if DSTFILE is a directory. +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + shift + shift + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t) dstarg=$2 + shift + shift + continue;; + + -T) no_target_directory=true + shift + continue;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac +done + +if test $# -ne 0 && test -z "$dir_arg$dstarg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix=/ ;; + -*) prefix=./ ;; + *) prefix= ;; + esac + + case $posix_glob in + '') + if (set -f) 2>/dev/null; then + posix_glob=true + else + posix_glob=false + fi ;; + esac + + oIFS=$IFS + IFS=/ + $posix_glob && set -f + set fnord $dstdir + shift + $posix_glob && set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dst"; then + $doit $rmcmd -f "$dst" 2>/dev/null \ + || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \ + && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\ + || { + echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + } || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/qpid/cpp-0-9/build-aux/ltmain.sh b/qpid/cpp-0-9/build-aux/ltmain.sh new file mode 100755 index 0000000000..c715b59412 --- /dev/null +++ b/qpid/cpp-0-9/build-aux/ltmain.sh @@ -0,0 +1,6871 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +basename="s,^.*/,,g" + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +progname=`echo "$progpath" | $SED $basename` +modename="$progname" + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION="1.5.22 Debian 1.5.22-4" +TIMESTAMP=" (1.1220.2.365 2005/12/18 22:14:06)" + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes. +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<EOF +$* +EOF + exit $EXIT_SUCCESS +fi + +default_mode= +help="Try \`$progname --help' for more information." +magic="%%%MAGIC variable%%%" +mkdir="mkdir" +mv="mv -f" +rm="rm -f" + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g' +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + SP2NL='tr \040 \012' + NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + SP2NL='tr \100 \n' + NL2SP='tr \r\n \100\100' + ;; +esac + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +# We save the old values to restore during execute mode. +if test "${LC_ALL+set}" = set; then + save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL +fi +if test "${LANG+set}" = set; then + save_LANG="$LANG"; LANG=C; export LANG +fi + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + $echo "$modename: not configured to build any kind of library" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +duplicate_deps=no +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" + +##################################### +# Shell function definitions: +# This seems to be the best place for them + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $mkdir "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || { + $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2 + exit $EXIT_FAILURE + } + fi + + $echo "X$my_tmpdir" | $Xsed +} + + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ + $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | \ + $SED -n -e '1,100{/ I /{s,.*,import,;p;q;};}'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $echo $win32_libid_type +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case "$@ " in + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + $echo "$modename: unable to infer tagged configuration" + $echo "$modename: specify a tag with \`--tag'" 1>&2 + exit $EXIT_FAILURE +# else +# $echo "$modename: using $tagname tagged configuration" + fi + ;; + esac + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + + $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)" + $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $? + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2 + exit $EXIT_FAILURE + fi +} + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + my_status="" + + $show "${rm}r $my_gentop" + $run ${rm}r "$my_gentop" + $show "$mkdir $my_gentop" + $run $mkdir "$my_gentop" + my_status=$? + if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then + exit $my_status + fi + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'` + my_xdir="$my_gentop/$my_xlib" + + $show "${rm}r $my_xdir" + $run ${rm}r "$my_xdir" + $show "$mkdir $my_xdir" + $run $mkdir "$my_xdir" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then + exit $exit_status + fi + case $host in + *-darwin*) + $show "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + if test -z "$run"; then + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'` + darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null` + if test -n "$darwin_arches"; then + darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + $show "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we have a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + lipo -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + ${rm}r unfat-$$ + cd "$darwin_orig_dir" + else + cd "$darwin_orig_dir" + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + fi # $run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + func_extract_archives_result="$my_oldobjs" +} +# End of Shell function definitions +##################################### + +# Darwin sucks +eval std_shrext=\"$shrext_cmds\" + +disable_libs=no + +# Parse our command line options once, thoroughly. +while test "$#" -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + tag) + tagname="$arg" + preserve_args="${preserve_args}=$arg" + + # Check whether tagname contains only valid characters + case $tagname in + *[!-_A-Za-z0-9,/]*) + $echo "$progname: invalid tag name: $tagname" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $tagname in + CC) + # Don't test for the "default" C tag, as we know, it's there, but + # not specially marked. + ;; + *) + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then + taglist="$taglist $tagname" + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`" + else + $echo "$progname: ignoring unknown tag $tagname" 1>&2 + fi + ;; + esac + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + $echo + $echo "Copyright (C) 2005 Free Software Foundation, Inc." + $echo "This is free software; see the source for copying conditions. There is NO" + $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + exit $? + ;; + + --config) + ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath + # Now print the configurations for the tags. + for tagname in $taglist; do + ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" + done + exit $? + ;; + + --debug) + $echo "$progname: enabling shell trace mode" + set -x + preserve_args="$preserve_args $arg" + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit $? + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --preserve-dup-deps) duplicate_deps="yes" ;; + + --quiet | --silent) + show=: + preserve_args="$preserve_args $arg" + ;; + + --tag) + prevopt="--tag" + prev=tag + preserve_args="$preserve_args --tag" + ;; + --tag=*) + set tag "$optarg" ${1+"$@"} + shift + prev=tag + preserve_args="$preserve_args --tag" + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE +fi + +case $disable_libs in +no) + ;; +shared) + build_libtool_libs=no + build_old_libs=yes + ;; +static) + build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` + ;; +esac + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 + $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2 + case $nonopt in + *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + if test -n "$libobj" ; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit $EXIT_FAILURE + fi + arg_mode=target + continue + ;; + + -static | -prefer-pic | -prefer-non-pic) + later="$later $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + base_compile="$base_compile $lastarg" + continue + ;; + + * ) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + case $lastarg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, and some SunOS ksh mistreat backslash-escaping + # in scan sets (worked around with variable expansion), + # and furthermore cannot handle '|' '&' '(' ')' in scan sets + # at all, so we specify them separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + lastarg="\"$lastarg\"" + ;; + esac + + base_compile="$base_compile $lastarg" + done # for arg + + case $arg_mode in + arg) + $echo "$modename: you must specify an argument for -Xcompile" + exit $EXIT_FAILURE + ;; + target) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit $EXIT_FAILURE + ;; + *) + # Get the name of the library object. + [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSifmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.ii) xform=ii ;; + *.class) xform=class ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + *.java) xform=java ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"` + case $qlibobj in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qlibobj="\"$qlibobj\"" ;; + esac + test "X$libobj" != "X$qlibobj" \ + && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && $echo "$modename: libobj name \`$libobj' may not contain shell special characters." + objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir= + else + xdir=$xdir/ + fi + lobj=${xdir}$objdir/$objname + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$progpath" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + $echo "$srcfile" > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"` + case $qsrcfile in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qsrcfile="\"$qsrcfile\"" ;; + esac + + $run $rm "$libobj" "${libobj}T" + + # Create a libtool object file (analogous to a ".la" file), + # but don't create it if we're doing a dry run. + test -z "$run" && cat > ${libobj}T <<EOF +# $libobj - a libtool object file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +EOF + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + if test ! -d "${xdir}$objdir"; then + $show "$mkdir ${xdir}$objdir" + $run $mkdir ${xdir}$objdir + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "${xdir}$objdir"; then + exit $exit_status + fi + fi + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + command="$command -o $lobj" + fi + + $run $rm "$lobj" "$output_obj" + + $show "$command" + if $run eval "$command"; then : + else + test -n "$output_obj" && $run $rm $removelist + exit $EXIT_FAILURE + fi + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + $show "$mv $output_obj $lobj" + if $run $mv $output_obj $lobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the PIC object to the libtool object file. + test -z "$run" && cat >> ${libobj}T <<EOF +pic_object='$objdir/$objname' + +EOF + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + else + # No PIC object so indicate it doesn't exist in the libtool + # object file. + test -z "$run" && cat >> ${libobj}T <<EOF +pic_object=none + +EOF + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + $run $rm "$obj" "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + $run $rm $removelist + exit $EXIT_FAILURE + fi + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <<EOF +# Name of the non-PIC object. +non_pic_object='$objname' + +EOF + else + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <<EOF +# Name of the non-PIC object. +non_pic_object=none + +EOF + fi + + $run $mv "${libobj}T" "${libobj}" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + $run $rm "$lockfile" + fi + + exit $EXIT_SUCCESS + ;; + + # libtool link mode + link | relink) + modename="$modename: link" + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args="$nonopt" + base_compile="$nonopt $@" + compile_command="$nonopt" + finalize_command="$nonopt" + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + notinst_path= # paths that contain not-installed libtool libraries + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -all-static | -static) + if test "X$arg" = "X-all-static"; then + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + fi + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit $EXIT_FAILURE + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat $save_arg` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + done + else + $echo "$modename: link input file \`$save_arg' does not exist" + exit $EXIT_FAILURE + fi + arg=$save_arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + darwin_framework|darwin_framework_skip) + test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit $EXIT_FAILURE + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework|-arch|-isysroot) + case " $CC " in + *" ${arg} ${1} "* | *" ${arg} ${1} "*) + prev=darwin_framework_skip ;; + *) compiler_flags="$compiler_flags $arg" + prev=darwin_framework ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + notinst_path="$notinst_path $dir" + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs -framework System" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + -model) + compile_command="$compile_command $arg" + compiler_flags="$compiler_flags $arg" + finalize_command="$finalize_command $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m* pass through architecture-specific compiler args for GCC + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -pg pass through profiling flag for GCC + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \ + -t[45]*|-txscale*|@*) + + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # The PATH hackery in wrapper scripts is required on Windows + # in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d "$output_objdir"; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then + exit $exit_status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + case $host in + *cygwin* | *mingw* | *pw32*) + # don't eliminate duplications in $postdeps and $predeps + duplicate_compiler_generated_deps=yes + ;; + *) + duplicate_compiler_generated_deps=$duplicate_deps + ;; + esac + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if test "X$duplicate_deps" = "Xyes" ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if (${SED} -e '2q' $lib | + grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + library_names= + old_library= + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + if eval $echo \"$deplib\" 2>/dev/null \ + | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $echo + $echo "*** Warning: Trying to link with static lib archive $deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because the file extensions .$libext of this argument makes me believe" + $echo "*** that it is just a static archive that I should not used here." + else + $echo + $echo "*** Warning: Linking the shared library $output against the" + $echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test "$found" = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2 + exit $EXIT_FAILURE + fi + + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit $EXIT_FAILURE + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $absdir" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes ; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + # This is a shared library + + # Warn about portability, can't link against -module's on + # some systems (darwin) + if test "$shouldnotlink" = yes && test "$pass" = link ; then + $echo + if test "$linkmode" = prog; then + $echo "*** Warning: Linking the executable $output against the loadable module" + else + $echo "*** Warning: Linking the shared library $output against the loadable module" + fi + $echo "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`$echo $soroot | ${SED} -e 's/^.*\///'` + newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$extract_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$old_archive_from_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a module then we can not link against + # it, someone is ignoring the new warnings I added + if /usr/bin/file -L $add 2> /dev/null | + $EGREP ": [^:]* bundle" >/dev/null ; then + $echo "** Warning, lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $echo + $echo "** And there doesn't seem to be a static archive available" + $echo "** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit $EXIT_FAILURE + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $echo + $echo "*** Warning: This system can not link to static lib archive $lib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $echo "*** But as you try to build a module library, libtool will still create " + $echo "*** a static module, that should work as long as the dlopening application" + $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="$absdir/$objdir" + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="$absdir" + fi + depdepl= + case $host in + *-*-darwin*) + # we do not want to link against static libs, + # but need to link against shared + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$path/$depdepl" ; then + depdepl="$path/$depdepl" + fi + # do not add paths which are already there + case " $newlib_search_path " in + *" $path "*) ;; + *) newlib_search_path="$newlib_search_path $path";; + esac + fi + path="" + ;; + *) + path="-L$path" + ;; + esac + ;; + -l*) + case $host in + *-*-darwin*) + # Again, we only want to link against shared libraries + eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` + for tmp in $newlib_search_path ; do + if test -f "$tmp/lib$tmp_libs.dylib" ; then + eval depdepl="$tmp/lib$tmp_libs.dylib" + break + fi + done + path="" + ;; + *) continue ;; + esac + ;; + *) continue ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + case " $deplibs " in + *" $depdepl "*) ;; + *) deplibs="$depdepl $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit $EXIT_FAILURE + else + $echo + $echo "*** Warning: Linking the shared library $output against the non-libtool" + $echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test "$#" -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$2" + number_minor="$3" + number_revision="$4" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + current=`expr $number_major + $number_minor - 1` + age="$number_minor" + revision="$number_minor" + ;; + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + ;; + no) + current="$2" + revision="$3" + age="$4" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test "$age" -gt "$current"; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + verstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix | nonstopux) + major=`expr $current - $age + 1` + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=.`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$echo "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + if test -n "$removelist"; then + $show "${rm}r $removelist" + $run ${rm}r $removelist + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + for path in $notinst_path; do + lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"` + deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"` + dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"` + done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c <<EOF + int main() { return 0; } +EOF + $rm conftest + $LTCC $LTCFLAGS -o conftest conftest.c $deplibs + if test "$?" -eq 0 ; then + ldd_output=`ldd conftest` + for i in $deplibs; do + name=`expr $i : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test "$name" != "" && test "$name" -ne "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $i "*) + newdeplibs="$newdeplibs $i" + i="" + ;; + esac + fi + if test -n "$i" ; then + libname=`eval \\$echo \"$libname_spec\"` + deplib_matches=`eval \\$echo \"$library_names_spec\"` + set dummy $deplib_matches + deplib_match=$2 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + newdeplibs="$newdeplibs $i" + else + droppeddeps=yes + $echo + $echo "*** Warning: dynamic linker does not accept needed library $i." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which I believe you do not have" + $echo "*** because a test_compile did reveal that the linker did not use it for" + $echo "*** its dynamic dependency list that programs get resolved with at runtime." + fi + fi + else + newdeplibs="$newdeplibs $i" + fi + done + else + # Error occurred in the first compile. Let's try to salvage + # the situation: Compile a separate program for each library. + for i in $deplibs; do + name=`expr $i : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test "$name" != "" && test "$name" != "0"; then + $rm conftest + $LTCC $LTCFLAGS -o conftest conftest.c $i + # Did it work? + if test "$?" -eq 0 ; then + ldd_output=`ldd conftest` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $i "*) + newdeplibs="$newdeplibs $i" + i="" + ;; + esac + fi + if test -n "$i" ; then + libname=`eval \\$echo \"$libname_spec\"` + deplib_matches=`eval \\$echo \"$library_names_spec\"` + set dummy $deplib_matches + deplib_match=$2 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + newdeplibs="$newdeplibs $i" + else + droppeddeps=yes + $echo + $echo "*** Warning: dynamic linker does not accept needed library $i." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because a test_compile did reveal that the linker did not use this one" + $echo "*** as a dynamic dependency that programs can get resolved with at runtime." + fi + fi + else + droppeddeps=yes + $echo + $echo "*** Warning! Library $i is needed by this library but I was not able to" + $echo "*** make it link in! You will probably need to install it or some" + $echo "*** library that it depends on before this library will be fully" + $echo "*** functional. Installing it before continuing would be even better." + fi + else + newdeplibs="$newdeplibs $i" + fi + done + fi + ;; + file_magic*) + set dummy $deplibs_check_method + file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name=`expr $a_deplib : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test "$name" != "" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for file magic test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a file magic. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name=`expr $a_deplib : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval $echo \"$potent_lib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a regex pattern. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` + done + fi + if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ + | grep . >/dev/null; then + $echo + if test "X$deplibs_check_method" = "Xnone"; then + $echo "*** Warning: inter-library dependencies are not supported in this platform." + else + $echo "*** Warning: inter-library dependencies are not known to be supported." + fi + $echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $echo + $echo "*** Warning: libtool could not satisfy all declared inter-library" + $echo "*** dependencies of module $libname. Therefore, libtool will create" + $echo "*** a static module, that should work as long as the dlopening" + $echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $echo "*** The inter-library dependencies that have been dropped here will be" + $echo "*** automatically added whenever a program is linked with this library" + $echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $echo + $echo "*** Since this library must not contain undefined symbols," + $echo "*** because either the platform does not support them or" + $echo "*** it was explicitly requested with -no-undefined," + $echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + if len=`expr "X$cmd" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + $show "$cmd" + $run eval "$cmd" || exit $? + skipped_export=false + else + # The command line is too long to execute in one step. + $show "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise. + $echo "creating reloadable object files..." + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$echo "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + delfiles= + last_robj= + k=1 + output=$output_objdir/$output_la-${k}.$objext + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + eval test_cmds=\"$reload_cmds $objlist $last_robj\" + if test "X$objlist" = X || + { len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; }; then + objlist="$objlist $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + k=`expr $k + 1` + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + len=1 + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + + if ${skipped_export-false}; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + libobjs=$output + # Append the command to create the export file. + eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" + fi + + # Set up a command to remove the reloadable object files + # after they are used. + i=0 + while test "$i" -lt "$k" + do + i=`expr $i + 1` + delfiles="$delfiles $output_objdir/$output_la-${i}.$objext" + done + + $echo "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + + # Append the command to remove the reloadable object files + # to the just-reset $cmds. + eval cmds=\"\$cmds~\$rm $delfiles\" + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit $EXIT_FAILURE + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $run eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + case $host in + *darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + if test "$tagname" = CXX ; then + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + fi + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $run $rm $export_symbols + $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + else + $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` + $run eval '$echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | + if sort -k 3 </dev/null >/dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + $echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +" + + case $host in + *cygwin* | *mingw* ) + $echo >> "$output_objdir/$dlsyms" "\ +/* DATA imports from DLLs on WIN32 can't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs */ +struct { +" + ;; + * ) + $echo >> "$output_objdir/$dlsyms" "\ +const struct { +" + ;; + esac + + + $echo >> "$output_objdir/$dlsyms" "\ + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{\ +" + + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + case $host in + *cygwin* | *mingw* ) + if test -f "$output_objdir/${outputname}.def" ; then + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"` + else + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + fi + ;; + * ) + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + esac + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + exit_status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $exit_status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + output_name=`basename $output` + output_path=`dirname $output` + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $rm $cwrappersource $cwrapper + trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + cat > $cwrappersource <<EOF + +/* $cwrappersource - temporary wrapper executable for $objdir/$outputname + Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP + + The $output program cannot be directly executed until all the libtool + libraries that it depends on are installed. + + This wrapper executable should never be moved out of the build directory. + If it is, it will not operate correctly. + + Currently, it simply execs the wrapper *script* "/bin/sh $output", + but could eventually absorb all of the scripts functionality and + exec $objdir/$outputname directly. +*/ +EOF + cat >> $cwrappersource<<"EOF" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <malloc.h> +#include <stdarg.h> +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include <sys/stat.h> + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +/* -DDEBUG is fairly common in CFLAGS. */ +#undef DEBUG +#if defined DEBUGWRAPPER +# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__) +#else +# define DEBUG(format, ...) +#endif + +const char *program_name = NULL; + +void * xmalloc (size_t num); +char * xstrdup (const char *string); +const char * base_name (const char *name); +char * find_executable(const char *wrapper); +int check_executable(const char *path); +char * strendzap(char *str, const char *pat); +void lt_fatal (const char *message, ...); + +int +main (int argc, char *argv[]) +{ + char **newargz; + int i; + + program_name = (char *) xstrdup (base_name (argv[0])); + DEBUG("(main) argv[0] : %s\n",argv[0]); + DEBUG("(main) program_name : %s\n",program_name); + newargz = XMALLOC(char *, argc+2); +EOF + + cat >> $cwrappersource <<EOF + newargz[0] = (char *) xstrdup("$SHELL"); +EOF + + cat >> $cwrappersource <<"EOF" + newargz[1] = find_executable(argv[0]); + if (newargz[1] == NULL) + lt_fatal("Couldn't find %s", argv[0]); + DEBUG("(main) found exe at : %s\n",newargz[1]); + /* we know the script has the same name, without the .exe */ + /* so make sure newargz[1] doesn't end in .exe */ + strendzap(newargz[1],".exe"); + for (i = 1; i < argc; i++) + newargz[i+1] = xstrdup(argv[i]); + newargz[argc+1] = NULL; + + for (i=0; i<argc+1; i++) + { + DEBUG("(main) newargz[%d] : %s\n",i,newargz[i]); + ; + } + +EOF + + case $host_os in + mingw*) + cat >> $cwrappersource <<EOF + execv("$SHELL",(char const **)newargz); +EOF + ;; + *) + cat >> $cwrappersource <<EOF + execv("$SHELL",newargz); +EOF + ;; + esac + + cat >> $cwrappersource <<"EOF" + return 127; +} + +void * +xmalloc (size_t num) +{ + void * p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL +; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char)name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable(const char * path) +{ + struct stat st; + + DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!"); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) && + ( + /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */ +#if defined (S_IXOTH) + ((st.st_mode & S_IXOTH) == S_IXOTH) || +#endif +#if defined (S_IXGRP) + ((st.st_mode & S_IXGRP) == S_IXGRP) || +#endif + ((st.st_mode & S_IXUSR) == S_IXUSR)) + ) + return 1; + else + return 0; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise */ +char * +find_executable (const char* wrapper) +{ + int has_slash = 0; + const char* p; + const char* p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char* concat_name; + + DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char* path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char* q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR(*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + return NULL; +} + +char * +strendzap(char *str, const char *pat) +{ + size_t len, patlen; + + assert(str != NULL); + assert(pat != NULL); + + len = strlen(str); + patlen = strlen(pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp(str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char * mode, + const char * message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} +EOF + # we should really use a build-platform specific compiler + # here, but OTOH, the wrappers (shell script and this C one) + # are only useful if you want to execute the "real" binary. + # Since the "real" binary is built for $host, then this + # wrapper might as well be built for $host, too. + $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource + ;; + esac + $rm $output + trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + $echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $echo \"\$relink_command_output\" >&2 + $rm \"\$progdir/\$file\" + exit $EXIT_FAILURE + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + $echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit $EXIT_FAILURE + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + $echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit $EXIT_FAILURE + fi +fi\ +" + chmod +x $output + fi + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + $echo "X$obj" | $Xsed -e 's%^.*/%%' + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "copying selected object files to avoid basename conflicts..." + + if test -z "$gentop"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$gentop"; then + exit $exit_status + fi + fi + + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + counter=`expr $counter + 1` + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + $run ln "$obj" "$gentop/$newobj" || + $run cp "$obj" "$gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + + eval cmds=\"$old_archive_cmds\" + + if len=`expr "X$cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + $echo "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + for obj in $save_oldobjs + do + oldobjs="$objlist $obj" + objlist="$objlist $obj" + eval test_cmds=\"$old_archive_cmds\" + if len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + eval cmd=\"$cmd\" + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit $EXIT_SUCCESS + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) prev=$arg ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test "$#" -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + if test "$inst_prefix_dir" = "$destdir"; then + $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + exit $EXIT_FAILURE + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=$postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + file=`$echo $file|${SED} 's,.exe$,,'` + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin*|*mingw*) + wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` + ;; + *) + wrapper=$file + ;; + esac + if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 + exit $EXIT_FAILURE + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir=`func_mktempdir` + file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + cmds=$old_postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + cmds=$finish_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit $EXIT_SUCCESS + + $echo "X----------------------------------------------------------------------" | $Xsed + $echo "Libraries have been installed in:" + for libdir in $libdirs; do + $echo " $libdir" + done + $echo + $echo "If you ever happen to want to link against installed libraries" + $echo "in a given directory, LIBDIR, you must either use libtool, and" + $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + $echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + $echo " during execution" + fi + if test -n "$runpath_var"; then + $echo " - add LIBDIR to the \`$runpath_var' environment variable" + $echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $echo + $echo "See any operating system documentation about shared libraries for" + $echo "more information, such as the ld(1) and ld.so(8) manual pages." + $echo "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit $EXIT_FAILURE + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit $EXIT_FAILURE + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit $EXIT_SUCCESS + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + cmds=$postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + cmds=$old_postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + + # Read the .lo file + . $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" \ + && test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" \ + && test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + file=`$echo $file|${SED} 's,.exe$,,'` + noexename=`$echo $name|${SED} 's,.exe$,,'` + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$noexename + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test -z "$exec_cmd"; then + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + fi +fi # test -z "$show_help" + +if test -n "$exec_cmd"; then + eval exec $exec_cmd + exit $EXIT_FAILURE +fi + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE. + +Report bugs to <bug-libtool@gnu.org>." + exit $EXIT_SUCCESS + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; +esac + +$echo +$echo "Try \`$modename --help' for more information about other modes." + +exit $? + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +disable_libs=shared +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +disable_libs=static +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/qpid/cpp-0-9/build-aux/mdate-sh b/qpid/cpp-0-9/build-aux/mdate-sh new file mode 100755 index 0000000000..cd916c0a34 --- /dev/null +++ b/qpid/cpp-0-9/build-aux/mdate-sh @@ -0,0 +1,201 @@ +#!/bin/sh +# Get modification time of a file or directory and pretty-print it. + +scriptversion=2005-06-29.22 + +# Copyright (C) 1995, 1996, 1997, 2003, 2004, 2005 Free Software +# Foundation, Inc. +# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to <bug-automake@gnu.org> or send patches to +# <automake-patches@gnu.org>. + +case $1 in + '') + echo "$0: No file. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: mdate-sh [--help] [--version] FILE + +Pretty-print the modification time of FILE. + +Report bugs to <bug-automake@gnu.org>. +EOF + exit $? + ;; + -v | --v*) + echo "mdate-sh $scriptversion" + exit $? + ;; +esac + +# Prevent date giving response in another language. +LANG=C +export LANG +LC_ALL=C +export LC_ALL +LC_TIME=C +export LC_TIME + +# GNU ls changes its time format in response to the TIME_STYLE +# variable. Since we cannot assume `unset' works, revert this +# variable to its documented default. +if test "${TIME_STYLE+set}" = set; then + TIME_STYLE=posix-long-iso + export TIME_STYLE +fi + +save_arg1=$1 + +# Find out how to get the extended ls output of a file or directory. +if ls -L /dev/null 1>/dev/null 2>&1; then + ls_command='ls -L -l -d' +else + ls_command='ls -l -d' +fi + +# A `ls -l' line looks as follows on OS/2. +# drwxrwx--- 0 Aug 11 2001 foo +# This differs from Unix, which adds ownership information. +# drwxrwx--- 2 root root 4096 Aug 11 2001 foo +# +# To find the date, we split the line on spaces and iterate on words +# until we find a month. This cannot work with files whose owner is a +# user named `Jan', or `Feb', etc. However, it's unlikely that `/' +# will be owned by a user whose name is a month. So we first look at +# the extended ls output of the root directory to decide how many +# words should be skipped to get the date. + +# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below. +set x`ls -l -d /` + +# Find which argument is the month. +month= +command= +until test $month +do + shift + # Add another shift to the command. + command="$command shift;" + case $1 in + Jan) month=January; nummonth=1;; + Feb) month=February; nummonth=2;; + Mar) month=March; nummonth=3;; + Apr) month=April; nummonth=4;; + May) month=May; nummonth=5;; + Jun) month=June; nummonth=6;; + Jul) month=July; nummonth=7;; + Aug) month=August; nummonth=8;; + Sep) month=September; nummonth=9;; + Oct) month=October; nummonth=10;; + Nov) month=November; nummonth=11;; + Dec) month=December; nummonth=12;; + esac +done + +# Get the extended ls output of the file or directory. +set dummy x`eval "$ls_command \"\$save_arg1\""` + +# Remove all preceding arguments +eval $command + +# Because of the dummy argument above, month is in $2. +# +# On a POSIX system, we should have +# +# $# = 5 +# $1 = file size +# $2 = month +# $3 = day +# $4 = year or time +# $5 = filename +# +# On Darwin 7.7.0 and 7.6.0, we have +# +# $# = 4 +# $1 = day +# $2 = month +# $3 = year or time +# $4 = filename + +# Get the month. +case $2 in + Jan) month=January; nummonth=1;; + Feb) month=February; nummonth=2;; + Mar) month=March; nummonth=3;; + Apr) month=April; nummonth=4;; + May) month=May; nummonth=5;; + Jun) month=June; nummonth=6;; + Jul) month=July; nummonth=7;; + Aug) month=August; nummonth=8;; + Sep) month=September; nummonth=9;; + Oct) month=October; nummonth=10;; + Nov) month=November; nummonth=11;; + Dec) month=December; nummonth=12;; +esac + +case $3 in + ???*) day=$1;; + *) day=$3; shift;; +esac + +# Here we have to deal with the problem that the ls output gives either +# the time of day or the year. +case $3 in + *:*) set `date`; eval year=\$$# + case $2 in + Jan) nummonthtod=1;; + Feb) nummonthtod=2;; + Mar) nummonthtod=3;; + Apr) nummonthtod=4;; + May) nummonthtod=5;; + Jun) nummonthtod=6;; + Jul) nummonthtod=7;; + Aug) nummonthtod=8;; + Sep) nummonthtod=9;; + Oct) nummonthtod=10;; + Nov) nummonthtod=11;; + Dec) nummonthtod=12;; + esac + # For the first six month of the year the time notation can also + # be used for files modified in the last year. + if (expr $nummonth \> $nummonthtod) > /dev/null; + then + year=`expr $year - 1` + fi;; + *) year=$3;; +esac + +# The result. +echo $day $month $year + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/qpid/cpp-0-9/build-aux/missing b/qpid/cpp-0-9/build-aux/missing new file mode 100755 index 0000000000..1c8ff7049d --- /dev/null +++ b/qpid/cpp-0-9/build-aux/missing @@ -0,0 +1,367 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2006-05-10.23 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to <bug-automake@gnu.org>." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case $1 in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $1 in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case $firstarg in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case $firstarg in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/qpid/cpp-0-9/configure.ac b/qpid/cpp-0-9/configure.ac new file mode 100644 index 0000000000..5a1d634184 --- /dev/null +++ b/qpid/cpp-0-9/configure.ac @@ -0,0 +1,153 @@ +dnl Process this file with autoconf to produce a configure script. +dnl +dnl This file is free software; as a special exception the author gives +dnl unlimited permission to copy and/or distribute it, with or without +dnl modifications, as long as this notice is preserved. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +AC_INIT([qpidc], [0.1], [qpid-dev@incubator.apache.org]) +AC_CONFIG_AUX_DIR([build-aux]) +AM_INIT_AUTOMAKE([dist-bzip2]) + +# Minimum Autoconf version required. +AC_PREREQ(2.59) + +AC_CONFIG_HEADERS([config.h:config.in]) +AC_CONFIG_SRCDIR([lib/broker/ExchangeBinding.cpp]) + +AC_PROG_CC_STDC +AM_PROG_CC_C_O +AC_PROG_CXX +AC_USE_SYSTEM_EXTENSIONS + +AM_MISSING_PROG([HELP2MAN], [help2man]) + +AC_ARG_ENABLE(warnings, +[ --enable-warnings turn on lots of compiler warnings (recommended)], +[case "${enableval}" in + yes|no) ;; + *) AC_MSG_ERROR([bad value ${enableval} for warnings option]) ;; + esac], + [enableval=yes]) + +# Turn on this automake conditional if we are in a qpid +# hierarchy (i.e. with gentools/ and specs/ sibling directories), +# and if we have working java + javac. +AC_CHECK_PROGS([JAVA], [java], [no]) +AC_CHECK_PROGS([JAVAC], [javac], [no]) +build=yes +test x$JAVA = xno && build=no +test x$JAVAC = xno && build=no +test -d $srcdir/../gentools || build=no +test -d $srcdir/../specs || build=no +AM_CONDITIONAL([CAN_GENERATE_CODE], [test x$build = xyes]) + +# Warnings: Enable as many as possible, keep the code clean. Please +# do not disable warnings or remove -Werror without discussing on +# qpid-dev list. +# +# The following warnings are deliberately omitted, they warn on valid code. +# -Wunreachable-code -Wpadded -Winline +# -Wshadow - warns about boost headers. + +if test "${enableval}" = yes; then + gl_COMPILER_FLAGS(-Werror) + gl_COMPILER_FLAGS(-pedantic) + gl_COMPILER_FLAGS(-Wall) + gl_COMPILER_FLAGS(-Wextra) + gl_COMPILER_FLAGS(-Wno-shadow) + gl_COMPILER_FLAGS(-Wpointer-arith) + gl_COMPILER_FLAGS(-Wcast-qual) + gl_COMPILER_FLAGS(-Wcast-align) + gl_COMPILER_FLAGS(-Wno-long-long) + gl_COMPILER_FLAGS(-Wvolatile-register-var) + gl_COMPILER_FLAGS(-Winvalid-pch) + gl_COMPILER_FLAGS(-Wno-system-headers) + gl_COMPILER_FLAGS(-Woverloaded-virtual) + AC_SUBST([WARNING_CFLAGS], [$COMPILER_FLAGS]) + AC_DEFINE([lint], 1, [Define to 1 if the compiler is checking for lint.]) + COMPILER_FLAGS= +fi + +AC_PROG_LIBTOOL +AC_SUBST([LIBTOOL_DEPS]) + +# For libraries (libcommon) that use dlopen, dlerror, etc., +# test whether we need to link with -ldl. +gl_saved_libs=$LIBS + AC_SEARCH_LIBS(dlopen, [dl], + [test "$ac_cv_search_dlopen" = "none required" || + LIB_DLOPEN=$ac_cv_search_dlopen]) + AC_SUBST([LIB_DLOPEN]) +LIBS=$gl_saved_libs + +# Set the argument to be used in "libtool -version-info ARG". +QPID_CURRENT=1 +QPID_REVISION=0 +QPID_AGE=1 +LIBTOOL_VERSION_INFO_ARG=$QPID_CURRENT:$QPID_REVISION:$QPID_AGE +AC_SUBST(LIBTOOL_VERSION_INFO_ARG) + +gl_CLOCK_TIME + +# Check for cppunit support. +CPPUNIT_MINIMUM_VERSION=1.10.2 +AM_PATH_CPPUNIT([$CPPUNIT_MINIMUM_VERSION], , [CPPUNIT_LIBS=-lcppunit]) +CPPUNIT_CXXFLAGS=$CPPUNIT_CFLAGS +AC_SUBST(CPPUNIT_LIBS) +AC_SUBST(CPPUNIT_CXXFLAGS) + +AC_ARG_ENABLE(apr, +[ --enable-apr use the Apache Portable Runtime library (default) + --disable-apr do not use the Apache Portable Runtime library], +[case $enableval in + yes|no) ;; + *) AC_MSG_ERROR([invalid APR enable/disable value: $enableval]) ;; + esac], +[enableval=yes]) + +APR_MINIMUM_VERSION=1.2.2 +AC_SUBST(APR_MINIMUM_VERSION) +AC_SUBST(APR_CXXFLAGS) +AC_SUBST(USE_APR) + +if test "$enableval" = yes; then + PKG_CHECK_MODULES([APR], [apr-1 >= $APR_MINIMUM_VERSION]) + APR_CXXFLAGS="$APR_CFLAGS -DUSE_APR=1" + USE_APR=1 +fi + +AC_ARG_ENABLE(valgrind, + [ --enable-valgrind enable testing via valgrind, if available (recommended) + --disable-valgrind do not use valgrind], + [case $enableval in + yes|no) enable_VALGRIND=$enableval;; + *) AC_MSG_ERROR([invalid valgrind enable/disable value: $enableval]);; + esac], + [enable_VALGRIND=yes] # no option given, default + ) + +# We use valgrind for the tests. See if it's available. +# Check for it unconditionally, so we don't have to duplicate its +# use of AC_SUBST([VALGRIND]). +AC_CHECK_PROG([VALGRIND], [valgrind], [valgrind]) +test "$enable_VALGRIND" = no && VALGRIND= + +AC_CONFIG_FILES([ + Makefile + gen/Makefile + lib/Makefile + lib/common/Makefile + lib/client/Makefile + lib/broker/Makefile + src/Makefile + tests/Makefile + docs/man/Makefile + docs/api/Makefile + rpm/Makefile + ]) + +AC_OUTPUT diff --git a/qpid/cpp-0-9/docs/api/Makefile.am b/qpid/cpp-0-9/docs/api/Makefile.am new file mode 100644 index 0000000000..a02e7dd084 --- /dev/null +++ b/qpid/cpp-0-9/docs/api/Makefile.am @@ -0,0 +1,21 @@ +html: doxygen.tstamp + +dist-hook: html + +EXTRA_DIST = \ + html \ + user.doxygen + +SOURCES = \ + $(wildcard $(top_srcdir)/gen/*.h) \ + $(wildcard $(top_srcdir)/lib/common/*.h) \ + $(wildcard $(top_srcdir)/lib/common/sys/*.h) \ + $(wildcard $(top_srcdir)/lib/common/framing/*.h) \ + $(wildcard $(top_srcdir)/lib/client/*.h) + +doxygen.tstamp: user.doxygen $(SOURCES) + doxygen $(srcdir)/user.doxygen + touch $@ + +clean-local: + rm -rf docs.tstamp html man latex doxygen.tstamp xml diff --git a/qpid/cpp-0-9/docs/api/developer.doxygen b/qpid/cpp-0-9/docs/api/developer.doxygen new file mode 100644 index 0000000000..4679876d09 --- /dev/null +++ b/qpid/cpp-0-9/docs/api/developer.doxygen @@ -0,0 +1,1241 @@ + # ---------------------------------------------------------------- +# Doxygen settings for Qpid developer documentation. +# +# ---------------------------------------------------------------- + +# 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 = YES + +# 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 = YES + +# 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 = NO + +# 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 = NO + +# 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 = YES + +# 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 = NO + +# 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 = YES + +# 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 = YES + +# 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 = doxygen.log + +#--------------------------------------------------------------------------- +# 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 = ../../lib ../../gen ../../src + +# 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 = *.h *.cpp + +# 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 = NO + +# 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 = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# 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/qpid/cpp-0-9/docs/api/user.doxygen b/qpid/cpp-0-9/docs/api/user.doxygen new file mode 100644 index 0000000000..0d92dc283b --- /dev/null +++ b/qpid/cpp-0-9/docs/api/user.doxygen @@ -0,0 +1,1244 @@ +# ---------------------------------------------------------------- +# Doxygen settings for Qpid user documentation. +# +# Note: Only public members of classes that are part of the public API +# should be documented here. For complete developer documentation use +# the developer.doxygen configuration. +# ---------------------------------------------------------------- + +# 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 = YES + +# 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 = YES + +# 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 = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# 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 = NO + +# 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 = YES + +# 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 = YES + +# 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 = ../../lib/common ../../lib/client ../../gen + +# 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 = *.h + +# 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 = NO + +# 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 = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# 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/qpid/cpp-0-9/docs/man/Makefile.am b/qpid/cpp-0-9/docs/man/Makefile.am new file mode 100644 index 0000000000..f637328cbb --- /dev/null +++ b/qpid/cpp-0-9/docs/man/Makefile.am @@ -0,0 +1,20 @@ +dist_man_MANS = qpidd.1 + +man_aux = $(dist_man_MANS:.1=.x) $(optional_mans:.1=.x) +EXTRA_DIST = $(man_aux) $(optional_mans) +MAINTAINERCLEANFILES = $(dist_man_MANS) + +dist-hook: $(man_aux) + +qpidd.1: $(srcdir)/qpidd.x $(top_srcdir)/src/qpidd + +# Depend on configure.ac to get version number changes. +$(dist_man_MANS): $(top_srcdir)/configure.ac + +SUFFIXES = .x .1 +.x.1: + @rm -f $@ + @echo "Updating man page $@" + $(HELP2MAN) --no-info --include=$(srcdir)/$*.x --output=$@-t ../../src/$* + @chmod a-w $@-t + @mv $@-t $@ diff --git a/qpid/cpp-0-9/docs/man/qpidd.x b/qpid/cpp-0-9/docs/man/qpidd.x new file mode 100644 index 0000000000..e60505cc9c --- /dev/null +++ b/qpid/cpp-0-9/docs/man/qpidd.x @@ -0,0 +1,5 @@ +[NAME] +qpidd \- the Qpid broker daemon + +[DESCRIPTION] +.\" Add any additional description here diff --git a/qpid/cpp-0-9/etc/qpidd b/qpid/cpp-0-9/etc/qpidd new file mode 100755 index 0000000000..cfd6049c9b --- /dev/null +++ b/qpid/cpp-0-9/etc/qpidd @@ -0,0 +1,66 @@ +#!/bin/bash +# +# qpidd Startup script for the Qpid messaging daemon. +# +# chkconfig: - 85 15 +# description: Qpidd is an AMQP broker. It receives, stores, routes and forwards messages using the AMQP protcol. +# processname: qpidd +# + +prog=qpidd +lockfile=/var/lock/subsys/$prog + +# Source function library. +. /etc/rc.d/init.d/functions + +RETVAL=0 + +start() { + echo -n $"Starting Qpid AMQP daemon: " + daemon $prog --daemon + RETVAL=$? + echo + [ $RETVAL = 0 ] && touch ${lockfile} + return $RETVAL +} + +stop() { + echo -n $"Stopping Qpid AMQP daemon: " + killproc $prog + RETVAL=$? + echo + [ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile} +} + +restart() { + stop + start +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status $prog + RETVAL=$? + ;; + restart|reload) + restart + ;; + condrestart) + if [ -e $lockfile ] ; then restart ; fi + ;; + reload) + reload + ;; + *) + echo $"Usage: $0 {start|stop|restart|condrestart|reload|status}" + exit 1 +esac + +exit $RETVAL diff --git a/qpid/cpp-0-9/gen/Makefile.am b/qpid/cpp-0-9/gen/Makefile.am new file mode 100644 index 0000000000..e16923fcc2 --- /dev/null +++ b/qpid/cpp-0-9/gen/Makefile.am @@ -0,0 +1,37 @@ +include gen-src.mk + +BUILT_SOURCES = $(generated_sources) $(generated_headers) +pkginclude_HEADERS=$(generated_headers) + +# Distribute the generated sources, at least for now, since +# the generator code is in java. +EXTRA_DIST = $(BUILT_SOURCES) +DISTCLEANFILES = $(BUILT_SOURCES) timestamp gen-src.mk + +# Don't attempt to run the code generator unless configure has set +# CAN_GENERATE_CODE, indicating that the amqp.xml and tools needed +# to run the code generator are available. +# +if CAN_GENERATE_CODE + +gentools_dir = $(srcdir)/../gentools +spec_dir = $(srcdir)/../../specs + +# FIXME aconway 2007-01-04: Enabling Basic class until +# new messaging class is ready to replace it. +# spec = $(spec_dir)/amqp.0-9.xml $(spec_dir)/amqp-errata.0-9.xml $(spec_dir)/amqp-nogen.0-9.xml +spec = $(spec_dir)/amqp.0-9.xml $(spec_dir)/amqp-errata.0-9.xml + +gentools_srcdir = $(gentools_dir)/src/org/apache/qpid/gentools + +$(BUILT_SOURCES) timestamp: $(spec) $(java_sources) $(cxx_templates) Makefile.am + rm -f $(generated_sources) + cd $(gentools_srcdir) && rm -f *.class && $(JAVAC) *.java + $(JAVA) -cp $(gentools_dir)/src org.apache.qpid.gentools.Main \ + -c -o . -t $(gentools_dir)/templ.cpp $(spec) + touch timestamp + +gen-src.mk: timestamp + ./make-gen-src-mk.sh $(gentools_dir) $(gentools_srcdir) > $@-t + mv $@-t $@ +endif diff --git a/qpid/cpp-0-9/gen/make-gen-src-mk.sh b/qpid/cpp-0-9/gen/make-gen-src-mk.sh new file mode 100755 index 0000000000..08eb8ea134 --- /dev/null +++ b/qpid/cpp-0-9/gen/make-gen-src-mk.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# Generate the gen-src.mk makefile fragment, to stdout. +# Usage: <gentools_dir> <gentools_srcdir> + +gentools_dir=$1 +gentools_srcdir=$2 + +wildcard() { echo `ls $* 2>/dev/null` ; } + +cat <<EOF +generated_sources = `wildcard *.cpp` + +generated_headers = `wildcard *.h` + +if CAN_GENERATE_CODE + +java_sources = `wildcard $gentools_srcdir/*.java` + +cxx_templates = `wildcard $gentools_dir/templ.cpp/*.tmpl` + +# Empty rules in case one of these files is removed, +# renamed or no longer generated. +\$(spec): +\$(java_sources): +\$(cxx_templates): +endif + +EOF + + diff --git a/qpid/cpp-0-9/gentools/README b/qpid/cpp-0-9/gentools/README new file mode 100644 index 0000000000..c4abecc199 --- /dev/null +++ b/qpid/cpp-0-9/gentools/README @@ -0,0 +1,61 @@ +================================================================================ +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +================================================================================ + +AMQP MULTI_VERSION CODE GENERATOR + +This directory contains the first part of the new multi-AMQP-version code +generator. The Java generation is almost complete, C++ will follow. + +NOTE: The generator has NOT been integrated into the current build, and is +included here to run stand-alone for the purposes of review and comment. As +currently configured, this generator will not interact with any file or +directory outside of this directory. + +To build (from this directory): +rm org/apache/qpid/gentools/*.class +javac org/apache/qpid/gentools/Main.java + +Make sure you are using Sun's JDK1.5.0; Eclipse and gcj do not work. + +To run (from this directory): +java org/apache/qpid/gentools/Main -j [xml_spec_file, ...] + +XML test files are located in the xml-src directory. Pay attention to the +Basic class and Basic.Consume method - these were the primary test vehicles +for this generator. *** NOTE *** These files do not represent any current or +future version of the AMQP specification - do not use in production! + +Folders: +-------- +org/apache/qpid/gentools/: Source. +xml-src/: Test AMQP specification files. +templ.java/: Templates for java code generation. +out.java/: Output folder for generated Java files (will be created with use + of -j flag on command-line). +templ.cpp/: (Future:) Templates for C++ code generation. +out.cpp/: Output folder for generated C++ files (will be created with use + of -c flag on command-line). + +For a more detaild description of the generator, see the Qpid Wiki +(http://cwiki.apache.org/qpid/multiple-amqp-version-support.html). + +Please send comments and bugs to me (kim.vdriet [at] redhat.com) or via the +Apache Qpid list (qpid-dev [at] incubator.apache.org). + +Kim van der Riet diff --git a/qpid/cpp-0-9/gentools/build b/qpid/cpp-0-9/gentools/build new file mode 100755 index 0000000000..ad9827b113 --- /dev/null +++ b/qpid/cpp-0-9/gentools/build @@ -0,0 +1,15 @@ +#!/bin/bash +cd src +echo "--------- Building gentools ----------" +echo "Clearing out old build files..." +for f in org/apache/qpid/gentools/*.class; do + if [ -e $f ]; then + rm $f + fi +done +echo "Compiling..." +javac org/apache/qpid/gentools/*.java +echo "Done. Try it out..." +java org.apache.qpid.gentools.Main +echo "--------- Building gentools completed ----------" +cd .. diff --git a/qpid/cpp-0-9/gentools/build.xml b/qpid/cpp-0-9/gentools/build.xml new file mode 100644 index 0000000000..8fba85bc57 --- /dev/null +++ b/qpid/cpp-0-9/gentools/build.xml @@ -0,0 +1,34 @@ +<!-- + - + - Licensed to the Apache Software Foundation (ASF) under one + - or more contributor license agreements. See the NOTICE file + - distributed with this work for additional information + - regarding copyright ownership. The ASF licenses this file + - to you under the Apache License, Version 2.0 (the + - "License"); you may not use this file except in compliance + - with the License. You may obtain a copy of the License at + - + - http://www.apache.org/licenses/LICENSE-2.0 + - + - Unless required by applicable law or agreed to in writing, + - software distributed under the License is distributed on an + - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + - KIND, either express or implied. See the License for the + - specific language governing permissions and limitations + - under the License. + - + --> +<project name="gentools" default="compile"> + <property name="src" location="src" /> + + <target name="compile"> + <javac srcdir="${src}" source="1.5" fork="true" /> + </target> + + <target name="clean"> + <delete> + <fileset dir="${src}/org/apache/qpid/gentools" includes="*.class" /> + </delete> + </target> + +</project> diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpClass.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpClass.java new file mode 100644 index 0000000000..2e8bdaf971 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpClass.java @@ -0,0 +1,148 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class AmqpClass implements Printable, NodeAware +{ + public LanguageConverter converter; + public AmqpVersionSet versionSet; + public AmqpFieldMap fieldMap; + public AmqpMethodMap methodMap; + public String name; + public AmqpOrdinalVersionMap indexMap; + + public AmqpClass(String name, LanguageConverter converter) + { + this.name = name; + this.converter = converter; + versionSet = new AmqpVersionSet(); + fieldMap = new AmqpFieldMap(); + methodMap = new AmqpMethodMap(); + indexMap = new AmqpOrdinalVersionMap(); + } + + public boolean addFromNode(Node classNode, int ordinal, AmqpVersion version) + throws AmqpParseException, AmqpTypeMappingException + { + versionSet.add(version); + int index = Utils.getNamedIntegerAttribute(classNode, "index"); + AmqpVersionSet indexVersionSet = indexMap.get(index); + if (indexVersionSet != null) + indexVersionSet.add(version); + else + { + indexVersionSet = new AmqpVersionSet(); + indexVersionSet.add(version); + indexMap.put(index, indexVersionSet); + } + NodeList nList = classNode.getChildNodes(); + int fieldCntr = fieldMap.size(); + for (int i=0; i<nList.getLength(); i++) + { + Node child = nList.item(i); + if (child.getNodeName().compareTo(Utils.ELEMENT_FIELD) == 0) + { + String fieldName = converter.prepareDomainName(Utils.getNamedAttribute(child, + Utils.ATTRIBUTE_NAME)); + AmqpField thisField = fieldMap.get(fieldName); + if (thisField == null) + { + thisField = new AmqpField(fieldName, converter); + fieldMap.put(fieldName, thisField); + } + if (!thisField.addFromNode(child, fieldCntr++, version)) + { + String className = converter.prepareClassName(Utils.getNamedAttribute(classNode, + Utils.ATTRIBUTE_NAME)); + System.out.println("INFO: Generation supression tag found for field " + + className + "." + fieldName + " - removing."); + thisField.removeVersion(version); + fieldMap.remove(fieldName); + } + } + else if (child.getNodeName().compareTo(Utils.ELEMENT_METHOD) == 0) + { + String methodName = converter.prepareMethodName(Utils.getNamedAttribute(child, + Utils.ATTRIBUTE_NAME)); + AmqpMethod thisMethod = methodMap.get(methodName); + if (thisMethod == null) + { + thisMethod = new AmqpMethod(methodName, converter); + methodMap.put(methodName, thisMethod); + } + if (!thisMethod.addFromNode(child, 0, version)) + { + String className = converter.prepareClassName(Utils.getNamedAttribute(classNode, + Utils.ATTRIBUTE_NAME)); + System.out.println("INFO: Generation supression tag found for method " + + className + "." + methodName + " - removing."); + thisMethod.removeVersion(version); + methodMap.remove(methodName); + } + } + else if (child.getNodeName().compareTo(Utils.ELEMENT_CODEGEN) == 0) + { + String value = Utils.getNamedAttribute(child, Utils.ATTRIBUTE_VALUE); + if (value.compareTo("no-gen") == 0) + return false; + } + } + return true; + } + + public void removeVersion(AmqpVersion version) + { + indexMap.removeVersion(version); + fieldMap.removeVersion(version); + methodMap.removeVersion(version); + versionSet.remove(version); + } + + public void print(PrintStream out, int marginSize, int tabSize) + { + String margin = Utils.createSpaces(marginSize); + String tab = Utils.createSpaces(tabSize); + out.println(margin + "[C] " + name + ": " + versionSet); + + for (Integer thisIndex : indexMap.keySet()) + { + AmqpVersionSet indexVersionSet = indexMap.get(thisIndex); + out.println(margin + tab + "[I] " + thisIndex + indexVersionSet); + } + + for (String thisFieldName : fieldMap.keySet()) + { + AmqpField thisField = fieldMap.get(thisFieldName); + thisField.print(out, marginSize + tabSize, tabSize); + } + + for (String thisMethodName : methodMap.keySet()) + { + AmqpMethod thisMethod = methodMap.get(thisMethodName); + thisMethod.print(out, marginSize + tabSize, tabSize); + } + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpClassMap.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpClassMap.java new file mode 100644 index 0000000000..01d4df283b --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpClassMap.java @@ -0,0 +1,29 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpClassMap extends TreeMap<String, AmqpClass> +{ + +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpConstant.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpConstant.java new file mode 100644 index 0000000000..6ccd2dbf99 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpConstant.java @@ -0,0 +1,205 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +import java.util.TreeMap; + +/** + * @author kpvdr + * Class to represent the <constant> declaration within the AMQP specification. + * Currently, only integer values exist within the specification, however looking forward + * to other possible types in the future, string and double types are also supported. + * + * The <constant> declaration in the specification contains only two attributes: + * name and value. + * + * The value of the constant is mapped against the version(s) for which the name is defined. + * This allows for a change in the value rather than the name only from one version to the next. + */ +@SuppressWarnings("serial") +public class AmqpConstant extends TreeMap<String, AmqpVersionSet> + implements Printable, VersionConsistencyCheck, Comparable<AmqpConstant> +{ + /** + * Constant name as defined by the name attribute of the <constant> declaration. + */ + protected String name; + + /** + * Set of versions for which this constant name is defined. + */ + protected AmqpVersionSet versionSet; + + /** + * Constructor + * @param name Constant name as defined by the name attribute of the <constant> declaration. + * @param value Constant value as defined by the value attribute of the <constant> declaration. + * @param version AMQP version for which this constant is defined + */ + public AmqpConstant (String name, String value, AmqpVersion version) + { + this.name = name; + versionSet = new AmqpVersionSet(version); + AmqpVersionSet valueVersionSet = new AmqpVersionSet(version); + put(value, valueVersionSet); + } + + /** + * Constructor + * @param name Constant name as defined by the name attribute of the <constant> declaration. + * @param value Constant value as defined by the value attribute of the <constant> declaration. + * @param version AMQP version for which this constant is defined + */ + public AmqpConstant (String name, int value, AmqpVersion version) + { + this.name = name; + versionSet = new AmqpVersionSet(version); + AmqpVersionSet valueVersionSet = new AmqpVersionSet(version); + put(String.valueOf(value), valueVersionSet); + } + + /** + * Constructor + * @param name Constant name as defined by the name attribute of the <constant> declaration. + * @param value Constant value as defined by the value attribute of the <constant> declaration. + * @param version AMQP version for which this constant is defined + */ + public AmqpConstant (String name, double value, AmqpVersion version) + { + this.name = name; + versionSet = new AmqpVersionSet(version); + AmqpVersionSet valueVersionSet = new AmqpVersionSet(version); + put(String.valueOf(value), valueVersionSet); + } + + /** + * Get the name of this constant. + * @return Name of this constant, being the name attribute of the <constant> declaration + * represented by this class. + */ + public String getName() + { + return name; + } + + /** + * Get the value of this constant as a String. + * @param version AMQP version for which this value is required. + * @return Value of this constant, being the value attribute of the <constant> declaration + * represented by this class. + * @throws AmqpTypeMappingException when a value is requested for a version for which it is not + * defined in the AMQP specifications. + */ + public String getStringValue(AmqpVersion version) + throws AmqpTypeMappingException + { + for (String thisValue : keySet()) + { + AmqpVersionSet versionSet = get(thisValue); + if (versionSet.contains(version)) + return thisValue; + } + throw new AmqpTypeMappingException("Unable to find value for constant \"" + name + + "\" for version " + version.toString() + "."); + } + + /** + * Get the value of this constant as an integer. + * @param version AMQP version for which this value is required. + * @return Value of this constant, being the value attribute of the <constant> declaration + * represented by this class. + * @throws AmqpTypeMappingException when a value is requested for a version for which it is not + * defined in the AMQP specifications. + */ + public int getIntegerValue(AmqpVersion version) + throws AmqpTypeMappingException + { + return Integer.parseInt(getStringValue(version)); + } + + /** + * Get the value of this constant as a double. + * @param version AMQP version for which this value is required. + * @return Value of this constant, being the value attribute of the <constant> declaration + * represented by this class. + * @throws AmqpTypeMappingException when a value is requested for a version for which it is not + * defined in the AMQP specifications. + */ + public double getDoubleValue(AmqpVersion version) + throws AmqpTypeMappingException + { + return Double.parseDouble(getStringValue(version)); + } + + /** + * Get the version set for this constant. It contains the all the versions for which this + * constant name exists. + * @return Set of versions for which this constant exists. + */ + public AmqpVersionSet getVersionSet() + { + return versionSet; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + + public int compareTo(AmqpConstant other) + { + int res = name.compareTo(other.name); + if (res != 0) + return res; + return versionSet.compareTo(other.versionSet); + } + + /* (non-Javadoc) + * @see org.apache.qpid.gentools.VersionConsistencyCheck#isVersionConsistent(org.apache.qpid.gentools.AmqpVersionSet) + */ + public boolean isVersionConsistent(AmqpVersionSet globalVersionSet) + { + if (size() != 1) + return false; + return get(firstKey()).equals(globalVersionSet); + } + + /* (non-Javadoc) + * @see org.apache.qpid.gentools.Printable#print(java.io.PrintStream, int, int) + */ + public void print(PrintStream out, int marginSize, int tabSize) + { + String margin = Utils.createSpaces(marginSize); + String tab = Utils.createSpaces(tabSize); + if (size() == 1) + { + out.println(margin + tab + "[C] " + name + " = \"" + firstKey() + "\" " + versionSet); + } + else + { + out.println(margin + tab + "[C] " + name + ": " + versionSet); + for (String thisValue : keySet()) + { + out.println(margin + tab + tab + "= \"" + thisValue + "\" " + get(thisValue)); + } + } + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpConstantSet.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpConstantSet.java new file mode 100644 index 0000000000..7b38f5cf3c --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpConstantSet.java @@ -0,0 +1,133 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +import java.util.Iterator; +import java.util.TreeSet; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * @author kpvdr + * This class implements a set collection for {@link #AmqpConstant AmqpConstant} objects, being the collection + * of constants accumulated from various AMQP specification files processed. Each name occurs once only in the set. + * The {@link #AmqpConstant AmqpConstant} objects (derived from {@link java.util#TreeMap TreeMap}) keep track of + * the value and version(s) assigned to this name. + */ +@SuppressWarnings("serial") +public class AmqpConstantSet extends TreeSet<AmqpConstant> implements Printable, NodeAware, Comparable<AmqpConstantSet> +{ + public LanguageConverter converter; + + public AmqpConstantSet(LanguageConverter converter) + { + this.converter = converter; + this.converter.setConstantSet(this); + } + + /* (non-Javadoc) + * @see org.apache.qpid.gentools.NodeAware#addFromNode(org.w3c.dom.Node, int, org.apache.qpid.gentools.AmqpVersion) + */ + public boolean addFromNode(Node node, int ordinal, AmqpVersion version) + throws AmqpParseException, AmqpTypeMappingException + { + NodeList nodeList = node.getChildNodes(); + for (int i=0; i<nodeList.getLength(); i++) + { + Node childNode = nodeList.item(i); + if (childNode.getNodeName().compareTo(Utils.ELEMENT_CONSTANT) == 0) + { + String name = converter.prepareDomainName(Utils.getNamedAttribute(childNode, Utils.ATTRIBUTE_NAME)); + String value = Utils.getNamedAttribute(childNode, Utils.ATTRIBUTE_VALUE); + // Find this name in the existing set of objects + boolean foundName = false; + Iterator<AmqpConstant> cItr = iterator(); + while (cItr.hasNext() && !foundName) + { + AmqpConstant thisConstant = cItr.next(); + if (name.compareTo(thisConstant.name) == 0) + { + foundName = true; + thisConstant.versionSet.add(version); + // Now, find the value in the map + boolean foundValue = false; + for (String thisValue : thisConstant.keySet()) + { + if (value.compareTo(thisValue) == 0) + { + foundValue = true; + // Add this version to existing version set. + AmqpVersionSet versionSet = thisConstant.get(thisValue); + versionSet.add(version); + } + } + // Check that the value was found - if not, add it + if (!foundValue) + { + thisConstant.put(value, new AmqpVersionSet(version)); + } + } + } + // Check that the name was found - if not, add it + if (!foundName) + { + add(new AmqpConstant(name, value, version)); + } + } + } + return true; + } + + /* (non-Javadoc) + * @see org.apache.qpid.gentools.Printable#print(java.io.PrintStream, int, int) + */ + public void print(PrintStream out, int marginSize, int tabSize) + { + out.println(Utils.createSpaces(marginSize) + "Constants: "); + for (AmqpConstant thisAmqpConstant : this) + { + thisAmqpConstant.print(out, marginSize, tabSize); + } + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(AmqpConstantSet other) + { + int res = size() - other.size(); + if (res != 0) + return res; + Iterator<AmqpConstant> cItr = iterator(); + Iterator<AmqpConstant> oItr = other.iterator(); + while (cItr.hasNext() && oItr.hasNext()) + { + AmqpConstant constant = cItr.next(); + AmqpConstant oConstant = oItr.next(); + res = constant.compareTo(oConstant); + if (res != 0) + return res; + } + return 0; + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpDomain.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpDomain.java new file mode 100644 index 0000000000..4796f31fb3 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpDomain.java @@ -0,0 +1,78 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpDomain extends TreeMap<String, AmqpVersionSet> implements Printable +{ + public String domainName; + + public AmqpDomain(String domainName) + { + this.domainName = domainName; + } + + public void addDomain(String domainType, AmqpVersion version) throws AmqpParseException + { + AmqpVersionSet versionSet = get(domainType); + if (versionSet == null) // First time, create new entry + { + versionSet = new AmqpVersionSet(); + put(domainType, versionSet); + } + versionSet.add(version); + } + + public String getDomainType(AmqpVersion version) + throws AmqpTypeMappingException + { + for (String thisDomainType : keySet()) + { + AmqpVersionSet versionSet = get(thisDomainType); + if (versionSet.contains(version)) + return thisDomainType; + } throw new AmqpTypeMappingException("Unable to find version " + version + "."); + } + + public boolean hasVersion(String type, AmqpVersion v) + { + AmqpVersionSet vs = get(type); + if (vs == null) + return false; + return vs.contains(v); + } + + public void print(PrintStream out, int marginSize, int tabSize) + { + String margin = Utils.createSpaces(marginSize); + String tab = Utils.createSpaces(tabSize); + out.println(margin + domainName + ":"); + + for (String thisDomainType : keySet()) + { + AmqpVersionSet vs = get(thisDomainType); + out.println(margin + tab + thisDomainType + " : " + vs.toString()); + } + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpDomainMap.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpDomainMap.java new file mode 100644 index 0000000000..7e2974a444 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpDomainMap.java @@ -0,0 +1,119 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +import java.util.TreeMap; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +@SuppressWarnings("serial") +public class AmqpDomainMap extends TreeMap<String, AmqpDomain> implements Printable, NodeAware +{ + public LanguageConverter converter; + + public AmqpDomainMap(LanguageConverter converter) + { + this.converter = converter; + this.converter.setDomainMap(this); + } + + public boolean addFromNode(Node n, int o, AmqpVersion v) + throws AmqpParseException, AmqpTypeMappingException + { + NodeList nl = n.getChildNodes(); + for (int i=0; i<nl.getLength(); i++) + { + Node c = nl.item(i); + // All versions 0.9 and greater use <domain> for all domains + if (c.getNodeName().compareTo(Utils.ELEMENT_DOMAIN) == 0) + { + String domainName = converter.prepareDomainName(Utils.getNamedAttribute(c, Utils.ATTRIBUTE_NAME)); + String type = Utils.getNamedAttribute(c, Utils.ATTRIBUTE_TYPE); + AmqpDomain thisDomain = get(domainName); + if (thisDomain == null) + { + thisDomain = new AmqpDomain(domainName); + put(domainName, thisDomain); + } + thisDomain.addDomain(type, v); + } + // Version(s) 0.8 and earlier use <domain> for all complex domains and use + // attribute <field type=""...> for simple types. Add these simple types to + // domain list - but beware of duplicates! + else if (c.getNodeName().compareTo(Utils.ELEMENT_FIELD) == 0) + { + try + { + String type = converter.prepareDomainName(Utils.getNamedAttribute(c, Utils.ATTRIBUTE_TYPE)); + AmqpDomain thisDomain = get(type); + if (thisDomain == null) + { + thisDomain = new AmqpDomain(type); + put(type, thisDomain); + } + if (!thisDomain.hasVersion(type, v)) + thisDomain.addDomain(type, v); + } + catch (AmqpParseException e) {} // Ignore fields without type attribute + } + else if (c.getNodeName().compareTo(Utils.ELEMENT_CLASS) == 0 || + c.getNodeName().compareTo(Utils.ELEMENT_METHOD) == 0) + { + addFromNode(c, 0, v); + } + } + return true; + } + + public String getDomainType(String domainName, AmqpVersion version) + throws AmqpTypeMappingException + { + AmqpDomain domainType = get(domainName); + // For AMQP 8.0, primitive types were not described as domains, so + // return itself as the type. + if (domainType == null) + { + return domainName; + } + try + { + return domainType.getDomainType(version); + } + catch (AmqpTypeMappingException e) + { + throw new AmqpTypeMappingException("Unable to find domain type for domain \"" + domainName + + "\" version " + version + "."); + } + } + + + public void print(PrintStream out, int marginSize, int tabSize) + { + out.println(Utils.createSpaces(marginSize) + "Domain Map:"); + for (String thisDomainName : keySet()) + { + AmqpDomain domain = get(thisDomainName); + domain.print(out, marginSize + tabSize, tabSize); + } + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpDomainVersionMap.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpDomainVersionMap.java new file mode 100644 index 0000000000..f91d98bfe7 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpDomainVersionMap.java @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.util.ArrayList; +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpDomainVersionMap extends TreeMap<String, AmqpVersionSet> implements VersionConsistencyCheck +{ + public boolean isVersionConsistent(AmqpVersionSet globalVersionSet) + { + if (size() != 1) + return false; + return get(firstKey()).equals(globalVersionSet); + } + + public boolean removeVersion(AmqpVersion version) + { + Boolean res = false; + ArrayList<String> removeList = new ArrayList<String>(); + for (String domainName : keySet()) + { + AmqpVersionSet versionSet = get(domainName); + if (versionSet.contains(version)) + { + versionSet.remove(version); + if (versionSet.isEmpty()) + removeList.add(domainName); + res = true; + } + } + // Get rid of domains no longer in use + for (String domainName : removeList) + { + remove(domainName); + } + return res; + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpField.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpField.java new file mode 100644 index 0000000000..e1177e0154 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpField.java @@ -0,0 +1,156 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +import java.util.ArrayList; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class AmqpField implements Printable, NodeAware, VersionConsistencyCheck +{ + public LanguageConverter converter; + public AmqpVersionSet versionSet; + public AmqpDomainVersionMap domainMap; + public AmqpOrdinalVersionMap ordinalMap; + public String name; + + public AmqpField(String name, LanguageConverter converter) + { + this.name = name; + this.converter = converter; + versionSet = new AmqpVersionSet(); + domainMap = new AmqpDomainVersionMap(); + ordinalMap = new AmqpOrdinalVersionMap(); + } + + public boolean addFromNode(Node fieldNode, int ordinal, AmqpVersion version) + throws AmqpParseException, AmqpTypeMappingException + { + versionSet.add(version); + String domainType; + // Early versions of the spec (8.0) used the "type" attribute instead of "domain" for some fields. + try + { + domainType = converter.prepareDomainName(Utils.getNamedAttribute(fieldNode, Utils.ATTRIBUTE_DOMAIN)); + } + catch (AmqpParseException e) + { + domainType = converter.prepareDomainName(Utils.getNamedAttribute(fieldNode, Utils.ATTRIBUTE_TYPE)); + } + AmqpVersionSet thisVersionList = domainMap.get(domainType); + if (thisVersionList == null) // First time, create new entry + { + thisVersionList = new AmqpVersionSet(); + domainMap.put(domainType, thisVersionList); + } + thisVersionList.add(version); + thisVersionList = ordinalMap.get(ordinal); + if (thisVersionList == null) // First time, create new entry + { + thisVersionList = new AmqpVersionSet(); + ordinalMap.put(ordinal, thisVersionList); + } + thisVersionList.add(version); + NodeList nList = fieldNode.getChildNodes(); + for (int i=0; i<nList.getLength(); i++) + { + Node child = nList.item(i); + if (child.getNodeName().compareTo(Utils.ELEMENT_CODEGEN) == 0) + { + String value = Utils.getNamedAttribute(child, Utils.ATTRIBUTE_VALUE); + if (value.compareTo("no-gen") == 0) + return false; + } + } + return true; + } + + public void removeVersion(AmqpVersion version) + { + domainMap.removeVersion(version); + ordinalMap.removeVersion(version); + versionSet.remove(version); + } + + public boolean isCodeTypeConsistent(LanguageConverter converter) + throws AmqpTypeMappingException + { + if (domainMap.size() == 1) + return true; // By definition + ArrayList<String> codeTypeList = new ArrayList<String>(); + for (String thisDomainName : domainMap.keySet()) + { + AmqpVersionSet versionSet = domainMap.get(thisDomainName); + String codeType = converter.getGeneratedType(thisDomainName, versionSet.first()); + if (!codeTypeList.contains(codeType)) + codeTypeList.add(codeType); + } + return codeTypeList.size() == 1; + } + + public boolean isConsistent(Generator generator) + throws AmqpTypeMappingException + { + if (!isCodeTypeConsistent(generator)) + return false; + if (ordinalMap.size() != 1) + return false; + // Since the various doamin names map to the same code type, add the version occurrences + // across all domains to see we have all possible versions covered + int vCntr = 0; + for (String thisDomainName : domainMap.keySet()) + { + vCntr += domainMap.get(thisDomainName).size(); + } + return vCntr == generator.globalVersionSet.size(); + } + + public void print(PrintStream out, int marginSize, int tabSize) + { + String margin = Utils.createSpaces(marginSize); + out.println(margin + "[F] " + name + ": " + versionSet); + + for (Integer thisOrdinal : ordinalMap.keySet()) + { + AmqpVersionSet versionList = ordinalMap.get(thisOrdinal); + out.println(margin + " [O] " + thisOrdinal + " : " + versionList.toString()); + } + + for (String thisDomainName : domainMap.keySet()) + { + AmqpVersionSet versionList = domainMap.get(thisDomainName); + out.println(margin + " [D] " + thisDomainName + " : " + versionList.toString()); + } + } + + public boolean isVersionConsistent(AmqpVersionSet globalVersionSet) + { + if (!versionSet.equals(globalVersionSet)) + return false; + if (!domainMap.isVersionConsistent(globalVersionSet)) + return false; + if (!ordinalMap.isVersionConsistent(globalVersionSet)) + return false; + return true; + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpFieldMap.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpFieldMap.java new file mode 100644 index 0000000000..c91ec3d623 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpFieldMap.java @@ -0,0 +1,348 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpFieldMap extends TreeMap<String, AmqpField> implements VersionConsistencyCheck +{ + public void removeVersion(AmqpVersion version) + { + String[] fieldNameArray = new String[size()]; + keySet().toArray(fieldNameArray); + for (String fieldName : fieldNameArray) + { + get(fieldName).removeVersion(version); + remove(fieldName); + } + } + + public AmqpFieldMap getFieldMapForOrdinal(int ordinal) + { + AmqpFieldMap newMap = new AmqpFieldMap(); + for (String thisFieldName: keySet()) + { + AmqpField field = get(thisFieldName); + TreeMap<Integer, AmqpVersionSet> ordinalMap = field.ordinalMap; + AmqpVersionSet ordinalVersions = ordinalMap.get(ordinal); + if (ordinalVersions != null) + { + newMap.put(field.name, field); + } + } + return newMap; + } + + public AmqpOrdinalFieldMap getMapForVersion(AmqpVersion version, boolean codeTypeFlag, + LanguageConverter converter) + throws AmqpTypeMappingException + { + // TODO: REVIEW THIS! There may be a bug here that affects C++ generation (only with >1 version)... + // If version == null (a common scenario) then the version map is built up on the + // basis of first found item, and ignores other version variations. + // This should probably be disallowed by throwing an NPE, as AmqpOrdinalFieldMap cannot + // represent these possibilities. + // *OR* + // Change the structure of AmqpOrdianlFieldMap to allow for the various combinations that + // will result from version variation - but that is what AmqpFieldMap is... :-$ + AmqpOrdinalFieldMap ordinalFieldMap = new AmqpOrdinalFieldMap(); + for (String thisFieldName: keySet()) + { + AmqpField field = get(thisFieldName); + if (version == null || field.versionSet.contains(version)) + { + // 1. Search for domain name in field domain map with version that matches + String domain = ""; + boolean dFound = false; + for (String thisDomainName : field.domainMap.keySet()) + { + domain = thisDomainName; + AmqpVersionSet versionSet = field.domainMap.get(domain); + if (version == null || versionSet.contains(version)) + { + if (codeTypeFlag) + domain = converter.getGeneratedType(domain, version); + dFound = true; + } + } + + // 2. Search for ordinal in field ordianl map with version that matches + int ordinal = -1; + boolean oFound = false; + for (Integer thisOrdinal : field.ordinalMap.keySet()) + { + ordinal = thisOrdinal; + AmqpVersionSet versionSet = field.ordinalMap.get(ordinal); + if (version == null || versionSet.contains(version)) + oFound = true; + } + + if (dFound && oFound) + { + String[] fieldDomainPair = {field.name, domain}; + ordinalFieldMap.put(ordinal, fieldDomainPair); + } + } + } + return ordinalFieldMap; + } + + public boolean isDomainConsistent(Generator generator, AmqpVersionSet versionSet) + throws AmqpTypeMappingException + { + if (size() != 1) // Only one field for this ordinal + return false; + return get(firstKey()).isConsistent(generator); + } + + public int getNumFields(AmqpVersion version) + { + int fCntr = 0; + for (String thisFieldName : keySet()) + { + AmqpField field = get(thisFieldName); + if (field.versionSet.contains(version)) + fCntr++; + } + return fCntr; + } + + public String parseFieldMap(Method commonGenerateMethod, Method mangledGenerateMethod, + int indentSize, int tabSize, LanguageConverter converter) + throws AmqpTypeMappingException, IllegalAccessException, InvocationTargetException + { + String indent = Utils.createSpaces(indentSize); + String cr = Utils.lineSeparator; + StringBuffer sb = new StringBuffer(); + + if (commonGenerateMethod == null) + { + // Generate warnings in code if required methods are null. + sb.append(indent + "/*********************************************************" + cr); + sb.append(indent + " * WARNING: Generated code could be missing." + cr); + sb.append(indent + " * In call to parseFieldMap(), generation method was null." + cr); + sb.append(indent + " * Check for NoSuchMethodException on startup." + cr); + sb.append(indent + " *********************************************************/" + cr); + } + + Iterator<String> itr = keySet().iterator(); + while (itr.hasNext()) + { + String fieldName = itr.next(); + AmqpField field = get(fieldName); + if (field.isCodeTypeConsistent(converter)) + { + // All versions identical - Common declaration + String domainName = field.domainMap.firstKey(); + AmqpVersionSet versionSet = field.domainMap.get(domainName); + String codeType = converter.getGeneratedType(domainName, versionSet.first()); + if (commonGenerateMethod != null) + sb.append(commonGenerateMethod.invoke(converter, codeType, field, versionSet, + indentSize, tabSize, itr.hasNext())); + } + else if (mangledGenerateMethod != null) // Version-mangled + { + sb.append(mangledGenerateMethod.invoke(converter, field, indentSize, tabSize, + itr.hasNext())); + } + } + return sb.toString(); + } + + public String parseFieldMapOrdinally(Method generateMethod, Method bitGenerateMethod, + int indentSize, int tabSize, Generator codeGenerator) + throws AmqpTypeMappingException, IllegalAccessException, InvocationTargetException + { + String indent = Utils.createSpaces(indentSize); + String cr = Utils.lineSeparator; + StringBuffer sb = new StringBuffer(); + + // Generate warnings in code if required methods are null. + if (generateMethod == null || bitGenerateMethod == null) + { + sb.append(indent + "/***********************************************" + cr); + sb.append(indent + " * WARNING: In call to parseFieldMapOrdinally():" + cr); + if (generateMethod == null) + sb.append(indent + " * => generateMethod is null." + cr); + if (bitGenerateMethod == null) + sb.append(indent + " * => bitGenerateMethod is null." + cr); + sb.append(indent + " * Generated code could be missing." + cr); + sb.append(indent + " * Check for NoSuchMethodException on startup." + cr); + sb.append(indent + " ***********************************************/" + cr); + } + + /* We must process elements in ordinal order because adjacent booleans (bits) + * must be combined into a single byte (in groups of up to 8). Start with shared + * declarations until an ordinal divergence is found. (For most methods where + * there is no difference between versions, this will simplify the generated + * code. */ + + ArrayList<String> bitFieldList = new ArrayList<String>(); + boolean ordinalDivergenceFlag = false; + int ordinal = 0; + while (ordinal < size() && !ordinalDivergenceFlag) + { + /* Since the getFieldMapOrdinal() function may map more than one Field to + * an ordinal, the number of ordinals may be less than the total number of + * fields in the fieldMap. Check for empty fieldmaps... */ + AmqpFieldMap ordinalFieldMap = getFieldMapForOrdinal(ordinal); + if (ordinalFieldMap.size() > 0) + { + if (ordinalFieldMap.isDomainConsistent(codeGenerator, codeGenerator.globalVersionSet)) + { + String fieldName = ordinalFieldMap.firstKey(); + String domain = ordinalFieldMap.get(fieldName).domainMap.firstKey(); + String domainType = codeGenerator.getDomainType(domain, + codeGenerator.globalVersionSet.first()); + if (domainType.compareTo("bit") == 0) + bitFieldList.add(fieldName); + else if (bitFieldList.size() > 0) + { + // End of bit types - handle deferred bit type generation + if (bitGenerateMethod != null) + sb.append(bitGenerateMethod.invoke(codeGenerator, bitFieldList, ordinal, + indentSize, tabSize)); + bitFieldList.clear(); + } + if (!ordinalDivergenceFlag) + { + // Defer generation of bit types until all adjacent bits have been + // accounted for. + if (bitFieldList.size() == 0 && generateMethod != null) + sb.append(generateMethod.invoke(codeGenerator, domainType, fieldName, ordinal, + indentSize, tabSize)); + } + ordinal++; + } + else + { + ordinalDivergenceFlag = true; + } + } + } + + // Check if there is still more to do under a version-specific breakout + if (ordinalDivergenceFlag && ordinal< size()) + { + // 1. Cycle through all versions in order, create outer if(version) structure + AmqpVersion[] versionArray = new AmqpVersion[codeGenerator.globalVersionSet.size()]; + codeGenerator.globalVersionSet.toArray(versionArray); + for (int v=0; v<versionArray.length; v++) + { + sb.append(indent); + if (v > 0) + sb.append("else "); + sb.append("if (major == " + versionArray[v].getMajor() + " && minor == " + + versionArray[v].getMinor() + ")" + cr); + sb.append(indent + "{" + cr); + + // 2. Cycle though each ordinal from where we left off in the loop above. + ArrayList<String> bitFieldList2 = new ArrayList<String>(bitFieldList); + for (int o = ordinal; o<size(); o++) + { + AmqpFieldMap ordinalFieldMap = getFieldMapForOrdinal(o); + if (ordinalFieldMap.size() > 0) + { + // 3. Cycle through each of the fields that have this ordinal. + Iterator<String> i = ordinalFieldMap.keySet().iterator(); + while (i.hasNext()) + { + String fieldName = i.next(); + AmqpField field = ordinalFieldMap.get(fieldName); + + // 4. Some fields may have more than one ordinal - match by both + // ordinal and version. + Iterator<Integer> j = field.ordinalMap.keySet().iterator(); + while (j.hasNext()) + { + int thisOrdinal = j.next(); + AmqpVersionSet v1 = field.ordinalMap.get(thisOrdinal); + if (thisOrdinal == o && v1.contains(versionArray[v])) + { + // 5. Now get the domain for this version + int domainCntr = 0; + Iterator<String> k = field.domainMap.keySet().iterator(); + while (k.hasNext()) + { + // Mangle domain-divergent field names + String mangledFieldName = fieldName; + if (field.domainMap.size() > 1) + mangledFieldName += "_" + (domainCntr++); + String domainName = k.next(); + AmqpVersionSet v2 = field.domainMap.get(domainName); + if (v2.contains(versionArray[v])) + { + // 6. (Finally!!) write the declaration + String domainType = codeGenerator.getDomainType(domainName, + versionArray[v]); + if (domainType.compareTo("bit") == 0) + bitFieldList2.add(mangledFieldName); + else if (bitFieldList2.size() > 0) + { + // End of bit types - handle deferred bit type generation + if (bitGenerateMethod != null) + sb.append(bitGenerateMethod.invoke(codeGenerator, + bitFieldList2, o, indentSize + tabSize, + tabSize)); + bitFieldList2.clear(); + } + // Defer generation of bit types until all adjacent bits have + // been accounted for. + if (bitFieldList2.size() == 0 && generateMethod != null) + sb.append(generateMethod.invoke(codeGenerator, domainType, + mangledFieldName, o, indentSize + tabSize, tabSize)); + } + } + } + } + } + } + } + // Check for remaining deferred bits + if (bitFieldList2.size() > 0 && bitGenerateMethod != null) + sb.append(bitGenerateMethod.invoke(codeGenerator, bitFieldList2, size(), + indentSize + tabSize, tabSize)); + sb.append(indent + "}" + cr); + } + } + // Check for remaining deferred bits + else if (bitFieldList.size() > 0 && bitGenerateMethod != null) + sb.append(bitGenerateMethod.invoke(codeGenerator, bitFieldList, size(), + indentSize, tabSize)); + return sb.toString(); + } + + public boolean isVersionConsistent(AmqpVersionSet globalVersionSet) + { + for (String thisFieldName : keySet()) + { + AmqpField field = get(thisFieldName); + if (!field.isVersionConsistent(globalVersionSet)) + return false; + } + return true; + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpFlagMap.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpFlagMap.java new file mode 100644 index 0000000000..3f86326ce2 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpFlagMap.java @@ -0,0 +1,84 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.util.ArrayList; +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpFlagMap extends TreeMap<Boolean, AmqpVersionSet> implements VersionConsistencyCheck +{ + public boolean isSet() + { + return containsKey(true); + } + + public boolean isSet(AmqpVersion version) + { + return containsKey(true) && get(true).contains(version); + } + + public void setFlagForVersion(boolean flag, AmqpVersion version) { + if (get(flag) == null) { + put(flag, new AmqpVersionSet(version)); + } else { + get(flag).add(version); + } + } + + public String toString() + { + AmqpVersionSet versionSet = get(true); + if (versionSet != null) + return versionSet.toString(); + return ""; + } + + public boolean isVersionConsistent(AmqpVersionSet globalVersionSet) + { + if (size() != 1) + return false; + return get(firstKey()).equals(globalVersionSet); + } + + public boolean removeVersion(AmqpVersion version) + { + Boolean res = false; + ArrayList<Boolean> removeList = new ArrayList<Boolean>(); + for (Boolean flag : keySet()) + { + AmqpVersionSet versionSet = get(flag); + if (versionSet.contains(version)) + { + versionSet.remove(version); + if (versionSet.isEmpty()) + removeList.add(flag); + res = true; + } + } + // Get rid of flags no longer in use + for (Boolean flag : removeList) + { + remove(flag); + } + return res; + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpMethod.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpMethod.java new file mode 100644 index 0000000000..f3c5bdd935 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpMethod.java @@ -0,0 +1,211 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Element; + +public class AmqpMethod implements Printable, NodeAware, VersionConsistencyCheck +{ + public LanguageConverter converter; + public AmqpVersionSet versionSet; + public AmqpFieldMap fieldMap; + public String name; + public AmqpOrdinalVersionMap indexMap; + public AmqpFlagMap clientMethodFlagMap; // Method called on client (<chassis name="server"> in XML) + public AmqpFlagMap serverMethodFlagMap; // Method called on server (<chassis name="client"> in XML) + public AmqpFlagMap isResponseFlagMap; + + public AmqpMethod(String name, LanguageConverter converter) + { + this.name = name; + this.converter = converter; + versionSet = new AmqpVersionSet(); + fieldMap = new AmqpFieldMap(); + indexMap = new AmqpOrdinalVersionMap(); + clientMethodFlagMap = new AmqpFlagMap(); + serverMethodFlagMap = new AmqpFlagMap(); + isResponseFlagMap = new AmqpFlagMap(); + } + + public boolean isResponse(AmqpVersion version) { + return (version == null) ? isResponseFlagMap.isSet() : isResponseFlagMap.isSet(version); + } + + /** Check if this method is named as a response by any other method in the class. */ + public void checkForResponse(Element methodElement, AmqpVersion version) { + Element clazz = (Element)methodElement.getParentNode(); + String methodName = methodElement.getAttribute("name"); + NodeList methods = clazz.getElementsByTagName("method"); + for (int i=0; i<methods.getLength(); ++i) { + Element method = (Element)methods.item(i); + NodeList responses = method.getElementsByTagName("response"); + for (int j =0; j<responses.getLength(); ++j) { + Element response = (Element)responses.item(j); + if (methodName.equals(response.getAttribute("name"))) { + isResponseFlagMap.setFlagForVersion(true, version); + } + } + } + } + + public boolean addFromNode(Node methodNode, int ordinal, AmqpVersion version) + throws AmqpParseException, AmqpTypeMappingException + { + versionSet.add(version); + boolean serverChassisFlag = false; + boolean clientChassisFlag = false; + int index = Utils.getNamedIntegerAttribute(methodNode, "index"); + AmqpVersionSet indexVersionSet = indexMap.get(index); + if (indexVersionSet != null) + indexVersionSet.add(version); + else + { + indexVersionSet = new AmqpVersionSet(); + indexVersionSet.add(version); + indexMap.put(index, indexVersionSet); + } + NodeList nList = methodNode.getChildNodes(); + int fieldCntr = fieldMap.size(); + for (int i=0; i<nList.getLength(); i++) + { + Node child = nList.item(i); + if (child.getNodeName().compareTo(Utils.ELEMENT_FIELD) == 0) + { + String fieldName = converter.prepareDomainName(Utils.getNamedAttribute(child, + Utils.ATTRIBUTE_NAME)); + AmqpField thisField = fieldMap.get(fieldName); + if (thisField == null) + { + thisField = new AmqpField(fieldName, converter); + fieldMap.put(fieldName, thisField); + } + if (!thisField.addFromNode(child, fieldCntr++, version)) + { + String className = converter.prepareClassName(Utils.getNamedAttribute(methodNode.getParentNode(), + Utils.ATTRIBUTE_NAME)); + String methodName = converter.prepareMethodName(Utils.getNamedAttribute(methodNode, + Utils.ATTRIBUTE_NAME)); + System.out.println("INFO: Generation supression tag found for field " + + className + "." + methodName + "." + fieldName + " - removing."); + thisField.removeVersion(version); + fieldMap.remove(fieldName); + } + } + else if (child.getNodeName().compareTo(Utils.ELEMENT_CHASSIS) == 0) + { + String chassisName = Utils.getNamedAttribute(child, Utils.ATTRIBUTE_NAME); + if (chassisName.compareTo("server") == 0) + serverChassisFlag = true; + else if (chassisName.compareTo("client") == 0) + clientChassisFlag = true; + } + else if (child.getNodeName().compareTo(Utils.ELEMENT_CODEGEN) == 0) + { + String value = Utils.getNamedAttribute(child, Utils.ATTRIBUTE_VALUE); + if (value.compareTo("no-gen") == 0) + return false; + } + } + checkForResponse((Element)methodNode, version); + processChassisFlags(serverChassisFlag, clientChassisFlag, version); + return true; + } + + public void removeVersion(AmqpVersion version) + { + clientMethodFlagMap.removeVersion(version); + serverMethodFlagMap.removeVersion(version); + isResponseFlagMap.removeVersion(version); + indexMap.removeVersion(version); + fieldMap.removeVersion(version); + versionSet.remove(version); + } + + public void print(PrintStream out, int marginSize, int tabSize) + { + String margin = Utils.createSpaces(marginSize); + String tab = Utils.createSpaces(tabSize); + out.println(margin + "[M] " + name + " {" + (serverMethodFlagMap.isSet() ? "S " + + serverMethodFlagMap + (clientMethodFlagMap.isSet() ? ", " : "") : "") + + (clientMethodFlagMap.isSet() ? "C " + clientMethodFlagMap : "") + "}" + ": " + + versionSet); + + for (Integer thisIndex : indexMap.keySet()) + { + AmqpVersionSet indexVersionSet = indexMap.get(thisIndex); + out.println(margin + tab + "[I] " + thisIndex + indexVersionSet); + } + + for (String thisFieldName : fieldMap.keySet()) + { + AmqpField thisField = fieldMap.get(thisFieldName); + thisField.print(out, marginSize + tabSize, tabSize); + } + } + + protected void processChassisFlags(boolean serverFlag, boolean clientFlag, AmqpVersion version) + { + serverMethodFlagMap.setFlagForVersion(serverFlag, version); + clientMethodFlagMap.setFlagForVersion(clientFlag, version); + } + + public AmqpOverloadedParameterMap getOverloadedParameterLists(AmqpVersionSet globalVersionSet, + Generator generator) + throws AmqpTypeMappingException + { + AmqpOverloadedParameterMap parameterVersionMap = new AmqpOverloadedParameterMap(); + for (AmqpVersion thisVersion : globalVersionSet) + { + AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(thisVersion, true, generator); + AmqpVersionSet methodVersionSet = parameterVersionMap.get(ordinalFieldMap); + if (methodVersionSet == null) + { + methodVersionSet = new AmqpVersionSet(); + methodVersionSet.add(thisVersion); + parameterVersionMap.put(ordinalFieldMap, methodVersionSet); + } + else + { + methodVersionSet.add(thisVersion); + } + } + return parameterVersionMap; + } + + public boolean isVersionConsistent(AmqpVersionSet globalVersionSet) + { + if (!versionSet.equals(globalVersionSet)) + return false; + if (!clientMethodFlagMap.isVersionConsistent(globalVersionSet)) + return false; + if (!serverMethodFlagMap.isVersionConsistent(globalVersionSet)) + return false; + if (!indexMap.isVersionConsistent(globalVersionSet)) + return false; + if (!fieldMap.isVersionConsistent(globalVersionSet)) + return false; + return true; + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpMethodMap.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpMethodMap.java new file mode 100644 index 0000000000..59eedd2a2b --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpMethodMap.java @@ -0,0 +1,36 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpMethodMap extends TreeMap<String, AmqpMethod> +{ + public void removeVersion(AmqpVersion version) + { + for (String methodName : keySet()) + { + get(methodName).removeVersion(version); + } + } + +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpModel.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpModel.java new file mode 100644 index 0000000000..721247a4b2 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpModel.java @@ -0,0 +1,80 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class AmqpModel implements Printable, NodeAware +{ + public LanguageConverter converter; + public AmqpClassMap classMap; + + public AmqpModel(LanguageConverter converter) + { + this.converter = converter; + this.converter.setModel(this); + classMap = new AmqpClassMap(); + } + + public boolean addFromNode(Node n, int o, AmqpVersion v) + throws AmqpParseException, AmqpTypeMappingException + { + NodeList nList = n.getChildNodes(); + int eCntr = 0; + for (int i=0; i<nList.getLength(); i++) + { + Node c = nList.item(i); + if (c.getNodeName().compareTo(Utils.ELEMENT_CLASS) == 0) + { + String className = converter.prepareClassName(Utils.getNamedAttribute(c, Utils.ATTRIBUTE_NAME)); + AmqpClass thisClass = classMap.get(className); + if (thisClass == null) + { + thisClass = new AmqpClass(className, converter); + classMap.put(className, thisClass); + } + if (!thisClass.addFromNode(c, eCntr++, v)) + { + System.out.println("INFO: Generation supression tag found for class " + className + " - removing."); + thisClass.removeVersion(v); + classMap.remove(className); + } + } + } + return true; + } + + public void print(PrintStream out, int marginSize, int tabSize) + { + out.println(Utils.createSpaces(marginSize) + + "[C]=class; [M]=method; [F]=field; [D]=domain; [I]=index; [O]=ordinal" + Utils.lineSeparator); + out.println(Utils.createSpaces(marginSize) + "Model:"); + + for (String thisClassName : classMap.keySet()) + { + AmqpClass thisClass = classMap.get(thisClassName); + thisClass.print(out, marginSize + tabSize, tabSize); + } + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpOrdinalFieldMap.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpOrdinalFieldMap.java new file mode 100644 index 0000000000..34d3b7ca5f --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpOrdinalFieldMap.java @@ -0,0 +1,89 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.util.Iterator; +import java.util.Set; +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpOrdinalFieldMap extends TreeMap<Integer, String[]> implements Comparable +{ + protected static final int FIELD_DOMAIN = 1; + protected boolean codeTypeFlag = false; + + public int compareTo(Object obj) + { + AmqpOrdinalFieldMap o = (AmqpOrdinalFieldMap)obj; + Set<Integer> thisKeySet = keySet(); + Set<Integer> oKeySet = o.keySet(); + if (!thisKeySet.equals(oKeySet)) // Not equal, but why? + { + // Size difference + int sizeDiff = thisKeySet.size() - oKeySet.size(); // -ve if this < other + if (sizeDiff != 0) + return sizeDiff; + // Conetent difference + Iterator<Integer> itr = thisKeySet.iterator(); + Iterator<Integer> oItr = oKeySet.iterator(); + while (itr.hasNext() && oItr.hasNext()) + { + int diff = itr.next() - oItr.next(); // -ve if this < other + if (diff != 0) + return diff; + } + // We should never get here... + System.err.println("AmqpOrdinalFieldMap.compareTo(): " + + "WARNING - unable to find cause of keySet difference."); + } + // Keys are equal, now check the String[]s + Iterator<Integer> itr = thisKeySet.iterator(); + Iterator<Integer> oItr = oKeySet.iterator(); + while (itr.hasNext() && oItr.hasNext()) + { + String[] thisPair = get(itr.next()); + String[] oPair = o.get(oItr.next()); + // Size difference + int sizeDiff = thisPair.length - oPair.length; // -ve if this < other + if (sizeDiff != 0) + return sizeDiff; + // Conetent difference + for (int i=0; i<thisPair.length; i++) + { + int diff = thisPair[i].compareTo(oPair[i]); + if (diff != 0) + return diff; + } + } + return 0; + } + + public String toString() + { + StringBuffer sb = new StringBuffer(); + for (Integer thisOrdinal : keySet()) + { + String[] pair = get(thisOrdinal); + sb.append("[" + thisOrdinal + "] " + pair[0] + " : " + pair[1] + Utils.lineSeparator); + } + return sb.toString(); + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpOrdinalVersionMap.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpOrdinalVersionMap.java new file mode 100644 index 0000000000..3706c9391d --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpOrdinalVersionMap.java @@ -0,0 +1,72 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.util.ArrayList; +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpOrdinalVersionMap extends TreeMap<Integer, AmqpVersionSet> implements VersionConsistencyCheck +{ + public boolean isVersionConsistent(AmqpVersionSet globalVersionSet) + { + if (size() != 1) + return false; + return get(firstKey()).equals(globalVersionSet); + } + + public int getOrdinal(AmqpVersion version) + throws AmqpTypeMappingException + { + for (Integer thisOrdinal : keySet()) + { + AmqpVersionSet versionSet = get(thisOrdinal); + if (versionSet.contains(version)) + return thisOrdinal; + } + throw new AmqpTypeMappingException("Unable to locate version " + version + " in ordianl version map."); + } + + public boolean removeVersion(AmqpVersion version) + { + Boolean res = false; + ArrayList<Integer> removeList = new ArrayList<Integer>(); + for (Integer ordinal : keySet()) + { + AmqpVersionSet versionSet = get(ordinal); + if (versionSet.contains(version)) + { + versionSet.remove(version); + if (versionSet.isEmpty()) + { + removeList.add(ordinal); + } + res = true; + } + } + // Get rid of ordinals no longer in use + for (Integer ordinal : removeList) + { + remove(ordinal); + } + return res; + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpOverloadedParameterMap.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpOverloadedParameterMap.java new file mode 100644 index 0000000000..10978d0e4a --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpOverloadedParameterMap.java @@ -0,0 +1,29 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpOverloadedParameterMap extends TreeMap<AmqpOrdinalFieldMap, AmqpVersionSet> +{ + +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpParseException.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpParseException.java new file mode 100644 index 0000000000..4d9f495390 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpParseException.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +@SuppressWarnings("serial") +public class AmqpParseException extends Exception +{ + public AmqpParseException(String msg) + { + super(msg); + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpTemplateException.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpTemplateException.java new file mode 100644 index 0000000000..b1e6f3d712 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpTemplateException.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +@SuppressWarnings("serial") +public class AmqpTemplateException extends Exception +{ + public AmqpTemplateException(String msg) + { + super(msg); + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpTypeMappingException.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpTypeMappingException.java new file mode 100644 index 0000000000..1053543fdd --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpTypeMappingException.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +@SuppressWarnings("serial") +public class AmqpTypeMappingException extends Exception +{ + public AmqpTypeMappingException(String msg) + { + super(msg); + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpVersion.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpVersion.java new file mode 100644 index 0000000000..579d8e28b2 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpVersion.java @@ -0,0 +1,68 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +public class AmqpVersion implements Comparable<AmqpVersion> +{ + private int major; + private int minor; + + public AmqpVersion(int major, int minor) + { + this.major = major; + this.minor = minor; + } + + public AmqpVersion(AmqpVersion version) + { + this.major = version.major; + this.minor = version.minor; + } + + public int getMajor() + { + return major; + } + + public int getMinor() + { + return minor; + } + + public int compareTo(AmqpVersion v) + { + if (major != v.major) + return major - v.major; + if (minor != v.minor) + return minor - v.minor; + return 0; + } + + public String namespace() + { + return "ver_" + major + "_" + minor; + } + + public String toString() + { + return major + "-" + minor; + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpVersionSet.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpVersionSet.java new file mode 100644 index 0000000000..4406893cbb --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/AmqpVersionSet.java @@ -0,0 +1,74 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +//import java.util.ArrayList; +import java.util.Iterator; +import java.util.TreeSet; + +@SuppressWarnings("serial") +public class AmqpVersionSet extends TreeSet<AmqpVersion> implements Printable, Comparable<AmqpVersionSet> +{ + public AmqpVersionSet() + { + super(); + } + + public AmqpVersionSet(AmqpVersion version) + { + super(); + add(version); + } + + public AmqpVersion find(AmqpVersion version) + { + for (AmqpVersion v : this) + { + if (v.compareTo(version) == 0) + return v; + } + return null; + } + + public void print(PrintStream out, int marginSize, int tabSize) + { + out.print(Utils.createSpaces(marginSize) + "Version Set: " + toString() + Utils.lineSeparator); + } + + public int compareTo(AmqpVersionSet other) + { + int res = size() - other.size(); + if (res != 0) + return res; + Iterator<AmqpVersion> vItr = iterator(); + Iterator<AmqpVersion> oItr = other.iterator(); + while (vItr.hasNext() && oItr.hasNext()) + { + AmqpVersion version = vItr.next(); + AmqpVersion oVersion = oItr.next(); + res = version.compareTo(oVersion); + if (res != 0) + return res; + } + return 0; + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/CppGenerator.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/CppGenerator.java new file mode 100644 index 0000000000..b46d6e8cfc --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/CppGenerator.java @@ -0,0 +1,1635 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.TreeMap; + +public class CppGenerator extends Generator +{ + protected static final String versionNamespaceStartToken = "${version_namespace_start}"; + protected static final String versionNamespaceEndToken = "${version_namespace_end}"; + + // TODO: Move this to parent class + protected static final int FIELD_NAME = 0; + protected static final int FIELD_CODE_TYPE = 1; + + /** + * A complete list of C++ reserved words. The names of varous XML elements within the AMQP + * specification file are used for C++ identifier names in the generated code. Each proposed + * name is checked against this list and is modified (by adding an '_' to the end of the + * name - see function parseForReservedWords()) if found to be present. + */ + protected static final String[] cppReservedWords = {"and", "and_eq", "asm", "auto", "bitand", + "bitor", "bool", "break", "case", "catch", "char", "class", "compl", "const", "const_cast", + "continue", "default", "delete", "do", "DomainInfo", "double", "dynamic_cast", "else", + "enum", "explicit", "extern", "false", "float", "for", "friend", "goto", "if", "inline", + "int", "long", "mutable", "namespace", "new", "not", "not_eq", "operator", "or", "or_eq", + "private", "protected", "public", "register", "reinterpret_cast", "return", "short", + "signed", "sizeof", "static", "static_cast", "struct", "switch", "template", "this", + "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", "using", + "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq"}; + + /** + * Although not reserved words, the following list of variable names that may cause compile + * problems within a C++ environment because they clash with common #includes. The names of + * varous XML elements within the AMQP specification file are used for C++ identifier names + * in the generated code. Each proposed name is checked against this list and is modified + * (by adding an '_' to the end of the name - see function parseForReservedWords()) if found + * to be present. This list is best added to on an as-needed basis. + */ + protected static final String[] cppCommonDefines = {"string"}; + + // TODO: Move this to the Generator superclass? + protected boolean quietFlag; // Supress warning messages to the console + + private class DomainInfo + { + public String type; + public String size; + public String encodeExpression; + public String decodeExpression; + public DomainInfo(String domain, String size, String encodeExpression, + String decodeExpression) + { + this.type = domain; + this.size = size; + this.encodeExpression = encodeExpression; + this.decodeExpression = decodeExpression; + } + } + + private static TreeMap<String, DomainInfo> typeMap = new TreeMap<String, DomainInfo>(); + + public CppGenerator(AmqpVersionSet versionList) + { + super(versionList); + quietFlag = true; + // Load C++ type and size maps. + // Adjust or add to these lists as new types are added/defined. + // The char '#' will be replaced by the field variable name (any type). + // The char '~' will be replaced by the compacted bit array size (type bit only). + typeMap.put("bit", new DomainInfo( + "bool", // type + "~", // size + "", // encodeExpression + "")); // decodeExpression + typeMap.put("content", new DomainInfo( + "Content", // type + "#.size()", // size + "buffer.putContent(#)", // encodeExpression + "buffer.getContent(#)")); // decodeExpression + typeMap.put("long", new DomainInfo( + "u_int32_t", // type + "4", // size + "buffer.putLong(#)", // encodeExpression + "# = buffer.getLong()")); // decodeExpression + typeMap.put("longlong", new DomainInfo( + "u_int64_t", // type + "8", // size + "buffer.putLongLong(#)", // encodeExpression + "# = buffer.getLongLong()")); // decodeExpression + typeMap.put("longstr", new DomainInfo( + "string", // type + "4 + #.length()", // size + "buffer.putLongString(#)", // encodeExpression + "buffer.getLongString(#)")); // decodeExpression + typeMap.put("octet", new DomainInfo( + "u_int8_t", // type + "1", // size + "buffer.putOctet(#)", // encodeExpression + "# = buffer.getOctet()")); // decodeExpression + typeMap.put("short", new DomainInfo( + "u_int16_t", // type + "2", // size + "buffer.putShort(#)", // encodeExpression + "# = buffer.getShort()")); // decodeExpression + typeMap.put("shortstr", new DomainInfo( + "string", // type + "1 + #.length()", // size + "buffer.putShortString(#)", // encodeExpression + "buffer.getShortString(#)")); // decodeExpression + typeMap.put("table", new DomainInfo( + "FieldTable", // type + "#.size()", // size + "buffer.putFieldTable(#)", // encodeExpression + "buffer.getFieldTable(#)")); // decodeExpression + typeMap.put("timestamp", new DomainInfo( + "u_int64_t", // type + "8", // size + "buffer.putLongLong(#)", // encodeExpression + "# = buffer.getLongLong()")); // decodeExpression + } + + public boolean isQuietFlag() + { + return quietFlag; + } + + public void setQuietFlag(boolean quietFlag) + { + this.quietFlag = quietFlag; + } + + // === Start of methods for Interface LanguageConverter === + + public String prepareClassName(String className) + { + return camelCaseName(className, true); + } + + public String prepareMethodName(String methodName) + { + return camelCaseName(methodName, false); + } + + public String prepareDomainName(String domainName) + { + return camelCaseName(domainName, false); + } + + public String getDomainType(String domainName, AmqpVersion version) + throws AmqpTypeMappingException + { + if (version == null) + version = globalVersionSet.first(); + return globalDomainMap.getDomainType(domainName, version); + } + + public String getGeneratedType(String domainName, AmqpVersion version) + throws AmqpTypeMappingException + { + String domainType = getDomainType(domainName, version); + if (domainType == null) + { + throw new AmqpTypeMappingException("Domain type \"" + domainName + + "\" not found in C++ typemap."); + } + DomainInfo info = typeMap.get(domainType); + if (info == null) + { + throw new AmqpTypeMappingException("Unknown domain: \"" + domainType + "\""); + } + return info.type; + } + + // === Abstract methods from class Generator - C++-specific implementation === + + @Override + protected String prepareFilename(String filenameTemplate, AmqpClass thisClass, AmqpMethod method, + AmqpField field) + { + StringBuffer sb = new StringBuffer(filenameTemplate); + if (thisClass != null) + replaceToken(sb, "${CLASS}", thisClass.name); + if (method != null) + replaceToken(sb, "${METHOD}", method.name); + if (field != null) + replaceToken(sb, "${FIELD}", field.name); + return sb.toString(); + } + + @Override + protected void processTemplateA(String[] template) + throws IOException, AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException + { + processTemplateD(template, null, null, null); + } + + @Override + protected void processTemplateB(String[] template, AmqpClass thisClass) + throws IOException, AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException + { + processTemplateD(template, thisClass, null, null); + } + + @Override + protected void processTemplateC(String[] template, AmqpClass thisClass, + AmqpMethod method) + throws IOException, AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException + { + StringBuffer sb = new StringBuffer(template[templateStringIndex]); + String filename = prepareFilename(getTemplateFileName(sb), thisClass, method, null); + boolean templateProcessedFlag = false; + + // If method is not version consistent, create a namespace for each version + // i.e. copy the bit between the versionNamespaceStartToken and versionNamespaceEndToken + // once for each namespace. + if (method != null) + { + if (!method.isVersionConsistent(globalVersionSet)) + { + int namespaceStartIndex = sb.indexOf(versionNamespaceStartToken); + int namespaceEndIndex = sb.indexOf(versionNamespaceEndToken) + + versionNamespaceEndToken.length(); + if (namespaceStartIndex >= 0 && namespaceEndIndex >= 0 && + namespaceStartIndex <= namespaceEndIndex) + { + String namespaceSpan = sb.substring(namespaceStartIndex, namespaceEndIndex) + cr; + sb.delete(namespaceStartIndex, namespaceEndIndex); + for (AmqpVersion v : method.versionSet) + { + StringBuffer nssb = new StringBuffer(namespaceSpan); + processTemplate(nssb, thisClass, method, null, template[templateFileNameIndex], v); + sb.insert(namespaceStartIndex, nssb); + } + // Process all tokens *not* within the namespace span prior to inserting namespaces + processTemplate(sb, thisClass, method, null, template[templateFileNameIndex], null); + } + templateProcessedFlag = true; + } + } + // Remove any remaining namespace tags + int nsTokenIndex = sb.indexOf(versionNamespaceStartToken); + while (nsTokenIndex > 0) + { + sb.delete(nsTokenIndex, nsTokenIndex + versionNamespaceStartToken.length()); + nsTokenIndex = sb.indexOf(versionNamespaceStartToken); + } + nsTokenIndex = sb.indexOf(versionNamespaceEndToken); + while (nsTokenIndex > 0) + { + sb.delete(nsTokenIndex, nsTokenIndex + versionNamespaceEndToken.length()); + nsTokenIndex = sb.indexOf(versionNamespaceEndToken); + } + + if (!templateProcessedFlag) + { + processTemplate(sb, thisClass, method, null, template[templateFileNameIndex], null); + } + writeTargetFile(sb, new File(genDir + Utils.fileSeparator + filename)); + generatedFileCounter ++; + } + + @Override + protected void processTemplateD(String[] template, AmqpClass thisClass, AmqpMethod method, + AmqpField field) + throws IOException, AmqpTemplateException, AmqpTypeMappingException, IllegalAccessException, + InvocationTargetException + { + StringBuffer sb = new StringBuffer(template[templateStringIndex]); + String filename = prepareFilename(getTemplateFileName(sb), thisClass, method, field); + processTemplate(sb, thisClass, method, field, template[templateFileNameIndex], null); + writeTargetFile(sb, new File(genDir + Utils.fileSeparator + filename)); + generatedFileCounter ++; + } + + protected void processTemplate(StringBuffer sb, AmqpClass thisClass, AmqpMethod method, + AmqpField field, String templateFileName, AmqpVersion version) + throws InvocationTargetException, IllegalAccessException, AmqpTypeMappingException + { + try { processAllLists(sb, thisClass, method, version); } + catch (AmqpTemplateException e) + { + System.out.println("ERROR: " + templateFileName + ": " + e.getMessage()); + } + try { processAllTokens(sb, thisClass, method, field, version); } + catch (AmqpTemplateException e) + { + System.out.println("ERROR: " + templateFileName + ": " + e.getMessage()); + } + } + + @Override + protected String processToken(String token, AmqpClass thisClass, AmqpMethod method, AmqpField field, + AmqpVersion version) + throws AmqpTemplateException, AmqpTypeMappingException + { + if (token.compareTo("${GENERATOR}") == 0) + return generatorInfo; + if (token.compareTo("${CLASS}") == 0 && thisClass != null) + return thisClass.name; + if (token.compareTo("${CLASS_ID_INIT}") == 0 && thisClass != null) + { + if (version == null) + return String.valueOf(thisClass.indexMap.firstKey()); + return getIndex(thisClass.indexMap, version); + } + if (token.compareTo("${METHOD}") == 0 && method != null) + return method.name; + if (token.compareTo("${METHOD_ID_INIT}") == 0 && method != null) + { + if (version == null) + return String.valueOf(method.indexMap.firstKey()); + return getIndex(method.indexMap, version); + } + if (token.compareTo("${FIELD}") == 0 && field != null) + return field.name; + if (token.equals(versionNamespaceStartToken) && version != null) + return "namespace " + version.namespace() + cr + "{"; + if (token.equals(versionNamespaceEndToken) && version != null) + return "} // namespace " + version.namespace(); + if (token.equals("${mb_constructor_with_initializers}")) + return generateConstructor(thisClass, method, version, 4, 4); + if (token.equals("${mb_server_operation_invoke}")) + return generateServerOperationsInvoke(thisClass, method, version, 4, 4); + if (token.equals("${mb_buffer_param}")) + return method.fieldMap.size() > 0 ? " buffer" : "/*buffer*/"; + if (token.equals("${hv_latest_major}")) + return String.valueOf(globalVersionSet.last().getMajor()); + if (token.equals("${hv_latest_minor}")) + return String.valueOf(globalVersionSet.last().getMinor()); + if (token.equals("${mb_base_class}")) + return baseClass(method, version); + + throw new AmqpTemplateException("Template token " + token + " unknown."); + } + + private String baseClass(AmqpMethod method, AmqpVersion version) { + String base = method.isResponse(version) ? "AMQResponseBody":"AMQRequestBody"; + return base; + } + + @Override + protected void processClassList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpModel model) + throws AmqpTemplateException, AmqpTypeMappingException + { + String codeSnippet; + int lend = sb.indexOf(cr, listMarkerStartIndex) + 1; // Include cr at end of line + String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr + int tokxStart = tline.indexOf('$'); + String token = tline.substring(tokxStart).trim(); + sb.delete(listMarkerStartIndex, lend); + + // ClientOperations.h + if (token.compareTo("${coh_method_handler_get_method}") == 0) + { + codeSnippet = generateOpsMethodHandlerGetMethods(model, false, 4); + } + else if (token.compareTo("${coh_inner_class}") == 0) + { + codeSnippet = generateOpsInnerClasses(model, false, 4, 4); + } + + // ServerOperations.h + else if (token.compareTo("${soh_method_handler_get_method}") == 0) + { + codeSnippet = generateOpsMethodHandlerGetMethods(model, true, 4); + } + else if (token.compareTo("${soh_inner_class}") == 0) + { + codeSnippet = generateOpsInnerClasses(model, true, 4, 4); + } + + // ClientProxy.h/cpp + else if (token.compareTo("${cph_inner_class_instance}") == 0) + { + codeSnippet = generateProxyInnerClassInstances(model, false, 4); + } + else if (token.compareTo("${cph_inner_class_get_method}") == 0) + { + codeSnippet = generateProxyInnerClassGetMethodDecls(model, false, 4); + } + else if (token.compareTo("${cph_inner_class_defn}") == 0) + { + codeSnippet = generateProxyInnerClassDeclarations(model, false, 4, 4); + } + else if (token.compareTo("${cpc_constructor_initializer}") == 0) + { + codeSnippet = generateProxyConstructorInitializers(model, false, 4); + } + else if (token.compareTo("${cpc_inner_class_get_method}") == 0) + { + codeSnippet = generateProxyInnerClassGetMethodImpls(model, false, 0, 4); + } + else if (token.compareTo("${cpc_inner_class_impl}") == 0) + { + codeSnippet = generateProxyInnerClassImpl(model, false, 0, 4); + } + else if (token.compareTo("${cph_handler_pointer_defn}") == 0) + { + codeSnippet = generateHandlerPointerDefinitions(model, false, 4); + } + else if (token.compareTo("${cph_handler_pointer_get_method}") == 0) + { + codeSnippet = generateHandlerPointerGetMethods(model, false, 4); + } + + // SerrverProxy.h/cpp + else if (token.compareTo("${sph_inner_class_instance}") == 0) + { + codeSnippet = generateProxyInnerClassInstances(model, true, 4); + } + else if (token.compareTo("${sph_inner_class_get_method}") == 0) + { + codeSnippet = generateProxyInnerClassGetMethodDecls(model, true, 4); + } + else if (token.compareTo("${sph_inner_class_defn}") == 0) + { + codeSnippet = generateProxyInnerClassDeclarations(model, true, 4, 4); + } + else if (token.compareTo("${spc_constructor_initializer}") == 0) + { + codeSnippet = generateProxyConstructorInitializers(model, true, 4); + } + else if (token.compareTo("${spc_inner_class_get_method}") == 0) + { + codeSnippet = generateProxyInnerClassGetMethodImpls(model, true, 0, 4); + } + else if (token.compareTo("${spc_inner_class_impl}") == 0) + { + codeSnippet = generateProxyInnerClassImpl(model, true, 0, 4); + } + else if (token.compareTo("${sph_handler_pointer_defn}") == 0) + { + codeSnippet = generateHandlerPointerDefinitions(model, true, 4); + } + else if (token.compareTo("${sph_handler_pointer_get_method}") == 0) + { + codeSnippet = generateHandlerPointerGetMethods(model, true, 4); + } + + // amqp_methods.h/cpp + else if (token.compareTo("${mh_method_body_class_indlude}") == 0) + { + codeSnippet = generateMethodBodyIncludeList(model, 0); + } + else if (token.compareTo("${mh_method_body_class_instance}") == 0) + { + codeSnippet = generateMethodBodyInstances(model, 0); + } + else if (token.compareTo("${mc_create_method_body_map_entry}") == 0) + { + codeSnippet = generateMethodBodyMapEntry(model, 4); + } + + else // Oops! + { + throw new AmqpTemplateException("Template token \"" + token + "\" unknown."); + } + sb.insert(listMarkerStartIndex, codeSnippet); + } + + @Override + protected void processMethodList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpClass thisClass) + throws AmqpTemplateException, AmqpTypeMappingException + { + String codeSnippet; + int lend = sb.indexOf(cr, listMarkerStartIndex) + 1; // Include cr at end of line + String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr + int tokxStart = tline.indexOf('$'); + String token = tline.substring(tokxStart).trim(); + sb.delete(listMarkerStartIndex, lend); + + if (token.compareTo("${cpc_method_body_include}") == 0) + { + codeSnippet = generateMethodBodyIncludes(thisClass, 0); + } + else if (token.compareTo("${spc_method_body_include}") == 0) + { + codeSnippet = generateMethodBodyIncludes(thisClass, 0); + } + else if (token.compareTo("${mc_method_body_include}") == 0) + { + codeSnippet = generateMethodBodyIncludes(thisClass, 0); + } + + else // Oops! + { + throw new AmqpTemplateException("Template token " + token + " unknown."); + } + sb.insert(listMarkerStartIndex, codeSnippet); + } + + @Override + protected void processFieldList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpFieldMap fieldMap, AmqpVersion version) + throws AmqpTypeMappingException, AmqpTemplateException, IllegalAccessException, + InvocationTargetException + { + String codeSnippet; + int lend = sb.indexOf(cr, listMarkerStartIndex) + 1; // Include cr at end of line + String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr + int tokxStart = tline.indexOf('$'); + String token = tline.substring(tokxStart).trim(); + sb.delete(listMarkerStartIndex, lend); + + if (token.equals("${mb_field_declaration}") ) + codeSnippet = generateFieldDeclarations(fieldMap, version, 4); + else if (token.equals("${mb_field_get_method}") ) + codeSnippet = generateFieldGetMethods(fieldMap, version, 4); + else if (token.equals("${mb_field_print}") ) + codeSnippet = generatePrintMethodContents(fieldMap, version, 8); + else if (token.equals("${mb_body_size}") ) + codeSnippet = generateBodySizeMethodContents(fieldMap, version, 8); + else if (token.equals("${mb_encode}") ) + codeSnippet = generateEncodeMethodContents(fieldMap, version, 8); + else if (token.equals("${mb_decode}") ) + codeSnippet = generateDecodeMethodContents(fieldMap, version, 8); + else // Oops! + throw new AmqpTemplateException("Template token " + token + " unknown."); + sb.insert(listMarkerStartIndex, codeSnippet); + } + + @Override + protected void processConstantList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpConstantSet constantSet) + throws AmqpTemplateException, AmqpTypeMappingException + { + String codeSnippet; + int lend = sb.indexOf(cr, listMarkerStartIndex) + 1; // Include cr at end of line + String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr + int tokxStart = tline.indexOf('$'); + String token = tline.substring(tokxStart).trim(); + sb.delete(listMarkerStartIndex, lend); + + if (token.compareTo("${ch_get_value_method}") == 0) + { + codeSnippet = generateConstantGetMethods(constantSet, 4, 4); + } + + else // Oops! + { + throw new AmqpTemplateException("Template token " + token + " unknown."); + } + sb.insert(listMarkerStartIndex, codeSnippet); + } + + // === Protected and private helper functions unique to C++ implementation === + + // Methods for generation of code snippets for AMQP_Constants.h file + + protected String generateConstantGetMethods(AmqpConstantSet constantSet, + int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + for (AmqpConstant thisConstant : constantSet) + { + if (thisConstant.isVersionConsistent(globalVersionSet)) + { + // return a constant + String value = thisConstant.firstKey(); + sb.append(indent + "static const char* " + thisConstant.name + "() { return \"" + + thisConstant.firstKey() + "\"; }" + cr); + if (Utils.containsOnlyDigits(value)) + { + sb.append(indent + "static int " + thisConstant.name + "AsInt() { return " + + thisConstant.firstKey() + "; }" + cr); + } + if (Utils.containsOnlyDigitsAndDecimal(value)) + { + sb.append(indent + "static double " + thisConstant.name + "AsDouble() { return (double)" + + thisConstant.firstKey() + "; }" + cr); + } + sb.append(cr); + } + else + { + // Return version-specific constant + sb.append(generateVersionDependentGet(thisConstant, "const char*", "", "\"", "\"", indentSize, tabSize)); + sb.append(generateVersionDependentGet(thisConstant, "int", "AsInt", "", "", indentSize, tabSize)); + sb.append(generateVersionDependentGet(thisConstant, "double", "AsDouble", "(double)", "", indentSize, tabSize)); + sb.append(cr); + } + } + return sb.toString(); + } + + protected String generateVersionDependentGet(AmqpConstant constant, String methodReturnType, + String methodNameSuffix, String returnPrefix, String returnPostfix, int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + sb.append(indent + methodReturnType + " " + constant.name + methodNameSuffix + + "() const" + cr); + sb.append(indent + "{" + cr); + boolean first = true; + for (String thisValue : constant.keySet()) + { + AmqpVersionSet versionSet = constant.get(thisValue); + sb.append(indent + tab + (first ? "" : "else ") + "if (" + generateVersionCheck(versionSet) + + ")" + cr); + sb.append(indent + tab + "{" + cr); + if (methodReturnType.compareTo("int") == 0 && !Utils.containsOnlyDigits(thisValue)) + { + sb.append(generateConstantDeclarationException(constant.name, methodReturnType, + indentSize + (2*tabSize), tabSize)); + } + else if (methodReturnType.compareTo("double") == 0 && !Utils.containsOnlyDigitsAndDecimal(thisValue)) + { + sb.append(generateConstantDeclarationException(constant.name, methodReturnType, + indentSize + (2*tabSize), tabSize)); + } + else + { + sb.append(indent + tab + tab + "return " + returnPrefix + thisValue + returnPostfix + ";" + cr); + } + sb.append(indent + tab + "}" + cr); + first = false; + } + sb.append(indent + tab + "else" + cr); + sb.append(indent + tab + "{" + cr); + sb.append(indent + tab + tab + "std::stringstream ss;" + cr); + sb.append(indent + tab + tab + "ss << \"Constant \\\"" + constant.name + + "\\\" is undefined for AMQP version \" <<" + cr); + sb.append(indent + tab + tab + tab + "version.toString() << \".\";" + cr); + sb.append(indent + tab + tab + "throw ProtocolVersionException(ss.str());" + cr); + sb.append(indent + tab + "}" + cr); + sb.append(indent + "}" + cr); + return sb.toString(); + } + + protected String generateConstantDeclarationException(String name, String methodReturnType, + int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + sb.append(indent + "std::stringstream ss;" + cr); + sb.append(indent + "ss << \"Constant \\\"" + name + "\\\" cannot be converted to type " + + methodReturnType + " for AMQP version \" <<" + cr); + sb.append(indent + tab + "version.toString() << \".\";" + cr); + sb.append(indent + "throw ProtocolVersionException(ss.str());" + cr); + return sb.toString(); + } + + // Methods used for generation of code snippets for Server/ClientOperations class generation + + protected String generateOpsMethodHandlerGetMethods(AmqpModel model, boolean serverFlag, int indentSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + for (String thisClassName : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(thisClassName); + // Only generate for this class if there is at least one method of the + // required chassis (server/client flag). + boolean chassisFoundFlag = false; + for (String thisMethodName : thisClass.methodMap.keySet()) + { + AmqpMethod method = thisClass.methodMap.get(thisMethodName); + boolean clientChassisFlag = method.clientMethodFlagMap.isSet(); + boolean serverChassisFlag = method.serverMethodFlagMap.isSet(); + if ((serverFlag && serverChassisFlag) || (!serverFlag && clientChassisFlag)) + chassisFoundFlag = true; + } + if (chassisFoundFlag) + { + sb.append(indent + "virtual AMQP_" + (serverFlag ? "Server" : "Client") + "Operations::" + + thisClass.name + "Handler* get" + thisClass.name + "Handler() = 0;" + cr); + } + } + return sb.toString(); + } + + protected String generateOpsInnerClasses(AmqpModel model, boolean serverFlag, int indentSize, int tabSize) + throws AmqpTypeMappingException + { + + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + boolean first = true; + for (String thisClassName : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(thisClassName); + String handlerClassName = thisClass.name + "Handler"; + if (!first) + sb.append(cr); + sb.append(indent + "// ==================== class " + handlerClassName + + " ====================" + cr); + sb.append(indent + "class " + handlerClassName); + if (thisClass.versionSet.size() != globalVersionSet.size()) + sb.append(" // AMQP Version(s) " + thisClass.versionSet + cr); + else + sb.append(cr); + sb.append(indent + "{" + cr); + sb.append(indent + tab + "// Constructors and destructors" + cr); + sb.append(indent + "public:" + cr); + sb.append(indent + tab + handlerClassName + "(){};\n"); + sb.append(indent + tab + "virtual ~" + handlerClassName + "() {}" + cr); + sb.append(cr); + sb.append(indent + tab + "// Protocol methods" + cr); + sb.append(cr); + sb.append(generateInnerClassMethods(thisClass, serverFlag, true, indentSize + tabSize, tabSize)); + sb.append(indent + "}; // class " + handlerClassName + cr); + first = false; + } + return sb.toString(); + } + + protected String generateInnerClassMethods(AmqpClass thisClass, boolean serverFlag, + boolean abstractMethodFlag, int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + String outerClassName = "AMQP_" + (serverFlag ? "Server" : "Client") + (abstractMethodFlag ? "Operations" : "Proxy"); + boolean first = true; + for (String thisMethodName : thisClass.methodMap.keySet()) + { + AmqpMethod method = thisClass.methodMap.get(thisMethodName); + String returnType = (abstractMethodFlag || method.isResponse(null))? "void" : "RequestId"; + boolean clientChassisFlag = method.clientMethodFlagMap.isSet(); + boolean serverChassisFlag = method.serverMethodFlagMap.isSet(); + if ((serverFlag && serverChassisFlag) || (!serverFlag && clientChassisFlag)) + { + String methodName = parseForReservedWords(method.name, outerClassName + "." + thisClass.name); + AmqpOverloadedParameterMap overloadededParameterMap = + method.getOverloadedParameterLists(thisClass.versionSet, this); + for (AmqpOrdinalFieldMap thisFieldMap : overloadededParameterMap.keySet()) + { + AmqpVersionSet versionSet = overloadededParameterMap.get(thisFieldMap); + if (!first) sb.append(cr); + sb.append(indent + "virtual "+returnType+" "+ methodName + "("); + if (abstractMethodFlag) sb.append("const MethodContext& context"); + boolean leadingComma = abstractMethodFlag; + int paramIndent = indentSize + (5*tabSize); + sb.append(generateMethodParameterList(thisFieldMap, paramIndent, leadingComma, true, true)); + if (!abstractMethodFlag && method.isResponse(null)) { + if (!thisFieldMap.isEmpty()) sb.append(", \n"+Utils.createSpaces(paramIndent)); + sb.append(" RequestId responseTo"); + } + sb.append(" )"); + if (abstractMethodFlag) + sb.append(" = 0"); + sb.append(";"); + if (versionSet.size() != globalVersionSet.size()) + sb.append(" // AMQP Version(s) " + versionSet); + sb.append(cr); + first = false; + } + } + } + return sb.toString(); + } + + // Methods used for generation of code snippets for Server/ClientProxy class generation + + protected String generateHandlerPointerDefinitions(AmqpModel model, boolean serverFlag, + int indentSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + String outerClassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Operations"; + for (String thisClassName : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(thisClassName); + sb.append(indent + outerClassName + "::" + thisClass.name + "Handler* " + + thisClass.name + "HandlerPtr;" + cr); + } + return sb.toString(); + } + + protected String generateHandlerPointerGetMethods(AmqpModel model, boolean serverFlag, + int indentSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + String outerClassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Operations"; + for (String thisClassName : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(thisClassName); + sb.append(indent + "virtual " + outerClassName + "::" + thisClass.name + "Handler* get" + + thisClass.name + "Handler() { return &" + Utils.firstLower(thisClass.name) + ";}" + cr); + } + return sb.toString(); + } + + public String proxyInstanceName(AmqpClass inner, String outer) { + return parseForReservedWords(Utils.firstLower(inner.name), outer) + + "Proxy"; + } + + protected String generateProxyInnerClassInstances(AmqpModel model, boolean serverFlag, + int indentSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + String outerClassName = proxyOuterClassName(serverFlag); + for (String thisClassName : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(thisClassName); + String className = parseForReservedWords(thisClass.name, null); + sb.append(indent + className + " " + + proxyInstanceName(thisClass, outerClassName) + ";"); + if (thisClass.versionSet.size() != globalVersionSet.size()) + sb.append(" // AMQP Version(s) " + thisClass.versionSet + cr); + else + sb.append(cr); + } + return sb.toString(); + } + + protected String generateProxyInnerClassGetMethodDecls(AmqpModel model, boolean serverFlag, + int indentSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + for (String thisClassName : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(thisClassName); + String className = parseForReservedWords(thisClass.name, proxyOuterClassName(serverFlag)); + sb.append(indent + className + "& get" + className + "();"); + if (thisClass.versionSet.size() != globalVersionSet.size()) + sb.append(" // AMQP Version(s) " + thisClass.versionSet + cr); + else + sb.append(cr); + } + return sb.toString(); + } + + private String proxyOuterClassName(boolean serverFlag) { + return "AMQP_" + (serverFlag ? "Server" : "Client") + "Proxy"; + } + + protected String generateProxyInnerClassDeclarations(AmqpModel model, boolean serverFlag, + int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + boolean first = true; + for (String thisClassName : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(thisClassName); + String className = thisClass.name; + if (!first) + sb.append(cr); + sb.append(indent + "// ==================== class " + className + + " ====================" + cr); + sb.append(indent + "class " + className); + if (thisClass.versionSet.size() != globalVersionSet.size()) + sb.append(" // AMQP Version(s) " + thisClass.versionSet + cr); + else + sb.append(cr); + sb.append(indent + "{" + cr); + sb.append(indent + "private:" + cr); + sb.append(indent + tab + "ChannelAdapter& channel;" + cr); + sb.append(cr); + sb.append(indent + "public:" + cr); + sb.append(indent + tab + "// Constructors and destructors" + cr); + sb.append(cr); + sb.append(indent + tab + className + "(ChannelAdapter& ch) : " + cr); + sb.append(indent + tab + tab + "channel(ch) {}" + cr); + sb.append(indent + tab + "virtual ~" + className + "() {}" + cr); + sb.append(cr); + sb.append(indent + tab + "static "+className+"& get(" + proxyOuterClassName(serverFlag)+"& proxy) { return proxy.get"+className+"();}\n\n"); + sb.append(indent + tab + "// Protocol methods" + cr); + sb.append(cr); + sb.append(generateInnerClassMethods(thisClass, serverFlag, false, indentSize + tabSize, tabSize)); + sb.append(indent + "}; // class " + className + cr); + first = false; + } + return sb.toString(); + } + + protected String generateProxyConstructorInitializers(AmqpModel model, boolean serverFlag, + int indentSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + Iterator<String> cItr = model.classMap.keySet().iterator(); + while (cItr.hasNext()) + { + AmqpClass thisClass = model.classMap.get(cItr.next()); + sb.append(",\n"); + sb.append(indent + proxyInstanceName(thisClass, proxyOuterClassName(serverFlag)) + + "(channel)"); + } + sb.append("\n"); + return sb.toString(); + } + + protected String generateProxyInnerClassGetMethodImpls(AmqpModel model, boolean serverFlag, + int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + String outerClassName = proxyOuterClassName(serverFlag); + Iterator<String> cItr = model.classMap.keySet().iterator(); + while (cItr.hasNext()) + { + AmqpClass thisClass = model.classMap.get(cItr.next()); + String className = thisClass.name; + sb.append(indent + outerClassName + "::" + className + "& " + + outerClassName + "::get" + className + "()" + cr); + sb.append(indent + "{" + cr); + if (thisClass.versionSet.size() != globalVersionSet.size()) + { + sb.append(indent + tab + "if (!" + generateVersionCheck(thisClass.versionSet) + ")" + cr); + sb.append(indent + tab + tab + "throw new ProtocolVersionException();" + cr); + } + sb.append(indent + tab + "return " + + proxyInstanceName(thisClass, outerClassName) + ";" + cr); + sb.append(indent + "}" + cr); + if (cItr.hasNext()) + sb.append(cr); + } + return sb.toString(); + } + + protected String generateProxyInnerClassImpl(AmqpModel model, boolean serverFlag, + int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + boolean firstClassFlag = true; + for (String thisClassName : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(thisClassName); + String className = thisClass.name; + if (!firstClassFlag) + sb.append(cr); + sb.append(indent + "// ==================== class " + className + + " ====================" + cr); + sb.append(generateInnerClassMethodImpls(thisClass, serverFlag, indentSize, tabSize)); + firstClassFlag = false; + } + return sb.toString(); + } + + protected String generateInnerClassMethodImpls(AmqpClass thisClass, boolean serverFlag, + int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + String outerclassName = proxyOuterClassName(serverFlag); + boolean first = true; + for (String thisMethodName : thisClass.methodMap.keySet()) + { + AmqpMethod method = thisClass.methodMap.get(thisMethodName); + String methodBodyClassName = thisClass.name + Utils.firstUpper(method.name) + "Body"; + boolean clientChassisFlag = method.clientMethodFlagMap.isSet(); + boolean serverChassisFlag = method.serverMethodFlagMap.isSet(); + boolean versionConsistentFlag = method.isVersionConsistent(globalVersionSet); + if ((serverFlag && serverChassisFlag) || (!serverFlag && clientChassisFlag)) + { + String methodName = parseForReservedWords(method.name, outerclassName + "." + thisClass.name); + AmqpOverloadedParameterMap overloadededParameterMap = + method.getOverloadedParameterLists(thisClass.versionSet, this); + for (AmqpOrdinalFieldMap thisFieldMap : overloadededParameterMap.keySet()) + { + AmqpVersionSet versionSet = overloadededParameterMap.get(thisFieldMap); + if (!first) + sb.append(cr); + String returnType = method.isResponse(null) ? "void" : "RequestId"; + sb.append(indent + returnType + " " + outerclassName + "::" + thisClass.name + "::" + + methodName + "("); + sb.append(generateMethodParameterList(thisFieldMap, indentSize + (5*tabSize), false, true, true)); + if (method.isResponse(null)) { + if (!thisFieldMap.isEmpty()) sb.append(", "); + sb.append("RequestId responseTo"); + } + sb.append(")"); + if (versionSet.size() != globalVersionSet.size()) + sb.append(" // AMQP Version(s) " + versionSet); + sb.append(cr); + sb.append(indent + "{" + cr); + sb.append(generateMethodBodyCallContext(method, thisFieldMap, outerclassName, methodBodyClassName, + versionConsistentFlag, versionSet, indentSize + tabSize, tabSize)); + sb.append(indent + "}" + cr); + sb.append(cr); + first = false; + } + } + } + return sb.toString(); + } + + protected String generateMethodBodyCallContext(AmqpMethod method, AmqpOrdinalFieldMap fieldMap, String outerclassName, + String methodBodyClassName, boolean versionConsistentFlag, AmqpVersionSet versionSet, + int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + if (versionConsistentFlag) + { + sb.append(generateProxyMethodBody(method, fieldMap, methodBodyClassName, null, indentSize, tabSize)); + } + else + { + boolean firstOverloadedMethodFlag = true; + for (AmqpVersion thisVersion : versionSet) + { + sb.append(indent); + if (!firstOverloadedMethodFlag) + sb.append("else "); + sb.append("if (" + generateVersionCheck(thisVersion) + ")" + cr); + sb.append(indent + "{" + cr); + sb.append(generateProxyMethodBody(method, fieldMap, methodBodyClassName, thisVersion, + indentSize + tabSize, tabSize)); + sb.append(indent + "}" + cr); + firstOverloadedMethodFlag = false; + } + sb.append(indent + "else" + cr); + sb.append(indent + "{" + cr); + sb.append(indent + tab + "std::stringstream ss;" + cr); + sb.append(indent + tab + "ss << \"Call to " + outerclassName + "::" + methodBodyClassName + + "(u_int16_t" + generateMethodParameterList(fieldMap, 0, true, true, false) + ")\"" + cr); + sb.append(indent + tab + tab + "<< \" is invalid for AMQP version \" << version.toString() << \".\";" + cr); + sb.append(indent + tab + "throw new ProtocolVersionException(ss.str());" + cr); + sb.append(indent + "}" + cr); + } + return sb.toString(); + } + + protected String generateProxyMethodBody(AmqpMethod method, AmqpOrdinalFieldMap fieldMap, String methodBodyClassName, + AmqpVersion version, int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + String namespace = version != null ? version.namespace() + "::" : ""; + StringBuffer sb = new StringBuffer(); + sb.append(indent+tab+(method.isResponse(version) ? "" : "return ")+"channel.send(new "); + sb.append(namespace + methodBodyClassName + "( channel.getVersion()"); + if (method.isResponse(version)) sb.append(", responseTo"); + sb.append(generateMethodParameterList(fieldMap, indentSize + (5*tabSize), true, false, true)); + sb.append("));\n"); + return sb.toString(); + } + + protected String generateMethodBodyIncludes(AmqpClass thisClass, int indentSize) + { + StringBuffer sb = new StringBuffer(); + if (thisClass != null) + { + sb.append(generateClassMethodBodyInclude(thisClass, indentSize)); + } + else + { + for (String thisClassName : model.classMap.keySet()) + { + thisClass = model.classMap.get(thisClassName); + sb.append(generateClassMethodBodyInclude(thisClass, indentSize)); + } + } + return sb.toString(); + } + + protected String generateClassMethodBodyInclude(AmqpClass thisClass, int indentSize) + { + StringBuffer sb = new StringBuffer(); + String indent = Utils.createSpaces(indentSize); + for (String thisMethodName : thisClass.methodMap.keySet()) + { + AmqpMethod method = thisClass.methodMap.get(thisMethodName); + sb.append(indent + "#include <" + thisClass.name + + Utils.firstUpper(method.name) + "Body.h>" + cr); + } + return sb.toString(); + } + + // Methods used for generation of code snippets for MethodBody class generation + + protected String getIndex(AmqpOrdinalVersionMap indexMap, AmqpVersion version) + throws AmqpTemplateException + { + for (Integer thisIndex : indexMap.keySet()) + { + AmqpVersionSet versionSet = indexMap.get(thisIndex); + if (versionSet.contains(version)) + return String.valueOf(thisIndex); + } + throw new AmqpTemplateException("Unable to find index for version " + version); + } + + protected String generateFieldDeclarations(AmqpFieldMap fieldMap, AmqpVersion version, int indentSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + + if (version == null) + version = globalVersionSet.first(); + AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, true, this); + for (Integer thisOrdinal : ordinalFieldMap.keySet()) + { + String[] fieldDomainPair = ordinalFieldMap.get(thisOrdinal); + sb.append(indent + fieldDomainPair[FIELD_CODE_TYPE] + " " + fieldDomainPair[FIELD_NAME] + ";" + cr); + } + return sb.toString(); + } + + protected String generateFieldGetMethods(AmqpFieldMap fieldMap, AmqpVersion version, int indentSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + + if (version == null) + version = globalVersionSet.first(); + AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, true, this); + for (Integer thisOrdinal : ordinalFieldMap.keySet()) + { + String[] fieldDomainPair = ordinalFieldMap.get(thisOrdinal); + sb.append(indent + "" + setRef(fieldDomainPair[FIELD_CODE_TYPE]) + " get" + + Utils.firstUpper(fieldDomainPair[FIELD_NAME]) + "() { return " + + fieldDomainPair[FIELD_NAME] + "; }" + cr); + } + return sb.toString(); + } + + protected String generatePrintMethodContents(AmqpFieldMap fieldMap, AmqpVersion version, int indentSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + + if (version == null) + version = globalVersionSet.first(); + AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, true, this); + boolean firstFlag = true; + for (Integer thisOrdinal : ordinalFieldMap.keySet()) + { + String[] fieldDomainPair = ordinalFieldMap.get(thisOrdinal); + String cast = fieldDomainPair[FIELD_CODE_TYPE].compareTo("u_int8_t") == 0 ? "(int)" : ""; + sb.append(indent + "out << \""); + if (!firstFlag) + sb.append("; "); + sb.append(fieldDomainPair[FIELD_NAME] + "=\" << " + cast + fieldDomainPair[FIELD_NAME] + ";" + cr); + firstFlag = false; + } + return sb.toString(); + } + + protected String generateBodySizeMethodContents(AmqpFieldMap fieldMap, AmqpVersion version, + int indentSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + ArrayList<String> bitFieldList = new ArrayList<String>(); + AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, false, this); + Iterator<Integer> oItr = ordinalFieldMap.keySet().iterator(); + int ordinal = 0; + while (oItr.hasNext()) + { + ordinal = oItr.next(); + String[] fieldDomainPair = ordinalFieldMap.get(ordinal); + AmqpVersion thisVersion = version == null ? globalVersionSet.first() : version; + String domainType = getDomainType(fieldDomainPair[FIELD_CODE_TYPE], thisVersion); + + // Defer bit types by adding them to an array. When the first subsequent non-bit + // type is encountered, then handle the bits. This allows consecutive bits to be + // placed into the same byte(s) - 8 bits to the byte. + if (domainType.compareTo("bit") == 0) + { + bitFieldList.add(fieldDomainPair[FIELD_NAME]); + } + else + { + if (bitFieldList.size() > 0) // Handle accumulated bit types (if any) + { + sb.append(generateBitArrayBodySizeMethodContents(bitFieldList, ordinal, indentSize)); + } + sb.append(indent + "sz += " + + typeMap.get(domainType).size.replaceAll("#", fieldDomainPair[FIELD_NAME]) + + "; /* " + fieldDomainPair[FIELD_NAME] + ": " + + domainType + " */" + cr); + } + } + if (bitFieldList.size() > 0) // Handle any remaining accumulated bit types + { + sb.append(generateBitArrayBodySizeMethodContents(bitFieldList, ordinal, indentSize)); + } + return sb.toString(); + } + + protected String generateBitArrayBodySizeMethodContents(ArrayList<String> bitFieldList, + int ordinal, int indentSize) + { + int numBytes = ((bitFieldList.size() - 1) / 8) + 1; + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + String comment = bitFieldList.size() == 1 ? + bitFieldList.get(0) + ": bit" : + "Combinded bits: " + bitFieldList; + sb.append(indent + "sz += " + + typeMap.get("bit").size.replaceAll("~", String.valueOf(numBytes)) + + "; /* " + comment + " */" + cr); + bitFieldList.clear(); + return sb.toString(); + } + + protected String generateEncodeMethodContents(AmqpFieldMap fieldMap, AmqpVersion version, + int indentSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + ArrayList<String> bitFieldList = new ArrayList<String>(); + AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, false, this); + Iterator<Integer> oItr = ordinalFieldMap.keySet().iterator(); + int ordinal = 0; + while (oItr.hasNext()) + { + ordinal = oItr.next(); + String[] fieldDomainPair = ordinalFieldMap.get(ordinal); + AmqpVersion thisVersion = version == null ? globalVersionSet.first() : version; + String domainType = getDomainType(fieldDomainPair[FIELD_CODE_TYPE], thisVersion); + + // Defer bit types by adding them to an array. When the first subsequent non-bit + // type is encountered, then handle the bits. This allows consecutive bits to be + // placed into the same byte(s) - 8 bits to the byte. + if (domainType.compareTo("bit") == 0) + { + bitFieldList.add(fieldDomainPair[FIELD_NAME]); + } + else + { + if (bitFieldList.size() > 0) // Handle accumulated bit types (if any) + { + sb.append(generateBitEncodeMethodContents(bitFieldList, ordinal, indentSize)); + } + sb.append(indent + + typeMap.get(domainType).encodeExpression.replaceAll("#", fieldDomainPair[FIELD_NAME]) + + "; /* " + fieldDomainPair[FIELD_NAME] + ": " + domainType + " */"+ cr); + } + } + if (bitFieldList.size() > 0) // Handle any remaining accumulated bit types + { + sb.append(generateBitEncodeMethodContents(bitFieldList, ordinal, indentSize)); + } + + return sb.toString(); + } + + protected String generateBitEncodeMethodContents(ArrayList<String> bitFieldList, int ordinal, + int indentSize) + { + int numBytes = ((bitFieldList.size() - 1) / 8) + 1; + String indent = Utils.createSpaces(indentSize); + String bitArrayName = "flags_" + ordinal; + StringBuffer sb = new StringBuffer(indent + "u_int8_t " + bitArrayName + + "[" + numBytes + "] = {0};" + + (numBytes != 1 ? " /* All array elements will be initialized to 0 */" : "") + + cr); + for (int i=0; i<bitFieldList.size(); i++) + { + int bitIndex = i%8; + int byteIndex = i/8; + sb.append(indent + bitArrayName + "[" + byteIndex + "] |= " + bitFieldList.get(i) + + " << " + bitIndex + "; /* " + bitFieldList.get(i) + ": bit */" + cr); + } + for (int i=0; i<numBytes; i++) + { + sb.append(indent + "buffer.putOctet(" + bitArrayName + "[" + i + "]);" + cr); + } + bitFieldList.clear(); + return sb.toString(); + } + + protected String generateDecodeMethodContents(AmqpFieldMap fieldMap, AmqpVersion version, + int indentSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + ArrayList<String> bitFieldList = new ArrayList<String>(); + AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, false, this); + Iterator<Integer> oItr = ordinalFieldMap.keySet().iterator(); + int ordinal = 0; + while (oItr.hasNext()) + { + ordinal = oItr.next(); + String[] fieldDomainPair = ordinalFieldMap.get(ordinal); + AmqpVersion thisVersion = version == null ? globalVersionSet.first() : version; + String domainType = getDomainType(fieldDomainPair[FIELD_CODE_TYPE], thisVersion); + + // Defer bit types by adding them to an array. When the first subsequent non-bit + // type is encountered, then handle the bits. This allows consecutive bits to be + // placed into the same byte(s) - 8 bits to the byte. + if (domainType.compareTo("bit") == 0) + { + bitFieldList.add(fieldDomainPair[FIELD_NAME]); + } + else + { + if (bitFieldList.size() > 0) // Handle accumulated bit types (if any) + { + sb.append(generateBitDecodeMethodContents(bitFieldList, ordinal, indentSize)); + } + sb.append(indent + + typeMap.get(domainType).decodeExpression.replaceAll("#", fieldDomainPair[FIELD_NAME]) + + "; /* " + fieldDomainPair[FIELD_NAME] + ": " + domainType + " */" + cr); + } + } + if (bitFieldList.size() > 0) // Handle any remaining accumulated bit types + { + sb.append(generateBitDecodeMethodContents(bitFieldList, ordinal, indentSize)); + } + + return sb.toString(); + } + + protected String generateBitDecodeMethodContents(ArrayList<String> bitFieldList, int ordinal, + int indentSize) + { + int numBytes = ((bitFieldList.size() - 1) / 8) + 1; + String indent = Utils.createSpaces(indentSize); + String bitArrayName = "flags_" + ordinal; + StringBuffer sb = new StringBuffer(indent + "u_int8_t " + bitArrayName + + "[" + numBytes + "];" + cr); + for (int i=0; i<numBytes; i++) + { + sb.append(indent + bitArrayName + "[" + i + "] = buffer.getOctet();" + cr); + } + for (int i=0; i<bitFieldList.size(); i++) + { + int bitIndex = i%8; + int byteIndex = i/8; + sb.append(indent + bitFieldList.get(i) + " = (1 << " + bitIndex + ") & " + + bitArrayName + "[" + byteIndex + "]; /* " + bitFieldList.get(i) + + ": bit */" + cr); + } + bitFieldList.clear(); + return sb.toString(); + } + + protected String generateFieldList(AmqpFieldMap fieldMap, AmqpVersion version, boolean defineFlag, + boolean initializerFlag, int indentSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, true, this); + Iterator<Integer> oItr = ordinalFieldMap.keySet().iterator(); + while (oItr.hasNext()) + { + int ordinal = oItr.next(); + String[] fieldDomainPair = ordinalFieldMap.get(ordinal); + sb.append(indent + (defineFlag ? setRef(fieldDomainPair[FIELD_CODE_TYPE]) + " " : "") + + fieldDomainPair[FIELD_NAME] + (initializerFlag ? "(" + fieldDomainPair[FIELD_NAME] + ")" : "") + + (oItr.hasNext() ? "," : "") + cr); + } + return sb.toString(); + } + + protected String generateMethodParameterList(AmqpOrdinalFieldMap fieldMap, int indentSize, + boolean leadingCommaFlag, boolean fieldTypeFlag, boolean fieldNameFlag) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + boolean first = true; + Iterator<Integer> pItr = fieldMap.keySet().iterator(); + while(pItr.hasNext()) + { + String[] field = fieldMap.get(pItr.next()); + if (first && leadingCommaFlag) + { + sb.append("," + (fieldNameFlag ? cr : " ")); + } + if (!first || leadingCommaFlag) + { + sb.append(indent); + } + sb.append( + (fieldTypeFlag ? setRef(field[FIELD_CODE_TYPE]) : "") + + (fieldNameFlag ? " " + field[FIELD_NAME] : "") + + (pItr.hasNext() ? "," + (fieldNameFlag ? cr : " ") : "")); + first = false; + } + return sb.toString(); + } + + protected String generateConstructor(AmqpClass thisClass, AmqpMethod method, + AmqpVersion version, int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + if (method.fieldMap.size() > 0 || method.isResponse(version)) + { + sb.append(indent + thisClass.name + Utils.firstUpper(method.name) + "Body(ProtocolVersion version," + cr); + if (method.isResponse(version)) { + sb.append(indent+tab+"RequestId toRequest"); + if (method.fieldMap.size() >0) + sb.append(",\n"); + } + sb.append(generateFieldList(method.fieldMap, version, true, false, 8)); + sb.append(indent + tab + ") : " + baseClass(method, version) + "(version"); + if (method.isResponse(version)) + sb.append(", 0, toRequest"); + sb.append(")"); + if (method.fieldMap.size() > 0) + sb.append(", \n" + generateFieldList(method.fieldMap, version, false, true, 8)); + sb.append(indent + "{ }\n"); + } + return sb.toString(); + } + + protected String generateServerOperationsInvoke(AmqpClass thisClass, AmqpMethod method, + AmqpVersion version, int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + + if (method.serverMethodFlagMap.size() > 0) // At least one AMQP version defines this method as a server method + { + Iterator<Boolean> bItr = method.serverMethodFlagMap.keySet().iterator(); + while (bItr.hasNext()) + { + if (bItr.next()) // This is a server operation + { + boolean fieldMapNotEmptyFlag = method.fieldMap.size() > 0; + sb.append(indent + "void invoke(AMQP_ServerOperations& target, const MethodContext& context)" + cr); + sb.append(indent + "{" + cr); + sb.append(indent + tab + "target.get" + thisClass.name + "Handler()->" + + parseForReservedWords(Utils.firstLower(method.name), + thisClass.name + Utils.firstUpper(method.name) + "Body.invoke()") + "(context"); + if (fieldMapNotEmptyFlag) + { + sb.append("," + cr); + sb.append(generateFieldList(method.fieldMap, version, false, false, indentSize + 4*tabSize)); + sb.append(indent + tab + tab + tab + tab); + } + sb.append(");" + cr); + sb.append(indent + "}" + cr); + } + } + } + return sb.toString(); + } + + // Methods for generation of code snippets for amqp_methods.h/cpp files + + protected String generateMethodBodyIncludeList(AmqpModel model, int indentSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + + for (String thisClassName : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(thisClassName); + for (String thisMethodName : thisClass.methodMap.keySet()) + { + AmqpMethod method = thisClass.methodMap.get(thisMethodName); + sb.append(indent + "#include \"" + thisClass.name + Utils.firstUpper(method.name) + "Body.h\"" + cr); + } + } + + return sb.toString(); + } + + protected String generateMethodBodyInstances(AmqpModel model, int indentSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + + for (String thisClassName : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(thisClassName); + for (String thisMethodName : thisClass.methodMap.keySet()) + { + AmqpMethod method = thisClass.methodMap.get(thisMethodName); + sb.append(indent + "const " + thisClass.name + Utils.firstUpper(method.name) + "Body " + + Utils.firstLower(thisClass.name) + "_" + method.name + ";" + cr); + } + } + + return sb.toString(); + } + + protected String generateMethodBodyMapEntry(AmqpModel model, int indentSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + + for (AmqpVersion version : globalVersionSet) + { + for (String thisClassName : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(thisClassName); + for (String thisMethodName : thisClass.methodMap.keySet()) + { + AmqpMethod method = thisClass.methodMap.get(thisMethodName); + String namespace = method.isVersionConsistent(globalVersionSet) ? "" : version.namespace() + "::"; + try + { + int classOrdinal = thisClass.indexMap.getOrdinal(version); + int methodOrdinal = method.indexMap.getOrdinal(version); + String methodModyClassName = namespace + thisClass.name + Utils.firstUpper(method.name) + "Body"; + sb.append(indent + "insert(std::make_pair(createMapKey(" + classOrdinal + ", " + + methodOrdinal + ", " + version.getMajor() + ", " + version.getMinor() + + "), &createMethodBodyFn<" + methodModyClassName + ">));" + cr); + } + catch (AmqpTypeMappingException e) {} // ignore + } + } + } + + return sb.toString(); + } + + + // Helper functions + + private String generateVersionCheck(AmqpVersion version) + { + return "version.equals(" + version.getMajor() + ", " + version.getMinor() + ")"; + } + + private String generateVersionCheck(AmqpVersionSet versionSet) + throws AmqpTypeMappingException + { + StringBuffer sb = new StringBuffer(); + for (AmqpVersion v : versionSet) + { + if (!v.equals(versionSet.first())) + sb.append(" || "); + if (versionSet.size() > 1) + sb.append("("); + sb.append("version.equals(" + v.getMajor() + ", " + v.getMinor() + ")"); + if (versionSet.size() > 1) + sb.append(")"); + } + return sb.toString(); + } + + private String parseForReservedWords(String name, String context) + { + for (String cppReservedWord : cppReservedWords) + if (name.compareTo(cppReservedWord) == 0) + { + if (!quietFlag) + { + System.out.println("WARNING: " + (context == null ? "" : context + ": ") + + "Found XML method \"" + name + "\", which is a C++ reserved word. " + + "Changing generated name to \"" + name + "_\"."); + } + return name + "_"; + } + + for (String cppCommonDefine : cppCommonDefines) + if (name.compareTo(cppCommonDefine) == 0) + { + if (!quietFlag) + { + System.out.println("WARNING: " + (context == null ? "" : context + ": ") + + "Found XML method \"" + name + "\", which may clash with commonly used defines within C++. " + + "Changing generated name to \"" + name + "_\"."); + } + return name + "_"; + } + + return name; + } + + private String setRef(String codeType) + { + if (codeType.equals("string") || + codeType.equals("FieldTable") || + codeType.equals("Content")) + return "const " + codeType + "&"; + return codeType; + } + + private String camelCaseName(String name, boolean upperFirstFlag) + { + StringBuffer ccn = new StringBuffer(); + String[] toks = name.split("[-_.\\ ]"); + for (int i=0; i<toks.length; i++) + { + StringBuffer b = new StringBuffer(toks[i]); + if (upperFirstFlag || i>0) + b.setCharAt(0, Character.toUpperCase(toks[i].charAt(0))); + ccn.append(b); + } + return ccn.toString(); + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/DotnetGenerator.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/DotnetGenerator.java new file mode 100644 index 0000000000..505a70dc85 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/DotnetGenerator.java @@ -0,0 +1,339 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.TreeMap; + +public class DotnetGenerator extends Generator +{ + private class DomainInfo + { + public String type; + public String size; + public String encodeExpression; + public String decodeExpression; + public DomainInfo(String domain, String size, String encodeExpression, String decodeExpression) + { + this.type = domain; + this.size = size; + this.encodeExpression = encodeExpression; + this.decodeExpression = decodeExpression; + } + } + + private static TreeMap<String, DomainInfo> typeMap = new TreeMap<String, DomainInfo>(); + + public DotnetGenerator(AmqpVersionSet versionList) + { + super(versionList); + // Load .NET type and size maps. + // Adjust or add to these lists as new types are added/defined. + // The char '#' will be replaced by the field variable name (any type). + // The char '~' will be replaced by the compacted bit array size (type bit only). + // TODO: I have left a copy of the Java typeMap here - replace with appropriate .NET values. + typeMap.put("bit", new DomainInfo( + "boolean", // .NET code type + "~", // size + "EncodingUtils.writeBooleans(buffer, #)", // encode expression + "# = EncodingUtils.readBooleans(buffer)")); // decode expression + typeMap.put("content", new DomainInfo( + "Content", // .NET code type + "EncodingUtils.encodedContentLength(#)", // size + "EncodingUtils.writeContentBytes(buffer, #)", // encode expression + "# = EncodingUtils.readContent(buffer)")); // decode expression + typeMap.put("long", new DomainInfo( + "long", // .NET code type + "4", // size + "EncodingUtils.writeUnsignedInteger(buffer, #)", // encode expression + "# = buffer.getUnsignedInt()")); // decode expression + typeMap.put("longlong", new DomainInfo( + "long", // .NET code type + "8", // size + "buffer.putLong(#)", // encode expression + "# = buffer.getLong()")); // decode expression + typeMap.put("longstr", new DomainInfo( + "byte[]", // .NET code type + "EncodingUtils.encodedLongstrLength(#)", // size + "EncodingUtils.writeLongStringBytes(buffer, #)", // encode expression + "# = EncodingUtils.readLongstr(buffer)")); // decode expression + typeMap.put("octet", new DomainInfo( + "short", // .NET code type + "1", // size + "EncodingUtils.writeUnsignedByte(buffer, #)", // encode expression + "# = buffer.getUnsigned()")); // decode expression + typeMap.put("short", new DomainInfo( + "int", // .NET code type + "2", // size + "EncodingUtils.writeUnsignedShort(buffer, #)", // encode expression + "# = buffer.getUnsignedShort()")); // decode expression + typeMap.put("shortstr", new DomainInfo( + "AMQShortString", // .NET code type + "EncodingUtils.encodedShortStringLength(#)", // size + "EncodingUtils.writeShortStringBytes(buffer, #)", // encode expression + "# = EncodingUtils.readAMQShortString(buffer)")); // decode expression + typeMap.put("table", new DomainInfo( + "FieldTable", // .NET code type + "EncodingUtils.encodedFieldTableLength(#)", // size + "EncodingUtils.writeFieldTableBytes(buffer, #)", // encode expression + "# = EncodingUtils.readFieldTable(buffer)")); // decode expression + typeMap.put("timestamp", new DomainInfo( + "long", // .NET code type + "8", // size + "EncodingUtils.writeTimestamp(buffer, #)", // encode expression + "# = EncodingUtils.readTimestamp(buffer)")); // decode expression + } + + @Override + protected String prepareFilename(String filenameTemplate, + AmqpClass thisClass, AmqpMethod method, AmqpField field) + { + StringBuffer sb = new StringBuffer(filenameTemplate); + if (thisClass != null) + replaceToken(sb, "${CLASS}", thisClass.name); + if (method != null) + replaceToken(sb, "${METHOD}", method.name); + if (field != null) + replaceToken(sb, "${FIELD}", field.name); + return sb.toString(); + } + + @Override + protected void processClassList(StringBuffer sb, int listMarkerStartIndex, + int listMarkerEndIndex, AmqpModel model) + throws AmqpTemplateException, AmqpTypeMappingException + { + String codeSnippet; + int lend = sb.indexOf(cr, listMarkerStartIndex) + 1; // Include cr at end of line + String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr + int tokStart = tline.indexOf('$'); + String token = tline.substring(tokStart).trim(); + sb.delete(listMarkerStartIndex, lend); + + // TODO: Add in tokens and calls to their corresponding generator methods here... + if (token.compareTo("${??????????}") == 0) + { + codeSnippet = token; // This is a stub to get the compile working - remove when gen method is present. +// codeSnippet = generateRegistry(model, 8, 4); + } + + else // Oops! + { + throw new AmqpTemplateException("Template token " + token + " unknown."); + } + sb.insert(listMarkerStartIndex, codeSnippet); + } + + @Override + protected void processConstantList(StringBuffer sb, + int listMarkerStartIndex, int listMarkerEndIndex, + AmqpConstantSet constantSet) throws AmqpTemplateException, + AmqpTypeMappingException + { + String codeSnippet; + int lend = sb.indexOf(cr, listMarkerStartIndex) + 1; // Include cr at end of line + String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr + int tokStart = tline.indexOf('$'); + String token = tline.substring(tokStart).trim(); + sb.delete(listMarkerStartIndex, lend); + + // TODO: Add in tokens and calls to their corresponding generator methods here... + if (token.compareTo("${??????????}") == 0) + { + codeSnippet = token; // This is a stub to get the compile working - remove when gen method is present. +// codeSnippet = generateConstantGetMethods(constantSet, 4, 4); + } + + else // Oops! + { + throw new AmqpTemplateException("Template token " + token + " unknown."); + } + sb.insert(listMarkerStartIndex, codeSnippet); + } + + @Override + protected void processFieldList(StringBuffer sb, int listMarkerStartIndex, + int listMarkerEndIndex, AmqpFieldMap fieldMap, AmqpVersion version) + throws AmqpTypeMappingException, AmqpTemplateException, + IllegalAccessException, InvocationTargetException + { + String codeSnippet; + int lend = sb.indexOf(cr, listMarkerStartIndex) + 1; // Include cr at end of line + String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr + int tokStart = tline.indexOf('$'); + String token = tline.substring(tokStart).trim(); + sb.delete(listMarkerStartIndex, lend); + + // TODO: Add in tokens and calls to their corresponding generator methods here... + if (token.compareTo("${??????????}") == 0) + { + codeSnippet = token; // This is a stub to get the compile working - remove when gen method is present. +// codeSnippet = fieldMap.parseFieldMap(declarationGenerateMethod, +// mangledDeclarationGenerateMethod, 4, 4, this); + } + + else // Oops! + { + throw new AmqpTemplateException("Template token " + token + " unknown."); + } + sb.insert(listMarkerStartIndex, codeSnippet); + } + + @Override + protected void processMethodList(StringBuffer sb, int listMarkerStartIndex, + int listMarkerEndIndex, AmqpClass thisClass) + throws AmqpTemplateException, AmqpTypeMappingException + { + String codeSnippet; + int lend = sb.indexOf(cr, listMarkerStartIndex) + 1; // Include cr at end of line + String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr + int tokStart = tline.indexOf('$'); + String token = tline.substring(tokStart).trim(); + sb.delete(listMarkerStartIndex, lend); + + // TODO: Add in tokens and calls to their corresponding generator methods here... + if (token.compareTo("${??????????}") == 0) + { + codeSnippet = token; // This is a stub to get the compile working - remove when gen method is present. + } + + else // Oops! + { + throw new AmqpTemplateException("Template token " + token + " unknown."); + } + sb.insert(listMarkerStartIndex, codeSnippet); + } + + @Override + protected void processTemplateA(String[] template) throws IOException, + AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException + { + // I've put in the Java model here - this can be changed if a different pattern is required. + processTemplateD(template, null, null, null); + } + + @Override + protected void processTemplateB(String[] template, AmqpClass thisClass) + throws IOException, AmqpTemplateException, + AmqpTypeMappingException, IllegalAccessException, + InvocationTargetException + { + // I've put in the Java model here - this can be changed if a different pattern is required. + processTemplateD(template, thisClass, null, null); + } + + @Override + protected void processTemplateC(String[] template, AmqpClass thisClass, + AmqpMethod method) throws IOException, AmqpTemplateException, + AmqpTypeMappingException, IllegalAccessException, + InvocationTargetException + { + // I've put in the Java model here - this can be changed if a different pattern is required. + processTemplateD(template, thisClass, method, null); + } + + @Override + protected void processTemplateD(String[] template, AmqpClass thisClass, + AmqpMethod method, AmqpField field) throws IOException, + AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException + { + // I've put in the Java model here - this can be changed if a different pattern is required. + StringBuffer sb = new StringBuffer(template[1]); + String filename = prepareFilename(getTemplateFileName(sb), thisClass, method, field); + try { processAllLists(sb, thisClass, method, null); } + catch (AmqpTemplateException e) + { + System.out.println("WARNING: " + template[templateFileNameIndex] + ": " + e.getMessage()); + } + try { processAllTokens(sb, thisClass, method, field, null); } + catch (AmqpTemplateException e) + { + System.out.println("WARNING: " + template[templateFileNameIndex] + ": " + e.getMessage()); + } + writeTargetFile(sb, new File(genDir + Utils.fileSeparator + filename)); + generatedFileCounter ++; + } + + @Override + protected String processToken(String token, AmqpClass thisClass, + AmqpMethod method, AmqpField field, AmqpVersion version) + throws AmqpTemplateException, AmqpTypeMappingException + { + // TODO Auto-generated method stub + return null; + } + + public String getDomainType(String domainName, AmqpVersion version) + throws AmqpTypeMappingException + { + return globalDomainMap.getDomainType(domainName, version); + } + + public String getGeneratedType(String domainName, AmqpVersion version) + throws AmqpTypeMappingException + { + String domainType = globalDomainMap.getDomainType(domainName, version); + if (domainType == null) + { + throw new AmqpTypeMappingException("Domain type \"" + domainName + + "\" not found in Java typemap."); + } + DomainInfo info = typeMap.get(domainType); + if (info == null) + { + throw new AmqpTypeMappingException("Unknown domain: \"" + domainType + "\""); + } + return info.type; + } + + public String prepareClassName(String className) + { + return camelCaseName(className, true); + } + + public String prepareDomainName(String domainName) + { + return camelCaseName(domainName, false); + } + + public String prepareMethodName(String methodName) + { + return camelCaseName(methodName, false); + } + + private String camelCaseName(String name, boolean upperFirstFlag) + { + StringBuffer ccn = new StringBuffer(); + String[] toks = name.split("[-_.\\ ]"); + for (int i=0; i<toks.length; i++) + { + StringBuffer b = new StringBuffer(toks[i]); + if (upperFirstFlag || i>0) + b.setCharAt(0, Character.toUpperCase(toks[i].charAt(0))); + ccn.append(b); + } + return ccn.toString(); + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/Generator.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/Generator.java new file mode 100644 index 0000000000..e7ccd64fbe --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/Generator.java @@ -0,0 +1,429 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.LineNumberReader; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; + +public abstract class Generator implements LanguageConverter +{ + protected static String cr = Utils.lineSeparator; + protected static enum EnumConstOutputTypes { OUTPUT_STRING, OUTPUT_INTEGER, OUTPUT_DOUBLE; }; + + // This string is reproduced in every generated file as a comment + // TODO: Tie the version info into the build system. + protected static final String generatorInfo = "Qpid Gentools v.0.1"; + protected static final int templateFileNameIndex = 0; + protected static final int templateStringIndex = 1; + + protected ArrayList<String[]> modelTemplateList; + protected ArrayList<String[]> classTemplateList; + protected ArrayList<String[]> methodTemplateList; + protected ArrayList<String[]> fieldTemplateList; + protected String genDir; + + protected AmqpVersionSet globalVersionSet; + protected AmqpDomainMap globalDomainMap; + protected AmqpConstantSet globalConstantSet; + protected AmqpModel model; + + protected int generatedFileCounter; + + public Generator(AmqpVersionSet versionList) + { + this.globalVersionSet = versionList; + modelTemplateList = new ArrayList<String[]>(); + classTemplateList = new ArrayList<String[]>(); + methodTemplateList = new ArrayList<String[]>(); + fieldTemplateList = new ArrayList<String[]>(); + generatedFileCounter = 0; + } + + public int getNumberGeneratedFiles() + { + return generatedFileCounter; + } + + public void setDomainMap(AmqpDomainMap domainMap) + { + this.globalDomainMap = domainMap; + } + + public AmqpDomainMap getDomainMap() + { + return globalDomainMap; + } + + public void setConstantSet(AmqpConstantSet constantSet) + { + this.globalConstantSet = constantSet; + } + + public AmqpConstantSet getConstantSet() + { + return globalConstantSet; + } + + public void setModel(AmqpModel model) + { + this.model = model; + } + + public AmqpModel getModel() + { + return model; + } + + public void initializeTemplates(File[] modelTemplateFiles, File[] classTemplatesFiles, + File[] methodTemplatesFiles, File[] fieldTemplatesFiles) + throws FileNotFoundException, IOException + { + if (modelTemplateFiles.length > 0) + { + System.out.println("Model template file(s):"); + for (File mtf : modelTemplateFiles) + { + System.out.println(" " + mtf.getAbsolutePath()); + String template[] = {mtf.getName(), loadTemplate(mtf)}; + modelTemplateList.add(template); + } + } + if (classTemplatesFiles.length > 0) + { + System.out.println("Class template file(s):"); + //for (int c=0; c<classTemplatesFiles.length; c++) + for (File ctf : classTemplatesFiles) + { + System.out.println(" " + ctf.getAbsolutePath()); + String template[] = {ctf.getName(), loadTemplate(ctf)}; + classTemplateList.add(template); + } + } + if (methodTemplatesFiles.length > 0) + { + System.out.println("Method template file(s):"); + for (File mtf : methodTemplatesFiles) + { + System.out.println(" " + mtf.getAbsolutePath()); + String template[] = {mtf.getName(), loadTemplate(mtf)}; + methodTemplateList.add(template); + } + } + if (fieldTemplatesFiles.length > 0) + { + System.out.println("Field template file(s):"); + for (File ftf : fieldTemplatesFiles) + { + System.out.println(" " + ftf.getAbsolutePath()); + String template[] = {ftf.getName(), loadTemplate(ftf)}; + fieldTemplateList.add(template); + } + } + } + + abstract protected String prepareFilename(String filenameTemplate, AmqpClass thisClass, AmqpMethod method, + AmqpField field); + + abstract protected String processToken(String token, AmqpClass thisClass, AmqpMethod method, + AmqpField field, AmqpVersion version) + throws AmqpTemplateException, AmqpTypeMappingException; + + abstract protected void processClassList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpModel model) + throws AmqpTemplateException, AmqpTypeMappingException; + + abstract protected void processMethodList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpClass thisClass) + throws AmqpTemplateException, AmqpTypeMappingException; + + abstract protected void processFieldList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpFieldMap fieldMap, AmqpVersion version) + throws AmqpTypeMappingException, AmqpTemplateException, IllegalAccessException, + InvocationTargetException; + + abstract protected void processConstantList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpConstantSet constantSet) + throws AmqpTemplateException, AmqpTypeMappingException; + + public void generate(File genDir) + throws TargetDirectoryException, IOException, AmqpTypeMappingException, + AmqpTemplateException, IllegalAccessException, InvocationTargetException + { + prepareTargetDirectory(genDir, true); + System.out.println("Generation directory: " + genDir.getAbsolutePath()); + this.genDir = genDir.getAbsolutePath(); + + // Use all model-level templates + for (String[] mt : modelTemplateList) + { + processTemplateA(mt); + } + + // Cycle through classes + for (String className : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(className); + // Use all class-level templates + for (String[] ct : classTemplateList) + { + processTemplateB(ct, thisClass); + } + + // Cycle through all methods + for (String methodName : thisClass.methodMap.keySet()) + { + AmqpMethod method = thisClass.methodMap.get(methodName); + // Use all method-level templates + for (String[] mt : methodTemplateList) + { + processTemplateC(mt, thisClass, method); + } + + // Cycle through all fields + for (String fieldName : method.fieldMap.keySet()) + { + AmqpField field = method.fieldMap.get(fieldName); + // Use all field-level templates + for (String[] ft : fieldTemplateList) + { + processTemplateD(ft, thisClass, method, field); + } + } + } + } + } + + protected void processVersionList(StringBuffer sb, int tokStart, int tokEnd) + throws AmqpTypeMappingException + { + int lend = sb.indexOf(Utils.lineSeparator, tokStart) + 1; // Include cr at end of line + String tline = sb.substring(tokEnd, lend); // Line excluding line marker, including cr + sb.delete(tokStart, lend); + + for (AmqpVersion v : globalVersionSet) + { + // Insert copy of target line + StringBuffer isb = new StringBuffer(tline); + if (isb.indexOf("${protocol-version-list-entry}") >= 0) + { + String versionListEntry = " { ${major}, ${minor} }" + + (v.equals(globalVersionSet.last()) ? "" : ","); + replaceToken(isb, "${protocol-version-list-entry}", String.valueOf(versionListEntry)); + } + if (isb.indexOf("${major}") >= 0) + replaceToken(isb, "${major}", String.valueOf(v.getMajor())); + if (isb.indexOf("${minor}") >= 0) + replaceToken(isb, "${minor}", String.valueOf(v.getMinor())); + sb.insert(tokStart, isb.toString()); + tokStart += isb.length(); + } + } + + // Model-level template processing + abstract protected void processTemplateA(String[] template) + throws IOException, AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException; + + // Class-level template processing + abstract protected void processTemplateB(String[] template, AmqpClass thisClass) + throws IOException, AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException; + + // Method-level template processing + abstract protected void processTemplateC(String[] template, AmqpClass thisClass, + AmqpMethod method) + throws IOException, AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException; + + // Field-level template processing + abstract protected void processTemplateD(String[] template, AmqpClass thisClass, + AmqpMethod method, AmqpField field) + throws IOException, AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException; + + // Helper functions common to all generators + + protected static void prepareTargetDirectory(File dir, boolean createFlag) + throws TargetDirectoryException + { + if (dir.exists()) + { + if (!dir.isDirectory()) + throw new TargetDirectoryException("\"" + dir.getAbsolutePath() + + "\" exists, but is not a directory."); + } + else if (createFlag) // Create dir + { + if(!dir.mkdirs()) + throw new TargetDirectoryException("Unable to create directory \"" + + dir.getAbsolutePath() + "\"."); + } + else + throw new TargetDirectoryException("Directory \"" + dir.getAbsolutePath() + + "\" not found."); + + } + + protected void processAllLists(StringBuffer sb, AmqpClass thisClass, AmqpMethod method, AmqpVersion version) + throws AmqpTemplateException, AmqpTypeMappingException, IllegalAccessException, + InvocationTargetException + { + int lstart = sb.indexOf("%{"); + while (lstart != -1) + { + int lend = sb.indexOf("}", lstart + 2); + if (lend > 0) + { + String listToken = sb.substring(lstart + 2, lend); + if (listToken.compareTo("VLIST") == 0) + { + processVersionList(sb, lstart, lend + 1); + } + else if (listToken.compareTo("CLIST") == 0) + { + processClassList(sb, lstart, lend + 1, model); + } + else if (listToken.compareTo("MLIST") == 0) + { + processMethodList(sb, lstart, lend + 1, thisClass); + } + else if (listToken.compareTo("FLIST") == 0) + { + // Pass the FieldMap from either a class or a method. + // If this is called from a class-level template, we assume that the + // class field list is required. In this case, method will be null. + processFieldList(sb, lstart, lend + 1, + (method == null ? thisClass.fieldMap : method.fieldMap), + version); + } + else if (listToken.compareTo("TLIST") == 0) + { + processConstantList(sb, lstart, lend + 1, globalConstantSet); + } + else + { + throw new AmqpTemplateException("Unknown list token \"%{" + listToken + + "}\" found in template at index " + lstart + "."); + } + } + lstart = sb.indexOf("%{", lstart + 1); + } + } + + protected void processAllTokens(StringBuffer sb, AmqpClass thisClass, AmqpMethod method, AmqpField field, + AmqpVersion version) + throws AmqpTemplateException, AmqpTypeMappingException + { + int lstart = sb.indexOf("${"); + while (lstart != -1) + { + int lend = sb.indexOf("}", lstart + 2); + if (lend > 0) + { + String token = sb.substring(lstart, lend + 1); + replaceToken(sb, lstart, token, processToken(token, thisClass, method, field, version)); + } + lstart = sb.indexOf("${", lstart); + } + } + + protected static void writeTargetFile(StringBuffer sb, File f) + throws IOException + { + FileWriter fw = new FileWriter(f); + fw.write(sb.toString().toCharArray()); + fw.flush(); + fw.close(); + } + + protected static String getTemplateFileName(StringBuffer sb) + throws AmqpTemplateException + { + if (sb.charAt(0) != '&') + throw new AmqpTemplateException("No filename marker &{filename} found at start of template."); + int cr = sb.indexOf(Utils.lineSeparator); + if (cr < 0) + throw new AmqpTemplateException("Bad template structure - unable to find first line."); + String fileName = sb.substring(2, cr-1); + sb.delete(0, cr + 1); + return fileName; + } + + protected static void replaceToken(StringBuffer sb, String token, String replacement) + { + replaceToken(sb, 0, token, replacement); + } + + protected static void replaceToken(StringBuffer sb, int index, String token, String replacement) + { + if (replacement != null) + { + int start = sb.indexOf(token, index); + int len = token.length(); + // Find first letter in token and determine if it is capitalized + char firstTokenLetter = getFirstLetter(token); + if (firstTokenLetter != 0 && Character.isUpperCase(firstTokenLetter)) + sb.replace(start, start+len, Utils.firstUpper(replacement)); + else + sb.replace(start, start+len, replacement); + } + } + + private static char getFirstLetter(String str) + { + int len = str.length(); + int index = 0; + char tokChar = str.charAt(index); + while (!Character.isLetter(tokChar) && index<len-1) + tokChar = str.charAt(++index); + if (Character.isLetter(tokChar)) + return tokChar; + return 0; + } + + private static String loadTemplate(File f) + throws FileNotFoundException, IOException + { + StringBuffer sb = new StringBuffer(); + FileReader fr = new FileReader(f); + LineNumberReader lnr = new LineNumberReader(fr); + String line = lnr.readLine(); + while (line != null) + { + // Strip lines starting with '#' in template - treat these lines as template comments +// if (line.length() > 0 && line.charAt(0) != '#') // Bad idea - '#' used in C/C++ files (#include)! + if (line.length() > 0) + sb.append(line + Utils.lineSeparator); + else + sb.append(Utils.lineSeparator); + line = lnr.readLine(); + } + lnr.close(); + fr.close(); + return sb.toString(); + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/JavaGenerator.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/JavaGenerator.java new file mode 100644 index 0000000000..9acfaf65fa --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/JavaGenerator.java @@ -0,0 +1,1702 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.TreeMap; + +public class JavaGenerator extends Generator +{ + // TODO: Move this to parent class + protected static final int FIELD_NAME = 0; + protected static final int FIELD_CODE_TYPE = 1; + + private class DomainInfo + { + public String type; + public String size; + public String encodeExpression; + public String decodeExpression; + public DomainInfo(String domain, String size, String encodeExpression, String decodeExpression) + { + this.type = domain; + this.size = size; + this.encodeExpression = encodeExpression; + this.decodeExpression = decodeExpression; + } + } + + private static TreeMap<String, DomainInfo> typeMap = new TreeMap<String, DomainInfo>(); + + // Methods used for generation of code snippets called from the field map parsers + + // Common methods + static private Method declarationGenerateMethod; + static private Method mangledDeclarationGenerateMethod; + + // Methods for MessageBody classes + static private Method mbGetGenerateMethod; + static private Method mbMangledGetGenerateMethod; + static private Method mbParamListGenerateMethod; + static private Method mbPassedParamListGenerateMethod; + static private Method mbMangledParamListGenerateMethod; + static private Method mbMangledPassedParamListGenerateMethod; + static private Method mbBodyInitGenerateMethod; + static private Method mbMangledBodyInitGenerateMethod; + static private Method mbSizeGenerateMethod; + static private Method mbBitSizeGenerateMethod; + static private Method mbEncodeGenerateMethod; + static private Method mbBitEncodeGenerateMethod; + static private Method mbDecodeGenerateMethod; + static private Method mbBitDecodeGenerateMethod; + static private Method mbToStringGenerateMethod; + static private Method mbBitToStringGenerateMethod; + + // Methods for PropertyContentHeader classes + static private Method pchClearGenerateMethod; + static private Method pchMangledClearGenerateMethod; + static private Method pchGetGenerateMethod; + static private Method pchMangledGetGenerateMethod; + static private Method pchSetGenerateMethod; + static private Method pchMangledSetGenerateMethod; + static private Method pchSizeGenerateMethod; + static private Method pchBitSizeGenerateMethod; + static private Method pchEncodeGenerateMethod; + static private Method pchBitEncodeGenerateMethod; + static private Method pchDecodeGenerateMethod; + static private Method pchBitDecodeGenerateMethod; + static private Method pchGetPropertyFlagsGenerateMethod; + static private Method pchBitGetPropertyFlagsGenerateMethod; + static private Method pchSetPropertyFlagsGenerateMethod; + static private Method pchBitSetPropertyFlagsGenerateMethod; + + static + { + // ************** + // Common methods + // ************** + + // Methods for AmqpFieldMap.parseFieldMap() + + try { declarationGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateFieldDeclaration", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mangledDeclarationGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMangledFieldDeclaration", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + + // ******************************* + // Methods for MessageBody classes + // ******************************* + + // Methods for AmqpFieldMap.parseFieldMap() + + try { mbGetGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbGetMethod", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbMangledGetGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbMangledGetMethod", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbParamListGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbParamList", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + + try { mbPassedParamListGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbPassedParamList", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbMangledParamListGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbMangledParamList", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbMangledPassedParamListGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbMangledPassedParamList", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbBodyInitGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbBodyInit", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbMangledBodyInitGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbMangledBodyInit", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + // Methods for AmqpFieldMap.parseFieldMapOrdinally() + + try { mbSizeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbFieldSize", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbBitSizeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbBitArrayFieldSize", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbEncodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbFieldEncode", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbBitEncodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbBitFieldEncode", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbDecodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbFieldDecode", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbBitDecodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbBitFieldDecode", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbToStringGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbFieldToString", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbBitToStringGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbBitFieldToString", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + // ***************************************** + // Methods for PropertyContentHeader classes + // ***************************************** + + // Methods for AmqpFieldMap.parseFieldMap() + + try { pchClearGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchClearMethod", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchMangledClearGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchMangledClearMethod", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchSetGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchSetMethod", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchMangledSetGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchMangledSetMethod", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchGetGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchGetMethod", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchMangledGetGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchMangledGetMethod", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + // Methods for AmqpFieldMap.parseFieldMapOrdinally() + + try { pchSizeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchFieldSize", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchBitSizeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchBitArrayFieldSize", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchEncodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchFieldEncode", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchBitEncodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchBitFieldEncode", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchDecodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchFieldDecode", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchBitDecodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchBitFieldDecode", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchGetPropertyFlagsGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchGetPropertyFlags", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchBitGetPropertyFlagsGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchBitGetPropertyFlags", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchSetPropertyFlagsGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchSetPropertyFlags", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchBitSetPropertyFlagsGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchBitSetPropertyFlags", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + } + + public JavaGenerator(AmqpVersionSet versionList) + { + super(versionList); + // Load Java type and size maps. + // Adjust or add to these lists as new types are added/defined. + // The char '#' will be replaced by the field variable name (any type). + // The char '~' will be replaced by the compacted bit array size (type bit only). + typeMap.put("bit", new DomainInfo( + "boolean", // Java code type + "~", // size + "EncodingUtils.writeBooleans(buffer, #)", // encode expression + "# = EncodingUtils.readBooleans(buffer)")); // decode expression + typeMap.put("content", new DomainInfo( + "Content", // Java code type + "EncodingUtils.encodedContentLength(#)", // size + "EncodingUtils.writeContentBytes(buffer, #)", // encode expression + "# = EncodingUtils.readContent(buffer)")); // decode expression + typeMap.put("long", new DomainInfo( + "long", // Java code type + "4", // size + "EncodingUtils.writeUnsignedInteger(buffer, #)", // encode expression + "# = buffer.getUnsignedInt()")); // decode expression + typeMap.put("longlong", new DomainInfo( + "long", // Java code type + "8", // size + "buffer.putLong(#)", // encode expression + "# = buffer.getLong()")); // decode expression + typeMap.put("longstr", new DomainInfo( + "byte[]", // Java code type + "EncodingUtils.encodedLongstrLength(#)", // size + "EncodingUtils.writeLongStringBytes(buffer, #)", // encode expression + "# = EncodingUtils.readLongstr(buffer)")); // decode expression + typeMap.put("octet", new DomainInfo( + "short", // Java code type + "1", // size + "EncodingUtils.writeUnsignedByte(buffer, #)", // encode expression + "# = buffer.getUnsigned()")); // decode expression + typeMap.put("short", new DomainInfo( + "int", // Java code type + "2", // size + "EncodingUtils.writeUnsignedShort(buffer, #)", // encode expression + "# = buffer.getUnsignedShort()")); // decode expression + typeMap.put("shortstr", new DomainInfo( + "AMQShortString", // Java code type + "EncodingUtils.encodedShortStringLength(#)", // size + "EncodingUtils.writeShortStringBytes(buffer, #)", // encode expression + "# = EncodingUtils.readAMQShortString(buffer)")); // decode expression + typeMap.put("table", new DomainInfo( + "FieldTable", // Java code type + "EncodingUtils.encodedFieldTableLength(#)", // size + "EncodingUtils.writeFieldTableBytes(buffer, #)", // encode expression + "# = EncodingUtils.readFieldTable(buffer)")); // decode expression + typeMap.put("timestamp", new DomainInfo( + "long", // Java code type + "8", // size + "EncodingUtils.writeTimestamp(buffer, #)", // encode expression + "# = EncodingUtils.readTimestamp(buffer)")); // decode expression + } + + // === Start of methods for Interface LanguageConverter === + + public String prepareClassName(String className) + { + return camelCaseName(className, true); + } + + public String prepareMethodName(String methodName) + { + return camelCaseName(methodName, false); + } + + public String prepareDomainName(String domainName) + { + return camelCaseName(domainName, false); + } + + public String getDomainType(String domainName, AmqpVersion version) + throws AmqpTypeMappingException + { + return globalDomainMap.getDomainType(domainName, version); + } + + public String getGeneratedType(String domainName, AmqpVersion version) + throws AmqpTypeMappingException + { + String domainType = globalDomainMap.getDomainType(domainName, version); + if (domainType == null) + { + throw new AmqpTypeMappingException("Domain type \"" + domainName + + "\" not found in Java typemap."); + } + DomainInfo info = typeMap.get(domainType); + if (info == null) + { + throw new AmqpTypeMappingException("Unknown domain: \"" + domainType + "\""); + } + return info.type; + } + + + // === Abstract methods from class Generator - Java-specific implementations === + + @Override + protected String prepareFilename(String filenameTemplate, AmqpClass thisClass, AmqpMethod method, + AmqpField field) + { + StringBuffer sb = new StringBuffer(filenameTemplate); + if (thisClass != null) + replaceToken(sb, "${CLASS}", thisClass.name); + if (method != null) + replaceToken(sb, "${METHOD}", method.name); + if (field != null) + replaceToken(sb, "${FIELD}", field.name); + return sb.toString(); + } + + @Override + protected void processTemplateA(String[] template) + throws IOException, AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException + { + processTemplateD(template, null, null, null); + } + + @Override + protected void processTemplateB(String[] template, AmqpClass thisClass) + throws IOException, AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException + { + processTemplateD(template, thisClass, null, null); + } + + @Override + protected void processTemplateC(String[] template, AmqpClass thisClass, + AmqpMethod method) + throws IOException, AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException + { + processTemplateD(template, thisClass, method, null); + } + + @Override + protected void processTemplateD(String[] template, AmqpClass thisClass, + AmqpMethod method, AmqpField field) + throws IOException, AmqpTemplateException, AmqpTypeMappingException, + IllegalAccessException, InvocationTargetException + { + StringBuffer sb = new StringBuffer(template[1]); + String filename = prepareFilename(getTemplateFileName(sb), thisClass, method, field); + processTemplate(sb, thisClass, method, field, template[templateFileNameIndex], null); + writeTargetFile(sb, new File(genDir + Utils.fileSeparator + filename)); + generatedFileCounter ++; + } + + protected void processTemplate(StringBuffer sb, AmqpClass thisClass, AmqpMethod method, + AmqpField field, String templateFileName, AmqpVersion version) + throws InvocationTargetException, IllegalAccessException, AmqpTypeMappingException + { + try { processAllLists(sb, thisClass, method, version); } + catch (AmqpTemplateException e) + { + System.out.println("WARNING: " + templateFileName + ": " + e.getMessage()); + } + try { processAllTokens(sb, thisClass, method, field, version); } + catch (AmqpTemplateException e) + { + System.out.println("WARNING: " + templateFileName + ": " + e.getMessage()); + } + } + + @Override + protected String processToken(String token, AmqpClass thisClass, AmqpMethod method, AmqpField field, + AmqpVersion version) + throws AmqpTemplateException, AmqpTypeMappingException + { + if (token.compareTo("${GENERATOR}") == 0) + return generatorInfo; + if (token.compareTo("${CLASS}") == 0 && thisClass != null) + return thisClass.name; + if (token.compareTo("${CLASS_ID_INIT}") == 0 && thisClass != null) + return generateIndexInitializer("registerClassId", thisClass.indexMap, 8); + if (token.compareTo("${METHOD}") == 0 && method != null) + return method.name; + if (token.compareTo("${METHOD_ID_INIT}") == 0 && method != null) + return generateIndexInitializer("registerMethodId", method.indexMap, 8); + if (token.compareTo("${FIELD}") == 0 && field != null) + return field.name; + + // This token is used only with class or method-level templates + if (token.compareTo("${pch_property_flags_declare}") == 0) + { + return generatePchPropertyFlagsDeclare(); + } + else if (token.compareTo("${pch_property_flags_initializer}") == 0) + { + int mapSize = method == null ? thisClass.fieldMap.size() : method.fieldMap.size(); + return generatePchPropertyFlagsInitializer(mapSize); + } + else if (token.compareTo("${pch_compact_property_flags_initializer}") == 0) + { + return generatePchCompactPropertyFlagsInitializer(thisClass, 8, 4); + } + else if (token.compareTo("${pch_compact_property_flags_check}") == 0) + { + return generatePchCompactPropertyFlagsCheck(thisClass, 8, 4); + } + + // Oops! + throw new AmqpTemplateException("Template token " + token + " unknown."); + } + + @Override + protected void processClassList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpModel model) + throws AmqpTemplateException, AmqpTypeMappingException + { + String codeSnippet; + int lend = sb.indexOf(cr, listMarkerStartIndex) + 1; // Include cr at end of line + String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr + int tokStart = tline.indexOf('$'); + String token = tline.substring(tokStart).trim(); + sb.delete(listMarkerStartIndex, lend); + + if (token.compareTo("${reg_map_put_method}") == 0) + { + codeSnippet = generateRegistry(model, 8, 4); + } + + else // Oops! + { + throw new AmqpTemplateException("Template token " + token + " unknown."); + } + + sb.insert(listMarkerStartIndex, codeSnippet); + } + + @Override + protected void processMethodList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpClass thisClass) + throws AmqpTemplateException, AmqpTypeMappingException + { + String codeSnippet; + int lend = sb.indexOf(cr, listMarkerStartIndex) + 1; // Include cr at end of line + String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr + int tokStart = tline.indexOf('$'); + String token = tline.substring(tokStart).trim(); + sb.delete(listMarkerStartIndex, lend); + + //TODO - we don't have any cases of this (yet). + if (token.compareTo("${???}") == 0) + { + codeSnippet = token; + } + else // Oops! + { + throw new AmqpTemplateException("Template token " + token + " unknown."); + } + + sb.insert(listMarkerStartIndex, codeSnippet); + } + + @Override + protected void processFieldList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpFieldMap fieldMap, AmqpVersion version) + throws AmqpTypeMappingException, AmqpTemplateException, IllegalAccessException, + InvocationTargetException + { + String codeSnippet; + int lend = sb.indexOf(cr, listMarkerStartIndex) + 1; // Include cr at end of line + String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr + int tokStart = tline.indexOf('$'); + String token = tline.substring(tokStart).trim(); + sb.delete(listMarkerStartIndex, lend); + + // Field declarations - common to MethodBody and PropertyContentHeader classes + if (token.compareTo("${field_declaration}") == 0) + { + codeSnippet = fieldMap.parseFieldMap(declarationGenerateMethod, + mangledDeclarationGenerateMethod, 4, 4, this); + } + + // MethodBody classes + else if (token.compareTo("${mb_field_get_method}") == 0) + { + codeSnippet = fieldMap.parseFieldMap(mbGetGenerateMethod, + mbMangledGetGenerateMethod, 4, 4, this); + } + else if (token.compareTo("${mb_field_parameter_list}") == 0) + { + // <cringe> The code generated by this is ugly... It puts a comma on a line by itself! + // TODO: Find a more elegant solution here sometime... + codeSnippet = fieldMap.size() > 0 ? Utils.createSpaces(42) + "," + cr : ""; + // </cringe> + codeSnippet += fieldMap.parseFieldMap(mbParamListGenerateMethod, + mbMangledParamListGenerateMethod, 42, 4, this); + } + + else if (token.compareTo("${mb_field_passed_parameter_list}") == 0) + { + // <cringe> The code generated by this is ugly... It puts a comma on a line by itself! + // TODO: Find a more elegant solution here sometime... + codeSnippet = fieldMap.size() > 0 ? Utils.createSpaces(42) + "," + cr : ""; + // </cringe> + codeSnippet += fieldMap.parseFieldMap(mbPassedParamListGenerateMethod, + mbMangledPassedParamListGenerateMethod, 42, 4, this); + } + else if (token.compareTo("${mb_field_body_initialize}") == 0) + { + codeSnippet = fieldMap.parseFieldMap(mbBodyInitGenerateMethod, + mbMangledBodyInitGenerateMethod, 8, 4, this); + } + else if (token.compareTo("${mb_field_size}") == 0) + { + codeSnippet = fieldMap.parseFieldMapOrdinally(mbSizeGenerateMethod, + mbBitSizeGenerateMethod, 8, 4, this); + } + else if (token.compareTo("${mb_field_encode}") == 0) + { + codeSnippet = fieldMap.parseFieldMapOrdinally(mbEncodeGenerateMethod, + mbBitEncodeGenerateMethod, 8, 4, this); + } + else if (token.compareTo("${mb_field_decode}") == 0) + { + codeSnippet = fieldMap.parseFieldMapOrdinally(mbDecodeGenerateMethod, + mbBitDecodeGenerateMethod, 8, 4, this); + } + else if (token.compareTo("${mb_field_to_string}") == 0) + { + codeSnippet = fieldMap.parseFieldMapOrdinally(mbToStringGenerateMethod, + mbBitToStringGenerateMethod, 8, 4, this); + } + + // PropertyContentHeader classes + else if (token.compareTo("${pch_field_list_size}") == 0) + { + codeSnippet = fieldMap.parseFieldMapOrdinally(pchSizeGenerateMethod, + pchBitSizeGenerateMethod, 12, 4, this); + } + else if (token.compareTo("${pch_field_list_payload}") == 0 ) + { + codeSnippet = fieldMap.parseFieldMapOrdinally(pchEncodeGenerateMethod, + pchBitEncodeGenerateMethod, 12, 4, this); + } + else if (token.compareTo("${pch_field_list_decode}") == 0) + { + codeSnippet = fieldMap.parseFieldMapOrdinally(pchDecodeGenerateMethod, + pchBitDecodeGenerateMethod, 12, 4, this); + } + else if (token.compareTo("${pch_get_compact_property_flags}") == 0) + { + codeSnippet = fieldMap.parseFieldMapOrdinally(pchGetPropertyFlagsGenerateMethod, + pchBitGetPropertyFlagsGenerateMethod, 8, 4, this); + } + else if (token.compareTo("${pch_set_compact_property_flags}") == 0) + { + codeSnippet = fieldMap.parseFieldMapOrdinally(pchSetPropertyFlagsGenerateMethod, + pchBitSetPropertyFlagsGenerateMethod, 8, 4, this); + } + else if (token.compareTo("${pch_field_clear_methods}") == 0) + { + codeSnippet = fieldMap.parseFieldMap(pchClearGenerateMethod, + pchMangledClearGenerateMethod, 4, 4, this); + } + else if (token.compareTo("${pch_field_get_methods}") == 0) + { + codeSnippet = fieldMap.parseFieldMap(pchGetGenerateMethod, + pchMangledGetGenerateMethod, 4, 4, this); + } + else if (token.compareTo("${pch_field_set_methods}") == 0) + { + codeSnippet = fieldMap.parseFieldMap(pchSetGenerateMethod, + pchMangledSetGenerateMethod, 4, 4, this); + } + + else // Oops! + { + throw new AmqpTemplateException("Template token " + token + " unknown."); + } + sb.insert(listMarkerStartIndex, codeSnippet); + } + + @Override + protected void processConstantList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpConstantSet constantSet) + throws AmqpTemplateException, AmqpTypeMappingException + + { + String codeSnippet; + int lend = sb.indexOf(cr, listMarkerStartIndex) + 1; // Include cr at end of line + String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr + int tokStart = tline.indexOf('$'); + String token = tline.substring(tokStart).trim(); + sb.delete(listMarkerStartIndex, lend); + + if (token.compareTo("${const_get_method}") == 0) + { + codeSnippet = generateConstantGetMethods(constantSet, 4, 4); + } + + else // Oops! + { + throw new AmqpTemplateException("Template token " + token + " unknown."); + } + + sb.insert(listMarkerStartIndex, codeSnippet); + } + + + // === Protected and private helper functions unique to Java implementation === + + // Methods used for generation of code snippets called from the field map parsers + + // Common methods + + protected String generateFieldDeclaration(String codeType, AmqpField field, + AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag) + { + return Utils.createSpaces(indentSize) + "public " + codeType + " " + field.name + + "; // AMQP version(s): " + versionSet + cr; + } + + protected String generateMangledFieldDeclaration(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + StringBuffer sb = new StringBuffer(); + Iterator<String> dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + String domainName = dItr.next(); + AmqpVersionSet versionSet = field.domainMap.get(domainName); + String codeType = getGeneratedType(domainName, versionSet.first()); + sb.append(Utils.createSpaces(indentSize) + "public " + codeType + " " + + field.name + "_" + (domainCntr++) + "; // AMQP Version(s): " + versionSet + + cr); + } + return sb.toString(); + } + + protected String generateIndexInitializer(String mapName, AmqpOrdinalVersionMap indexMap, int indentSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + + for (Integer index : indexMap.keySet()) + { + AmqpVersionSet versionSet = indexMap.get(index); + for (AmqpVersion version : versionSet) + { + sb.append(indent + mapName + "( (byte) " + version.getMajor() +", (byte) " + version.getMinor() + ", " + index + ");" + cr); + } + } + return sb.toString(); + } + + protected String generateRegistry(AmqpModel model, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + + for (String className : model.classMap.keySet()) + { + AmqpClass thisClass = model.classMap.get(className); + for (String methodName : thisClass.methodMap.keySet()) + { + AmqpMethod method = thisClass.methodMap.get(methodName); + for (AmqpVersion version : globalVersionSet) + { + // Find class and method index for this version (if it exists) + try + { + int classIndex = findIndex(thisClass.indexMap, version); + int methodIndex = findIndex(method.indexMap, version); + sb.append(indent + "registerMethod(" + cr); + sb.append(indent + tab + "(short)" + classIndex + + ", (short)" + methodIndex + ", (byte)" + version.getMajor() + + ", (byte)" + version.getMinor() + ", " + cr); + sb.append(indent + tab + Utils.firstUpper(thisClass.name) + + Utils.firstUpper(method.name) + "Body.getFactory());" + cr); + } + catch (Exception e) {} // Ignore + } + } + } + return sb.toString(); + } + + protected int findIndex(TreeMap<Integer, AmqpVersionSet> map, AmqpVersion version) + throws Exception + { + Iterator<Integer> iItr = map.keySet().iterator(); + while (iItr.hasNext()) + { + int index = iItr.next(); + AmqpVersionSet versionSet = map.get(index); + if (versionSet.contains(version)) + return index; + } + throw new Exception("Index not found"); + } + + // Methods for AmqpConstants class + + protected String generateConstantGetMethods(AmqpConstantSet constantSet, + int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + Iterator<AmqpConstant> cItr = constantSet.iterator(); + while (cItr.hasNext()) + { + AmqpConstant constant = cItr.next(); + if (constant.isVersionConsistent(globalVersionSet)) + { + // return a constant + String value = constant.firstKey(); + sb.append(indent + "public static String " + constant.name + "() { return \"" + + constant.firstKey() + "\"; }" + cr); + if (Utils.containsOnlyDigits(value)) + { + sb.append(indent + "public static int " + constant.name + "AsInt() { return " + + constant.firstKey() + "; }" + cr); + } + if (Utils.containsOnlyDigitsAndDecimal(value)) + { + sb.append(indent + "public static double " + constant.name + "AsDouble() { return (double)" + + constant.firstKey() + "; }" + cr); + } + sb.append(cr); + } + else + { + // Return version-specific constant + sb.append(generateVersionDependentGet(constant, "String", "", "\"", "\"", indentSize, tabSize)); + sb.append(generateVersionDependentGet(constant, "int", "AsInt", "", "", indentSize, tabSize)); + sb.append(generateVersionDependentGet(constant, "double", "AsDouble", "(double)", "", indentSize, tabSize)); + sb.append(cr); + } + } + return sb.toString(); + } + + protected String generateVersionDependentGet(AmqpConstant constant, + String methodReturnType, String methodNameSuffix, String returnPrefix, String returnPostfix, + int indentSize, int tabSize) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + sb.append(indent + "public static " + methodReturnType + " " + constant.name + + methodNameSuffix + "(byte major, byte minor) throws AMQProtocolVersionException" + cr); + sb.append(indent + "{" + cr); + boolean first = true; + Iterator<String> sItr = constant.keySet().iterator(); + while (sItr.hasNext()) + { + String value = sItr.next(); + AmqpVersionSet versionSet = constant.get(value); + sb.append(indent + tab + (first ? "" : "else ") + "if (" + generateVersionCheck(versionSet) + + ")" + cr); + sb.append(indent + tab + "{" + cr); + if (methodReturnType.compareTo("int") == 0 && !Utils.containsOnlyDigits(value)) + { + sb.append(generateConstantDeclarationException(constant.name, methodReturnType, + indentSize + (2*tabSize), tabSize)); + } + else if (methodReturnType.compareTo("double") == 0 && !Utils.containsOnlyDigitsAndDecimal(value)) + { + sb.append(generateConstantDeclarationException(constant.name, methodReturnType, + indentSize + (2*tabSize), tabSize)); + } + else + { + sb.append(indent + tab + tab + "return " + returnPrefix + value + returnPostfix + ";" + cr); + } + sb.append(indent + tab + "}" + cr); + first = false; + } + sb.append(indent + tab + "else" + cr); + sb.append(indent + tab + "{" + cr); + sb.append(indent + tab + tab + "throw new AMQProtocolVersionException(\"Constant \\\"" + + constant.name + "\\\" \" +" + cr); + sb.append(indent + tab + tab + tab + + "\"is undefined for AMQP version \" + major + \"-\" + minor + \".\");" + cr); + sb.append(indent + tab + "}" + cr); + sb.append(indent + "}" + cr); + return sb.toString(); + } + + protected String generateConstantDeclarationException(String name, String methodReturnType, + int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + sb.append(indent + "throw new AMQProtocolVersionException(\"Constant \\\"" + + name + "\\\" \" +" + cr); + sb.append(indent + tab + "\"cannot be converted to type " + methodReturnType + + " for AMQP version \" + major + \"-\" + minor + \".\");" + cr); + return sb.toString(); + } + + // Methods for MessageBody classes + protected String generateMbGetMethod(String codeType, AmqpField field, + AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag) + { + return Utils.createSpaces(indentSize) + "public " + codeType + " get" + + Utils.firstUpper(field.name) + "() { return " + field.name + "; }" + + cr; + } + + protected String generateMbMangledGetMethod(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(cr); + sb.append(indent + "public <T> T get" + Utils.firstUpper(field.name) + + "(Class<T> classObj) throws AMQProtocolVersionException" + cr); + sb.append(indent + "{" + cr); + Iterator<String> dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + String domainName = dItr.next(); + AmqpVersionSet versionSet = field.domainMap.get(domainName); + String codeType = getGeneratedType(domainName, versionSet.first()); + sb.append(indent + tab + "if (classObj.equals(" + codeType + + ".class)) // AMQP Version(s): " + versionSet + cr); + sb.append(indent + tab + tab + "return (T)(Object)" + field.name + "_" + + (domainCntr++) + ";" + cr); + } + sb.append(indent + tab + + "throw new AMQProtocolVersionException(\"None of the AMQP versions defines \" +" + + cr + " \"field \\\"" + field.name + + "\\\" as domain \\\"\" + classObj.getName() + \"\\\".\");" + cr); + sb.append(indent + "}" + cr); + sb.append(cr); + return sb.toString(); + } + + protected String generateMbParamList(String codeType, AmqpField field, + AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag) + { + return Utils.createSpaces(indentSize) + codeType + " " + field.name + + (nextFlag ? "," : "") + " // AMQP version(s): " + versionSet + cr; + } + + + protected String generateMbPassedParamList(String codeType, AmqpField field, + AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag) + { + return Utils.createSpaces(indentSize) + field.name + + (nextFlag ? "," : "") + " // AMQP version(s): " + versionSet + cr; + } + + + protected String generateMbMangledParamList(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + StringBuffer sb = new StringBuffer(); + Iterator<String> dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + String domainName = dItr.next(); + AmqpVersionSet versionSet = field.domainMap.get(domainName); + String codeType = getGeneratedType(domainName, versionSet.first()); + sb.append(Utils.createSpaces(indentSize) + codeType + " " + field.name + "_" + + (domainCntr++) + (nextFlag ? "," : "") + " // AMQP version(s): " + + versionSet + cr); + } + return sb.toString(); + } + + protected String generateMbMangledPassedParamList(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + StringBuffer sb = new StringBuffer(); + Iterator<String> dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + String domainName = dItr.next(); + AmqpVersionSet versionSet = field.domainMap.get(domainName); + sb.append(Utils.createSpaces(indentSize) + field.name + "_" + + (domainCntr++) + (nextFlag ? "," : "") + " // AMQP version(s): " + + versionSet + cr); + } + return sb.toString(); + } + + + protected String generateMbBodyInit(String codeType, AmqpField field, + AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag) + { + return Utils.createSpaces(indentSize) + "this." + field.name + " = " + field.name + + ";" + cr; + } + + protected String generateMbMangledBodyInit(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + StringBuffer sb = new StringBuffer(); + Iterator<String> dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + dItr.next(); + sb.append(Utils.createSpaces(indentSize) + "bodyFrame." + field.name + "_" + domainCntr + + " = " + field.name + "_" + (domainCntr++) + ";" + cr); + } + return sb.toString(); + } + + protected String generateMbFieldSize(String domainType, String fieldName, + int ordinal, int indentSize, int tabSize) + { + StringBuffer sb = new StringBuffer(); + sb.append(Utils.createSpaces(indentSize) + "size += " + + typeMap.get(domainType).size.replaceAll("#", fieldName) + + "; // " + fieldName + ": " + domainType + cr); + return sb.toString(); + } + + protected String generateMbBitArrayFieldSize(ArrayList<String> bitFieldList, + int ordinal, int indentSize, int tabSize) + { + StringBuffer sb = new StringBuffer(); + int numBytes = ((bitFieldList.size() - 1) / 8) + 1; + String comment = bitFieldList.size() == 1 ? + bitFieldList.get(0) + ": bit" : + "Combinded bits: " + bitFieldList; + sb.append(Utils.createSpaces(indentSize) + "size += " + + typeMap.get("bit").size.replaceAll("~", String.valueOf(numBytes)) + + "; // " + comment + cr); + return sb.toString(); + } + + protected String generateMbFieldEncode(String domain, String fieldName, + int ordinal, int indentSize, int tabSize) + { + StringBuffer sb = new StringBuffer(); + sb.append(Utils.createSpaces(indentSize) + + typeMap.get(domain).encodeExpression.replaceAll("#", fieldName) + + "; // " + fieldName + ": " + domain + cr); + return sb.toString(); + } + + protected String generateMbBitFieldEncode(ArrayList<String> bitFieldList, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + + StringBuilder sb = new StringBuilder(); + int i = 0; + while(i <bitFieldList.size()) + { + + StringBuilder line = new StringBuilder(); + + for (int j=0; i<bitFieldList.size() && j<8; i++, j++) + { + if (j != 0) + { + line.append(", "); + } + line.append(bitFieldList.get(i)); + } + + sb.append(indent + + typeMap.get("bit").encodeExpression.replaceAll("#", line.toString()) + ";" + cr); + } + return sb.toString(); + } + + protected String generateMbFieldDecode(String domain, String fieldName, + int ordinal, int indentSize, int tabSize) + { + StringBuffer sb = new StringBuffer(); + sb.append(Utils.createSpaces(indentSize) + + typeMap.get(domain).decodeExpression.replaceAll("#", fieldName) + + "; // " + fieldName + ": " + domain + cr); + return sb.toString(); + } + + protected String generateMbBitFieldDecode(ArrayList<String> bitFieldList, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + + StringBuilder sb = new StringBuilder(indent); + // Multiple occurrences of byte value blocks will result in multiple declarations + // unless each is named uniquely. + String varName = "packedValue_" + ordinal; + sb.append("byte " + varName + ";"); + sb.append(cr); + + // RG HERE! + + int i = 0; + while(i < bitFieldList.size()) + { + sb.append(indent + varName + " = EncodingUtils.readByte(buffer);" + cr); + + for(int j = 0; i < bitFieldList.size() && j < 8; i++, j++) + { + sb.append(indent + bitFieldList.get(i) + " = ( " + varName + " & (byte) (1 << " + j + ") ) != 0;" + cr); + } + } + return sb.toString(); + } + + protected String generateMbFieldToString(String domain, String fieldName, + int ordinal, int indentSize, int tabSize) + { + StringBuffer sb = new StringBuffer(); + if (domain.compareTo("longstr") == 0) + { + sb.append(Utils.createSpaces(indentSize) + + "buf.append(\" " + fieldName + ": \" + (" + fieldName + + " == null ? \"<null>\" : new String(" + fieldName + ")));" + cr); + } + else + { + sb.append(Utils.createSpaces(indentSize) + + "buf.append(\" " + fieldName + ": \" + " + fieldName + ");" + cr); + } + return sb.toString(); + } + + protected String generateMbBitFieldToString(ArrayList<String> bitFieldList, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + for (int i=0; i<bitFieldList.size(); i++) + { + String bitFieldName = bitFieldList.get(i); + sb.append(indent + "buf.append(\" " + bitFieldName + ": \" + " + bitFieldName + + ");" + cr); + } + return sb.toString(); + } + + // Methods for PropertyContentHeader classes + + protected String generatePchClearMethod(String codeType, AmqpField field, + AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + // This is one case where the ordinal info is the only significant factor, + // the domain info plays no part. Defer to the mangled version; the code would be + // identical anyway... + return generatePchMangledClearMethod(field, indentSize, tabSize, nextFlag); + } + + protected String generatePchMangledClearMethod(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + sb.append(indent + "public void clear" + Utils.firstUpper(field.name) + + "()" + cr); + sb.append(indent + "{" + cr); + + // If there is more than one ordinal for this field or the ordinal does not + // apply to all known versions, then we need to generate version checks so + // we know which fieldProperty to clear. + if (field.ordinalMap.size() == 1 && + field.ordinalMap.get(field.ordinalMap.firstKey()).size() == globalVersionSet.size()) + { + int ordinal = field.ordinalMap.firstKey(); + sb.append(indent + tab + "clearEncodedForm();" + cr); + sb.append(indent + tab + "propertyFlags[" + ordinal + "] = false;" + cr); + } + else + { + Iterator<Integer> oItr = field.ordinalMap.keySet().iterator(); + while (oItr.hasNext()) + { + int ordinal = oItr.next(); + AmqpVersionSet versionSet = field.ordinalMap.get(ordinal); + sb.append(indent + tab); + if (ordinal != field.ordinalMap.firstKey()) + sb.append("else "); + sb.append("if ("); + sb.append(generateVersionCheck(versionSet)); + sb.append(")" + cr); + sb.append(indent + tab + "{" + cr); + sb.append(indent + tab + tab + "clearEncodedForm();" + cr); + sb.append(indent + tab + tab + "propertyFlags[" + ordinal + "] = false;" + cr); + sb.append(indent + tab + "}" + cr); + } + } + sb.append(indent + "}" + cr); + sb.append(cr); + return sb.toString(); + } + + protected String generatePchGetMethod(String codeType, AmqpField field, + AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(indent + "public " + codeType + " get" + + Utils.firstUpper(field.name) + "()" + cr); + sb.append(indent + "{" + cr); + sb.append(indent + tab + "decodeIfNecessary();" + cr); + sb.append(indent + tab + "return " + field.name + ";" + cr); + sb.append(indent + "}" + cr); + sb.append(cr); + return sb.toString(); + } + + protected String generatePchMangledGetMethod(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(indent + "public <T> T get" + + Utils.firstUpper(field.name) + + "(Class<T> classObj) throws AMQProtocolVersionException" + cr); + sb.append(indent + "{" + cr); + Iterator<String> dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + String domainName = dItr.next(); + AmqpVersionSet versionSet = field.domainMap.get(domainName); + String codeType = getGeneratedType(domainName, versionSet.first()); + sb.append(indent + tab + "if (classObj.equals(" + codeType + + ".class)) // AMQP Version(s): " + versionSet + cr); + sb.append(indent + tab + "{" + cr); + sb.append(indent + tab + tab + "decodeIfNecessary();" + cr); + sb.append(indent + tab + tab + "return (T)(Object)" + field.name + "_" + + (domainCntr++) + ";" + cr); + sb.append(indent + tab + "}" + cr); + } + sb.append(indent + tab + + "throw new AMQProtocolVersionException(\"None of the AMQP versions defines \" +" + + cr + " \"field \\\"" + field.name + + "\\\" as domain \\\"\" + classObj.getName() + \"\\\".\");" + cr); + sb.append(indent + "}" + cr); + sb.append(cr); + return sb.toString(); + } + + protected String generatePchSetMethod(String codeType, AmqpField field, + AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + sb.append(indent + "public void set" + Utils.firstUpper(field.name) + + "(" + codeType + " " + field.name + ")" + cr); + sb.append(indent + "{" + cr); + + // If there is more than one ordinal for this field or the ordinal does not + // apply to all known versions, then we need to generate version checks so + // we know which fieldProperty to clear. + if (field.ordinalMap.size() == 1 && + field.ordinalMap.get(field.ordinalMap.firstKey()).size() == globalVersionSet.size()) + { + int ordinal = field.ordinalMap.firstKey(); + sb.append(indent + tab + "clearEncodedForm();" + cr); + sb.append(indent + tab + "propertyFlags[" + ordinal + "] = true;" + cr); + sb.append(indent + tab + "this." + field.name + " = " + field.name + ";" + cr); + } + else + { + Iterator<Integer> oItr = field.ordinalMap.keySet().iterator(); + while (oItr.hasNext()) + { + int ordinal = oItr.next(); + AmqpVersionSet oVersionSet = field.ordinalMap.get(ordinal); + sb.append(indent + tab); + if (ordinal != field.ordinalMap.firstKey()) + sb.append("else "); + sb.append("if ("); + sb.append(generateVersionCheck(oVersionSet)); + sb.append(")" + cr); + sb.append(indent + tab + "{" + cr); + sb.append(indent + tab + tab + "clearEncodedForm();" + cr); + sb.append(indent + tab + tab + "propertyFlags[" + ordinal + "] = true;" + cr); + sb.append(indent + tab + tab + "this." + field.name + " = " + field.name + ";" + cr); + sb.append(indent + tab + "}" + cr); + } + } + sb.append(indent + "}" + cr); + sb.append(cr); + return sb.toString(); + } + + protected String generatePchMangledSetMethod(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + + Iterator<String> dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + String domainName = dItr.next(); + AmqpVersionSet versionSet = field.domainMap.get(domainName); + String codeType = getGeneratedType(domainName, versionSet.first()); + + // Find ordinal with matching version + AmqpVersionSet commonVersionSet = new AmqpVersionSet(); + Iterator<Integer> oItr = field.ordinalMap.keySet().iterator(); + while (oItr.hasNext()) + { + int ordinal = oItr.next(); + AmqpVersionSet oVersionSet = field.ordinalMap.get(ordinal); + Iterator<AmqpVersion> vItr = oVersionSet.iterator(); + boolean first = true; + while (vItr.hasNext()) + { + AmqpVersion thisVersion = vItr.next(); + if (versionSet.contains(thisVersion)) + commonVersionSet.add(thisVersion); + } + if (!commonVersionSet.isEmpty()) + { + sb.append(indent + "public void set" + Utils.firstUpper(field.name) + + "(" + codeType + " " + field.name + ")" + cr); + sb.append(indent + "{" + cr); + sb.append(indent + tab); + if (!first) + sb.append("else "); + sb.append("if ("); + sb.append(generateVersionCheck(commonVersionSet)); + sb.append(")" + cr); + sb.append(indent + tab + "{" + cr); + sb.append(indent + tab + tab + "clearEncodedForm();" + cr); + sb.append(indent + tab + tab + "propertyFlags[" + ordinal + "] = true;" + cr); + sb.append(indent + tab + tab + "this." + field.name + "_" + (domainCntr++) + + " = " + field.name + ";" + cr); + sb.append(indent + tab + "}" + cr); + sb.append(indent + "}" + cr); + sb.append(cr); + first = false; + } + } + } + return sb.toString(); + } + + protected String generatePchFieldSize(String domainType, String fieldName, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(indent + "if (propertyFlags[" + ordinal + "]) // " + + fieldName + ": " + domainType + cr); + sb.append(indent + Utils.createSpaces(tabSize) + "size += " + + typeMap.get(domainType).size.replaceAll("#", fieldName) + ";" + cr); + sb.append(cr); + return sb.toString(); + } + + protected String generatePchBitArrayFieldSize(ArrayList<String> bitFieldList, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + String comment = bitFieldList.size() == 1 ? + bitFieldList.get(0) + ": bit" : + "Combinded bits: " + bitFieldList; + StringBuffer sb = new StringBuffer(); + + if (bitFieldList.size() == 1) // single bit + { + sb.append(indent + "if (propertyFlags[" + (ordinal - 1) + "]) // " + comment + cr); + sb.append(indent + tab + "size += " + + typeMap.get("bit").size.replaceAll("~", "1") + ";" + cr); + } + else // multiple bits - up to 8 are combined into one byte + { + String bitCntrName = "bitCntr_" + ordinal; + int startOrdinal = ordinal - bitFieldList.size(); + sb.append(indent + "// " + comment + cr); + sb.append(indent + "int " + bitCntrName + " = 0;" + cr); + sb.append(indent + "for (int i=" + startOrdinal + "; i<" + ordinal + "; i++)" + cr); + sb.append(indent + "{" + cr); + sb.append(indent + tab + "if (propertyFlags[i])" + cr); + sb.append(indent + tab + tab + bitCntrName + "++;" + cr); + sb.append(indent + "}" + cr); + sb.append(indent + "size += " + + typeMap.get("bit").size.replaceAll("~", bitCntrName + + " > 0 ? ((" + bitCntrName + " - 1) / 8) + 1 : 0") + ";" + cr); + } + sb.append(cr); + return sb.toString(); + } + + protected String generatePchFieldEncode(String domainType, String fieldName, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + sb.append(indent + "if (propertyFlags[" + ordinal + "]) // " + fieldName + ": " + + domainType + cr); + sb.append(indent + Utils.createSpaces(tabSize) + + typeMap.get(domainType).encodeExpression.replaceAll("#", fieldName) + ";" + cr); + sb.append(cr); + return sb.toString(); + } + + protected String generatePchBitFieldEncode(ArrayList<String> bitFieldList, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + String comment = bitFieldList.size() == 1 ? + bitFieldList.get(0) + ": bit" : + "Combinded bits: " + bitFieldList; + StringBuffer sb = new StringBuffer(); + + if (bitFieldList.size() == 1) // single bit + { + sb.append(indent + "if (propertyFlags[" + (ordinal - 1) + "]) // " + + bitFieldList.get(0) + ": bit" + cr); + sb.append(indent + tab + typeMap.get("bit").encodeExpression.replaceAll("#", + "new boolean[] {" + bitFieldList.get(0) + "}") + ";" + cr); + } + else // multiple bits - up to 8 are combined into one byte + { + int startOrdinal = ordinal - bitFieldList.size(); + String bitCntrName = "bitCntr" + startOrdinal; + sb.append(indent + "// " + comment + cr); + sb.append(indent + "int " + bitCntrName + " = 0;" + cr); + sb.append(indent + "for (int i=" + startOrdinal + "; i<=" + (ordinal - 1) + "; i++)" + cr); + sb.append(indent + "{" + cr); + sb.append(indent + tab + "if (propertyFlags[i])" + cr); + sb.append(indent + tab + tab + bitCntrName + "++;" + cr); + sb.append(indent + "}" + cr); + sb.append(indent + "if (" + bitCntrName + " > 0) // Are any of the property bits set?" + cr); + sb.append(indent + "{" + cr); + sb.append(indent + tab + "boolean[] fullBitArray = new boolean[] { "); + for (int i=0; i<bitFieldList.size(); i++) + { + if (i != 0) + sb.append(", "); + sb.append(bitFieldList.get(i)); + } + sb.append(" };" + cr); + sb.append(indent + tab + "boolean[] flaggedBitArray = new boolean[" +bitCntrName + + "];" + cr); + sb.append(indent + tab + bitCntrName + " = 0;" + cr); + sb.append(indent + tab + "for (int i=" + startOrdinal + "; i<=" + (ordinal - 1) + + "; i++)" + cr); + sb.append(indent + tab + "{" + cr); + sb.append(indent + tab + tab+ "if (propertyFlags[i])" + cr); + sb.append(indent + tab + tab + tab + "flaggedBitArray[" + bitCntrName + + "++] = fullBitArray[i];" + cr); + sb.append(indent + tab + "}" + cr); + sb.append(indent + tab + typeMap.get("bit").encodeExpression.replaceAll("#", + "flaggedBitArray") + ";" + cr); + sb.append(indent + "}" + cr); + } + sb.append(cr); + return sb.toString(); + } + + protected String generatePchFieldDecode(String domainType, String fieldName, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + sb.append(indent + "if (propertyFlags[" + ordinal + "]) // " + fieldName + ": " + + domainType + cr); + sb.append(indent + Utils.createSpaces(tabSize) + + typeMap.get(domainType).decodeExpression.replaceAll("#", fieldName) + ";" + cr); + sb.append(cr); + return sb.toString(); + } + + protected String generatePchBitFieldDecode(ArrayList<String> bitFieldList, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + String comment = bitFieldList.size() == 1 ? + bitFieldList.get(0) + ": bit" : + "Combinded bits: " + bitFieldList; + StringBuffer sb = new StringBuffer(); + + if (bitFieldList.size() == 1) // single bit + { + sb.append(indent + "if (propertyFlags[" + (ordinal - 1) + "]) // " + + bitFieldList.get(0) + ": bit" + cr); + sb.append(indent + "{" + cr); + sb.append(indent + tab + typeMap.get("bit").decodeExpression.replaceAll("#", + "boolean[] flaggedBitArray") + ";" + cr); + sb.append(indent + tab + bitFieldList.get(0) + " = flaggedBitArray[0];" + cr); + sb.append(indent + "}" + cr); + } + else // multiple bits - up to 8 are combined into one byte + { + int startOrdinal = ordinal - bitFieldList.size(); + String bitCntr = "bitCntr" + startOrdinal; + sb.append(indent + "// " + comment + cr); + sb.append(indent + "int " + bitCntr + " = 0;" + cr); + sb.append(indent + "for (int i=" + startOrdinal + "; i<=" + (ordinal - 1) + "; i++)" + cr); + sb.append(indent + "{" + cr); + sb.append(indent + tab + "if (propertyFlags[i])" + cr); + sb.append(indent + tab + tab + bitCntr + "++;" + cr); + sb.append(indent + "}" + cr); + sb.append(indent + "if (" + bitCntr + " > 0) // Are any of the property bits set?" + cr); + sb.append(indent + "{" + cr); + sb.append(indent + tab + typeMap.get("bit").decodeExpression.replaceAll("#", + "boolean[] flaggedBitArray") + ";" + cr); + sb.append(indent + tab + bitCntr + " = 0;" + cr); + for (int i=0; i<bitFieldList.size(); i++) + { + sb.append(indent + tab + "if (propertyFlags[" + (startOrdinal + i) + "])" + cr); + sb.append(indent + tab + tab + bitFieldList.get(i) + " = flaggedBitArray[" + + bitCntr + "++];" + cr); + } + sb.append(indent + "}" + cr); + } + + sb.append(cr); + return sb.toString(); + } + + protected String generatePchGetPropertyFlags(String domainType, String fieldName, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + int word = ordinal / 15; + int bit = 15 - (ordinal % 15); + sb.append(indent + "if (propertyFlags[" + ordinal + "]) // " + fieldName + ": " + + domainType + cr); + sb.append(indent + tab + "compactPropertyFlags[" + word + "] |= (1 << " + + bit + ");" + cr); + sb.append(cr); + return sb.toString(); + } + + protected String generatePchBitGetPropertyFlags(ArrayList<String> bitFieldList, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + int startOrdinal = ordinal - bitFieldList.size(); + + for (int i=0; i<bitFieldList.size(); i++) + { + int thisOrdinal = startOrdinal + i; + int word = thisOrdinal / 15; + int bit = 15 - (thisOrdinal % 15); + sb.append(indent + "if (propertyFlags[" + thisOrdinal + "])" + cr); + sb.append(indent + tab + "compactPropertyFlags[" + word + + "] |= (1 << " + bit + ");" + cr); + } + + sb.append(cr); + return sb.toString(); + } + + protected String generatePchSetPropertyFlags(String domainType, String fieldName, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + int word = ordinal / 15; + int bit = 15 - (ordinal % 15); + sb.append(indent + "propertyFlags[" + ordinal + "] = (compactPropertyFlags[" + + word + "] & (1 << " + bit + ")) > 0;" + cr); + return sb.toString(); + } + + protected String generatePchBitSetPropertyFlags(ArrayList<String> bitFieldList, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + int startOrdinal = ordinal - bitFieldList.size(); + + for (int i=0; i<bitFieldList.size(); i++) + { + int thisOrdinal = startOrdinal + i; + int word = thisOrdinal / 15; + int bit = 15 - (thisOrdinal % 15); + sb.append(indent + "propertyFlags[" + thisOrdinal + "] = (compactPropertyFlags[" + + word + "] & (1 << " + bit + ")) > 0;" + cr); + } + return sb.toString(); + } + + private String generatePchPropertyFlagsDeclare() + { + return "private boolean[] propertyFlags;"; + } + + private String generatePchPropertyFlagsInitializer(int totNumFields) + { + return "propertyFlags = new boolean[" + totNumFields + "];"; + } + + private String generatePchCompactPropertyFlagsInitializer(AmqpClass thisClass, int indentSize, + int tabSize) + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + Iterator<AmqpVersion> vItr = globalVersionSet.iterator(); + while (vItr.hasNext()) + { + AmqpVersion version = vItr.next(); + int numBytes = ((thisClass.fieldMap.getNumFields(version) - 1) / 15) + 1; + + sb.append(indent); + if (!version.equals(globalVersionSet.first())) + sb.append("else "); + sb.append("if ( major == " + version.getMajor() + " && minor == " + + version.getMinor() + " )" + cr); + sb.append(indent + tab + "compactPropertyFlags = new int[] { "); + for (int i=0; i<numBytes; i++) + { + if (i!= 0) + sb.append(", "); + sb.append(i < numBytes - 1 ? "1" : "0"); // Set the "continue" flag where required + } + sb.append(" };" + cr); + } + return sb.toString(); + } + + private String generatePchCompactPropertyFlagsCheck(AmqpClass thisClass, int indentSize, + int tabSize) + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + Iterator<AmqpVersion> vItr = globalVersionSet.iterator(); + while (vItr.hasNext()) + { + AmqpVersion version = vItr.next(); + int numFields = thisClass.fieldMap.getNumFields(version); + int numBytes = ((numFields - 1) / 15) + 1; + + sb.append(indent); + if (!version.equals(globalVersionSet.first())) + sb.append("else "); + sb.append("if ( major == " + version.getMajor() + " && minor == " + + version.getMinor() + " && compactPropertyFlags.length != " + numBytes + " )" + cr); + sb.append(indent + tab + + "throw new AMQProtocolVersionException(\"Property flag array size mismatch:\" +" + cr); + sb.append(indent + tab + tab + "\"(Size found: \" + compactPropertyFlags.length +" + cr); + sb.append(indent + tab + tab + "\") Version " + version + " has " + numFields + + " fields which requires an int array of size " + numBytes + ".\");" + cr); + } + return sb.toString(); + } + + private String generateVersionCheck(AmqpVersionSet v) + throws AmqpTypeMappingException + { + StringBuffer sb = new StringBuffer(); + AmqpVersion[] versionArray = new AmqpVersion[v.size()]; + v.toArray(versionArray); + for (int i=0; i<versionArray.length; i++) + { + if (i != 0) + sb.append(" || "); + if (versionArray.length > 1) + sb.append("("); + sb.append("major == (byte)" + versionArray[i].getMajor() + " && minor == (byte)" + + versionArray[i].getMinor()); + if (versionArray.length > 1) + sb.append(")"); + } + return sb.toString(); + } + + private String camelCaseName(String name, boolean upperFirstFlag) + { + StringBuffer ccn = new StringBuffer(); + String[] toks = name.split("[-_.\\ ]"); + for (int i=0; i<toks.length; i++) + { + StringBuffer b = new StringBuffer(toks[i]); + if (upperFirstFlag || i>0) + b.setCharAt(0, Character.toUpperCase(toks[i].charAt(0))); + ccn.append(b); + } + return ccn.toString(); + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/LanguageConverter.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/LanguageConverter.java new file mode 100644 index 0000000000..cb0a14e3bc --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/LanguageConverter.java @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +public interface LanguageConverter +{ + public void setDomainMap(AmqpDomainMap domainMap); + public AmqpDomainMap getDomainMap(); + + public void setConstantSet(AmqpConstantSet constantSet); + public AmqpConstantSet getConstantSet(); + + public void setModel(AmqpModel model); + public AmqpModel getModel(); + + public String prepareClassName(String className); + public String prepareMethodName(String methodName); + public String prepareDomainName(String domainName); + public String getDomainType(String domainName, AmqpVersion version) throws AmqpTypeMappingException; + public String getGeneratedType(String domainName, AmqpVersion version) throws AmqpTypeMappingException; +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/Main.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/Main.java new file mode 100644 index 0000000000..f1728ab290 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/Main.java @@ -0,0 +1,353 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +public class Main +{ + private static final String defaultOutDir = ".." + Utils.fileSeparator + "gen"; + private static final String defaultCppTemplateDir = ".." + Utils.fileSeparator + "templ.cpp"; + private static final String defaultDotnetTemplateDir = ".." + Utils.fileSeparator + "templ.net"; + private static final String defaultJavaTemplateDir = ".." + Utils.fileSeparator + "templ.java"; + + private enum GeneratorLangEnum { CPP, DOTNET, JAVA } + + private DocumentBuilder docBuilder; + private AmqpVersionSet versionSet; + private Generator generator; + private AmqpConstantSet constants; + private AmqpDomainMap domainMap; + private AmqpModel model; + + private String outDir; + private String tmplDir; + private GeneratorLangEnum generatorLang; + private ArrayList<String> xmlFiles; + private File[] modelTemplateFiles; + private File[] classTemplateFiles; + private File[] methodTemplateFiles; + private File[] fieldTemplateFiles; + + public Main() throws ParserConfigurationException + { + docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + versionSet = new AmqpVersionSet(); + xmlFiles = new ArrayList<String>(); + } + + public void run(String[] args) + throws IOException, + SAXException, + AmqpParseException, + AmqpTypeMappingException, + AmqpTemplateException, + TargetDirectoryException, + IllegalAccessException, + InvocationTargetException + { + modelTemplateFiles = new File[]{}; + classTemplateFiles = new File[]{}; + methodTemplateFiles = new File[]{}; + fieldTemplateFiles = new File[]{}; + + // 0. Initialize + outDir = defaultOutDir; + tmplDir = null; + generatorLang = GeneratorLangEnum.CPP; // Default generation language + xmlFiles.clear(); + processArgs(args); + switch (generatorLang) + { + case JAVA: + prepareJava(); + break; + case DOTNET: + prepareDotnet(); + break; + default: + prepareCpp(); + } + + if (modelTemplateFiles.length == 0 && classTemplateFiles.length == 0 && + methodTemplateFiles.length == 0 && fieldTemplateFiles.length == 0) + System.err.println(" WARNING: No template files."); + + // 1. Suck in all the XML spec files provided on the command line + analyzeXML(); + + // 2. Load up all templates + try + { + generator.initializeTemplates(modelTemplateFiles, classTemplateFiles, + methodTemplateFiles, fieldTemplateFiles); + } + catch (FileNotFoundException e) + { + System.err.println("Error: Unable to load template file (check -t option on command-line):"); + System.err.println(e.getMessage()); + return; + } + + // 3. Generate output + generator.generate(new File(outDir)); + + System.out.println("Files generated: " + generator.getNumberGeneratedFiles()); + System.out.println("Done."); + } + + private void processArgs(String[] args) + { + // Crude but simple... + for (int i=0; i<args.length; i++) + { + String arg = args[i]; + if (arg.charAt(0) == '-') + { + switch (arg.charAt(1)) + { + case 'c': + case 'C': + generatorLang = GeneratorLangEnum.CPP; + break; + case 'j': + case 'J': + generatorLang = GeneratorLangEnum.JAVA; + break; + case 'n': + case 'N': + generatorLang = GeneratorLangEnum.DOTNET; + break; + case 'o': + case 'O': + if (++i < args.length) + { + outDir = args[i]; + } + break; + case 't': + case 'T': + if (++i < args.length) + { + tmplDir = args[i]; + } + break; + } + } + else + { + xmlFiles.add(args[i]); + } + } + } + + private void prepareJava() + { + if (tmplDir == null) + tmplDir = defaultJavaTemplateDir; + System.out.println("Java generation mode."); + generator = new JavaGenerator(versionSet); + constants = new AmqpConstantSet(generator); + domainMap = new AmqpDomainMap(generator); + model = new AmqpModel(generator); + modelTemplateFiles = new File[] + { + new File(tmplDir + Utils.fileSeparator + "MethodRegistryClass.tmpl"), + new File(tmplDir + Utils.fileSeparator + "AmqpConstantsClass.tmpl"), + new File(tmplDir + Utils.fileSeparator + "ProtocolVersionListClass.tmpl") + }; + classTemplateFiles = new File[] + { +// new File(tmplDir + Utils.fileSeparator + "PropertyContentHeaderClass.tmpl") + }; + methodTemplateFiles = new File[] + { + new File(tmplDir + Utils.fileSeparator + "MethodBodyClass.tmpl") + }; + } + + private void prepareDotnet() + { + if (tmplDir == null) + tmplDir = defaultDotnetTemplateDir; + System.out.println(".NET generation mode."); + generator = new DotnetGenerator(versionSet); + constants = new AmqpConstantSet(generator); + domainMap = new AmqpDomainMap(generator); + model = new AmqpModel(generator); + // TODO: Add templated that should be handled in here... + modelTemplateFiles = new File[] + { +// new File(tmplDir + Utils.fileSeparator + "XXXClass.tmpl"), + }; + classTemplateFiles = new File[] + { +// new File(tmplDir + Utils.fileSeparator + "XXXClass.tmpl"), + }; + methodTemplateFiles = new File[] + { +// new File(tmplDir + Utils.fileSeparator + "XXXClass.tmpl"), + }; + } + + private void prepareCpp() + { + if (tmplDir == null) + tmplDir = defaultCppTemplateDir; + System.out.println("C++ generation mode."); + generator = new CppGenerator(versionSet); + constants = new AmqpConstantSet(generator); + domainMap = new AmqpDomainMap(generator); + model = new AmqpModel(generator); + modelTemplateFiles = new File[] + { + new File(tmplDir + Utils.fileSeparator + "AMQP_ServerOperations.h.tmpl"), + new File(tmplDir + Utils.fileSeparator + "AMQP_ClientOperations.h.tmpl"), + new File(tmplDir + Utils.fileSeparator + "AMQP_ServerProxy.h.tmpl"), + new File(tmplDir + Utils.fileSeparator + "AMQP_ClientProxy.h.tmpl"), + new File(tmplDir + Utils.fileSeparator + "AMQP_ServerProxy.cpp.tmpl"), + new File(tmplDir + Utils.fileSeparator + "AMQP_ClientProxy.cpp.tmpl"), + new File(tmplDir + Utils.fileSeparator + "AMQP_Constants.h.tmpl"), + new File(tmplDir + Utils.fileSeparator + "AMQP_MethodVersionMap.h.tmpl"), + new File(tmplDir + Utils.fileSeparator + "AMQP_MethodVersionMap.cpp.tmpl"), + new File(tmplDir + Utils.fileSeparator + "AMQP_HighestVersion.h.tmpl") + }; + methodTemplateFiles = new File[] + { + new File(tmplDir + Utils.fileSeparator + "MethodBodyClass.h.tmpl") + }; + } + + private void analyzeXML() + throws IOException, SAXException, AmqpParseException, AmqpTypeMappingException + { + System.out.println("XML files: " + xmlFiles); + for (String filename : xmlFiles) + { + File f = new File(filename); + if (f.exists()) + { + // 1a. Initialize dom + System.out.print(" \"" + filename + "\":"); + Document doc = docBuilder.parse(new File(filename)); + Node amqpNode = Utils.findChild(doc, Utils.ELEMENT_AMQP); + + // 1b. Extract version (major and minor) from the XML file + int major = Utils.getNamedIntegerAttribute(amqpNode, Utils.ATTRIBUTE_MAJOR); + int minor = Utils.getNamedIntegerAttribute(amqpNode, Utils.ATTRIBUTE_MINOR); + AmqpVersion version = new AmqpVersion(major, minor); + System.out.println(" Found version " + version.toString() + "."); + versionSet.add(version); + + // 1c. Extract domains + constants.addFromNode(amqpNode, 0, version); + + // 1d. Extract domains + domainMap.addFromNode(amqpNode, 0, version); + + // 1e. Extract class/method/field heirarchy + model.addFromNode(amqpNode, 0, version); + } + else + System.err.println("ERROR: AMQP XML file \"" + filename + "\" not found."); + } +// *** DEBUG INFO *** Uncomment bits from this block to see lots of stuff.... +// System.out.println(); +// System.out.println("*** Debug output ***"); +// System.out.println(); +// versionSet.print(System.out, 0, 2); // List of loaded versions +// System.out.println(); +// constants.print(System.out, 0, 2); // List of constants +// System.out.println(); +// domainMap.print(System.out, 0, 2); // List of domains +// System.out.println(); +// model.print(System.out, 0, 2); // Internal version map model +// System.out.println(); +// System.out.println("*** End debug output ***"); +// System.out.println(); + } + + public static void main(String[] args) + { + int exitCode = 1; + // TODO: This is a simple and klunky way of hangling command-line args, and could be improved upon. + if (args.length < 2) + { + usage(); + } + else + { + try + { + new Main().run(args); + exitCode = 0; + } + catch (IOException e) { e.printStackTrace(); } + catch (ParserConfigurationException e) { e.printStackTrace(); } + catch (SAXException e) { e.printStackTrace(); } + catch (AmqpParseException e) { e.printStackTrace(); } + catch (AmqpTypeMappingException e) { e.printStackTrace(); } + catch (AmqpTemplateException e) { e.printStackTrace(); } + catch (TargetDirectoryException e) { e.printStackTrace(); } + catch (IllegalAccessException e) { e.printStackTrace(); } + catch (InvocationTargetException e) { e.printStackTrace(); } + } + System.exit(exitCode); + } + + public static void usage() + { + System.out.println("AMQP XML generator v.0.0"); + System.out.println("Usage: Main -c|-j [-o outDir] [-t tmplDir] XMLfile [XMLfile ...]"); + System.out.println(" where -c: Generate C++."); + System.out.println(" -j: Generate Java."); + System.out.println(" -n: Generate .NET."); + System.out.println(" -o outDir: Use outDir as the output dir (default=\"" + defaultOutDir + "\")."); + System.out.println(" -t tmplDir: Find templates in tmplDir."); + System.out.println(" Defaults: \"" + defaultCppTemplateDir + "\" for C++;"); + System.out.println(" \"" + defaultJavaTemplateDir + "\" for java."); + System.out.println(" XMLfile is a space-separated list of AMQP XML files to be parsed."); + } + + public static String ListTemplateList(File[] list) + { + StringBuffer sb = new StringBuffer(); + for (int i=0; i<list.length; i++) + { + if (i != 0) + sb.append(", "); + sb.append(list[i].getName()); + } + return sb.toString(); + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/NodeAware.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/NodeAware.java new file mode 100644 index 0000000000..df4e0ecb02 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/NodeAware.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import org.w3c.dom.Node; + +/** + * @author kpvdr + * Interface allowing the addition of elements from a node in the + * DOM of the AMQP specification. It is used by each of the model + * elements in a recursive fashion to build the model. + */ +public interface NodeAware +{ + /** + * Add a model element from the current DOM node. All model elements must implement + * this interface. If the node contains children that are also a part of the model, + * then this method is called on new instances of those model elements. + * @param n Node from which the current model element is to be added. + * @param o Ordinal value of the current model elemet. + * @param v Verion of the DOM from which the node comes. + * @throws AmqpParseException + * @throws AmqpTypeMappingException + * @returns true if a node was added, false if not + */ + public boolean addFromNode(Node n, int o, AmqpVersion v) + throws AmqpParseException, AmqpTypeMappingException; +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/Printable.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/Printable.java new file mode 100644 index 0000000000..a73878c506 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/Printable.java @@ -0,0 +1,28 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; + +public interface Printable +{ + public void print(PrintStream out, int marginSize, int tabSize); +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/TargetDirectoryException.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/TargetDirectoryException.java new file mode 100644 index 0000000000..cdaf381f0a --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/TargetDirectoryException.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +@SuppressWarnings("serial") +public class TargetDirectoryException extends Exception +{ + public TargetDirectoryException(String msg) + { + super(msg); + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/Utils.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/Utils.java new file mode 100644 index 0000000000..ade00cd8c7 --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/Utils.java @@ -0,0 +1,146 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +import org.w3c.dom.Attr; +//import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class Utils +{ + public final static String fileSeparator = System.getProperty("file.separator"); + public final static String lineSeparator = System.getProperty("line.separator"); + + public final static String ATTRIBUTE_NAME = "name"; + public final static String ATTRIBUTE_MAJOR = "major"; + public final static String ATTRIBUTE_MINOR = "minor"; + public final static String ATTRIBUTE_INDEX = "index"; + public final static String ATTRIBUTE_LABEL = "label"; + public final static String ATTRIBUTE_SYNCHRONOUS = "synchronous"; + public final static String ATTRIBUTE_CONTENT = "content"; + public final static String ATTRIBUTE_HANDLER = "handler"; + public final static String ATTRIBUTE_DOMAIN = "domain"; + public final static String ATTRIBUTE_VALUE = "value"; + public final static String ATTRIBUTE_TYPE = "type"; // For compatibility with AMQP 8.0 + + public final static String ELEMENT_AMQP = "amqp"; + public final static String ELEMENT_CHASSIS = "chassis"; + public final static String ELEMENT_CLASS = "class"; + public final static String ELEMENT_CODEGEN = "codegen"; + public final static String ELEMENT_CONSTANT = "constant"; + public final static String ELEMENT_DOMAIN = "domain"; + public final static String ELEMENT_METHOD = "method"; + public final static String ELEMENT_FIELD = "field"; + public final static String ELEMENT_VERSION = "version"; + + // Attribute functions + + public static String getNamedAttribute(Node n, String attrName) throws AmqpParseException + { + NamedNodeMap nnm = n.getAttributes(); + if (nnm == null) + throw new AmqpParseException("Node \"" + n.getNodeName() + "\" has no attributes."); + Attr a = (Attr)nnm.getNamedItem(attrName); + if (a == null) + throw new AmqpParseException("Node \"" + n.getNodeName() + "\" has no attribute \"" + attrName + "\"."); + return a.getNodeValue(); + } + + public static int getNamedIntegerAttribute(Node n, String attrName) throws AmqpParseException + { + return Integer.parseInt(getNamedAttribute(n, attrName)); + } + + // Element functions + + public static Node findChild(Node n, String eltName) throws AmqpParseException + { + NodeList nl = n.getChildNodes(); + for (int i=0; i<nl.getLength(); i++) + { + Node cn = nl.item(i); + if (cn.getNodeName().compareTo(eltName) == 0) + return cn; + } + throw new AmqpParseException("Node \"" + n.getNodeName() + + "\" does not contain child element \"" + eltName + "\"."); + } + + // String functions + + public static String firstUpper(String str) + { + if (!Character.isLowerCase(str.charAt(0))) + return str; + StringBuffer sb = new StringBuffer(str); + sb.setCharAt(0, Character.toUpperCase(str.charAt(0))); + return sb.toString(); + } + + public static String firstLower(String str) + { + if (!Character.isUpperCase(str.charAt(0))) + return str; + StringBuffer sb = new StringBuffer(str); + sb.setCharAt(0, Character.toLowerCase(str.charAt(0))); + return sb.toString(); + } + + public static String createSpaces(int cnt) + { + StringBuffer sb = new StringBuffer(); + for (int i=0; i<cnt; i++) + sb.append(' '); + return sb.toString(); + } + + public static boolean containsOnlyDigits(String str) + { + boolean foundNonDigit = false; + for (int i=0; i<str.length() && !foundNonDigit; i++) + { + if (!Character.isDigit(str.charAt(i))) + { + foundNonDigit = true; + } + } + return !foundNonDigit; + } + + public static boolean containsOnlyDigitsAndDecimal(String str) + { + boolean foundNonDigit = false; + int decimalCntr = 0; + for (int i=0; i<str.length() && !foundNonDigit && decimalCntr<2; i++) + { + char ch = str.charAt(i); + if (!(Character.isDigit(ch) || ch == '.')) + { + foundNonDigit = true; + } + else if (ch == '.') + decimalCntr++; + } + return !foundNonDigit && decimalCntr<2; + } +} diff --git a/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/VersionConsistencyCheck.java b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/VersionConsistencyCheck.java new file mode 100644 index 0000000000..1f6b9f1a6d --- /dev/null +++ b/qpid/cpp-0-9/gentools/src/org/apache/qpid/gentools/VersionConsistencyCheck.java @@ -0,0 +1,26 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.gentools; + +public interface VersionConsistencyCheck +{ + public boolean isVersionConsistent(AmqpVersionSet globalVersionSet); +} diff --git a/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ClientOperations.h.tmpl b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ClientOperations.h.tmpl new file mode 100644 index 0000000000..2b96e55444 --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ClientOperations.h.tmpl @@ -0,0 +1,64 @@ +&{AMQP_ClientOperations.h} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +#ifndef qpid_framing_AMQP_ClientOperations__ +#define qpid_framing_AMQP_ClientOperations__ + +#include <sstream> + +#include "ProtocolVersion.h" + +namespace qpid { +namespace framing { + +class MethodContext; + +class AMQP_ClientOperations +{ +public: + virtual ~AMQP_ClientOperations() {} + + virtual ProtocolVersion getVersion() const = 0; + + // Include framing constant declarations + #include <AMQP_Constants.h> + + // Inner classes + +%{CLIST} ${coh_inner_class} + + // Method handler get methods + +%{CLIST} ${coh_method_handler_get_method} + +}; /* class AMQP_ClientOperations */ + +} /* namespace framing */ +} /* namespace qpid */ + +#endif diff --git a/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ClientProxy.cpp.tmpl b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ClientProxy.cpp.tmpl new file mode 100644 index 0000000000..6a0e6eedb3 --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ClientProxy.cpp.tmpl @@ -0,0 +1,52 @@ +&{AMQP_ClientProxy.cpp} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ +#include <sstream> +#include "AMQP_ClientProxy.h" +#include "framing/ChannelAdapter.h" +#include "framing/amqp_types_full.h" + +%{MLIST} ${cpc_method_body_include} + +namespace qpid { +namespace framing { + + +AMQP_ClientProxy::AMQP_ClientProxy(ChannelAdapter& ch) : + Proxy(ch)%{CLIST} ${cpc_constructor_initializer} + {} + + // Inner class instance get methods + +%{CLIST} ${cpc_inner_class_get_method} + + // Inner class implementation + +%{CLIST} ${cpc_inner_class_impl} + +}} // namespae qpid::framing + diff --git a/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ClientProxy.h.tmpl b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ClientProxy.h.tmpl new file mode 100644 index 0000000000..b43b3a6747 --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ClientProxy.h.tmpl @@ -0,0 +1,59 @@ +&{AMQP_ClientProxy.h} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +#ifndef qpid_framing_AMQP_ClientProxy__ +#define qpid_framing_AMQP_ClientProxy__ + +#include "framing/Proxy.h" + +namespace qpid { +namespace framing { + +class AMQP_ClientProxy : public Proxy +{ +public: + AMQP_ClientProxy(ChannelAdapter& ch); + + // Inner class definitions + +%{CLIST} ${cph_inner_class_defn} + + // Inner class instance get methods + +%{CLIST} ${cph_inner_class_get_method} + +private: + // Inner class instances + +%{CLIST} ${cph_inner_class_instance} +}; /* class AMQP_ClientProxy */ + +} /* namespace framing */ +} /* namespace qpid */ + +#endif diff --git a/qpid/cpp-0-9/gentools/templ.cpp/AMQP_Constants.h.tmpl b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_Constants.h.tmpl new file mode 100644 index 0000000000..4631bc8de6 --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_Constants.h.tmpl @@ -0,0 +1,34 @@ +&{AMQP_Constants.h} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + // NOTE: This file is intended to be included within the class structure of both + // the client and server operations classes. These need to have <sstream> included. + + // Constant getValue methods + +%{TLIST} ${ch_get_value_method} +
\ No newline at end of file diff --git a/qpid/cpp-0-9/gentools/templ.cpp/AMQP_HighestVersion.h.tmpl b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_HighestVersion.h.tmpl new file mode 100644 index 0000000000..9753b454ba --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_HighestVersion.h.tmpl @@ -0,0 +1,42 @@ +&{AMQP_HighestVersion.h} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ +#ifndef qpid_framing_highestProtocolVersion__ +#define qpid_framing_highestProtocolVersion__ + +#include <ProtocolVersion.h> + + +namespace qpid { +namespace framing { + +static ProtocolVersion highestProtocolVersion(${hv_latest_major}, ${hv_latest_minor}); + +} /* namespace framing */ +} /* namespace qpid */ + +#endif diff --git a/qpid/cpp-0-9/gentools/templ.cpp/AMQP_MethodVersionMap.cpp.tmpl b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_MethodVersionMap.cpp.tmpl new file mode 100644 index 0000000000..6fc79180b2 --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_MethodVersionMap.cpp.tmpl @@ -0,0 +1,62 @@ +&{AMQP_MethodVersionMap.cpp} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +#include <sstream> +#include "framing/ProtocolVersionException.h" +#include "AMQP_MethodVersionMap.h" + +namespace qpid +{ +namespace framing +{ + +AMQP_MethodVersionMap::AMQP_MethodVersionMap() +{ +%{CLIST} ${mc_create_method_body_map_entry} +} + +AMQMethodBody* AMQP_MethodVersionMap::createMethodBody(u_int16_t classId, u_int16_t methodId, u_int8_t major, u_int8_t minor) +{ + iterator itr = find(createMapKey(classId, methodId, major, minor)); + if (itr == end()) + { + std::stringstream ss; + ss << "Unable to find MethodBody class for classId = " << classId << ", methodId = " << + methodId << ", AMQ protocol version = " << major << "-" << minor << "."; + throw ProtocolVersionException(ss.str()); + } + return (itr->second)(major, minor); +} + +u_int64_t AMQP_MethodVersionMap::createMapKey(u_int16_t classId, u_int16_t methodId, u_int8_t major, u_int8_t minor) +{ + return ((u_int64_t)classId<<48) + ((u_int64_t)methodId<<32) + ((u_int64_t)major<<16) + minor; +} + +} /* namespace framing */ +} /* namespace qpid */ diff --git a/qpid/cpp-0-9/gentools/templ.cpp/AMQP_MethodVersionMap.h.tmpl b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_MethodVersionMap.h.tmpl new file mode 100644 index 0000000000..84596ea5a0 --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_MethodVersionMap.h.tmpl @@ -0,0 +1,57 @@ +&{AMQP_MethodVersionMap.h} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +#ifndef qpid_framing_AMQP_MethodVersionMap__ +#define qpid_framing_AMQP_MethodVersionMap__ + +#include <map> +#include <AMQMethodBody.h> + +%{MLIST} ${mc_method_body_include} + +namespace qpid +{ +namespace framing +{ + +template <class T> AMQMethodBody* createMethodBodyFn(u_int8_t major, u_int8_t minor) { return new T(ProtocolVersion(major, minor)); } +typedef AMQMethodBody* (*fnPtr)(u_int8_t, u_int8_t); + +class AMQP_MethodVersionMap: public std::map<u_int64_t, fnPtr> +{ +protected: + u_int64_t createMapKey(u_int16_t classId, u_int16_t methodId, u_int8_t major, u_int8_t minor); +public: + AMQP_MethodVersionMap(); + AMQMethodBody* createMethodBody(u_int16_t classId, u_int16_t methodId, u_int8_t major, u_int8_t minor); +}; + +} /* namespace framing */ +} /* namespace qpid */ + +#endif diff --git a/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ServerOperations.h.tmpl b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ServerOperations.h.tmpl new file mode 100644 index 0000000000..7f47ac8efb --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ServerOperations.h.tmpl @@ -0,0 +1,65 @@ +&{AMQP_ServerOperations.h} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +#ifndef qpid_framing_AMQP_ServerOperations__ +#define qpid_framing_AMQP_ServerOperations__ + +#include "ProtocolVersion.h" + +namespace qpid { +namespace framing { + +class MethodContext; + +class AMQP_ServerOperations +{ +protected: + ProtocolVersion version; + +public: + virtual ~AMQP_ServerOperations() {} + + virtual ProtocolVersion getVersion() const = 0; + + // Include framing constant declarations + #include "AMQP_Constants.h" + + // Inner classes + +%{CLIST} ${soh_inner_class} + + // Method handler get methods + +%{CLIST} ${soh_method_handler_get_method} + +}; /* class AMQP_ServerOperations */ + +} /* namespace framing */ +} /* namespace qpid */ + +#endif diff --git a/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ServerProxy.cpp.tmpl b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ServerProxy.cpp.tmpl new file mode 100644 index 0000000000..5575f3b1df --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ServerProxy.cpp.tmpl @@ -0,0 +1,51 @@ +&{AMQP_ServerProxy.cpp} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +#include <sstream> +#include "AMQP_ServerProxy.h" +#include "framing/ChannelAdapter.h" +#include "framing/amqp_types_full.h" + +%{MLIST} ${spc_method_body_include} + +namespace qpid { +namespace framing { + +AMQP_ServerProxy::AMQP_ServerProxy(ChannelAdapter& ch) : + Proxy(ch)%{CLIST} ${spc_constructor_initializer} + {} + + // Inner class instance get methods + +%{CLIST} ${spc_inner_class_get_method} + + // Inner class implementation + +%{CLIST} ${spc_inner_class_impl} + +}} // namespae qpid::framing diff --git a/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ServerProxy.h.tmpl b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ServerProxy.h.tmpl new file mode 100644 index 0000000000..5b8a12ee34 --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.cpp/AMQP_ServerProxy.h.tmpl @@ -0,0 +1,59 @@ +&{AMQP_ServerProxy.h} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +#ifndef qpid_framing_AMQP_ServerProxy__ +#define qpid_framing_AMQP_ServerProxy__ + +#include "framing/Proxy.h" + +namespace qpid { +namespace framing { + +class AMQP_ServerProxy : public Proxy +{ +public: + AMQP_ServerProxy(ChannelAdapter& ch); + + // Inner class definitions + +%{CLIST} ${sph_inner_class_defn} + + // Inner class instance get methods + +%{CLIST} ${sph_inner_class_get_method} + +private: + // Inner class instances + +%{CLIST} ${sph_inner_class_instance} +}; /* class AMQP_ServerProxy */ + +} /* namespace framing */ +} /* namespace qpid */ + +#endif diff --git a/qpid/cpp-0-9/gentools/templ.cpp/MethodBodyClass.h.tmpl b/qpid/cpp-0-9/gentools/templ.cpp/MethodBodyClass.h.tmpl new file mode 100644 index 0000000000..351399a991 --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.cpp/MethodBodyClass.h.tmpl @@ -0,0 +1,110 @@ +&{${CLASS}${METHOD}Body.h} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +#ifndef qpid_framing_${CLASS}${METHOD}Body__ +#define qpid_framing_${CLASS}${METHOD}Body__ + +#include <string> +#include <sstream> + +#include <amqp_types.h> +#include <${mb_base_class}.h> +#include <Buffer.h> +#include <FieldTable.h> +#include <FramingContent.h> + +namespace qpid +{ +namespace framing +{ +${version_namespace_start} + +class ${CLASS}${METHOD}Body : public ${mb_base_class} +{ + + // Method field declarations + +%{FLIST} ${mb_field_declaration} + + +public: + static const ClassId CLASS_ID= ${CLASS_ID_INIT}; + static const MethodId METHOD_ID = ${METHOD_ID_INIT}; + + typedef boost::shared_ptr<${CLASS}${METHOD}Body> shared_ptr; + + // Constructors and destructors + +${mb_constructor_with_initializers} + + ${CLASS}${METHOD}Body(ProtocolVersion version): ${mb_base_class}(version) {} + virtual ~${CLASS}${METHOD}Body() {} + + // Attribute get methods + +%{FLIST} ${mb_field_get_method} + + // Helper methods + + inline void print(std::ostream& out) const + { + printPrefix(out); + out << "${CLASS}${METHOD}: "; +%{FLIST} ${mb_field_print} + } + + inline ClassId amqpClassId() const { return CLASS_ID; } + inline MethodId amqpMethodId() const { return METHOD_ID; } + + u_int32_t size() const + { + u_int32_t sz = baseSize(); +%{FLIST} ${mb_body_size} + return sz; + } + + void encodeContent(Buffer& ${mb_buffer_param}) const + { +%{FLIST} ${mb_encode} + } + + inline void decodeContent(Buffer& ${mb_buffer_param}) + { +%{FLIST} ${mb_decode} + } + +${mb_server_operation_invoke} + +}; // class ${CLASS}${METHOD}Body + +${version_namespace_end} +} // namespace framing +} // namespace qpid + +#endif + diff --git a/qpid/cpp-0-9/gentools/templ.java/AmqpConstantsClass.tmpl b/qpid/cpp-0-9/gentools/templ.java/AmqpConstantsClass.tmpl new file mode 100644 index 0000000000..8d459f2977 --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.java/AmqpConstantsClass.tmpl @@ -0,0 +1,37 @@ +&{AmqpConstants.java} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +package org.apache.qpid.framing; + +class AmqpConstants +{ + // Constant getValue methods + +%{TLIST} ${const_get_method} + +} diff --git a/qpid/cpp-0-9/gentools/templ.java/MethodBodyClass.tmpl b/qpid/cpp-0-9/gentools/templ.java/MethodBodyClass.tmpl new file mode 100644 index 0000000000..42582fcb7c --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.java/MethodBodyClass.tmpl @@ -0,0 +1,180 @@ +&{${CLASS}${METHOD}Body.java} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +package org.apache.qpid.framing; + +import java.util.HashMap; + +import org.apache.mina.common.ByteBuffer; + +public class ${CLASS}${METHOD}Body extends AMQMethodBody implements EncodableAMQDataBlock +{ + private static final AMQMethodBodyInstanceFactory factory = new AMQMethodBodyInstanceFactory() + { + public AMQMethodBody newInstance(byte major, byte minor, ByteBuffer in, long size) throws AMQFrameDecodingException + { + return new ${CLASS}${METHOD}Body(major, minor, in); + } + + public AMQMethodBody newInstance(byte major, byte minor, int clazzID, int methodID, ByteBuffer in, long size) throws AMQFrameDecodingException + { + return new ${CLASS}${METHOD}Body(major, minor, clazzID, methodID, in); + } + + }; + + public static AMQMethodBodyInstanceFactory getFactory() + { + return factory; + } + + public static HashMap<Integer, Integer> classIdMap = new HashMap<Integer, Integer>(); + public static HashMap<Integer, Integer> methodIdMap = new HashMap<Integer, Integer>(); + + private static void registerMethodId(byte major, byte minor, int methodId) + { + methodIdMap.put((0xff & (int) major) | ((0xff & (int) minor)<<8), methodId); + } + + private static void registerClassId(byte major, byte minor, int classId) + { + classIdMap.put((0xff & (int) major) | ((0xff & (int) minor)<<8), classId); + } + + + static + { + ${CLASS_ID_INIT} + ${METHOD_ID_INIT} + } + + // Fields declared in specification +%{FLIST} ${field_declaration} + + private final int _clazz; + private final int _method; + + + // Constructor + + public ${CLASS}${METHOD}Body(byte major, byte minor, ByteBuffer buffer) throws AMQFrameDecodingException + { + this(major, minor, getClazz(major,minor), getMethod(major,minor), buffer); + } + + public ${CLASS}${METHOD}Body(byte major, byte minor, int clazzID, int methodID, ByteBuffer buffer) throws AMQFrameDecodingException + { + super(major, minor); + _clazz = clazzID; + _method = methodID; +%{FLIST} ${mb_field_decode} + } + + public ${CLASS}${METHOD}Body(byte major, byte minor, int clazzID, int methodID +%{FLIST} ${mb_field_parameter_list} + ) + { + super(major, minor); + _clazz = getClazz(major,minor); + _method = getMethod(major,minor); +%{FLIST} ${mb_field_body_initialize} + } + + public int getClazz() + { + return _clazz; + } + + public int getMethod() + { + return _method; + } + + public static int getClazz(byte major, byte minor) + { + return classIdMap.get((0xff & (int) major) | ((0xff & (int) minor)<<8)); + } + + public static int getMethod(byte major, byte minor) + { + return methodIdMap.get((0xff & (int) major) | ((0xff & (int) minor)<<8)); + } + + + // Field methods +%{FLIST} ${mb_field_get_method} + + public int getBodySize() + { + int size = 0; +%{FLIST} ${mb_field_size} + return size; + } + + protected void writeMethodPayload(ByteBuffer buffer) + { +%{FLIST} ${mb_field_encode} + } + + public void populateMethodBodyFromBuffer(ByteBuffer buffer) throws AMQFrameDecodingException + { +%{FLIST} ${mb_field_decode} + } + + public String toString() + { + StringBuffer buf = new StringBuffer(super.toString()); +%{FLIST} ${mb_field_to_string} + return buf.toString(); + } + + public static ${CLASS}${METHOD}Body createMethodBody(byte major, byte minor +%{FLIST} ${mb_field_parameter_list} + ) + { + return createMethodBody(major, minor, getClazz(major, minor), getMethod(major, minor) +%{FLIST} ${mb_field_passed_parameter_list} + ); + } + + public static ${CLASS}${METHOD}Body createMethodBody(byte major, byte minor, int clazzID, int methodID +%{FLIST} ${mb_field_parameter_list} + ) + { + return new ${CLASS}${METHOD}Body(major, minor, clazzID, methodID +%{FLIST} ${mb_field_passed_parameter_list} + ); + } + + public ${CLASS}${METHOD}Body copy() + { + return new ${CLASS}${METHOD}Body(major, minor, getClazz(major, minor), getMethod(major, minor) +%{FLIST} ${mb_field_passed_parameter_list} + ); + } +} diff --git a/qpid/cpp-0-9/gentools/templ.java/MethodRegistryClass.tmpl b/qpid/cpp-0-9/gentools/templ.java/MethodRegistryClass.tmpl new file mode 100644 index 0000000000..12e6fe250e --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.java/MethodRegistryClass.tmpl @@ -0,0 +1,125 @@ +&{MainRegistry.java} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +package org.apache.qpid.framing; + +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; + +public class MainRegistry +{ + private static final Logger _log = Logger.getLogger(MainRegistry.class); + + private static final int DEFAULT_MINOR_VERSION_COUNT = 10; + private static final int DEFAULT_MAJOR_VERSION_COUNT = 10; + + private static VersionSpecificRegistry[][] _specificRegistries = new VersionSpecificRegistry[DEFAULT_MAJOR_VERSION_COUNT][]; + + static + { +%{CLIST} ${reg_map_put_method} + } + + public static AMQMethodBody get(short classID, short methodID, byte major, byte minor, ByteBuffer in, long size) + throws AMQFrameDecodingException + { + VersionSpecificRegistry registry = getVersionSpecificRegistry(major, minor); + AMQMethodBodyInstanceFactory bodyFactory = registry.getMethodBody(classID,methodID); + + if (bodyFactory == null) + { + throw new AMQFrameDecodingException(_log, + "Unable to find a suitable decoder for class " + classID + " and method " + + methodID + " in AMQP version " + major + "-" + minor + "."); + } + return bodyFactory.newInstance(major, minor, in, size); + + + } + + public static VersionSpecificRegistry getVersionSpecificRegistry(byte major, byte minor) + { + try + { + return _specificRegistries[(int)major][(int)minor]; + } + catch (IndexOutOfBoundsException e) + { + return null; + } + catch (NullPointerException e) + { + return null; + } + + + } + + private static VersionSpecificRegistry addVersionSpecificRegistry(byte major, byte minor) + { + VersionSpecificRegistry[][] registries = _specificRegistries; + if(major >= registries.length) + { + _specificRegistries = new VersionSpecificRegistry[(int)major + 1][]; + System.arraycopy(registries, 0, _specificRegistries, 0, registries.length); + registries = _specificRegistries; + } + if(registries[major] == null) + { + registries[major] = new VersionSpecificRegistry[ minor >= DEFAULT_MINOR_VERSION_COUNT ? minor + 1 : DEFAULT_MINOR_VERSION_COUNT ]; + } + else if(registries[major].length <= minor) + { + VersionSpecificRegistry[] minorArray = registries[major]; + registries[major] = new VersionSpecificRegistry[ minor + 1 ]; + System.arraycopy(minorArray, 0, registries[major], 0, minorArray.length); + + } + + VersionSpecificRegistry newRegistry = new VersionSpecificRegistry(major,minor); + + registries[major][minor] = newRegistry; + + return newRegistry; + } + + private static void registerMethod(short classID, short methodID, byte major, byte minor, AMQMethodBodyInstanceFactory instanceFactory ) + { + VersionSpecificRegistry registry = getVersionSpecificRegistry(major,minor); + if(registry == null) + { + registry = addVersionSpecificRegistry(major,minor); + + } + + registry.registerMethod(classID, methodID, instanceFactory); + + } + + +} diff --git a/qpid/cpp-0-9/gentools/templ.java/PropertyContentHeaderClass.tmpl b/qpid/cpp-0-9/gentools/templ.java/PropertyContentHeaderClass.tmpl new file mode 100644 index 0000000000..3c147cf6b6 --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.java/PropertyContentHeaderClass.tmpl @@ -0,0 +1,207 @@ +&{${CLASS}ContentHeaderProperties.java} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +package org.apache.qpid.framing; + +import org.apache.log4j.Logger; +import org.apache.mina.common.ByteBuffer; + +public class ${CLASS}ContentHeaderProperties implements ContentHeaderProperties +{ + private static final Logger logger = Logger.getLogger(BasicContentHeaderProperties.class); + + /** + * We store the encoded form when we decode the content header so that if we need to + * write it out without modifying it we can do so without incurring the expense of + * reencoding it. + */ + private byte[] encodedBuffer; + + /** + * Flag indicating whether the entire content header has been decoded yet. + */ + private boolean decodedFlag = true; + + /** + * We have some optimisations for partial decoding for maximum performance. The + * headers are used in the broker for routing in some cases so we can decode that + * separately. + */ + private boolean decodedHeadersFlag = true; + + /** + * We have some optimisations for partial decoding for maximum performance. The + * content type is used by all clients to determine the message type. + */ + private boolean decodedContentTypeFlag = true; + + /** + * AMQP major and minor version of this instance. + */ + private byte major; + private byte minor; + + /** + * Property flags. + */ + ${pch_property_flags_declare} + + // Header fields from specification +%{FLIST} ${field_declaration} + + /** + * Constructor + */ + public ${CLASS}ContentHeaderProperties(byte major, byte minor) + { + this.major = major; + this.minor = minor; + + // Although one flag is initialized per property, the flags are used + // in ordinal order of the AMQP version represented by this instance, + // thus the number of flags actually used may be less than the total + // number defined. + ${pch_property_flags_initializer} + } + + public int getPropertyListSize() + { + if (encodedBuffer != null) + { + return encodedBuffer.length; + } + else + { + int size = 0; +%{FLIST} ${pch_field_list_size} + return size; + } + } + + private void clearEncodedForm() + { + if (!decodedFlag && encodedBuffer != null) + { + //decode(); + } + encodedBuffer = null; + } + + public void setPropertyFlags(int[] compactPropertyFlags) + throws AMQProtocolVersionException + { + clearEncodedForm(); +${pch_compact_property_flags_check} +%{FLIST} ${pch_set_compact_property_flags} + } + + public int[] getPropertyFlags() + { + int[] compactPropertyFlags = new int[] { 0 }; +${pch_compact_property_flags_initializer} +%{FLIST} ${pch_get_compact_property_flags} + return compactPropertyFlags; + } + + public void writePropertyListPayload(ByteBuffer buffer) + { + if (encodedBuffer != null) + { + buffer.put(encodedBuffer); + } + else + { +%{FLIST} ${pch_field_list_payload} + } + } + + public void populatePropertiesFromBuffer(ByteBuffer buffer, int[] propertyFlags, int size) + throws AMQFrameDecodingException, AMQProtocolVersionException + { + setPropertyFlags(propertyFlags); + + if (logger.isDebugEnabled()) + { + logger.debug("Property flags: " + propertyFlags); + } + decode(buffer); + /*encodedBuffer = new byte[size]; + buffer.get(encodedBuffer, 0, size); + decodedFlag = false; + decodedHeadersFlag = false; + decodedContentTypeFlag = false;*/ + } + + private void decode(ByteBuffer buffer) + { + //ByteBuffer buffer = ByteBuffer.wrap(encodedBuffer); + int pos = buffer.position(); + try + { +%{FLIST} ${pch_field_list_decode} + // This line does nothing, but prevents a compiler error (Exception not thrown) + // if this block is empty. + if (false) throw new AMQFrameDecodingException(""); + } + catch (AMQFrameDecodingException e) + { + throw new RuntimeException("Error in content header data: " + e); + } + + final int endPos = buffer.position(); + buffer.position(pos); + final int len = endPos - pos; + encodedBuffer = new byte[len]; + final int limit = buffer.limit(); + buffer.limit(endPos); + buffer.get(encodedBuffer, 0, len); + buffer.limit(limit); + buffer.position(endPos); + decodedFlag = true; + } + + private void decodeIfNecessary() + { + if (!decodedFlag) + { + //decode(); + } + } + + // Field clear methods + +%{FLIST} ${pch_field_clear_methods} + + // Field get methods + +%{FLIST} ${pch_field_get_methods} + + // Field set methods + +%{FLIST} ${pch_field_set_methods} +} diff --git a/qpid/cpp-0-9/gentools/templ.java/ProtocolVersionListClass.tmpl b/qpid/cpp-0-9/gentools/templ.java/ProtocolVersionListClass.tmpl new file mode 100644 index 0000000000..bc98e0c1ea --- /dev/null +++ b/qpid/cpp-0-9/gentools/templ.java/ProtocolVersionListClass.tmpl @@ -0,0 +1,38 @@ +&{ProtocolVersionList.java} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by ${GENERATOR} - do not modify. + * Supported AMQP versions: +%{VLIST} * ${major}-${minor} + */ + +package org.apache.qpid.framing; + +public interface ProtocolVersionList +{ + public final int PROTOCOL_MAJOR = 0; + public final int PROTOCOL_MINOR = 1; + public final byte pv[][] = { +%{VLIST} ${protocol-version-list-entry} + }; +} diff --git a/qpid/cpp-0-9/gentools/xml-src/amqp-0.10.test.xml b/qpid/cpp-0-9/gentools/xml-src/amqp-0.10.test.xml new file mode 100644 index 0000000000..5d3d80648b --- /dev/null +++ b/qpid/cpp-0-9/gentools/xml-src/amqp-0.10.test.xml @@ -0,0 +1,4241 @@ +<?xml version = "1.0"?> + +<!-- + EDITORS: (PH) Pieter Hintjens <ph@imatix.com> + (KvdR) Kim van der Riet <kim.vdriet@redhat.com> + + These editors have been assigned by the AMQP working group. + Please do not edit/commit this file without consulting with + one of the above editors. + ======================================================== + + TODOs + - see TODO comments in the text +--> + +<!-- + Copyright Notice + ================ + (c) Copyright JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc., + iMatix Corporation, IONA\ufffd Technologies, Red Hat, Inc., + TWIST Process Innovations, and 29West Inc. 2006. All rights reserved. + + License + ======= + JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc., iMatix + Corporation, IONA\ufffd Technologies, Red Hat, Inc., TWIST Process Innovations, and + 29West Inc. (collectively, the "Authors") each hereby grants to you a worldwide, + perpetual, royalty-free, nontransferable, nonexclusive license to + (i) copy, display, and implement the Advanced Messaging Queue Protocol + ("AMQP") Specification and (ii) the Licensed Claims that are held by + the Authors, all for the purpose of implementing the Advanced Messaging + Queue Protocol Specification. Your license and any rights under this + Agreement will terminate immediately without notice from + any Author if you bring any claim, suit, demand, or action related to + the Advanced Messaging Queue Protocol Specification against any Author. + Upon termination, you shall destroy all copies of the Advanced Messaging + Queue Protocol Specification in your possession or control. + + As used hereunder, "Licensed Claims" means those claims of a patent or + patent application, throughout the world, excluding design patents and + design registrations, owned or controlled, or that can be sublicensed + without fee and in compliance with the requirements of this + Agreement, by an Author or its affiliates now or at any + future time and which would necessarily be infringed by implementation + of the Advanced Messaging Queue Protocol Specification. A claim is + necessarily infringed hereunder only when it is not possible to avoid + infringing it because there is no plausible non-infringing alternative + for implementing the required portions of the Advanced Messaging Queue + Protocol Specification. Notwithstanding the foregoing, Licensed Claims + shall not include any claims other than as set forth above even if + contained in the same patent as Licensed Claims; or that read solely + on any implementations of any portion of the Advanced Messaging Queue + Protocol Specification that are not required by the Advanced Messaging + Queue Protocol Specification, or that, if licensed, would require a + payment of royalties by the licensor to unaffiliated third parties. + Moreover, Licensed Claims shall not include (i) any enabling technologies + that may be necessary to make or use any Licensed Product but are not + themselves expressly set forth in the Advanced Messaging Queue Protocol + Specification (e.g., semiconductor manufacturing technology, compiler + technology, object oriented technology, networking technology, operating + system technology, and the like); or (ii) the implementation of other + published standards developed elsewhere and merely referred to in the + body of the Advanced Messaging Queue Protocol Specification, or + (iii) any Licensed Product and any combinations thereof the purpose or + function of which is not required for compliance with the Advanced + Messaging Queue Protocol Specification. For purposes of this definition, + the Advanced Messaging Queue Protocol Specification shall be deemed to + include both architectural and interconnection requirements essential + for interoperability and may also include supporting source code artifacts + where such architectural, interconnection requirements and source code + artifacts are expressly identified as being required or documentation to + achieve compliance with the Advanced Messaging Queue Protocol Specification. + + As used hereunder, "Licensed Products" means only those specific portions + of products (hardware, software or combinations thereof) that implement + and are compliant with all relevant portions of the Advanced Messaging + Queue Protocol Specification. + + The following disclaimers, which you hereby also acknowledge as to any + use you may make of the Advanced Messaging Queue Protocol Specification: + + THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION IS PROVIDED "AS IS," + AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE + CONTENTS OF THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION ARE + SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF THE ADVANCED + MESSAGING QUEUE PROTOCOL SPECIFICATION WILL NOT INFRINGE ANY THIRD PARTY + PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + + THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, + INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO ANY + USE, IMPLEMENTATION OR DISTRIBUTION OF THE ADVANCED MESSAGING QUEUE + PROTOCOL SPECIFICATION. + + The name and trademarks of the Authors may NOT be used in any manner, + including advertising or publicity pertaining to the Advanced Messaging + Queue Protocol Specification or its contents without specific, written + prior permission. Title to copyright in the Advanced Messaging Queue + Protocol Specification will at all times remain with the Authors. + + No other rights are granted by implication, estoppel or otherwise. + + Upon termination of your license or rights under this Agreement, you + shall destroy all copies of the Advanced Messaging Queue Protocol + Specification in your possession or control. + + Trademarks + ========== + "JPMorgan", "JPMorgan Chase", "Chase", the JPMorgan Chase logo and the + Octagon Symbol are trademarks of JPMorgan Chase & Co. + + IMATIX and the iMatix logo are trademarks of iMatix Corporation sprl. + + IONA, IONA Technologies, and the IONA logos are trademarks of IONA + Technologies PLC and/or its subsidiaries. + + LINUX is a trademark of Linus Torvalds. RED HAT and JBOSS are registered + trademarks of Red Hat, Inc. in the US and other countries. + + Java, all Java-based trademarks and OpenOffice.org are trademarks of + Sun Microsystems, Inc. in the United States, other countries, or both. + + Other company, product, or service names may be trademarks or service + marks of others. + + Links to full AMQP specification: + ================================= + http://www.envoytech.org/spec/amq/ + http://www.iona.com/opensource/amqp/ + http://www.redhat.com/solutions/specifications/amqp/ + http://www.twiststandards.org/tiki-index.php?page=AMQ + http://www.imatix.com/amqp +--> + +<!-- + <!DOCTYPE amqp SYSTEM "amqp.dtd"> +--> + +<!-- XML Notes + + We use entities to indicate repetition; attributes to indicate properties. + + We use the 'name' attribute as an identifier, usually within the context + of the surrounding entities. + + We use spaces to seperate words in names, so that we can print names in + their natural form depending on the context - underlines for source code, + hyphens for written text, etc. + + We do not enforce any particular validation mechanism but we support all + mechanisms. The protocol definition conforms to a formal grammar that is + published seperately in several technologies. + + --> + +<amqp major = "0" minor = "10" port = "5672" comment = "AMQ Protocol"> + <!-- + ====================================================== + == CONSTANTS + ====================================================== + --> + <!-- Frame types --> + <constant name = "frame-method" value = "1" /> + <constant name = "frame-header" value = "2" /> + <constant name = "frame-body" value = "3" /> + <constant name = "frame-oob-method" value = "4" /> + <constant name = "frame-oob-header" value = "5" /> + <constant name = "frame-oob-body" value = "6" /> + <constant name = "frame-trace" value = "7" /> + <constant name = "frame-heartbeat" value = "8" /> + + <!-- Protocol constants --> + <constant name = "frame-min-size" value = "4096" /> + <constant name = "frame-end" value = "206" /> + + <!-- Reply codes --> + <constant name = "reply-success" value = "200"> + <doc> + Indicates that the method completed successfully. This reply code is + reserved for future use - the current protocol design does not use positive + confirmation and reply codes are sent only in case of an error. + </doc> + </constant> + + <constant name = "not-delivered" value = "310" class = "soft-error"> + <doc> + The client asked for a specific message that is no longer available. + The message was delivered to another client, or was purged from the queue + for some other reason. + </doc> + </constant> + + <constant name = "content-too-large" value = "311" class = "soft-error"> + <doc> + The client attempted to transfer content larger than the server could accept + at the present time. The client may retry at a later time. + </doc> + </constant> + + <constant name = "connection-forced" value = "320" class = "hard-error"> + <doc> + An operator intervened to close the connection for some reason. The client + may retry at some later date. + </doc> + </constant> + + <constant name = "invalid-path" value = "402" class = "hard-error"> + <doc> + The client tried to work with an unknown virtual host. + </doc> + </constant> + + <constant name = "access-refused" value = "403" class = "soft-error"> + <doc> + The client attempted to work with a server entity to which it has no + access due to security settings. + </doc> + </constant> + + <constant name = "not-found" value = "404" class = "soft-error"> + <doc>The client attempted to work with a server entity that does not exist.</doc> + </constant> + + <constant name = "resource-locked" value = "405" class = "soft-error"> + <doc> + The client attempted to work with a server entity to which it has no + access because another client is working with it. + </doc> + </constant> + + <constant name = "precondition-failed" value = "406" class = "soft-error"> + <doc> + The client requested a method that was not allowed because some precondition + failed. + </doc> + </constant> + + <constant name = "frame-error" value = "501" class = "hard-error"> + <doc> + The client sent a malformed frame that the server could not decode. This + strongly implies a programming error in the client. + </doc> + </constant> + + <constant name = "syntax-error" value = "502" class = "hard-error"> + <doc> + The client sent a frame that contained illegal values for one or more + fields. This strongly implies a programming error in the client. + </doc> + </constant> + + <constant name = "command-invalid" value = "503" class = "hard-error"> + <doc> + The client sent an invalid sequence of frames, attempting to perform an + operation that was considered invalid by the server. This usually implies + a programming error in the client. + </doc> + </constant> + + <constant name = "channel-error" value = "504" class = "hard-error"> + <doc> + The client attempted to work with a channel that had not been correctly + opened. This most likely indicates a fault in the client layer. + </doc> + </constant> + + <constant name = "resource-error" value = "506" class = "hard-error"> + <doc> + The server could not complete the method because it lacked sufficient + resources. This may be due to the client creating too many of some type + of entity. + </doc> + </constant> + + <constant name = "not-allowed" value = "530" class = "hard-error"> + <doc> + The client tried to work with some entity in a manner that is prohibited + by the server, due to security settings or by some other criteria. + </doc> + </constant> + + <constant name = "not-implemented" value = "540" class = "hard-error"> + <doc> + The client tried to use functionality that is not implemented in the + server. + </doc> + </constant> + + <constant name = "internal-error" value = "545" class = "hard-error"> + <doc> + The server could not complete the method because of an internal error. + The server may require intervention by an operator in order to resume + normal operations. + </doc> + </constant> + + <constant name = "test-double" value = "3.141592654"/> + <constant name = "test-str1" value = "hello, world!"/> + <constant name = "test-str2" value = "1.2.3.4"/> + + <!-- + ====================================================== + == DOMAIN TYPES + ====================================================== + --> + + <domain name = "access-ticket" type = "short" label = "access ticket granted by server"> + <doc> + An access ticket granted by the server for a certain set of access rights + within a specific realm. Access tickets are valid within the channel where + they were created, and expire when the channel closes. + </doc> + <assert check = "ne" value = "0" /> + </domain> + + <domain name = "class-id" type = "short" /> + + <domain name = "consumer-tag" type = "shortstr" label = "consumer tag"> + <doc> + Identifier for the consumer, valid within the current connection. + </doc> + </domain> + + <domain name = "delivery-tag" type = "longlong" label = "server-assigned delivery tag"> + <doc> + The server-assigned and channel-specific delivery tag + </doc> + <rule name = "channel-local"> + <doc> + The delivery tag is valid only within the channel from which the message was + received. I.e. a client MUST NOT receive a message on one channel and then + acknowledge it on another. + </doc> + </rule> + <rule name = "non-zero"> + <doc> + The server MUST NOT use a zero value for delivery tags. Zero is reserved + for client use, meaning "all messages so far received". + </doc> + </rule> + </domain> + + <domain name = "exchange-name" type = "shortstr" label = "exchange name"> + <doc> + The exchange name is a client-selected string that identifies the exchange for publish + methods. Exchange names may consist of any mixture of digits, letters, and underscores. + Exchange names are scoped by the virtual host. + </doc> + <assert check = "length" value = "127" /> + </domain> + + <domain name = "known-hosts" type = "shortstr" label = "list of known hosts"> + <doc> + Specifies the list of equivalent or alternative hosts that the server knows about, + which will normally include the current server itself. Clients can cache this + information and use it when reconnecting to a server after a failure. This field + may be empty. + </doc> + </domain> + + <domain name = "method-id" type = "long" /> + + <domain name = "no-ack" type = "bit" label = "no acknowledgement needed"> + <doc> + If this field is set the server does not expect acknowledgments for + messages. That is, when a message is delivered to the client the server + automatically and silently acknowledges it on behalf of the client. This + functionality increases performance but at the cost of reliability. + Messages can get lost if a client dies before it can deliver them to the + application. + </doc> + </domain> + + <domain name = "no-local" type = "bit" label = "do not deliver own messages"> + <doc> + If the no-local field is set the server will not send messages to the client that + published them. + </doc> + </domain> + + <domain name = "path" type = "shortstr"> + <doc> + Must start with a slash "/" and continue with path names separated by slashes. A path + name consists of any combination of at least one of [A-Za-z0-9] plus zero or more of + [.-_+!=:]. + </doc> + + <assert check = "notnull" /> + <assert check = "syntax" rule = "path" /> + <assert check = "length" value = "127" /> + </domain> + + <domain name = "peer-properties" type = "table"> + <doc> + This string provides a set of peer properties, used for identification, debugging, and + general information. + </doc> + </domain> + + <domain name = "queue-name" type = "shortstr" label = "queue name"> + <doc> + The queue name identifies the queue within the vhost. Queue names may consist of any + mixture of digits, letters, and underscores. + </doc> + <assert check = "length" value = "127" /> + </domain> + + <domain name = "redelivered" type = "bit" label = "message is being redelivered"> + <doc> + This indicates that the message has been previously delivered to this or + another client. + </doc> + <rule name = "implementation"> + <doc> + The server SHOULD try to signal redelivered messages when it can. When + redelivering a message that was not successfully acknowledged, the server + SHOULD deliver it to the original client if possible. + </doc> + <doc type = "scenario"> + Create a shared queue and publish a message to the queue. Consume the + message using explicit acknowledgements, but do not acknowledge the + message. Close the connection, reconnect, and consume from the queue + again. The message should arrive with the redelivered flag set. + </doc> + </rule> + <rule name = "hinting"> + <doc> + The client MUST NOT rely on the redelivered field but should take it as a + hint that the message may already have been processed. A fully robust + client must be able to track duplicate received messages on non-transacted, + and locally-transacted channels. + </doc> + </rule> + </domain> + + <domain name = "reply-code" type = "short" label = "reply code from server"> + <doc> + The reply code. The AMQ reply codes are defined as constants at the start + of this formal specification. + </doc> + <assert check = "notnull" /> + </domain> + + <domain name = "reply-text" type = "shortstr" label = "localised reply text"> + <doc> + The localised reply text. This text can be logged as an aid to resolving + issues. + </doc> + <assert check = "notnull" /> + </domain> + + <!-- Elementary domains --> + <domain name = "bit" type = "bit" label = "single bit" /> + <domain name = "octet" type = "octet" label = "single octet" /> + <domain name = "short" type = "short" label = "16-bit integer" /> + <domain name = "long" type = "long" label = "32-bit integer" /> + <domain name = "longlong" type = "longlong" label = "64-bit integer" /> + <domain name = "shortstr" type = "shortstr" label = "short string" /> + <domain name = "longstr" type = "longstr" label = "long string" /> + <domain name = "timestamp" type = "timestamp" label = "64-bit timestamp" /> + <domain name = "table" type = "table" label = "field table" /> + + <!-- == CONNECTION ======================================================= --> + + <!-- TODO 0.81 - the 'handler' attribute of methods needs to be reviewed, and if + no current implementations use it, removed. /PH 2006/07/20 + --> + + <class name = "connection" handler = "connection" index = "10" label = "work with socket connections"> + <doc> + The connection class provides methods for a client to establish a network connection to + a server, and for both peers to operate the connection thereafter. + </doc> + + <doc type = "grammar"> + connection = open-connection *use-connection close-connection + open-connection = C:protocol-header + S:START C:START-OK + *challenge + S:TUNE C:TUNE-OK + C:OPEN S:OPEN-OK | S:REDIRECT + challenge = S:SECURE C:SECURE-OK + use-connection = *channel + close-connection = C:CLOSE S:CLOSE-OK + / S:CLOSE C:CLOSE-OK + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "start" synchronous = "1" index = "10" label = "start connection negotiation"> + <doc> + This method starts the connection negotiation process by telling the client the + protocol version that the server proposes, along with a list of security mechanisms + which the client can use for authentication. + </doc> + + <rule name = "protocol-name"> + <doc> + If the server cannot support the protocol specified in the protocol header, + it MUST close the socket connection without sending any response method. + </doc> + <doc type = "scenario"> + The client sends a protocol header containing an invalid protocol name. + The server must respond by closing the connection. + </doc> + </rule> + <rule name = "server-support"> + <doc> + The server MUST provide a protocol version that is lower than or equal to + that requested by the client in the protocol header. + </doc> + <doc type = "scenario"> + The client requests a protocol version that is higher than any valid + implementation, e.g. 9.0. The server must respond with a current + protocol version, e.g. 1.0. + </doc> + </rule> + <rule name = "client-support"> + <doc> + If the client cannot handle the protocol version suggested by the server + it MUST close the socket connection. + </doc> + <doc type = "scenario"> + The server sends a protocol version that is lower than any valid + implementation, e.g. 0.1. The client must respond by closing the + connection. + </doc> + </rule> + + <chassis name = "client" implement = "MUST" /> + <response name = "start-ok" /> + + <field name = "version-major" domain = "octet" label = "protocol major version"> + <doc> + The version of the protocol, expressed in protocol units of 0.1 public + versions and properly printed as two digits with a leading zero. I.e. a + protocol version of "09" represents a public version "0.9". The decimal + shift allows the correct expression of pre-1.0 protocol releases. + </doc> + <doc type = "todo"> + This field should be renamed to "protocol version". + </doc> + </field> + + <field name = "version-minor" domain = "octet" label = "protocol major version"> + <doc> + The protocol revision, expressed as an integer from 0 to 9. The use of more + than ten revisions is discouraged. The public version string is constructed + from the protocol version and revision as follows: we print the protocol + version with one decimal position, and we append the protocol revision. A + version=10 and revision=2 are printed as "1.02". + </doc> + <doc type = "todo"> + This field should be renamed to "protocol revision". + </doc> + </field> + + <field name = "server-properties" domain = "peer-properties" label = "server properties"> + <rule name = "required-fields"> + <doc> + The properties SHOULD contain at least these fields: "host", specifying the + server host name or address, "product", giving the name of the server product, + "version", giving the name of the server version, "platform", giving the name + of the operating system, "copyright", if appropriate, and "information", giving + other general information. + </doc> + <doc type = "scenario"> + Client connects to server and inspects the server properties. It checks for + the presence of the required fields. + </doc> + </rule> + </field> + + <field name = "mechanisms" domain = "longstr" label = "available security mechanisms"> + <doc> + A list of the security mechanisms that the server supports, delimited by spaces. + Currently ASL supports these mechanisms: PLAIN. + </doc> + <assert check = "notnull" /> + </field> + + <field name = "locales" domain = "longstr" label = "available message locales"> + <doc> + A list of the message locales that the server supports, delimited by spaces. The + locale defines the language in which the server will send reply texts. + </doc> + <rule name = "required-support"> + <doc> + The server MUST support at least the en_US locale. + </doc> + <doc type = "scenario"> + Client connects to server and inspects the locales field. It checks for + the presence of the required locale(s). + </doc> + </rule> + <assert check = "notnull" /> + </field> + </method> + + <method name = "start-ok" synchronous = "1" index = "11" + label = "select security mechanism and locale"> + <doc> + This method selects a SASL security mechanism. ASL uses SASL (RFC2222) to + negotiate authentication and encryption. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "client-properties" domain = "peer-properties" label = "client properties"> + <rule name = "required-fields"> + <!-- This rule is not testable from the client side --> + <doc> + The properties SHOULD contain at least these fields: "product", giving the name + of the client product, "version", giving the name of the client version, "platform", + giving the name of the operating system, "copyright", if appropriate, and + "information", giving other general information. + </doc> + </rule> + </field> + + <field name = "mechanism" domain = "shortstr" label = "selected security mechanism"> + <doc> + A single security mechanisms selected by the client, which must be one of those + specified by the server. + </doc> + <rule name = "security"> + <doc> + The client SHOULD authenticate using the highest-level security profile it + can handle from the list provided by the server. + </doc> + </rule> + <rule name = "validity"> + <doc> + If the mechanism field does not contain one of the security mechanisms + proposed by the server in the Start method, the server MUST close the + connection without sending any further data. + </doc> + <doc type = "scenario"> + Client connects to server and sends an invalid security mechanism. The + server must respond by closing the connection (a socket close, with no + connection close negotiation). + </doc> + </rule> + <assert check = "notnull" /> + </field> + + <field name = "response" domain = "longstr" label = "security response data"> + <doc> + A block of opaque data passed to the security mechanism. The contents of this + data are defined by the SASL security mechanism. + </doc> + <assert check = "notnull" /> + </field> + + <field name = "locale" domain = "shortstr" label = "selected message locale"> + <doc> + A single message local selected by the client, which must be one of those + specified by the server. + </doc> + <assert check = "notnull" /> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "secure" synchronous = "1" index = "20" label = "security mechanism challenge"> + <doc> + The SASL protocol works by exchanging challenges and responses until both peers have + received sufficient information to authenticate each other. This method challenges + the client to provide more information. + </doc> + + <chassis name = "client" implement = "MUST" /> + <response name = "secure-ok" /> + + <field name = "challenge" domain = "longstr" label = "security challenge data"> + <doc> + Challenge information, a block of opaque binary data passed to the security + mechanism. + </doc> + </field> + </method> + + <method name = "secure-ok" synchronous = "1" index = "21" label = "security mechanism response"> + <doc> + This method attempts to authenticate, passing a block of SASL data for the security + mechanism at the server side. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "response" domain = "longstr" label = "security response data"> + <doc> + A block of opaque data passed to the security mechanism. The contents of this + data are defined by the SASL security mechanism. + </doc> + <assert check = "notnull" /> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "tune" synchronous = "1" index = "30" + label = "propose connection tuning parameters"> + <doc> + This method proposes a set of connection configuration values to the client. The + client can accept and/or adjust these. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <response name = "tune-ok" /> + + <field name = "channel-max" domain = "short" label = "proposed maximum channels"> + <doc> + The maximum total number of channels that the server allows per connection. Zero + means that the server does not impose a fixed limit, but the number of allowed + channels may be limited by available server resources. + </doc> + </field> + + <field name = "frame-max" domain = "long" label = "proposed maximum frame size"> + <doc> + The largest frame size that the server proposes for the connection. The client + can negotiate a lower value. Zero means that the server does not impose any + specific limit but may reject very large frames if it cannot allocate resources + for them. + </doc> + <rule name = "minimum"> + <doc> + Until the frame-max has been negotiated, both peers MUST accept frames of up + to frame-min-size octets large, and the minimum negotiated value for frame-max + is also frame-min-size. + </doc> + <doc type = "scenario"> + Client connects to server and sends a large properties field, creating a frame + of frame-min-size octets. The server must accept this frame. + </doc> + </rule> + </field> + + <field name = "heartbeat" domain = "short" label = "desired heartbeat delay"> + <!-- TODO 0.82 - the heartbeat negotiation mechanism was changed during + implementation because the model documented here does not actually + work properly. The best model we found is that the server proposes + a heartbeat value to the client; the client can reply with zero, meaning + 'do not use heartbeats (as documented here), or can propose its own + heartbeat value, which the server should then accept. This is different + from the model here which is disconnected - e.g. each side requests a + heartbeat independently. Basically a connection is heartbeated in + both ways, or not at all, depending on whether both peers support + heartbeating or not, and the heartbeat value should itself be chosen + by the client so that remote links can get a higher value. Also, the + actual heartbeat mechanism needs documentation, and is as follows: so + long as there is activity on a connection - in or out - both peers + assume the connection is active. When there is no activity, each peer + must send heartbeat frames. When no heartbeat frame is received after + N cycles (where N is at least 2), the connection can be considered to + have died. /PH 2006/07/19 + --> + <doc> + The delay, in seconds, of the connection heartbeat that the server wants. + Zero means the server does not want a heartbeat. + </doc> + </field> + </method> + + <method name = "tune-ok" synchronous = "1" index = "31" + label = "negotiate connection tuning parameters"> + <doc> + This method sends the client's connection tuning parameters to the server. + Certain fields are negotiated, others provide capability information. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "channel-max" domain = "short" label = "negotiated maximum channels"> + <doc> + The maximum total number of channels that the client will use per connection. + </doc> + <rule name = "upper-limit"> + <doc> + If the client specifies a channel max that is higher than the value provided + by the server, the server MUST close the connection without attempting a + negotiated close. The server may report the error in some fashion to assist + implementors. + </doc> + </rule> + <assert check = "notnull" /> + <assert check = "le" method = "tune" field = "channel-max" /> + </field> + + <field name = "frame-max" domain = "long" label = "negotiated maximum frame size"> + <doc> + The largest frame size that the client and server will use for the connection. + Zero means that the client does not impose any specific limit but may reject + very large frames if it cannot allocate resources for them. Note that the + frame-max limit applies principally to content frames, where large contents can + be broken into frames of arbitrary size. + </doc> + <rule name = "minimum"> + <doc> + Until the frame-max has been negotiated, both peers MUST accept frames of up + to frame-min-size octets large, and the minimum negotiated value for frame-max + is also frame-min-size. + </doc> + </rule> + <rule name = "upper-limit"> + <doc> + If the client specifies a frame max that is higher than the value provided + by the server, the server MUST close the connection without attempting a + negotiated close. The server may report the error in some fashion to assist + implementors. + </doc> + </rule> + </field> + + <field name = "heartbeat" domain = "short" label = "desired heartbeat delay"> + <doc> + The delay, in seconds, of the connection heartbeat that the client wants. Zero + means the client does not want a heartbeat. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "open" synchronous = "1" index = "40" label = "open connection to virtual host"> + <doc> + This method opens a connection to a virtual host, which is a collection of + resources, and acts to separate multiple application domains within a server. + The server may apply arbitrary limits per virtual host, such as the number + of each type of entity that may be used, per connection and/or in total. + </doc> + + <chassis name = "server" implement = "MUST" /> + <response name = "open-ok" /> + <response name = "redirect" /> + + <field name = "virtual-host" domain = "path" label = "virtual host name"> + <!-- TODO 0.82 - the entire vhost model needs review. This concept was + prompted by the HTTP vhost concept but does not fit very well into + AMQP. Currently we use the vhost as a "cluster identifier" which is + inaccurate usage. /PH 2006/07/19 + --> + <assert check = "regexp" value = "^[a-zA-Z0-9/-_]+$" /> + <doc> + The name of the virtual host to work with. + </doc> + <rule name = "separation"> + <doc> + If the server supports multiple virtual hosts, it MUST enforce a full + separation of exchanges, queues, and all associated entities per virtual + host. An application, connected to a specific virtual host, MUST NOT be able + to access resources of another virtual host. + </doc> + </rule> + <rule name = "security"> + <doc> + The server SHOULD verify that the client has permission to access the + specified virtual host. + </doc> + </rule> + </field> + + <field name = "capabilities" domain = "shortstr" label = "required capabilities"> + <doc> + The client can specify zero or more capability names, delimited by spaces. + The server can use this string to how to process the client's connection + request. + </doc> + </field> + + <field name = "insist" domain = "bit" label = "insist on connecting to server"> + <doc> + In a configuration with multiple collaborating servers, the server may respond + to a Connection.Open method with a Connection.Redirect. The insist option tells + the server that the client is insisting on a connection to the specified server. + </doc> + <rule name = "behaviour"> + <doc> + When the client uses the insist option, the server MUST NOT respond with a + Connection.Redirect method. If it cannot accept the client's connection + request it should respond by closing the connection with a suitable reply + code. + </doc> + </rule> + </field> + </method> + + <method name = "open-ok" synchronous = "1" index = "41" label = "signal that connection is ready"> + <doc> + This method signals to the client that the connection is ready for use. + </doc> + <chassis name = "client" implement = "MUST" /> + <field name = "known-hosts" domain = "known-hosts" /> + </method> + + <method name = "redirect" synchronous = "1" index = "42" label = "redirects client to other server"> + <doc> + This method redirects the client to another server, based on the requested virtual + host and/or capabilities. + </doc> + <rule name = "usage"> + <doc> + When getting the Connection.Redirect method, the client SHOULD reconnect to + the host specified, and if that host is not present, to any of the hosts + specified in the known-hosts list. + </doc> + </rule> + <chassis name = "client" implement = "MUST" /> + <field name = "host" domain = "shortstr" label = "server to connect to"> + <doc> + Specifies the server to connect to. This is an IP address or a DNS name, + optionally followed by a colon and a port number. If no port number is + specified, the client should use the default port number for the protocol. + </doc> + <assert check = "notnull" /> + </field> + <field name = "known-hosts" domain = "known-hosts" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "close" synchronous = "1" index = "50" label = "request a connection close"> + <doc> + This method indicates that the sender wants to close the connection. This may be + due to internal conditions (e.g. a forced shut-down) or due to an error handling + a specific method, i.e. an exception. When a close is due to an exception, the + sender provides the class and method id of the method which caused the exception. + </doc> + <!-- TODO: the connection close mechanism needs to be reviewed from the ODF + documentation and better expressed as rules here. /PH 2006/07/20 + --> + <rule name = "stability"> + <doc> + After sending this method any received method except the Close-OK method MUST + be discarded. + </doc> + </rule> + + <chassis name = "client" implement = "MUST" /> + <chassis name = "server" implement = "MUST" /> + <response name = "close-ok" /> + + <field name = "reply-code" domain = "reply-code" /> + <field name = "reply-text" domain = "reply-text" /> + + <field name = "class-id" domain = "class-id" label = "failing method class"> + <doc> + When the close is provoked by a method exception, this is the class of the + method. + </doc> + </field> + + <field name = "method-id" domain = "method-id" label = "failing method ID"> + <doc> + When the close is provoked by a method exception, this is the ID of the method. + </doc> + </field> + </method> + + <method name = "close-ok" synchronous = "1" index = "51" label = "confirm a connection close"> + <doc> + This method confirms a Connection.Close method and tells the recipient that it is + safe to release resources for the connection and close the socket. + </doc> + <rule name = "reporting"> + <doc> + A peer that detects a socket closure without having received a Close-Ok + handshake method SHOULD log the error. + </doc> + </rule> + <chassis name = "client" implement = "MUST" /> + <chassis name = "server" implement = "MUST" /> + </method> + </class> + + <!-- == CHANNEL ========================================================== --> + + <class name = "channel" handler = "channel" index = "20" label = "work with channels"> + <doc> + The channel class provides methods for a client to establish a channel to a + server and for both peers to operate the channel thereafter. + </doc> + + <doc type = "grammar"> + channel = open-channel *use-channel close-channel + open-channel = C:OPEN S:OPEN-OK + use-channel = C:FLOW S:FLOW-OK + / S:FLOW C:FLOW-OK + / S:ALERT + / functional-class + close-channel = C:CLOSE S:CLOSE-OK + / S:CLOSE C:CLOSE-OK + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "open" synchronous = "1" index = "10" label = "open a channel for use"> + <doc> + This method opens a channel to the server. + </doc> + <rule name = "state" on-failure = "channel-error"> + <doc> + The client MUST NOT use this method on an alread-opened channel. + </doc> + <doc type = "scenario"> + Client opens a channel and then reopens the same channel. + </doc> + </rule> + <chassis name = "server" implement = "MUST" /> + <response name = "open-ok" /> + <field name = "out of band" domain = "shortstr" label = "out-of-band settings"> + <doc> + Configures out-of-band transfers on this channel. The syntax and meaning of this + field will be formally defined at a later date. + </doc> + <assert check = "null" /> + </field> + </method> + + <method name = "open-ok" synchronous = "1" index = "11" label = "signal that the channel is ready"> + <doc> + This method signals to the client that the channel is ready for use. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "flow" synchronous = "1" index = "20" label = "enable/disable flow from peer"> + <doc> + This method asks the peer to pause or restart the flow of content data. This is a + simple flow-control mechanism that a peer can use to avoid oveflowing its queues or + otherwise finding itself receiving more messages than it can process. Note that this + method is not intended for window control. The peer that receives a disable flow + method should finish sending the current content frame, if any, then pause. + </doc> + + <rule name = "initial-state"> + <doc> + When a new channel is opened, it is active (flow is active). Some applications + assume that channels are inactive until started. To emulate this behaviour a + client MAY open the channel, then pause it. + </doc> + </rule> + + <rule name = "bidirectional"> + <doc> + When sending content frames, a peer SHOULD monitor the channel for incoming + methods and respond to a Channel.Flow as rapidly as possible. + </doc> + </rule> + + <rule name = "throttling"> + <doc> + A peer MAY use the Channel.Flow method to throttle incoming content data for + internal reasons, for example, when exchanging data over a slower connection. + </doc> + </rule> + + <rule name = "expected-behaviour"> + <doc> + The peer that requests a Channel.Flow method MAY disconnect and/or ban a peer + that does not respect the request. This is to prevent badly-behaved clients + from overwhelming a broker. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <response name = "flow-ok" /> + + <field name = "active" domain = "bit" label = "start/stop content frames"> + <doc> + If 1, the peer starts sending content frames. If 0, the peer stops sending + content frames. + </doc> + </field> + </method> + + <method name = "flow-ok" index = "21" label = "confirm a flow method"> + <doc> + Confirms to the peer that a flow command was received and processed. + </doc> + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + <field name = "active" domain = "bit" label = "current flow setting"> + <doc> + Confirms the setting of the processed flow method: 1 means the peer will start + sending or continue to send content frames; 0 means it will not. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <!-- TODO 0.82 - remove this method entirely + /PH 2006/07/20 + --> + <method name = "alert" index = "30" label = "send a non-fatal warning message"> + <doc> + This method allows the server to send a non-fatal warning to the client. This is + used for methods that are normally asynchronous and thus do not have confirmations, + and for which the server may detect errors that need to be reported. Fatal errors + are handled as channel or connection exceptions; non-fatal errors are sent through + this method. + </doc> + <chassis name = "client" implement = "MUST" /> + <field name = "reply-code" domain = "reply-code" /> + <field name = "reply-text" domain = "reply-text" /> + <field name = "details" domain = "table" label = "detailed information for warning"> + <doc> + A set of fields that provide more information about the problem. The meaning of + these fields are defined on a per-reply-code basis (TO BE DEFINED). + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "close" synchronous = "1" index = "40" label = "request a channel close"> + <doc> + This method indicates that the sender wants to close the channel. This may be due to + internal conditions (e.g. a forced shut-down) or due to an error handling a specific + method, i.e. an exception. When a close is due to an exception, the sender provides + the class and method id of the method which caused the exception. + </doc> + + <!-- TODO: the channel close behaviour needs to be reviewed from the ODF + documentation and better expressed as rules here. /PH 2006/07/20 + --> + <rule name = "stability"> + <doc> + After sending this method any received method except the Close-OK method MUST + be discarded. + </doc> + </rule> + + <chassis name = "client" implement = "MUST" /> + <chassis name = "server" implement = "MUST" /> + <response name = "close-ok" /> + + <field name = "reply-code" domain = "reply-code" /> + <field name = "reply-text" domain = "reply-text" /> + + <field name = "class-id" domain = "class-id" label = "failing method class"> + <doc> + When the close is provoked by a method exception, this is the class of the + method. + </doc> + </field> + + <field name = "method-id" domain = "method-id" label = "failing method ID"> + <doc> + When the close is provoked by a method exception, this is the ID of the method. + </doc> + </field> + </method> + + <method name = "close-ok" synchronous = "1" index = "41" label = "confirm a channel close"> + <doc> + This method confirms a Channel.Close method and tells the recipient that it is safe + to release resources for the channel and close the socket. + </doc> + <rule name = "reporting"> + <doc> + A peer that detects a socket closure without having received a Channel.Close-Ok + handshake method SHOULD log the error. + </doc> + </rule> + <chassis name = "client" implement = "MUST" /> + <chassis name = "server" implement = "MUST" /> + </method> + </class> + + <!-- == ACCESS =========================================================== --> + + <!-- TODO 0.82 - this class must be implemented by two teams before we can + consider it matured. + --> + + <class name = "access" handler = "connection" index = "30" label = "work with access tickets"> + <doc> + The protocol control access to server resources using access tickets. A + client must explicitly request access tickets before doing work. An access + ticket grants a client the right to use a specific set of resources - + called a "realm" - in specific ways. + </doc> + + <doc type = "grammar"> + access = C:REQUEST S:REQUEST-OK + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "request" synchronous = "1" index = "10" label = "request an access ticket"> + <doc> + This method requests an access ticket for an access realm. The server + responds by granting the access ticket. If the client does not have + access rights to the requested realm this causes a connection exception. + Access tickets are a per-channel resource. + </doc> + + <chassis name = "server" implement = "MUST" /> + <response name = "request-ok" /> + + <field name = "realm" domain = "shortstr" label = "name of requested realm"> + <doc> + Specifies the name of the realm to which the client is requesting access. + The realm is a configured server-side object that collects a set of + resources (exchanges, queues, etc.). If the channel has already requested + an access ticket onto this realm, the previous ticket is destroyed and a + new ticket is created with the requested access rights, if allowed. + </doc> + <rule name = "validity" on-failure = "access-refused"> + <doc> + The client MUST specify a realm that is known to the server. The server + makes an identical response for undefined realms as it does for realms + that are defined but inaccessible to this client. + </doc> + <doc type = "scenario"> + Client specifies an undefined realm. + </doc> + </rule> + </field> + + <field name = "exclusive" domain = "bit" label = "request exclusive access"> + <doc> + Request exclusive access to the realm, meaning that this will be the only + channel that uses the realm's resources. + </doc> + <rule name = "validity" on-failure = "access-refused"> + <doc> + The client MAY NOT request exclusive access to a realm that has active + access tickets, unless the same channel already had the only access + ticket onto that realm. + </doc> + <doc type = "scenario"> + Client opens two channels and requests exclusive access to the same realm. + </doc> + </rule> + </field> + <field name = "passive" domain = "bit" label = "request passive access"> + <doc> + Request message passive access to the specified access realm. Passive + access lets a client get information about resources in the realm but + not to make any changes to them. + </doc> + </field> + <field name = "active" domain = "bit" label = "request active access"> + <doc> + Request message active access to the specified access realm. Active access lets + a client get create and delete resources in the realm. + </doc> + </field> + <field name = "write" domain = "bit" label = "request write access"> + <doc> + Request write access to the specified access realm. Write access lets a client + publish messages to all exchanges in the realm. + </doc> + </field> + <field name = "read" domain = "bit" label = "request read access"> + <doc> + Request read access to the specified access realm. Read access lets a client + consume messages from queues in the realm. + </doc> + </field> + </method> + + <method name = "request-ok" synchronous = "1" index = "11" label = "grant access to server resources"> + <doc> + This method provides the client with an access ticket. The access ticket is valid + within the current channel and for the lifespan of the channel. + </doc> + <rule name = "per-channel" on-failure = "not-allowed"> + <doc> + The client MUST NOT use access tickets except within the same channel as + originally granted. + </doc> + <doc type = "scenario"> + Client opens two channels, requests a ticket on one channel, and then + tries to use that ticket in a seconc channel. + </doc> + </rule> + <chassis name = "client" implement = "MUST" /> + <field name = "ticket" domain = "access-ticket" /> + </method> + </class> + + <!-- == EXCHANGE ========================================================= --> + + <class name = "exchange" handler = "channel" index = "40" label = "work with exchanges"> + <doc> + Exchanges match and distribute messages across queues. Exchanges can be configured in + the server or created at runtime. + </doc> + + <doc type = "grammar"> + exchange = C:DECLARE S:DECLARE-OK + / C:DELETE S:DELETE-OK + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <rule name = "required-types"> + <doc> + The server MUST implement these standard exchange types: fanout, direct. + </doc> + <doc type = "scenario"> + Client attempts to declare an exchange with each of these standard types. + </doc> + </rule> + <rule name = "recommended-types"> + <doc> + The server SHOULD implement these standard exchange types: topic, headers. + </doc> + <doc type = "scenario"> + Client attempts to declare an exchange with each of these standard types. + </doc> + </rule> + <rule name = "required-instances"> + <doc> + The server MUST, in each virtual host, pre-declare an exchange instance + for each standard exchange type that it implements, where the name of the + exchange instance is "amq." followed by the exchange type name. + </doc> + <doc type = "scenario"> + Client creates a temporary queue and attempts to bind to each required + exchange instance (amq.fanout, amq.direct, and amq.topic, amq.headers if + those types are defined). + </doc> + </rule> + <rule name = "default-exchange"> + <doc> + The server MUST predeclare a direct exchange to act as the default exchange + for content Publish methods and for default queue bindings. + </doc> + <doc type = "scenario"> + Client checks that the default exchange is active by specifying a queue + binding with no exchange name, and publishing a message with a suitable + routing key but without specifying the exchange name, then ensuring that + the message arrives in the queue correctly. + </doc> + </rule> + <rule name = "default-access"> + <doc> + The server MUST NOT allow clients to access the default exchange except + by specifying an empty exchange name in the Queue.Bind and content Publish + methods. + </doc> + </rule> + <rule name = "extensions"> + <doc> + The server MAY implement other exchange types as wanted. + </doc> + </rule> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "declare" synchronous = "1" index = "10" label = "declare exchange, create if needed"> + <doc> + This method creates an exchange if it does not already exist, and if the exchange + exists, verifies that it is of the correct and expected class. + </doc> + <rule name = "minimum"> + <doc> + The server SHOULD support a minimum of 16 exchanges per virtual host and + ideally, impose no limit except as defined by available resources. + </doc> + <doc type = "scenario"> + The client creates as many exchanges as it can until the server reports + an error; the number of exchanges successfuly created must be at least + sixteen. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + <response name = "declare-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <doc> + When a client defines a new exchange, this belongs to the access realm of the + ticket used. All further work done with that exchange must be done with an + access ticket for the same realm. + </doc> + <rule name = "validity" on-failure = "access-refused"> + <doc> + The client MUST provide a valid access ticket giving "active" access to + the realm in which the exchange exists or will be created, or "passive" + access if the if-exists flag is set. + </doc> + <doc type = "scenario"> + Client creates access ticket with wrong access rights and attempts to use + in this method. + </doc> + </rule> + </field> + + <field name = "exchange" domain = "exchange-name"> + <rule name = "reserved" on-failure = "access-refused"> + <doc> + Exchange names starting with "amq." are reserved for predeclared and + standardised exchanges. The client MUST NOT attempt to create an exchange + starting with "amq.". + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + <assert check = "regexp" value = "^[a-zA-Z0-9-_.:]+$" /> + </field> + + <field name = "type" domain = "shortstr" label = "exchange type"> + <doc> + Each exchange belongs to one of a set of exchange types implemented by the + server. The exchange types define the functionality of the exchange - i.e. how + messages are routed through it. It is not valid or meaningful to attempt to + change the type of an existing exchange. + </doc> + <rule name = "typed" on-failure = "not-allowed"> + <doc> + Exchanges cannot be redeclared with different types. The client MUST not + attempt to redeclare an existing exchange with a different type than used + in the original Exchange.Declare method. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + <rule name = "support" on-failure = "command-invalid"> + <doc> + The client MUST NOT attempt to create an exchange with a type that the + server does not support. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + <assert check = "regexp" value = "^[a-zA-Z0-9-_.:]+$" /> + </field> + + <field name = "passive" domain = "bit" label = "do not create exchange"> + <doc> + If set, the server will not create the exchange. The client can use this to + check whether an exchange exists without modifying the server state. + </doc> + <rule name = "not-found"> + <doc> + If set, and the exchange does not already exist, the server MUST raise a + channel exception with reply code 404 (not found). + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "durable" domain = "bit" label = "request a durable exchange"> + <doc> + If set when creating a new exchange, the exchange will be marked as durable. + Durable exchanges remain active when a server restarts. Non-durable exchanges + (transient exchanges) are purged if/when a server restarts. + </doc> + <rule name = "support"> + <doc> + The server MUST support both durable and transient exchanges. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + <rule name = "sticky"> + <doc> + The server MUST ignore the durable field if the exchange already exists. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <!-- TODO 0.82 - clarify how this works; there is no way to cancel a binding + except by deleting a queue. + --> + <field name = "auto-delete" domain = "bit" label = "auto-delete when unused"> + <doc> + If set, the exchange is deleted when all queues have finished using it. + </doc> + <rule name = "sticky"> + <doc> + The server MUST ignore the auto-delete field if the exchange already + exists. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "internal" domain = "bit" label = "create internal exchange"> + <doc> + If set, the exchange may not be used directly by publishers, but only when bound + to other exchanges. Internal exchanges are used to construct wiring that is not + visible to applications. + </doc> + </field> + + <field name = "arguments" domain = "table" label = "arguments for declaration"> + <doc> + A set of arguments for the declaration. The syntax and semantics of these + arguments depends on the server implementation. This field is ignored if passive + is 1. + </doc> + </field> + </method> + + <method name = "declare-ok" synchronous = "1" index = "11" label = "confirm exchange declaration"> + <doc> + This method confirms a Declare method and confirms the name of the exchange, + essential for automatically-named exchanges. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "delete" synchronous = "1" index = "20" label = "delete an exchange"> + <doc> + This method deletes an exchange. When an exchange is deleted all queue bindings on + the exchange are cancelled. + </doc> + + <chassis name = "server" implement = "MUST" /> + <response name = "delete-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "validity" on-failure = "access-refused"> + <doc> + The client MUST provide a valid access ticket giving "active" access + rights to the exchange's access realm. + </doc> + <doc type = "scenario"> + Client creates access ticket with wrong access rights and attempts to use + in this method. + </doc> + </rule> + </field> + + <field name = "exchange" domain = "exchange-name"> + <rule name = "exists" on-failure = "not-found"> + <doc> + The client MUST NOT attempt to delete an exchange that does not exist. + </doc> + </rule> + <assert check = "notnull" /> + </field> + + <!-- TODO 0.82 - discuss whether this option is useful or not. I don't have + any real use case for it. /PH 2006-07-23. + --> + <field name = "if-unused" domain = "bit" label = "delete only if unused"> + <doc> + If set, the server will only delete the exchange if it has no queue bindings. If + the exchange has queue bindings the server does not delete it but raises a + channel exception instead. + </doc> + </field> + </method> + + <method name = "delete-ok" synchronous = "1" index = "21" + label = "confirm deletion of an exchange"> + <doc>This method confirms the deletion of an exchange.</doc> + <chassis name = "client" implement = "MUST" /> + </method> + </class> + + <!-- == QUEUE ============================================================ --> + + <class name = "queue" handler = "channel" index = "50" label = "work with queues"> + <doc> + Queues store and forward messages. Queues can be configured in the server or created at + runtime. Queues must be attached to at least one exchange in order to receive messages + from publishers. + </doc> + + <doc type = "grammar"> + queue = C:DECLARE S:DECLARE-OK + / C:BIND S:BIND-OK + / C:PURGE S:PURGE-OK + / C:DELETE S:DELETE-OK + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <rule name = "any-content"> + <doc> + A server MUST allow any content class to be sent to any queue, in any mix, and + queue and deliver these content classes independently. Note that all methods + that fetch content off queues are specific to a given content class. + </doc> + <doc type = "scenario"> + Client creates an exchange of each standard type and several queues that + it binds to each exchange. It must then sucessfully send each of the standard + content types to each of the available queues. + </doc> + </rule> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "declare" synchronous = "1" index = "10" label = "declare queue, create if needed"> + <doc> + This method creates or checks a queue. When creating a new queue the client can + specify various properties that control the durability of the queue and its + contents, and the level of sharing for the queue. + </doc> + + <rule name = "default-binding"> + <doc> + The server MUST create a default binding for a newly-created queue to the + default exchange, which is an exchange of type 'direct'. + </doc> + <doc type = "scenario"> + Client creates a new queue, and then without explicitly binding it to an + exchange, attempts to send a message through the default exchange binding, + i.e. publish a message to the empty exchange, with the queue name as routing + key. + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_35" --> + <rule name = "minimum-queues"> + <doc> + The server SHOULD support a minimum of 256 queues per virtual host and ideally, + impose no limit except as defined by available resources. + </doc> + <doc type = "scenario"> + Client attempts to create as many queues as it can until the server reports + an error. The resulting count must at least be 256. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + <response name = "declare-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <doc> + When a client defines a new queue, this belongs to the access realm of the + ticket used. All further work done with that queue must be done with an access + ticket for the same realm. + </doc> + <rule name = "validity" on-failure = "access-refused"> + <doc> + The client MUST provide a valid access ticket giving "active" access to + the realm in which the queue exists or will be created. + </doc> + <doc type = "scenario"> + Client creates access ticket with wrong access rights and attempts to use + in this method. + </doc> + </rule> + </field> + + <field name = "queue" domain = "queue-name"> + <rule name = "default-name"> + <doc> + The queue name MAY be empty, in which case the server MUST create a new + queue with a unique generated name and return this to the client in the + Declare-Ok method. + </doc> + <doc type = "scenario"> + Client attempts to create several queues with an empty name. The client then + verifies that the server-assigned names are unique and different. + </doc> + </rule> + <rule name = "reserved-prefix" on-failure = "not-allowed"> + <doc> + Queue names starting with "amq." are reserved for predeclared and + standardised server queues. A client MAY NOT attempt to declare a queue with a + name that starts with "amq." and the passive option set to zero. + </doc> + <doc type = "scenario"> + A client attempts to create a queue with a name starting with "amq." and with + the passive option set to zero. + </doc> + </rule> + <assert check = "regexp" value = "^[a-zA-Z0-9-_.:]*$" /> + </field> + + <field name = "passive" domain = "bit" label = "do not create queue"> + <doc> + If set, the server will not create the queue. This field allows the client + to assert the presence of a queue without modifying the server state. + </doc> + <rule name = "passive" on-failure = "not-found"> + <doc> + The client MAY ask the server to assert that a queue exists without + creating the queue if not. If the queue does not exist, the server + treats this as a failure. + </doc> + <doc type = "scenario"> + Client declares an existing queue with the passive option and expects + the server to respond with a declare-ok. Client then attempts to declare + a non-existent queue with the passive option, and the server must close + the channel with the correct reply-code. + </doc> + </rule> + </field> + + <field name = "durable" domain = "bit" label = "request a durable queue"> + <doc> + If set when creating a new queue, the queue will be marked as durable. Durable + queues remain active when a server restarts. Non-durable queues (transient + queues) are purged if/when a server restarts. Note that durable queues do not + necessarily hold persistent messages, although it does not make sense to send + persistent messages to a transient queue. + </doc> + <!-- Rule test name: was "amq_queue_03" --> + <rule name = "persistence"> + <doc>The server MUST recreate the durable queue after a restart.</doc> + + <!-- TODO: use 'client does something' rather than 'a client does something'. --> + <doc type = "scenario"> + A client creates a durable queue. The server is then restarted. The client + then attempts to send a message to the queue. The message should be successfully + delivered. + </doc> + </rule> + <!-- Rule test name: was "amq_queue_36" --> + <rule name = "types"> + <doc>The server MUST support both durable and transient queues.</doc> + <doc type = "scenario"> + A client creates two named queues, one durable and one transient. + </doc> + </rule> + <!-- Rule test name: was "amq_queue_37" --> + <rule name = "pre-existence"> + <doc>The server MUST ignore the durable field if the queue already exists.</doc> + <doc type = "scenario"> + A client creates two named queues, one durable and one transient. The client + then attempts to declare the two queues using the same names again, but reversing + the value of the durable flag in each case. Verify that the queues still exist + with the original durable flag values. + <!-- TODO: but how? --> + </doc> + </rule> + </field> + + <field name = "exclusive" domain = "bit" label = "request an exclusive queue"> + <doc> + Exclusive queues may only be consumed from by the current connection. Setting + the 'exclusive' flag always implies 'auto-delete'. + </doc> + + <!-- Rule test name: was "amq_queue_38" --> + <rule name = "types"> + <doc> + The server MUST support both exclusive (private) and non-exclusive (shared) + queues. + </doc> + <doc type = "scenario"> + A client creates two named queues, one exclusive and one non-exclusive. + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_04" --> + <rule name = "02" on-failure = "channel-error"> + <doc> + The client MAY NOT attempt to declare any existing and exclusive queue + on multiple connections. + </doc> + <doc type = "scenario"> + A client declares an exclusive named queue. A second client on a different + connection attempts to declare a queue of the same name. + </doc> + </rule> + </field> + + <field name = "auto-delete" domain = "bit" label = "auto-delete queue when unused"> + <doc> + If set, the queue is deleted when all consumers have finished using it. Last + consumer can be cancelled either explicitly or because its channel is closed. If + there was no consumer ever on the queue, it won't be deleted. + </doc> + + <!-- Rule test name: was "amq_queue_31" --> + <rule name = "pre-existence"> + <doc> + The server MUST ignore the auto-delete field if the queue already exists. + </doc> + <doc type = "scenario"> + A client creates two named queues, one as auto-delete and one explicit-delete. + The client then attempts to declare the two queues using the same names again, + but reversing the value of the auto-delete field in each case. Verify that the + queues still exist with the original auto-delete flag values. + <!-- TODO: but how? --> + </doc> + </rule> + </field> + + <field name = "arguments" domain = "table" label = "arguments for declaration"> + <doc> + A set of arguments for the declaration. The syntax and semantics of these + arguments depends on the server implementation. This field is ignored if passive + is 1. + </doc> + </field> + </method> + + <method name = "declare-ok" synchronous = "1" index = "11" label = "confirms a queue definition"> + <doc> + This method confirms a Declare method and confirms the name of the queue, essential + for automatically-named queues. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "queue" domain = "queue-name"> + <doc> + Reports the name of the queue. If the server generated a queue name, this field + contains that name. + </doc> + <assert check = "notnull" /> + </field> + + <field name = "message-count" domain = "long" label = "number of messages in queue"> + <doc> + Reports the number of messages in the queue, which will be zero for + newly-created queues. + </doc> + </field> + + <field name = "consumer-count" domain = "long" label = "number of consumers"> + <doc> + Reports the number of active consumers for the queue. Note that consumers can + suspend activity (Channel.Flow) in which case they do not appear in this count. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "bind" synchronous = "1" index = "20" label = "bind queue to an exchange"> + <doc> + This method binds a queue to an exchange. Until a queue is bound it will not receive + any messages. In a classic messaging model, store-and-forward queues are bound to a + dest exchange and subscription queues are bound to a dest_wild exchange. + </doc> + + <!-- Rule test name: was "amq_queue_25" --> + <rule name = "duplicates"> + <doc> + A server MUST allow ignore duplicate bindings - that is, two or more bind + methods for a specific queue, with identical arguments - without treating these + as an error. + </doc> + <doc type = "scenario"> + A client binds a named queue to an exchange. The client then repeats the bind + (with identical arguments). + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_39" --> + <rule name = "failure" on-failure = "??????"> + <!-- + TODO: Find correct code. The on-failure code returned should depend on why the bind + failed. Assuming that failures owing to bad parameters are covered in the rules relating + to those parameters, the only remaining reason for a failure would be the lack of + server resorces or some internal error - such as too many queues open. Would these + cases qualify as "resource error" 506 or "internal error" 541? + --> + <doc>If a bind fails, the server MUST raise a connection exception.</doc> + <doc type = "scenario"> + TODO + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_12" --> + <rule name = "transient-exchange" on-failure = "not-allowed"> + <doc> + The server MUST NOT allow a durable queue to bind to a transient exchange. + </doc> + <doc type = "scenario"> + A client creates a transient exchange. The client then declares a named durable + queue and then attempts to bind the transient exchange to the durable queue. + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_13" --> + <rule name = "durable-exchange"> + <doc> + Bindings for durable queues are automatically durable and the server SHOULD + restore such bindings after a server restart. + </doc> + <doc type = "scenario"> + A server creates a named durable queue and binds it to a durable exchange. The + server is restarted. The client then attempts to use the queue/exchange combination. + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_17" --> + <rule name = "internal-exchange"> + <doc> + If the client attempts to bind to an exchange that was declared as internal, the server + MUST raise a connection exception with reply code 530 (not allowed). + </doc> + <doc type = "scenario"> + A client attempts to bind a named queue to an internal exchange. + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_40" --> + <rule name = "binding-count"> + <doc> + The server SHOULD support at least 4 bindings per queue, and ideally, impose no + limit except as defined by available resources. + </doc> + <doc type = "scenario"> + A client creates a named queue and attempts to bind it to 4 different non-internal + exchanges. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <response name = "bind-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <doc> + The client provides a valid access ticket giving "active" access rights to the + queue's access realm. + </doc> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to bind. If the queue name is empty, refers to + the current queue for the channel, which is the last declared queue. + </doc> + + <rule name = "empty-queue" on-failure = "not-allowed"> + <doc> + A client MUST NOT be allowed to bind a non-existent and unnamed queue (i.e. + empty queue name) to an exchange. + </doc> + <doc type = "scenario"> + A client attempts to bind with an unnamed (empty) queue name to an exchange. + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_26" --> + <rule name = "queue-existence" on-failure = "not-found"> + <doc> + A client MUST NOT be allowed to bind a non-existent queue (i.e. not previously + declared) to an exchange. + </doc> + <doc type = "scenario"> + A client attempts to bind an undeclared queue name to an exchange. + </doc> + </rule> + </field> + + <field name = "exchange" domain = "exchange-name" label = "name of the exchange to bind to"> + <!-- Rule test name: was "amq_queue_14" --> + <rule name = "exchange-existence" on-failure = "not-found"> + <doc> + A client MUST NOT be allowed to bind a queue to a non-existent exchange. + </doc> + <doc type = "scenario"> + A client attempts to bind an named queue to a undeclared exchange. + </doc> + </rule> + </field> + + <field name = "routing-key" domain = "shortstr" label = "message routing key"> + <doc> + Specifies the routing key for the binding. The routing key is used for routing + messages depending on the exchange configuration. Not all exchanges use a + routing key - refer to the specific exchange documentation. If the queue name + is empty, the server uses the last queue declared on the channel. If the + routing key is also empty, the server uses this queue name for the routing + key as well. If the queue name is provided but the routing key is empty, the + server does the binding with that empty routing key. The meaning of empty + routing keys depends on the exchange implementation. + </doc> + </field> + + <field name = "arguments" domain = "table" label = "arguments for binding"> + <doc> + A set of arguments for the binding. The syntax and semantics of these arguments + depends on the exchange class. + </doc> + </field> + </method> + + <method name = "bind-ok" synchronous = "1" index = "21" label = "confirm bind successful"> + <doc>This method confirms that the bind was successful.</doc> + + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "purge" synchronous = "1" index = "30" label = "purge a queue"> + <doc> + This method removes all messages from a queue. It does not cancel consumers. Purged + messages are deleted without any formal "undo" mechanism. + </doc> + + <!-- Rule test name: was "amq_queue_15" --> + <rule name = "01"> + <doc>A call to purge MUST result in an empty queue.</doc> + </rule> + + <!-- Rule test name: was "amq_queue_41" --> + <rule name = "02"> + <doc> + On transacted channels the server MUST not purge messages that have already been + sent to a client but not yet acknowledged. + </doc> + </rule> + + <!-- TODO: Rule split? --> + + <!-- Rule test name: was "amq_queue_42" --> + <rule name = "03"> + <doc> + The server MAY implement a purge queue or log that allows system administrators + to recover accidentally-purged messages. The server SHOULD NOT keep purged + messages in the same storage spaces as the live messages since the volumes of + purged messages may get very large. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <response name = "purge-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <doc>The access ticket must be for the access realm that holds the queue.</doc> + + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "read" access rights to + the queue's access realm. Note that purging a queue is equivalent to reading + all messages and discarding them. + </doc> + </rule> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to purge. If the queue name is empty, refers to + the current queue for the channel, which is the last declared queue. + </doc> + + <rule name = "01"> + <doc> + If the client did not previously declare a queue, and the queue name in this + method is empty, the server MUST raise a connection exception with reply + code 530 (not allowed). + </doc> + </rule> + + <!-- TODO Rule split? --> + + <!-- Rule test name: was "amq_queue_16" --> + <rule name = "02"> + <doc> + The queue MUST exist. Attempting to purge a non-existing queue MUST cause a + channel exception. + </doc> + </rule> + </field> + </method> + + <method name = "purge-ok" synchronous = "1" index = "31" label = "confirms a queue purge"> + <doc>This method confirms the purge of a queue.</doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "message-count" domain = "long" label = "number of messages purged"> + <doc>Reports the number of messages purged.</doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "delete" synchronous = "1" index = "40" label = "delete a queue"> + <doc> + This method deletes a queue. When a queue is deleted any pending messages are sent + to a dead-letter queue if this is defined in the server configuration, and all + consumers on the queue are cancelled. + </doc> + + <!-- TODO: Rule split? --> + + <!-- Rule test name: was "amq_queue_43" --> + <rule name = "01"> + <doc> + The server SHOULD use a dead-letter queue to hold messages that were pending on + a deleted queue, and MAY provide facilities for a system administrator to move + these messages back to an active queue. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <response name = "delete-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <doc> + The client provides a valid access ticket giving "active" access rights to the + queue's access realm. + </doc> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to delete. If the queue name is empty, refers to + the current queue for the channel, which is the last declared queue. + </doc> + + <rule name = "01"> + <doc> + If the client did not previously declare a queue, and the queue name in this + method is empty, the server MUST raise a connection exception with reply + code 530 (not allowed). + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_21" --> + <rule name = "02"> + <doc> + The queue must exist. If the client attempts to delete a non-existing queue + the server MUST raise a channel exception with reply code 404 (not found). + </doc> + </rule> + </field> + + <field name = "if-unused" domain = "bit" label = "delete only if unused"> + <doc> + If set, the server will only delete the queue if it has no consumers. If the + queue has consumers the server does does not delete it but raises a channel + exception instead. + </doc> + + <!-- Rule test name: was "amq_queue_29" and "amq_queue_30" --> + <rule name = "01"> + <doc>The server MUST respect the if-unused flag when deleting a queue.</doc> + </rule> + </field> + + <field name = "if-empty" domain = "bit" label = "delete only if empty"> + <doc> + If set, the server will only delete the queue if it has no messages. + </doc> + <rule name = "01"> + <doc> + If the queue is not empty the server MUST raise a channel exception with + reply code 406 (precondition failed). + </doc> + </rule> + </field> + </method> + + <method name = "delete-ok" synchronous = "1" index = "41" label = "confirm deletion of a queue"> + <doc>This method confirms the deletion of a queue.</doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "message-count" domain = "long" label = "number of messages purged"> + <doc>Reports the number of messages purged.</doc> + </field> + </method> + </class> + + <!-- == BASIC ============================================================ --> + + <class name = "basic" handler = "channel" index = "60" label = "work with basic content"> + <doc> + The Basic class provides methods that support an industry-standard messaging model. + </doc> + + <doc type = "grammar"> + basic = C:QOS S:QOS-OK + / C:CONSUME S:CONSUME-OK + / C:CANCEL S:CANCEL-OK + / C:PUBLISH content + / S:RETURN content + / S:DELIVER content + / C:GET ( S:GET-OK content / S:GET-EMPTY ) + / C:ACK + / C:REJECT + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MAY" /> + + <!-- Rule test name: was "amq_basic_08" --> + <rule name = "01"> + <doc> + The server SHOULD respect the persistent property of basic messages and + SHOULD make a best-effort to hold persistent basic messages on a reliable + storage mechanism. + </doc> + <doc type = "scenario"> + Send a persistent message to queue, stop server, restart server and then + verify whether message is still present. Assumes that queues are durable. + Persistence without durable queues makes no sense. + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_09" --> + <rule name = "02"> + <doc> + The server MUST NOT discard a persistent basic message in case of a queue + overflow. + </doc> + <doc type = "scenario"> + Create a queue overflow situation with persistent messages and verify that + messages do not get lost (presumably the server will write them to disk). + </doc> + </rule> + + <rule name = "03"> + <doc> + The server MAY use the Channel.Flow method to slow or stop a basic message + publisher when necessary. + </doc> + <doc type = "scenario"> + Create a queue overflow situation with non-persistent messages and verify + whether the server responds with Channel.Flow or not. Repeat with persistent + messages. + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_10" --> + <rule name = "04"> + <doc> + The server MAY overflow non-persistent basic messages to persistent + storage. + </doc> + <!-- Test scenario: untestable --> + </rule> + + <rule name = "05"> + <doc> + The server MAY discard or dead-letter non-persistent basic messages on a + priority basis if the queue size exceeds some configured limit. + </doc> + <!-- Test scenario: untestable --> + </rule> + + <!-- Rule test name: was "amq_basic_11" --> + <rule name = "06"> + <doc> + The server MUST implement at least 2 priority levels for basic messages, + where priorities 0-4 and 5-9 are treated as two distinct levels. + </doc> + <doc type = "scenario"> + Send a number of priority 0 messages to a queue. Send one priority 9 + message. Consume messages from the queue and verify that the first message + received was priority 9. + </doc> + </rule> + + <rule name = "07"> + <doc> + The server MAY implement up to 10 priority levels. + </doc> + <doc type = "scenario"> + Send a number of messages with mixed priorities to a queue, so that all + priority values from 0 to 9 are exercised. A good scenario would be ten + messages in low-to-high priority. Consume from queue and verify how many + priority levels emerge. + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_12" --> + <rule name = "08"> + <doc> + The server MUST deliver messages of the same priority in order irrespective of + their individual persistence. + </doc> + <doc type = "scenario"> + Send a set of messages with the same priority but different persistence + settings to a queue. Consume and verify that messages arrive in same order + as originally published. + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_13" --> + <rule name = "09"> + <doc> + The server MUST support automatic acknowledgements on Basic content, i.e. + consumers with the no-ack field set to FALSE. + </doc> + <doc type = "scenario"> + Create a queue and a consumer using automatic acknowledgements. Publish + a set of messages to the queue. Consume the messages and verify that all + messages are received. + </doc> + </rule> + + <rule name = "10"> + <doc> + The server MUST support explicit acknowledgements on Basic content, i.e. + consumers with the no-ack field set to TRUE. + </doc> + <doc type = "scenario"> + Create a queue and a consumer using explicit acknowledgements. Publish a + set of messages to the queue. Consume the messages but acknowledge only + half of them. Disconnect and reconnect, and consume from the queue. + Verify that the remaining messages are received. + </doc> + </rule> + + <!-- These are the properties for a Basic content --> + + <field name = "content-type" domain = "shortstr" label = "MIME content type" /> + <field name = "content-encoding" domain = "shortstr" label = "MIME content encoding" /> + <field name = "headers" domain = "table" label = "message header field table" /> + <field name = "delivery-mode" domain = "octet" label = "non-persistent (1) or persistent (2)" /> + <field name = "priority" domain = "short" label = "message priority, 0 to 9" /> + <field name = "correlation-id" domain = "shortstr" label = "application correlation identifier" /> + <field name = "reply-to" domain = "shortstr" label = "destination to reply to" /> + <field name = "expiration" domain = "shortstr" label = "message expiration specification" /> + <field name = "timestamp" domain = "timestamp" label = "message timestamp" /> + <field name = "message-id" domain = "shortstr" label = "application message identifier" /> + <field name = "type" domain = "shortstr" label = "message type name" /> + <field name = "user-id" domain = "shortstr" label = "creating user id" /> + <field name = "app-id" domain = "shortstr" label = "creating application id" /> + <!-- This field is deprecated pending review --> + <field name = "cluster-id" domain = "shortstr" label = "intra-cluster routing identifier" /> + + <!-- Type diversity test --> + <field name = "property-bit" domain = "bit" label = "Extra property for testing only" /> + <field name = "property-octet" domain = "octet" label = "Extra property for testing only" /> + <field name = "property-short" domain = "short" label = "Extra property for testing only" /> + <field name = "property-long" domain = "long" label = "Extra property for testing only" /> + <field name = "property-longlong" domain = "longlong" label = "Extra property for testing only" /> + <field name = "property-shortstr" domain = "shortstr" label = "Extra property for testing only" /> + <field name = "property-longstr" domain = "longstr" label = "Extra property for testing only" /> + <field name = "property-timestamp" domain = "timestamp" label = "Extra property for testing only" /> + <field name = "property-table" domain = "table" label = "Extra property for testing only" /> + <field name = "property-access-ticket" domain = "access-ticket" label = "Extra property for testing only" /> + <field name = "property-class-id" domain = "class-id" label = "Extra property for testing only" /> + <field name = "property-consumer-tag" domain = "consumer-tag" label = "Extra property for testing only" /> + <field name = "property-delivery-tag" domain = "delivery-tag" label = "Extra property for testing only" /> + <field name = "property-exchange-name" domain = "exchange-name" label = "Extra property for testing only" /> + <field name = "property-known-hosts" domain = "known-hosts" label = "Extra property for testing only" /> + <field name = "property-method-id" domain = "method-id" label = "Extra property for testing only" /> + <field name = "property-no-ack" domain = "no-ack" label = "Extra property for testing only" /> + <field name = "property-no-local" domain = "no-local" label = "Extra property for testing only" /> + <field name = "property-path" domain = "path" label = "Extra property for testing only" /> + <field name = "property-peer-properties" domain = "peer-properties" label = "Extra property for testing only" /> + <field name = "property-queue-name" domain = "queue-name" label = "Extra property for testing only" /> + <field name = "property-redelivered" domain = "redelivered" label = "Extra property for testing only" /> + <field name = "property-reply-code" domain = "reply-code" label = "Extra property for testing only" /> + <field name = "property-reply-text" domain = "reply-text" label = "Extra property for testing only" /> + + <!-- Bit field test --> + <field name = "property-long-A" domain = "long" label = "Extra property for testing only" /> + <field name = "property-bit-B" domain = "bit" label = "Extra property for testing only" /> + <field name = "property-bit-C" domain = "bit" label = "Extra property for testing only" /> + <field name = "property-bit-D" domain = "bit" label = "Extra property for testing only" /> + <field name = "property-bit-E" domain = "bit" label = "Extra property for testing only" /> + <field name = "property-bit-F" domain = "bit" label = "Extra property for testing only" /> + <field name = "property-shortstr-G" domain = "shortstr" label = "Extra property for testing only" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "qos" synchronous = "1" index = "10" label = "specify quality of service"> + <doc> + This method requests a specific quality of service. The QoS can be specified for the + current channel or for all channels on the connection. The particular properties and + semantics of a qos method always depend on the content class semantics. Though the + qos method could in principle apply to both peers, it is currently meaningful only + for the server. + </doc> + + <chassis name = "server" implement = "MUST" /> + <response name = "qos-ok" /> + + <field name = "prefetch-size" domain = "long" label = "prefetch window in octets"> + <doc> + The client can request that messages be sent in advance so that when the client + finishes processing a message, the following message is already held locally, + rather than needing to be sent down the channel. Prefetching gives a performance + improvement. This field specifies the prefetch window size in octets. The server + will send a message in advance if it is equal to or smaller in size than the + available prefetch size (and also falls into other prefetch limits). May be set + to zero, meaning "no specific limit", although other prefetch limits may still + apply. The prefetch-size is ignored if the no-ack option is set. + </doc> + <!-- Rule test name: was "amq_basic_17" --> + <rule name = "01"> + <doc> + The server MUST ignore this setting when the client is not processing any + messages - i.e. the prefetch size does not limit the transfer of single + messages to a client, only the sending in advance of more messages while + the client still has one or more unacknowledged messages. + </doc> + <doc type = "scenario"> + Define a QoS prefetch-size limit and send a single message that exceeds + that limit. Verify that the message arrives correctly. + </doc> + </rule> + </field> + + <field name = "prefetch-count" domain = "short" label = "prefetch window in messages"> + <doc> + Specifies a prefetch window in terms of whole messages. This field may be used + in combination with the prefetch-size field; a message will only be sent in + advance if both prefetch windows (and those at the channel and connection level) + allow it. The prefetch-count is ignored if the no-ack option is set. + </doc> + <!-- Rule test name: was "amq_basic_18" --> + <rule name = "01"> + <doc> + The server may send less data in advance than allowed by the client's + specified prefetch windows but it MUST NOT send more. + </doc> + <doc type = "scenario"> + Define a QoS prefetch-size limit and a prefetch-count limit greater than + one. Send multiple messages that exceed the prefetch size. Verify that + no more than one message arrives at once. + </doc> + </rule> + </field> + + <field name = "global" domain = "bit" label = "apply to entire connection"> + <doc> + By default the QoS settings apply to the current channel only. If this field is + set, they are applied to the entire connection. + </doc> + </field> + </method> + + <method name = "qos-ok" synchronous = "1" index = "11" label = "confirm the requested qos"> + <doc> + This method tells the client that the requested QoS levels could be handled by the + server. The requested QoS applies to all active consumers until a new QoS is + defined. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "consume" synchronous = "1" index = "20" label = "start a queue consumer"> + <doc> + This method asks the server to start a "consumer", which is a transient request for + messages from a specific queue. Consumers last as long as the channel they were + created on, or until the client cancels them. + </doc> + + <!-- Rule test name: was "amq_basic_01" --> + <rule name = "01"> + <doc> + The server SHOULD support at least 16 consumers per queue, and ideally, impose + no limit except as defined by available resources. + </doc> + <doc type = "scenario"> + Create a queue and create consumers on that queue until the server closes the + connection. Verify that the number of consumers created was at least sixteen + and report the total number. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + <response name = "consume-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01" on-failure = "access-refused"> + <doc> + The client MUST provide a valid access ticket giving "read" access rights to + the realm for the queue. + </doc> + <doc type = "scenario"> + Attempt to create a consumer with an invalid (non-zero) access ticket. + </doc> + </rule> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to consume from. If the queue name is null, + refers to the current queue for the channel, which is the last declared queue. + </doc> + <rule name = "01" on-failure = "not-allowed"> + <doc> + If the queue name is empty the client MUST have previously declared a + queue using this channel. + </doc> + <doc type = "scenario"> + Attempt to create a consumer with an empty queue name and no previously + declared queue on the channel. + </doc> + </rule> + </field> + + <field name = "consumer-tag" domain = "consumer-tag"> + <doc> + Specifies the identifier for the consumer. The consumer tag is local to a + connection, so two clients can use the same consumer tags. If this field is + empty the server will generate a unique tag. + </doc> + <rule name = "01" on-failure = "not-allowed"> + <doc> + The client MUST NOT specify a tag that refers to an existing consumer. + </doc> + <doc type = "scenario"> + Attempt to create two consumers with the same non-empty tag. + </doc> + </rule> + <rule name = "02" on-failure = "not-allowed"> + <doc> + The consumer tag is valid only within the channel from which the + consumer was created. I.e. a client MUST NOT create a consumer in one + channel and then use it in another. + </doc> + <doc type = "scenario"> + Attempt to create a consumer in one channel, then use in another channel, + in which consumers have also been created (to test that the server uses + unique consumer tags). + </doc> + </rule> + </field> + + <field name = "no-local" domain = "no-local" /> + + <field name = "nowait" domain = "bit" label = "do not send a reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise + a channel or connection exception. + </doc> + </field> + + <field name = "bit-test-1" domain = "bit" /> + <field name = "bit-test-2" domain = "bit" /> + <field name = "bit-test-3" domain = "bit" /> + <field name = "bit-test-4" domain = "bit" /> + <field name = "bit-test-5" domain = "bit" /> + <field name = "bit-test-6" domain = "bit" /> + <field name = "bit-test-7" domain = "bit" /> + <field name = "bit-test-8" domain = "bit" /> + <field name = "bit-test-9" domain = "bit" /> + + <field name = "no-ack" domain = "short" /> + + <field name = "exclusive" domain = "bit" label = "request exclusive access"> + <doc> + Request exclusive consumer access, meaning only this consumer can access the + queue. + </doc> + <!-- Rule test name: was "amq_basic_02" --> + <rule name = "01" on-failure = "access-refused"> + <doc> + The client MAY NOT gain exclusive access to a queue that already has + active consumers. + </doc> + <doc type = "scenario"> + Open two connections to a server, and in one connection create a shared + (non-exclusive) queue and then consume from the queue. In the second + connection attempt to consume from the same queue using the exclusive + option. + </doc> + </rule> + </field> + + <field name = "priority" domain = "short" label = "consume priority"/> + </method> + + <method name = "consume-ok" synchronous = "1" index = "21" label = "confirm a new consumer"> + <doc> + The server provides the client with a consumer tag, which is used by the client + for methods called on the consumer at a later stage. + </doc> + <chassis name = "client" implement = "MUST" /> + <field name = "consumer-tag" domain = "consumer-tag"> + <doc> + Holds the consumer tag specified by the client or provided by the server. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "cancel" synchronous = "1" index = "30" label = "end a queue consumer"> + <doc> + This method cancels a consumer. This does not affect already delivered + messages, but it does mean the server will not send any more messages for + that consumer. The client may receive an abitrary number of messages in + between sending the cancel method and receiving the cancel-ok reply. + </doc> + + <rule name = "01"> + <doc> + If the queue does not exist the server MUST ignore the cancel method, so + long as the consumer tag is valid for that channel. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + <response name = "cancel-ok" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + </method> + + <method name = "cancel-ok" synchronous = "1" index = "31" label = "confirm a cancelled consumer"> + <doc> + This method confirms that the cancellation was completed. + </doc> + <chassis name = "client" implement = "MUST" /> + <field name = "consumer-tag" domain = "consumer-tag" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "publish" content = "1" index = "40" label = "publish a message"> + <doc> + This method publishes a message to a specific exchange. The message will be routed + to queues as defined by the exchange configuration and distributed to any active + consumers when the transaction, if any, is committed. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "write" access rights + to the access realm for the exchange. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange to publish to. The exchange name can be + empty, meaning the default exchange. If the exchange name is specified, and that + exchange does not exist, the server will raise a channel exception. + </doc> + + <!-- Rule test name: was "amq_basic_06" --> + <rule name = "01"> + <doc> + The server MUST accept a blank exchange name to mean the default exchange. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_14" --> + <rule name = "02"> + <doc> + If the exchange was declared as an internal exchange, the server MUST raise + a channel exception with a reply code 403 (access refused). + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_15" --> + <rule name = "03"> + <doc> + The exchange MAY refuse basic content in which case it MUST raise a channel + exception with reply code 540 (not implemented). + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc> + Specifies the routing key for the message. The routing key is used for routing + messages depending on the exchange configuration. + </doc> + </field> + + <field name = "mandatory" domain = "bit" label = "indicate mandatory routing"> + <doc> + This flag tells the server how to react if the message cannot be routed to a + queue. If this flag is set, the server will return an unroutable message with a + Return method. If this flag is zero, the server silently drops the message. + </doc> + <!-- Rule test name: was "amq_basic_07" --> + <rule name = "01"> + <doc> + The server SHOULD implement the mandatory flag. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "immediate" domain = "bit" label = "request immediate delivery"> + <doc> + This flag tells the server how to react if the message cannot be routed to a + queue consumer immediately. If this flag is set, the server will return an + undeliverable message with a Return method. If this flag is zero, the server + will queue the message, but with no guarantee that it will ever be consumed. + </doc> + <!-- Rule test name: was "amq_basic_16" --> + <rule name = "01"> + <doc> + The server SHOULD implement the immediate flag. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + <method name = "return" content = "1" index = "50" label = "return a failed message"> + <doc> + This method returns an undeliverable message that was published with the "immediate" + flag set, or an unroutable message published with the "mandatory" flag set. The + reply code and text provide information about the reason that the message was + undeliverable. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "reply-code" domain = "reply-code" /> + + <field name = "reply-text" domain = "reply-text" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + </doc> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc> + Specifies the routing key name specified when the message was published. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "deliver" content = "1" index = "60" + label = "notify the client of a consumer message"> + <doc> + This method delivers a message to the client, via a consumer. In the asynchronous + message delivery model, the client starts a consumer using the Consume method, then + the server responds with Deliver methods as and when messages arrive for that + consumer. + </doc> + + <!-- Rule test name: was "amq_basic_19" --> + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The server SHOULD track the number of times a message has been delivered to + clients and when a message is redelivered a certain number of times - e.g. 5 + times - without being acknowledged, the server SHOULD consider the message to be + unprocessable (possibly causing client applications to abort), and move the + message to a dead letter queue. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "redelivered" domain = "redelivered" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + </doc> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc>Specifies the routing key name specified when the message was published.</doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "get" synchronous = "1" index = "70" label = "direct access to a queue"> + <doc> + This method provides a direct access to the messages in a queue using a synchronous + dialogue that is designed for specific types of application where synchronous + functionality is more important than performance. + </doc> + + <response name = "get-ok" /> + <response name = "get-empty" /> + <chassis name = "server" implement = "MUST" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "read" access rights to + the realm for the queue. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to consume from. If the queue name is null, + refers to the current queue for the channel, which is the last declared queue. + </doc> + <rule name = "01"> + <doc> + If the client did not previously declare a queue, and the queue name in this + method is empty, the server MUST raise a connection exception with reply + code 530 (not allowed). + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "no-ack" domain = "no-ack" /> + </method> + + <method name = "get-ok" synchronous = "1" content = "1" index = "71" + label = "provide client with a message"> + <doc> + This method delivers a message to the client following a get method. A message + delivered by 'get-ok' must be acknowledged unless the no-ack option was set in the + get method. + </doc> + + <chassis name = "client" implement = "MAY" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "redelivered" domain = "redelivered" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + If empty, the message was published to the default exchange. + </doc> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc>Specifies the routing key name specified when the message was published.</doc> + </field> + + <field name = "message-count" domain = "long" label = "number of messages pending"> + <doc> + This field reports the number of messages pending on the queue, excluding the + message being delivered. Note that this figure is indicative, not reliable, and + can change arbitrarily as messages are added to the queue and removed by other + clients. + </doc> + </field> + </method> + + <method name = "get-empty" synchronous = "1" index = "72" + label = "indicate no messages available"> + <doc> + This method tells the client that the queue has no messages available for the + client. + </doc> + + <chassis name = "client" implement = "MAY" /> + + <!-- This field is deprecated pending review --> + <field name = "cluster-id" domain = "shortstr" label = "Cluster id"> + <doc> + For use by cluster applications, should not be used by client applications. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "ack" index = "80" label = "acknowledge one or more messages"> + <doc> + This method acknowledges one or more messages delivered via the Deliver or Get-Ok + methods. The client can ask to confirm a single message or a set of messages up to + and including a specific message. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "multiple" domain = "bit" label = "acknowledge multiple messages"> + <doc> + If set to 1, the delivery tag is treated as "up to and including", so that the + client can acknowledge multiple messages with a single method. If set to zero, + the delivery tag refers to a single message. If the multiple field is 1, and the + delivery tag is zero, tells the server to acknowledge all outstanding mesages. + </doc> + + <!-- Rule test name: was "amq_basic_20" --> + <rule name = "01"> + <doc> + The server MUST validate that a non-zero delivery-tag refers to an delivered + message, and raise a channel exception if this is not the case. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "reject" index = "90" label = "reject an incoming message"> + <doc> + This method allows a client to reject a message. It can be used to interrupt and + cancel large incoming messages, or return untreatable messages to their original + queue. + </doc> + + <!-- Rule test name: was "amq_basic_21" --> + <rule name = "01"> + <doc> + The server SHOULD be capable of accepting and process the Reject method while + sending message content with a Deliver or Get-Ok method. I.e. the server should + read and process incoming methods while sending output frames. To cancel a + partially-send content, the server sends a content body frame of size 1 (i.e. + with no data except the frame-end octet). + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_22" --> + <rule name = "02"> + <doc> + The server SHOULD interpret this method as meaning that the client is unable to + process the message at this time. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <rule name = "03"> + <!-- TODO: Rule split? --> + <doc> + A client MUST NOT use this method as a means of selecting messages to process. A + rejected message MAY be discarded or dead-lettered, not necessarily passed to + another client. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "requeue" domain = "bit" label = "requeue the message"> + <doc> + If this field is zero, the message will be discarded. If this bit is 1, the + server will attempt to requeue the message. + </doc> + + <!-- Rule test name: was "amq_basic_23" --> + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The server MUST NOT deliver the message to the same client within the + context of the current channel. The recommended strategy is to attempt to + deliver the message to an alternative consumer, and if that is not possible, + to move the message to a dead-letter queue. The server MAY use more + sophisticated tracking to hold the message on the queue and redeliver it to + the same client at a later stage. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + <method name = "recover" index = "100" label = "redeliver unacknowledged messages"> + <doc> + This method asks the broker to redeliver all unacknowledged messages on a specified + channel. Zero or more messages may be redelivered. This method is only allowed on + non-transacted channels. + </doc> + + <rule name = "01"> + <doc> + The server MUST set the redelivered flag on all messages that are resent. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <rule name = "02"> + <doc> + The server MUST raise a channel exception if this is called on a transacted + channel. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <field name = "requeue" domain = "bit" label = "requeue the message"> + <doc> + If this field is zero, the message will be redelivered to the original + recipient. If this bit is 1, the server will attempt to requeue the message, + potentially then delivering it to an alternative subscriber. + </doc> + </field> + </method> + </class> + + <!-- == FILE ============================================================= --> + + <class name = "file" handler = "channel" index = "70" label = "work with file content"> + <doc> + The file class provides methods that support reliable file transfer. File + messages have a specific set of properties that are required for interoperability + with file transfer applications. File messages and acknowledgements are subject to + channel transactions. Note that the file class does not provide message browsing + methods; these are not compatible with the staging model. Applications that need + browsable file transfer should use Basic content and the Basic class. + </doc> + + <doc type = "grammar"> + file = C:QOS S:QOS-OK + / C:CONSUME S:CONSUME-OK + / C:CANCEL S:CANCEL-OK + / C:OPEN S:OPEN-OK C:STAGE content + / S:OPEN C:OPEN-OK S:STAGE content + / C:PUBLISH + / S:DELIVER + / S:RETURN + / C:ACK + / C:REJECT + </doc> + + <chassis name = "server" implement = "MAY" /> + <chassis name = "client" implement = "MAY" /> + + <rule name = "01"> + <doc> + The server MUST make a best-effort to hold file messages on a reliable storage + mechanism. + </doc> + </rule> + + <!-- TODO Rule implement attr inverse? --> + + <!-- TODO: Rule split? --> + + <rule name = "02"> + <doc> + The server MUST NOT discard a file message in case of a queue overflow. The server + MUST use the Channel.Flow method to slow or stop a file message publisher when + necessary. + </doc> + </rule> + + <!-- TODO: Rule split? --> + + <rule name = "03"> + <doc> + The server MUST implement at least 2 priority levels for file messages, where + priorities 0-4 and 5-9 are treated as two distinct levels. The server MAY implement + up to 10 priority levels. + </doc> + </rule> + + <rule name = "04"> + <doc> + The server MUST support both automatic and explicit acknowledgements on file + content. + </doc> + </rule> + + <!-- These are the properties for a File content --> + + <field name = "content-type" domain = "shortstr" label = "MIME content type" /> + <field name = "content-encoding" domain = "shortstr" label = "MIME content encoding" /> + <field name = "headers" domain = "table" label = "message header field table" /> + <field name = "priority" domain = "octet" label = "message priority, 0 to 9" /> + <field name = "reply-to" domain = "shortstr" label = "destination to reply to" /> + <field name = "message-id" domain = "shortstr" label = "application message identifier" /> + <field name = "filename" domain = "shortstr" label = "message filename" /> + <field name = "timestamp" domain = "timestamp" label = "message timestamp" /> + <!-- This field is deprecated pending review --> + <field name = "cluster-id" domain = "shortstr" label = "intra-cluster routing identifier" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "qos" synchronous = "1" index = "10" label = "specify quality of service"> + <doc> + This method requests a specific quality of service. The QoS can be specified for the + current channel or for all channels on the connection. The particular properties and + semantics of a qos method always depend on the content class semantics. Though the + qos method could in principle apply to both peers, it is currently meaningful only + for the server. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <response name = "qos-ok" /> + + <field name = "prefetch-size" domain = "long" label = "prefetch window in octets"> + <doc> + The client can request that messages be sent in advance so that when the client + finishes processing a message, the following message is already held locally, + rather than needing to be sent down the channel. Prefetching gives a performance + improvement. This field specifies the prefetch window size in octets. May be set + to zero, meaning "no specific limit". Note that other prefetch limits may still + apply. The prefetch-size is ignored if the no-ack option is set. + </doc> + </field> + + <field name = "prefetch-count" domain = "short" label = "prefetch window in messages"> + <doc> + Specifies a prefetch window in terms of whole messages. This is compatible with + some file API implementations. This field may be used in combination with the + prefetch-size field; a message will only be sent in advance if both prefetch + windows (and those at the channel and connection level) allow it. The + prefetch-count is ignored if the no-ack option is set. + </doc> + + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The server MAY send less data in advance than allowed by the client's + specified prefetch windows but it MUST NOT send more. + </doc> + </rule> + </field> + + <field name = "global" domain = "bit" label = "apply to entire connection"> + <doc> + By default the QoS settings apply to the current channel only. If this field is + set, they are applied to the entire connection. + </doc> + </field> + </method> + + <method name = "qos-ok" synchronous = "1" index = "11" label = "confirm the requested qos"> + <doc> + This method tells the client that the requested QoS levels could be handled by the + server. The requested QoS applies to all active consumers until a new QoS is + defined. + </doc> + + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "consume" synchronous = "1" index = "20" label = "start a queue consumer"> + <doc> + This method asks the server to start a "consumer", which is a transient request for + messages from a specific queue. Consumers last as long as the channel they were + created on, or until the client cancels them. + </doc> + + <rule name = "01"> + <doc> + The server SHOULD support at least 16 consumers per queue, unless the queue was + declared as private, and ideally, impose no limit except as defined by available + resources. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <response name = "consume-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "read" access rights to + the realm for the queue. + </doc> + </rule> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to consume from. If the queue name is null, + refers to the current queue for the channel, which is the last declared queue. + </doc> + + <rule name = "01"> + <doc> + If the client did not previously declare a queue, and the queue name in this + method is empty, the server MUST raise a connection exception with reply + code 530 (not allowed). + </doc> + </rule> + </field> + + <field name = "consumer-tag" domain = "consumer-tag"> + <doc> + Specifies the identifier for the consumer. The consumer tag is local to a + connection, so two clients can use the same consumer tags. If this field is + empty the server will generate a unique tag. + </doc> + + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The tag MUST NOT refer to an existing consumer. If the client attempts to + create two consumers with the same non-empty tag the server MUST raise a + connection exception with reply code 530 (not allowed). + </doc> + </rule> + </field> + + <field name = "no-local" domain = "no-local" /> + + <field name = "no-ack" domain = "no-ack" /> + + <field name = "exclusive" domain = "bit" label = "request exclusive access"> + <doc> + Request exclusive consumer access, meaning only this consumer can access the + queue. + </doc> + + <!-- Rule test name: was "amq_file_00" --> + <rule name = "01"> + <doc> + If the server cannot grant exclusive access to the queue when asked, - + because there are other consumers active - it MUST raise a channel exception + with return code 405 (resource locked). + </doc> + </rule> + </field> + </method> + + <method name = "consume-ok" synchronous = "1" index = "21" label = "confirm a new consumer"> + <doc> + This method provides the client with a consumer tag which it MUST use in methods + that work with the consumer. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag"> + <doc>Holds the consumer tag specified by the client or provided by the server.</doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "cancel" synchronous = "1" index = "30" label = "end a queue consumer"> + <doc> + This method cancels a consumer. This does not affect already delivered messages, but + it does mean the server will not send any more messages for that consumer. + </doc> + + <response name = "cancel-ok" /> + + <chassis name = "server" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + </method> + + <method name = "cancel-ok" synchronous = "1" index = "31" label = "confirm a cancelled consumer"> + <doc>This method confirms that the cancellation was completed.</doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "open" synchronous = "1" index = "40" label = "request to start staging"> + <doc> + This method requests permission to start staging a message. Staging means sending + the message into a temporary area at the recipient end and then delivering the + message by referring to this temporary area. Staging is how the protocol handles + partial file transfers - if a message is partially staged and the connection breaks, + the next time the sender starts to stage it, it can restart from where it left off. + </doc> + + <response name = "open-ok" /> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <field name = "identifier" domain = "shortstr" label = "staging identifier"> + <doc> + This is the staging identifier. This is an arbitrary string chosen by the + sender. For staging to work correctly the sender must use the same staging + identifier when staging the same message a second time after recovery from a + failure. A good choice for the staging identifier would be the SHA1 hash of the + message properties data (including the original filename, revised time, etc.). + </doc> + </field> + + <field name = "content-size" domain = "longlong" label = "message content size"> + <doc> + The size of the content in octets. The recipient may use this information to + allocate or check available space in advance, to avoid "disk full" errors during + staging of very large messages. + </doc> + + <rule name = "01"> + <doc> + The sender MUST accurately fill the content-size field. Zero-length content + is permitted. + </doc> + </rule> + </field> + </method> + + <method name = "open-ok" synchronous = "1" index = "41" label = "confirm staging ready"> + <doc> + This method confirms that the recipient is ready to accept staged data. If the + message was already partially-staged at a previous time the recipient will report + the number of octets already staged. + </doc> + + <response name = "stage" /> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <field name = "staged-size" domain = "longlong" label = "already staged amount"> + <doc> + The amount of previously-staged content in octets. For a new message this will + be zero. + </doc> + + <rule name = "01"> + <doc> + The sender MUST start sending data from this octet offset in the message, + counting from zero. + </doc> + </rule> + + <rule name = "02"> + <!-- TODO: Rule split? --> + <doc> + The recipient MAY decide how long to hold partially-staged content and MAY + implement staging by always discarding partially-staged content. However if + it uses the file content type it MUST support the staging methods. + </doc> + </rule> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "stage" content = "1" index = "50" label = "stage message content"> + <doc> + This method stages the message, sending the message content to the recipient from + the octet offset specified in the Open-Ok method. + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "publish" index = "60" label = "publish a message"> + <doc> + This method publishes a staged file message to a specific exchange. The file message + will be routed to queues as defined by the exchange configuration and distributed to + any active consumers when the transaction, if any, is committed. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "write" access rights + to the access realm for the exchange. + </doc> + </rule> + </field> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange to publish to. The exchange name can be + empty, meaning the default exchange. If the exchange name is specified, and that + exchange does not exist, the server will raise a channel exception. + </doc> + + <rule name = "01"> + <doc> + The server MUST accept a blank exchange name to mean the default exchange. + </doc> + </rule> + + <rule name = "02"> + <doc> + If the exchange was declared as an internal exchange, the server MUST + respond with a reply code 403 (access refused) and raise a channel + exception. + </doc> + </rule> + + <!-- TODO: Rule split? --> + + <rule name = "03"> + <doc> + The exchange MAY refuse file content in which case it MUST respond with a + reply code 540 (not implemented) and raise a channel exception. + </doc> + </rule> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc> + Specifies the routing key for the message. The routing key is used for routing + messages depending on the exchange configuration. + </doc> + </field> + + <field name = "mandatory" domain = "bit" label = "indicate mandatory routing"> + <doc> + This flag tells the server how to react if the message cannot be routed to a + queue. If this flag is set, the server will return an unroutable message with a + Return method. If this flag is zero, the server silently drops the message. + </doc> + + <!-- Rule test name: was "amq_file_00" --> + <rule name = "01"> + <doc>The server SHOULD implement the mandatory flag.</doc> + </rule> + </field> + + <field name = "immediate" domain = "bit" label = "request immediate delivery"> + <doc> + This flag tells the server how to react if the message cannot be routed to a + queue consumer immediately. If this flag is set, the server will return an + undeliverable message with a Return method. If this flag is zero, the server + will queue the message, but with no guarantee that it will ever be consumed. + </doc> + + <!-- Rule test name: was "amq_file_00" --> + <rule name = "01"> + <doc>The server SHOULD implement the immediate flag.</doc> + </rule> + </field> + + <field name = "identifier" domain = "shortstr" label = "staging identifier"> + <doc> + This is the staging identifier of the message to publish. The message must have + been staged. Note that a client can send the Publish method asynchronously + without waiting for staging to finish. + </doc> + </field> + </method> + + <method name = "return" content = "1" index = "70" label = "return a failed message"> + <doc> + This method returns an undeliverable message that was published with the "immediate" + flag set, or an unroutable message published with the "mandatory" flag set. The + reply code and text provide information about the reason that the message was + undeliverable. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "reply-code" domain = "reply-code" /> + + <field name = "reply-text" domain = "reply-text" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + </doc> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc>Specifies the routing key name specified when the message was published.</doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "deliver" index = "80" label = "notify the client of a consumer message"> + <doc> + This method delivers a staged file message to the client, via a consumer. In the + asynchronous message delivery model, the client starts a consumer using the Consume + method, then the server responds with Deliver methods as and when messages arrive + for that consumer. + </doc> + + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The server SHOULD track the number of times a message has been delivered to + clients and when a message is redelivered a certain number of times - e.g. 5 + times - without being acknowledged, the server SHOULD consider the message to be + unprocessable (possibly causing client applications to abort), and move the + message to a dead letter queue. + </doc> + </rule> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "redelivered" domain = "redelivered" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + </doc> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc>Specifies the routing key name specified when the message was published.</doc> + </field> + + <field name = "identifier" domain = "shortstr" label = "staging identifier"> + <doc> + This is the staging identifier of the message to deliver. The message must have + been staged. Note that a server can send the Deliver method asynchronously + without waiting for staging to finish. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "ack" index = "90" label = "acknowledge one or more messages"> + <doc> + This method acknowledges one or more messages delivered via the Deliver method. The + client can ask to confirm a single message or a set of messages up to and including + a specific message. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "multiple" domain = "bit" label = "acknowledge multiple messages"> + <doc> + If set to 1, the delivery tag is treated as "up to and including", so that the + client can acknowledge multiple messages with a single method. If set to zero, + the delivery tag refers to a single message. If the multiple field is 1, and the + delivery tag is zero, tells the server to acknowledge all outstanding mesages. + </doc> + + <rule name = "01"> + <doc> + The server MUST validate that a non-zero delivery-tag refers to an delivered + message, and raise a channel exception if this is not the case. + </doc> + </rule> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "reject" index = "100" label = "reject an incoming message"> + <doc> + This method allows a client to reject a message. It can be used to return + untreatable messages to their original queue. Note that file content is staged + before delivery, so the client will not use this method to interrupt delivery of a + large message. + </doc> + + <rule name = "01"> + <doc> + The server SHOULD interpret this method as meaning that the client is unable to + process the message at this time. + </doc> + </rule> + + <!-- TODO: Rule split? --> + + <rule name = "02"> + <doc> + A client MUST NOT use this method as a means of selecting messages to process. A + rejected message MAY be discarded or dead-lettered, not necessarily passed to + another client. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "requeue" domain = "bit" label = "requeue the message"> + <doc> + If this field is zero, the message will be discarded. If this bit is 1, the + server will attempt to requeue the message. + </doc> + + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The server MUST NOT deliver the message to the same client within the + context of the current channel. The recommended strategy is to attempt to + deliver the message to an alternative consumer, and if that is not possible, + to move the message to a dead-letter queue. The server MAY use more + sophisticated tracking to hold the message on the queue and redeliver it to + the same client at a later stage. + </doc> + </rule> + </field> + </method> + </class> + + <!-- == STREAM =========================================================== --> + + <class name = "stream" handler = "channel" index = "80" label = "work with streaming content"> + <doc> + The stream class provides methods that support multimedia streaming. The stream class + uses the following semantics: one message is one packet of data; delivery is + unacknowleged and unreliable; the consumer can specify quality of service parameters + that the server can try to adhere to; lower-priority messages may be discarded in favour + of high priority messages. + </doc> + + <doc type = "grammar"> + stream = C:QOS S:QOS-OK + / C:CONSUME S:CONSUME-OK + / C:CANCEL S:CANCEL-OK + / C:PUBLISH content + / S:RETURN + / S:DELIVER content + </doc> + + <chassis name = "server" implement = "MAY" /> + <chassis name = "client" implement = "MAY" /> + + <rule name = "01"> + <doc> + The server SHOULD discard stream messages on a priority basis if the queue size + exceeds some configured limit. + </doc> + </rule> + + <rule name = "02"> + <!-- TODO: Rule split? --> + <doc> + The server MUST implement at least 2 priority levels for stream messages, where + priorities 0-4 and 5-9 are treated as two distinct levels. The server MAY implement + up to 10 priority levels. + </doc> + </rule> + + <rule name = "03"> + <doc> + The server MUST implement automatic acknowledgements on stream content. That is, as + soon as a message is delivered to a client via a Deliver method, the server must + remove it from the queue. + </doc> + </rule> + + <!-- These are the properties for a Stream content --> + + <field name = "content-type" domain = "shortstr" label = "MIME content type" /> + <field name = "content-encoding" domain = "shortstr" label = "MIME content encoding" /> + <field name = "headers" domain = "table" label = "message header field table" /> + <field name = "priority" domain = "octet" label = "message priority, 0 to 9" /> + <field name = "timestamp" domain = "timestamp" label = "message timestamp" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "qos" synchronous = "1" index = "10" label = "specify quality of service"> + <doc> + This method requests a specific quality of service. The QoS can be specified for the + current channel or for all channels on the connection. The particular properties and + semantics of a qos method always depend on the content class semantics. Though the + qos method could in principle apply to both peers, it is currently meaningful only + for the server. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <response name = "qos-ok" /> + + <field name = "prefetch-size" domain = "long" label = "prefetch window in octets"> + <doc> + The client can request that messages be sent in advance so that when the client + finishes processing a message, the following message is already held locally, + rather than needing to be sent down the channel. Prefetching gives a performance + improvement. This field specifies the prefetch window size in octets. May be set + to zero, meaning "no specific limit". Note that other prefetch limits may still + apply. + </doc> + </field> + + <field name = "prefetch-count" domain = "short" label = "prefetch window in messages"> + <doc> + Specifies a prefetch window in terms of whole messages. This field may be used + in combination with the prefetch-size field; a message will only be sent in + advance if both prefetch windows (and those at the channel and connection level) + allow it. + </doc> + </field> + + <field name = "consume-rate" domain = "long" label = "transfer rate in octets/second"> + <doc> + Specifies a desired transfer rate in octets per second. This is usually + determined by the application that uses the streaming data. A value of zero + means "no limit", i.e. as rapidly as possible. + </doc> + + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The server MAY ignore the prefetch values and consume rates, depending on + the type of stream and the ability of the server to queue and/or reply it. + The server MAY drop low-priority messages in favour of high-priority + messages. + </doc> + </rule> + </field> + + <field name = "global" domain = "bit" label = "apply to entire connection"> + <doc> + By default the QoS settings apply to the current channel only. If this field is + set, they are applied to the entire connection. + </doc> + </field> + </method> + + <method name = "qos-ok" synchronous = "1" index = "11" label = "confirm the requested qos"> + <doc> + This method tells the client that the requested QoS levels could be handled by the + server. The requested QoS applies to all active consumers until a new QoS is + defined. + </doc> + + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "consume" synchronous = "1" index = "20" label = "start a queue consumer"> + <doc> + This method asks the server to start a "consumer", which is a transient request for + messages from a specific queue. Consumers last as long as the channel they were + created on, or until the client cancels them. + </doc> + + <rule name = "01"> + <doc> + The server SHOULD support at least 16 consumers per queue, unless the queue was + declared as private, and ideally, impose no limit except as defined by available + resources. + </doc> + </rule> + + <rule name = "02"> + <doc> + Streaming applications SHOULD use different channels to select different + streaming resolutions. AMQP makes no provision for filtering and/or transforming + streams except on the basis of priority-based selective delivery of individual + messages. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + <response name = "consume-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "read" access rights to + the realm for the queue. + </doc> + </rule> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to consume from. If the queue name is null, + refers to the current queue for the channel, which is the last declared queue. + </doc> + + <rule name = "01"> + <doc> + If the client did not previously declare a queue, and the queue name in this + method is empty, the server MUST raise a connection exception with reply + code 530 (not allowed). + </doc> + </rule> + </field> + + <field name = "consumer-tag" domain = "consumer-tag"> + <doc> + Specifies the identifier for the consumer. The consumer tag is local to a + connection, so two clients can use the same consumer tags. If this field is + empty the server will generate a unique tag. + </doc> + + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The tag MUST NOT refer to an existing consumer. If the client attempts to + create two consumers with the same non-empty tag the server MUST raise a + connection exception with reply code 530 (not allowed). + </doc> + </rule> + </field> + + <field name = "no-local" domain = "no-local" /> + + <field name = "exclusive" domain = "bit" label = "request exclusive access"> + <doc> + Request exclusive consumer access, meaning only this consumer can access the + queue. + </doc> + + + <!-- Rule test name: was "amq_file_00" --> + <rule name = "01"> + <doc> + If the server cannot grant exclusive access to the queue when asked, - + because there are other consumers active - it MUST raise a channel exception + with return code 405 (resource locked). + </doc> + </rule> + </field> + </method> + + <method name = "consume-ok" synchronous = "1" index = "21" label = "confirm a new consumer"> + <doc> + This method provides the client with a consumer tag which it may use in methods that + work with the consumer. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag"> + <doc>Holds the consumer tag specified by the client or provided by the server.</doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "cancel" synchronous = "1" index = "30" label = "end a queue consumer"> + <doc> + This method cancels a consumer. Since message delivery is asynchronous the client + may continue to receive messages for a short while after canceling a consumer. It + may process or discard these as appropriate. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <response name = "cancel-ok" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + </method> + + <method name = "cancel-ok" synchronous = "1" index = "31" label = "confirm a cancelled consumer"> + <doc>This method confirms that the cancellation was completed.</doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "publish" content = "1" index = "40" label = "publish a message"> + <doc> + This method publishes a message to a specific exchange. The message will be routed + to queues as defined by the exchange configuration and distributed to any active + consumers as appropriate. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "write" access rights + to the access realm for the exchange. + </doc> + </rule> + </field> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange to publish to. The exchange name can be + empty, meaning the default exchange. If the exchange name is specified, and that + exchange does not exist, the server will raise a channel exception. + </doc> + + <rule name = "01"> + <doc> + The server MUST accept a blank exchange name to mean the default exchange. + </doc> + </rule> + + <rule name = "02"> + <doc> + If the exchange was declared as an internal exchange, the server MUST + respond with a reply code 403 (access refused) and raise a channel + exception. + </doc> + </rule> + + <rule name = "03"> + <doc> + The exchange MAY refuse stream content in which case it MUST respond with a + reply code 540 (not implemented) and raise a channel exception. + </doc> + </rule> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc> + Specifies the routing key for the message. The routing key is used for routing + messages depending on the exchange configuration. + </doc> + </field> + + <field name = "mandatory" domain = "bit" label = "indicate mandatory routing"> + <doc> + This flag tells the server how to react if the message cannot be routed to a + queue. If this flag is set, the server will return an unroutable message with a + Return method. If this flag is zero, the server silently drops the message. + </doc> + + <!-- Rule test name: was "amq_stream_00" --> + <rule name = "01"> + <doc>The server SHOULD implement the mandatory flag.</doc> + </rule> + </field> + + <field name = "immediate" domain = "bit" label = "request immediate delivery"> + <doc> + This flag tells the server how to react if the message cannot be routed to a + queue consumer immediately. If this flag is set, the server will return an + undeliverable message with a Return method. If this flag is zero, the server + will queue the message, but with no guarantee that it will ever be consumed. + </doc> + + <!-- Rule test name: was "amq_stream_00" --> + <rule name = "01"> + <doc>The server SHOULD implement the immediate flag.</doc> + </rule> + </field> + </method> + + <method name = "return" content = "1" index = "50" label = "return a failed message"> + <doc> + This method returns an undeliverable message that was published with the "immediate" + flag set, or an unroutable message published with the "mandatory" flag set. The + reply code and text provide information about the reason that the message was + undeliverable. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "reply-code" domain = "reply-code" /> + + <field name = "reply-text" domain = "reply-text" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + </doc> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc>Specifies the routing key name specified when the message was published.</doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "deliver" content = "1" index = "60" + label = "notify the client of a consumer message"> + <doc> + This method delivers a message to the client, via a consumer. In the asynchronous + message delivery model, the client starts a consumer using the Consume method, then + the server responds with Deliver methods as and when messages arrive for that + consumer. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + </doc> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue that the message came from. Note that a single + channel can start many consumers on different queues. + </doc> + <assert check = "notnull" /> + </field> + </method> + </class> + + <!-- == TX =============================================================== --> + + <class name = "tx" handler = "channel" index = "90" label = "work with standard transactions"> + <doc> + Standard transactions provide so-called "1.5 phase commit". We can ensure that work is + never lost, but there is a chance of confirmations being lost, so that messages may be + resent. Applications that use standard transactions must be able to detect and ignore + duplicate messages. + </doc> + + <!-- TODO: Rule split? --> + + <rule name = "01"> + <doc> + An client using standard transactions SHOULD be able to track all messages received + within a reasonable period, and thus detect and reject duplicates of the same + message. It SHOULD NOT pass these to the application layer. + </doc> + </rule> + + <doc type = "grammar"> + tx = C:SELECT S:SELECT-OK + / C:COMMIT S:COMMIT-OK + / C:ROLLBACK S:ROLLBACK-OK + </doc> + + <chassis name = "server" implement = "SHOULD" /> + <chassis name = "client" implement = "MAY" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "select" synchronous = "1" index = "10" label = "select standard transaction mode"> + <doc> + This method sets the channel to use standard transactions. The client must use this + method at least once on a channel before using the Commit or Rollback methods. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "select-ok" /> + </method> + + <method name = "select-ok" synchronous = "1" index = "11" label = "confirm transaction mode"> + <doc> + This method confirms to the client that the channel was successfully set to use + standard transactions. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "commit" synchronous = "1" index = "20" label = "commit the current transaction"> + <doc> + This method commits all messages published and acknowledged in the current + transaction. A new transaction starts immediately after a commit. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "commit-ok" /> + </method> + + <method name = "commit-ok" synchronous = "1" index = "21" label = "confirm a successful commit"> + <doc> + This method confirms to the client that the commit succeeded. Note that if a commit + fails, the server raises a channel exception. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "rollback" synchronous = "1" index = "30" + label = "abandon the current transaction"> + <doc> + This method abandons all messages published and acknowledged in the current + transaction. A new transaction starts immediately after a rollback. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "rollback-ok" /> + </method> + + <method name = "rollback-ok" synchronous = "1" index = "31" label = "confirm successful rollback"> + <doc> + This method confirms to the client that the rollback succeeded. Note that if an + rollback fails, the server raises a channel exception. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + </class> + + <!-- == DTX ============================================================== --> + + <class name = "dtx" handler = "channel" index = "100" label = "work with distributed transactions"> + <doc> + Distributed transactions provide so-called "2-phase commit". The AMQP distributed + transaction model supports the X-Open XA architecture and other distributed transaction + implementations. The Dtx class assumes that the server has a private communications + channel (not AMQP) to a distributed transaction coordinator. + </doc> + + <doc type = "grammar"> + dtx = C:SELECT S:SELECT-OK + C:START S:START-OK + </doc> + + <chassis name = "server" implement = "MAY" /> + <chassis name = "client" implement = "MAY" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "select" synchronous = "1" index = "10" label = "select standard transaction mode"> + <doc> + This method sets the channel to use distributed transactions. The client must use + this method at least once on a channel before using the Start method. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "select-ok" /> + </method> + + <method name = "select-ok" synchronous = "1" index = "11" label = "confirm transaction mode"> + <doc> + This method confirms to the client that the channel was successfully set to use + distributed transactions. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "start" synchronous = "1" index = "20" + label = "start a new distributed transaction"> + <doc> + This method starts a new distributed transaction. This must be the first method on a + new channel that uses the distributed transaction mode, before any methods that + publish or consume messages. + </doc> + <chassis name = "server" implement = "MAY" /> + <response name = "start-ok" /> + <field name = "dtx-identifier" domain = "shortstr" label = "transaction identifier"> + <doc> + The distributed transaction key. This identifies the transaction so that the + AMQP server can coordinate with the distributed transaction coordinator. + </doc> + <assert check = "notnull" /> + </field> + </method> + + <method name = "start-ok" synchronous = "1" index = "21" + label = "confirm the start of a new distributed transaction"> + <doc> + This method confirms to the client that the transaction started. Note that if a + start fails, the server raises a channel exception. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + </class> + + <!-- == TUNNEL =========================================================== --> + + <class name = "tunnel" handler = "tunnel" index = "110" label = "methods for protocol tunneling"> + <doc> + The tunnel methods are used to send blocks of binary data - which can be serialised AMQP + methods or other protocol frames - between AMQP peers. + </doc> + + <doc type = "grammar"> + tunnel = C:REQUEST + / S:REQUEST + </doc> + + <chassis name = "server" implement = "MAY" /> + <chassis name = "client" implement = "MAY" /> + + <field name = "headers" domain = "table" label = "message header field table" /> + <field name = "proxy-name" domain = "shortstr" label = "identity of tunnelling proxy" /> + <field name = "data-name" domain = "shortstr" label = "name or type of message being tunnelled" /> + <field name = "durable" domain = "octet" label = "message durability indicator" /> + <field name = "broadcast" domain = "octet" label = "message broadcast mode" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "request" content = "1" index = "10" label = "sends a tunnelled method"> + <doc> + This method tunnels a block of binary data, which can be an encoded + AMQP method or other data. The binary data is sent as the content for + the Tunnel.Request method. + </doc> + <chassis name = "server" implement = "MUST" /> + <field name = "meta-data" domain = "table" label = "meta data for the tunnelled block"> + <doc> + This field table holds arbitrary meta-data that the sender needs to + pass to the recipient. + </doc> + </field> + </method> + </class> +</amqp> diff --git a/qpid/cpp-0-9/gentools/xml-src/amqp-0.8.test.xml b/qpid/cpp-0-9/gentools/xml-src/amqp-0.8.test.xml new file mode 100644 index 0000000000..b0adf31828 --- /dev/null +++ b/qpid/cpp-0-9/gentools/xml-src/amqp-0.8.test.xml @@ -0,0 +1,3959 @@ +<?xml version="1.0"?> + +<!-- + Copyright Notice + ================ + (c) Copyright JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc., + iMatix Corporation, IONA\ufffd Technologies, Red Hat, Inc., + TWIST Process Innovations, and 29West Inc. 2006. All rights reserved. + + License + ======= + JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc., iMatix + Corporation, IONA\ufffd Technologies, Red Hat, Inc., TWIST Process Innovations, and + 29West Inc. (collectively, the "Authors") each hereby grants to you a worldwide, + perpetual, royalty-free, nontransferable, nonexclusive license to + (i) copy, display, and implement the Advanced Messaging Queue Protocol + ("AMQP") Specification and (ii) the Licensed Claims that are held by + the Authors, all for the purpose of implementing the Advanced Messaging + Queue Protocol Specification. Your license and any rights under this + Agreement will terminate immediately without notice from + any Author if you bring any claim, suit, demand, or action related to + the Advanced Messaging Queue Protocol Specification against any Author. + Upon termination, you shall destroy all copies of the Advanced Messaging + Queue Protocol Specification in your possession or control. + + As used hereunder, "Licensed Claims" means those claims of a patent or + patent application, throughout the world, excluding design patents and + design registrations, owned or controlled, or that can be sublicensed + without fee and in compliance with the requirements of this + Agreement, by an Author or its affiliates now or at any + future time and which would necessarily be infringed by implementation + of the Advanced Messaging Queue Protocol Specification. A claim is + necessarily infringed hereunder only when it is not possible to avoid + infringing it because there is no plausible non-infringing alternative + for implementing the required portions of the Advanced Messaging Queue + Protocol Specification. Notwithstanding the foregoing, Licensed Claims + shall not include any claims other than as set forth above even if + contained in the same patent as Licensed Claims; or that read solely + on any implementations of any portion of the Advanced Messaging Queue + Protocol Specification that are not required by the Advanced Messaging + Queue Protocol Specification, or that, if licensed, would require a + payment of royalties by the licensor to unaffiliated third parties. + Moreover, Licensed Claims shall not include (i) any enabling technologies + that may be necessary to make or use any Licensed Product but are not + themselves expressly set forth in the Advanced Messaging Queue Protocol + Specification (e.g., semiconductor manufacturing technology, compiler + technology, object oriented technology, networking technology, operating + system technology, and the like); or (ii) the implementation of other + published standards developed elsewhere and merely referred to in the + body of the Advanced Messaging Queue Protocol Specification, or + (iii) any Licensed Product and any combinations thereof the purpose or + function of which is not required for compliance with the Advanced + Messaging Queue Protocol Specification. For purposes of this definition, + the Advanced Messaging Queue Protocol Specification shall be deemed to + include both architectural and interconnection requirements essential + for interoperability and may also include supporting source code artifacts + where such architectural, interconnection requirements and source code + artifacts are expressly identified as being required or documentation to + achieve compliance with the Advanced Messaging Queue Protocol Specification. + + As used hereunder, "Licensed Products" means only those specific portions + of products (hardware, software or combinations thereof) that implement + and are compliant with all relevant portions of the Advanced Messaging + Queue Protocol Specification. + + The following disclaimers, which you hereby also acknowledge as to any + use you may make of the Advanced Messaging Queue Protocol Specification: + + THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION IS PROVIDED "AS IS," + AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE + CONTENTS OF THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION ARE + SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF THE ADVANCED + MESSAGING QUEUE PROTOCOL SPECIFICATION WILL NOT INFRINGE ANY THIRD PARTY + PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + + THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, + INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO ANY + USE, IMPLEMENTATION OR DISTRIBUTION OF THE ADVANCED MESSAGING QUEUE + PROTOCOL SPECIFICATION. + + The name and trademarks of the Authors may NOT be used in any manner, + including advertising or publicity pertaining to the Advanced Messaging + Queue Protocol Specification or its contents without specific, written + prior permission. Title to copyright in the Advanced Messaging Queue + Protocol Specification will at all times remain with the Authors. + + No other rights are granted by implication, estoppel or otherwise. + + Upon termination of your license or rights under this Agreement, you + shall destroy all copies of the Advanced Messaging Queue Protocol + Specification in your possession or control. + + Trademarks + ========== + "JPMorgan", "JPMorgan Chase", "Chase", the JPMorgan Chase logo and the + Octagon Symbol are trademarks of JPMorgan Chase & Co. + + IMATIX and the iMatix logo are trademarks of iMatix Corporation sprl. + + IONA, IONA Technologies, and the IONA logos are trademarks of IONA + Technologies PLC and/or its subsidiaries. + + LINUX is a trademark of Linus Torvalds. RED HAT and JBOSS are registered + trademarks of Red Hat, Inc. in the US and other countries. + + Java, all Java-based trademarks and OpenOffice.org are trademarks of + Sun Microsystems, Inc. in the United States, other countries, or both. + + Other company, product, or service names may be trademarks or service + marks of others. + + Links to full AMQP specification: + ================================= + http://www.envoytech.org/spec/amq/ + http://www.iona.com/opensource/amqp/ + http://www.redhat.com/solutions/specifications/amqp/ + http://www.twiststandards.org/tiki-index.php?page=AMQ + http://www.imatix.com/amqp + +--> + +<!-- +======================================================== +EDITORS: (PH) Pieter Hintjens <ph@imatix.com> + (KvdR) Kim van der Riet <kim.vdriet@redhat.com> + +NOTE: These editors have been assigned by the AMQP working group. Please do not +edit/commit this file without consulting with one of the above editors. +======================================================== + +Revision history: + 2006-06-07 (PH) - version number changed to 0.8 to conform to public + release documentation. + + 2006-05-15 (PH) - fixed comments on queue name in basic.get to clarify + use of current queue in this method. + + 2006-05-15 (PH) - fixed comments on routing key in queue.bind to clarify + how routing key is filled when empty (to allow asynch queue.declare). + + 2006-05-11 (PH) - reset version to 0.70 so that putatitive standards + group can release 2-3 major new versions before hitting 1.0 (again). + + 2006-05-11 (PH) - TODO in documentation: cycle field in frame header + has been removed. + + 2006-05-11 (PH) - added nowait option to exchange.declare, delete, + queue.declare, delete, bind, purge, basic.consume, cancel, + file.consume, cancel, stream.consume and cancel methods. + + 2006-05-11 (PH) - removed notnull rule and added explanations on queue + name in queue.bind, purge, delete, basic.consume, cancel, file.consume, + cancel, stream.consume and cancel methods. + + 2006-05-11 (PH) - added basic.qos, file.qos, and stream.qos methods that + regroup all prefetch options from the consume methods. Also removed the + prefetch option from channel.open. + + 2006-05-11 (PH) - renumbered method indexes to show request-response + nature of methods; requests are 10, 20, 30 while responses are 11, 21, + etc. + + 2006-05-11 (PH) - removed OpenAMQ extension methods from this definition + since these are maintained seperately. + + 2006-05-26 (RG) - added Basic.Recover method to allow replay of + unacknowledged messages on a channel. + + 2006-07-03 (PH) - cosmetic clean-up of Basic.Recover comments. +--> + +<amqp major="8" minor="0" port="5672" comment="AMQ protocol 0.80"> + AMQ Protocol 0.80 + +<!-- +====================================================== +== CONSTANTS +====================================================== +--> + <constant name="frame method" value="1"/> + <constant name="frame header" value="2"/> + <constant name="frame body" value="3"/> + <constant name="frame oob method" value="4"/> + <constant name="frame oob header" value="5"/> + <constant name="frame oob body" value="6"/> + <constant name="frame trace" value="7"/> + <constant name="frame heartbeat" value="8"/> + <constant name="frame min size" value="4096"/> + <constant name="frame end" value="206"/> + <constant name="reply success" value="200"> + Indicates that the method completed successfully. This reply code is + reserved for future use - the current protocol design does not use + positive confirmation and reply codes are sent only in case of an + error. +</constant> + <constant name="not delivered" value="310" class="soft error"> + The client asked for a specific message that is no longer available. + The message was delivered to another client, or was purged from the + queue for some other reason. +</constant> + <constant name="content too large" value="311" class="soft error"> + The client attempted to transfer content larger than the server + could accept at the present time. The client may retry at a later + time. +</constant> + <constant name="connection forced" value="320" class="hard error"> + An operator intervened to close the connection for some reason. + The client may retry at some later date. +</constant> + <constant name="invalid path" value="402" class="hard error"> + The client tried to work with an unknown virtual host or cluster. +</constant> + <constant name="access refused" value="403" class="soft error"> + The client attempted to work with a server entity to which it has + no due to security settings. +</constant> + <constant name="not found" value="404" class="soft error"> + The client attempted to work with a server entity that does not exist. +</constant> + <constant name="resource locked" value="405" class="soft error"> + The client attempted to work with a server entity to which it has + no access because another client is working with it. +</constant> + <constant name="frame error" value="501" class="hard error"> + The client sent a malformed frame that the server could not decode. + This strongly implies a programming error in the client. +</constant> + <constant name="syntax error" value="502" class="hard error"> + The client sent a frame that contained illegal values for one or more + fields. This strongly implies a programming error in the client. +</constant> + <constant name="command invalid" value="503" class="hard error"> + The client sent an invalid sequence of frames, attempting to perform + an operation that was considered invalid by the server. This usually + implies a programming error in the client. +</constant> + <constant name="channel error" value="504" class="hard error"> + The client attempted to work with a channel that had not been + correctly opened. This most likely indicates a fault in the client + layer. +</constant> + <constant name="resource error" value="506" class="hard error"> + The server could not complete the method because it lacked sufficient + resources. This may be due to the client creating too many of some + type of entity. +</constant> + <constant name="not allowed" value="530" class="hard error"> + The client tried to work with some entity in a manner that is + prohibited by the server, due to security settings or by some other + criteria. +</constant> + <constant name="not implemented" value="540" class="hard error"> + The client tried to use functionality that is not implemented in the + server. +</constant> + <constant name="internal error" value="541" class="hard error"> + The server could not complete the method because of an internal error. + The server may require intervention by an operator in order to resume + normal operations. +</constant> + <!-- +====================================================== +== DOMAIN TYPES +====================================================== +--> + <domain name="access ticket" type="short"> + access ticket granted by server + <doc> + An access ticket granted by the server for a certain set of access + rights within a specific realm. Access tickets are valid within the + channel where they were created, and expire when the channel closes. + </doc> + <assert check="ne" value="0"/> + </domain> + <domain name="class id" type="short"/> + <domain name="consumer tag" type="shortstr"> + consumer tag + <doc> + Identifier for the consumer, valid within the current connection. + </doc> + <rule implement="MUST"> + The consumer tag is valid only within the channel from which the + consumer was created. I.e. a client MUST NOT create a consumer in + one channel and then use it in another. + </rule> + </domain> + <domain name="delivery tag" type="longlong"> + server-assigned delivery tag + <doc> + The server-assigned and channel-specific delivery tag + </doc> + <rule implement="MUST"> + The delivery tag is valid only within the channel from which the + message was received. I.e. a client MUST NOT receive a message on + one channel and then acknowledge it on another. + </rule> + <rule implement="MUST"> + The server MUST NOT use a zero value for delivery tags. Zero is + reserved for client use, meaning "all messages so far received". + </rule> + </domain> + <domain name="exchange name" type="shortstr"> + exchange name + <doc> + The exchange name is a client-selected string that identifies + the exchange for publish methods. Exchange names may consist + of any mixture of digits, letters, and underscores. Exchange + names are scoped by the virtual host. + </doc> + <assert check="length" value="127"/> + </domain> + <domain name="known hosts" type="shortstr"> +list of known hosts +<doc> +Specifies the list of equivalent or alternative hosts that the server +knows about, which will normally include the current server itself. +Clients can cache this information and use it when reconnecting to a +server after a failure. +</doc> + <rule implement="MAY"> +The server MAY leave this field empty if it knows of no other +hosts than itself. +</rule> + </domain> + <domain name="method id" type="short"/> + <domain name="no ack" type="bit"> + no acknowledgement needed + <doc> + If this field is set the server does not expect acknowledgments + for messages. That is, when a message is delivered to the client + the server automatically and silently acknowledges it on behalf + of the client. This functionality increases performance but at + the cost of reliability. Messages can get lost if a client dies + before it can deliver them to the application. + </doc> + </domain> + <domain name="no local" type="bit"> + do not deliver own messages + <doc> + If the no-local field is set the server will not send messages to + the client that published them. + </doc> + </domain> + <domain name="path" type="shortstr"> + <doc> + Must start with a slash "/" and continue with path names + separated by slashes. A path name consists of any combination + of at least one of [A-Za-z0-9] plus zero or more of [.-_+!=:]. +</doc> + <assert check="notnull"/> + <assert check="syntax" rule="path"/> + <assert check="length" value="127"/> + </domain> + <domain name="peer properties" type="table"> + <doc> +This string provides a set of peer properties, used for +identification, debugging, and general information. +</doc> + <rule implement="SHOULD"> +The properties SHOULD contain these fields: +"product", giving the name of the peer product, "version", giving +the name of the peer version, "platform", giving the name of the +operating system, "copyright", if appropriate, and "information", +giving other general information. +</rule> + </domain> + <domain name="queue name" type="shortstr"> + queue name + <doc> + The queue name identifies the queue within the vhost. Queue + names may consist of any mixture of digits, letters, and + underscores. + </doc> + <assert check="length" value="127"/> + </domain> + <domain name="redelivered" type="bit"> + message is being redelivered + <doc> + This indicates that the message has been previously delivered to + this or another client. + </doc> + <rule implement="SHOULD"> + The server SHOULD try to signal redelivered messages when it can. + When redelivering a message that was not successfully acknowledged, + the server SHOULD deliver it to the original client if possible. + </rule> + <rule implement="MUST"> + The client MUST NOT rely on the redelivered field but MUST take it + as a hint that the message may already have been processed. A + fully robust client must be able to track duplicate received messages + on non-transacted, and locally-transacted channels. + </rule> + </domain> + <domain name="reply code" type="short"> +reply code from server +<doc> + The reply code. The AMQ reply codes are defined in AMQ RFC 011. +</doc> + <assert check="notnull"/> + </domain> + <domain name="reply text" type="shortstr"> +localised reply text +<doc> + The localised reply text. This text can be logged as an aid to + resolving issues. +</doc> + <assert check="notnull"/> + </domain> + <class name="connection" handler="connection" index="10"> + <!-- +====================================================== +== CONNECTION +====================================================== +--> + work with socket connections +<doc> + The connection class provides methods for a client to establish a + network connection to a server, and for both peers to operate the + connection thereafter. +</doc> + <doc name="grammar"> + connection = open-connection *use-connection close-connection + open-connection = C:protocol-header + S:START C:START-OK + *challenge + S:TUNE C:TUNE-OK + C:OPEN S:OPEN-OK | S:REDIRECT + challenge = S:SECURE C:SECURE-OK + use-connection = *channel + close-connection = C:CLOSE S:CLOSE-OK + / S:CLOSE C:CLOSE-OK +</doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="start" synchronous="1" index="10"> + start connection negotiation + <doc> + This method starts the connection negotiation process by telling + the client the protocol version that the server proposes, along + with a list of security mechanisms which the client can use for + authentication. + </doc> + <rule implement="MUST"> + If the client cannot handle the protocol version suggested by the + server it MUST close the socket connection. + </rule> + <rule implement="MUST"> + The server MUST provide a protocol version that is lower than or + equal to that requested by the client in the protocol header. If + the server cannot support the specified protocol it MUST NOT send + this method, but MUST close the socket connection. + </rule> + <chassis name="client" implement="MUST"/> + <response name="start-ok"/> + <field name="version major" type="octet"> + protocol major version + <doc> + The protocol major version that the server agrees to use, which + cannot be higher than the client's major version. + </doc> + </field> + <field name="version minor" type="octet"> + protocol major version + <doc> + The protocol minor version that the server agrees to use, which + cannot be higher than the client's minor version. + </doc> + </field> + <field name="server properties" domain="peer properties"> + server properties + </field> + <field name="mechanisms" type="longstr"> + available security mechanisms + <doc> + A list of the security mechanisms that the server supports, delimited + by spaces. Currently ASL supports these mechanisms: PLAIN. + </doc> + <see name="security mechanisms"/> + <assert check="notnull"/> + </field> + <field name="locales" type="longstr"> + available message locales + <doc> + A list of the message locales that the server supports, delimited + by spaces. The locale defines the language in which the server + will send reply texts. + </doc> + <rule implement="MUST"> + All servers MUST support at least the en_US locale. + </rule> + <assert check="notnull"/> + </field> + </method> + <method name="start-ok" synchronous="1" index="11"> + select security mechanism and locale + <doc> + This method selects a SASL security mechanism. ASL uses SASL + (RFC2222) to negotiate authentication and encryption. + </doc> + <chassis name="server" implement="MUST"/> + <field name="client properties" domain="peer properties"> + client properties + </field> + <field name="mechanism" type="shortstr"> + selected security mechanism + <doc> + A single security mechanisms selected by the client, which must be + one of those specified by the server. + </doc> + <rule implement="SHOULD"> + The client SHOULD authenticate using the highest-level security + profile it can handle from the list provided by the server. + </rule> + <rule implement="MUST"> + The mechanism field MUST contain one of the security mechanisms + proposed by the server in the Start method. If it doesn't, the + server MUST close the socket. + </rule> + <assert check="notnull"/> + </field> + <field name="response" type="longstr"> + security response data + <doc> + A block of opaque data passed to the security mechanism. The contents + of this data are defined by the SASL security mechanism. For the + PLAIN security mechanism this is defined as a field table holding + two fields, LOGIN and PASSWORD. + </doc> + <assert check="notnull"/> + </field> + <field name="locale" type="shortstr"> + selected message locale + <doc> + A single message local selected by the client, which must be one + of those specified by the server. + </doc> + <assert check="notnull"/> + </field> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="secure" synchronous="1" index="20"> + security mechanism challenge + <doc> + The SASL protocol works by exchanging challenges and responses until + both peers have received sufficient information to authenticate each + other. This method challenges the client to provide more information. + </doc> + <chassis name="client" implement="MUST"/> + <response name="secure-ok"/> + <field name="challenge" type="longstr"> + security challenge data + <doc> + Challenge information, a block of opaque binary data passed to + the security mechanism. + </doc> + <see name="security mechanisms"/> + </field> + </method> + <method name="secure-ok" synchronous="1" index="21"> + security mechanism response + <doc> + This method attempts to authenticate, passing a block of SASL data + for the security mechanism at the server side. + </doc> + <chassis name="server" implement="MUST"/> + <field name="response" type="longstr"> + security response data + <doc> + A block of opaque data passed to the security mechanism. The contents + of this data are defined by the SASL security mechanism. + </doc> + <assert check="notnull"/> + </field> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="tune" synchronous="1" index="30"> + propose connection tuning parameters + <doc> + This method proposes a set of connection configuration values + to the client. The client can accept and/or adjust these. + </doc> + <chassis name="client" implement="MUST"/> + <response name="tune-ok"/> + <field name="channel max" type="short"> + proposed maximum channels + <doc> + The maximum total number of channels that the server allows + per connection. Zero means that the server does not impose a + fixed limit, but the number of allowed channels may be limited + by available server resources. + </doc> + </field> + <field name="frame max" type="long"> + proposed maximum frame size + <doc> + The largest frame size that the server proposes for the + connection. The client can negotiate a lower value. Zero means + that the server does not impose any specific limit but may reject + very large frames if it cannot allocate resources for them. + </doc> + <rule implement="MUST"> + Until the frame-max has been negotiated, both peers MUST accept + frames of up to 4096 octets large. The minimum non-zero value for + the frame-max field is 4096. + </rule> + </field> + <field name="heartbeat" type="short"> + desired heartbeat delay + <doc> + The delay, in seconds, of the connection heartbeat that the server + wants. Zero means the server does not want a heartbeat. + </doc> + </field> + </method> + <method name="tune-ok" synchronous="1" index="31"> + negotiate connection tuning parameters + <doc> + This method sends the client's connection tuning parameters to the + server. Certain fields are negotiated, others provide capability + information. + </doc> + <chassis name="server" implement="MUST"/> + <field name="channel max" type="short"> + negotiated maximum channels + <doc> + The maximum total number of channels that the client will use + per connection. May not be higher than the value specified by + the server. + </doc> + <rule implement="MAY"> + The server MAY ignore the channel-max value or MAY use it for + tuning its resource allocation. + </rule> + <assert check="notnull"/> + <assert check="le" method="tune" field="channel max"/> + </field> + <field name="frame max" type="long"> + negotiated maximum frame size + <doc> + The largest frame size that the client and server will use for + the connection. Zero means that the client does not impose any + specific limit but may reject very large frames if it cannot + allocate resources for them. Note that the frame-max limit + applies principally to content frames, where large contents + can be broken into frames of arbitrary size. + </doc> + <rule implement="MUST"> + Until the frame-max has been negotiated, both peers must accept + frames of up to 4096 octets large. The minimum non-zero value for + the frame-max field is 4096. + </rule> + </field> + <field name="heartbeat" type="short"> + desired heartbeat delay + <doc> + The delay, in seconds, of the connection heartbeat that the client + wants. Zero means the client does not want a heartbeat. + </doc> + </field> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="open" synchronous="1" index="40"> + open connection to virtual host + <doc> + This method opens a connection to a virtual host, which is a + collection of resources, and acts to separate multiple application + domains within a server. + </doc> + <rule implement="MUST"> + The client MUST open the context before doing any work on the + connection. + </rule> + <chassis name="server" implement="MUST"/> + <response name="open-ok"/> + <response name="redirect"/> + <field name="virtual host" domain="path"> + virtual host name + <assert check="regexp" value="^[a-zA-Z0-9/-_]+$"/> + <doc> + The name of the virtual host to work with. + </doc> + <rule implement="MUST"> + If the server supports multiple virtual hosts, it MUST enforce a + full separation of exchanges, queues, and all associated entities + per virtual host. An application, connected to a specific virtual + host, MUST NOT be able to access resources of another virtual host. + </rule> + <rule implement="SHOULD"> + The server SHOULD verify that the client has permission to access + the specified virtual host. + </rule> + <rule implement="MAY"> + The server MAY configure arbitrary limits per virtual host, such + as the number of each type of entity that may be used, per + connection and/or in total. + </rule> + </field> + <field name="capabilities" type="shortstr"> + required capabilities + <doc> + The client may specify a number of capability names, delimited by + spaces. The server can use this string to how to process the + client's connection request. + </doc> + </field> + <field name="insist" type="bit"> + insist on connecting to server + <doc> + In a configuration with multiple load-sharing servers, the server + may respond to a Connection.Open method with a Connection.Redirect. + The insist option tells the server that the client is insisting on + a connection to the specified server. + </doc> + <rule implement="SHOULD"> + When the client uses the insist option, the server SHOULD accept + the client connection unless it is technically unable to do so. + </rule> + </field> + </method> + <method name="open-ok" synchronous="1" index="41"> + signal that the connection is ready + <doc> + This method signals to the client that the connection is ready for + use. + </doc> + <chassis name="client" implement="MUST"/> + <field name="known hosts" domain="known hosts"/> + </method> + <method name="redirect" synchronous="1" index="50"> + asks the client to use a different server + <doc> + This method redirects the client to another server, based on the + requested virtual host and/or capabilities. + </doc> + <rule implement="SHOULD"> + When getting the Connection.Redirect method, the client SHOULD + reconnect to the host specified, and if that host is not present, + to any of the hosts specified in the known-hosts list. + </rule> + <chassis name="client" implement="MAY"/> + <field name="host" type="shortstr"> + server to connect to + <doc> + Specifies the server to connect to. This is an IP address or a + DNS name, optionally followed by a colon and a port number. If + no port number is specified, the client should use the default + port number for the protocol. + </doc> + <assert check="notnull"/> + </field> + <field name="known hosts" domain="known hosts"/> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="close" synchronous="1" index="60"> + request a connection close + <doc> + This method indicates that the sender wants to close the connection. + This may be due to internal conditions (e.g. a forced shut-down) or + due to an error handling a specific method, i.e. an exception. When + a close is due to an exception, the sender provides the class and + method id of the method which caused the exception. + </doc> + <rule implement="MUST"> + After sending this method any received method except the Close-OK + method MUST be discarded. + </rule> + <rule implement="MAY"> + The peer sending this method MAY use a counter or timeout to + detect failure of the other peer to respond correctly with + the Close-OK method. + </rule> + <rule implement="MUST"> + When a server receives the Close method from a client it MUST + delete all server-side resources associated with the client's + context. A client CANNOT reconnect to a context after sending + or receiving a Close method. + </rule> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <response name="close-ok"/> + <field name="reply code" domain="reply code"/> + <field name="reply text" domain="reply text"/> + <field name="class id" domain="class id"> + failing method class + <doc> + When the close is provoked by a method exception, this is the + class of the method. + </doc> + </field> + <field name="method id" domain="class id"> + failing method ID + <doc> + When the close is provoked by a method exception, this is the + ID of the method. + </doc> + </field> + </method> + <method name="close-ok" synchronous="1" index="61"> + confirm a connection close + <doc> + This method confirms a Connection.Close method and tells the + recipient that it is safe to release resources for the connection + and close the socket. + </doc> + <rule implement="SHOULD"> + A peer that detects a socket closure without having received a + Close-Ok handshake method SHOULD log the error. + </rule> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + </method> + </class> + <class name="channel" handler="channel" index="20"> + <!-- +====================================================== +== CHANNEL +====================================================== +--> + work with channels +<doc> + The channel class provides methods for a client to establish a virtual + connection - a channel - to a server and for both peers to operate the + virtual connection thereafter. +</doc> + <doc name="grammar"> + channel = open-channel *use-channel close-channel + open-channel = C:OPEN S:OPEN-OK + use-channel = C:FLOW S:FLOW-OK + / S:FLOW C:FLOW-OK + / S:ALERT + / functional-class + close-channel = C:CLOSE S:CLOSE-OK + / S:CLOSE C:CLOSE-OK +</doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="open" synchronous="1" index="10"> + open a channel for use + <doc> + This method opens a virtual connection (a channel). + </doc> + <rule implement="MUST"> + This method MUST NOT be called when the channel is already open. + </rule> + <chassis name="server" implement="MUST"/> + <response name="open-ok"/> + <field name="out of band" type="shortstr"> + out-of-band settings + <doc> + Configures out-of-band transfers on this channel. The syntax and + meaning of this field will be formally defined at a later date. + </doc> + <assert check="null"/> + </field> + </method> + <method name="open-ok" synchronous="1" index="11"> + signal that the channel is ready + <doc> + This method signals to the client that the channel is ready for use. + </doc> + <chassis name="client" implement="MUST"/> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="flow" synchronous="1" index="20"> + enable/disable flow from peer + <doc> + This method asks the peer to pause or restart the flow of content + data. This is a simple flow-control mechanism that a peer can use + to avoid oveflowing its queues or otherwise finding itself receiving + more messages than it can process. Note that this method is not + intended for window control. The peer that receives a request to + stop sending content should finish sending the current content, if + any, and then wait until it receives a Flow restart method. + </doc> + <rule implement="MAY"> + When a new channel is opened, it is active. Some applications + assume that channels are inactive until started. To emulate this + behaviour a client MAY open the channel, then pause it. + </rule> + <rule implement="SHOULD"> + When sending content data in multiple frames, a peer SHOULD monitor + the channel for incoming methods and respond to a Channel.Flow as + rapidly as possible. + </rule> + <rule implement="MAY"> + A peer MAY use the Channel.Flow method to throttle incoming content + data for internal reasons, for example, when exchangeing data over a + slower connection. + </rule> + <rule implement="MAY"> + The peer that requests a Channel.Flow method MAY disconnect and/or + ban a peer that does not respect the request. + </rule> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + <response name="flow-ok"/> + <field name="active" type="bit"> + start/stop content frames + <doc> + If 1, the peer starts sending content frames. If 0, the peer + stops sending content frames. + </doc> + </field> + </method> + <method name="flow-ok" index="21"> + confirm a flow method + <doc> + Confirms to the peer that a flow command was received and processed. + </doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + <field name="active" type="bit"> + current flow setting + <doc> + Confirms the setting of the processed flow method: 1 means the + peer will start sending or continue to send content frames; 0 + means it will not. + </doc> + </field> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="alert" index="30"> + send a non-fatal warning message + <doc> + This method allows the server to send a non-fatal warning to the + client. This is used for methods that are normally asynchronous + and thus do not have confirmations, and for which the server may + detect errors that need to be reported. Fatal errors are handled + as channel or connection exceptions; non-fatal errors are sent + through this method. + </doc> + <chassis name="client" implement="MUST"/> + <field name="reply code" domain="reply code"/> + <field name="reply text" domain="reply text"/> + <field name="details" type="table"> + detailed information for warning + <doc> + A set of fields that provide more information about the + problem. The meaning of these fields are defined on a + per-reply-code basis (TO BE DEFINED). + </doc> + </field> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="close" synchronous="1" index="40"> + request a channel close + <doc> + This method indicates that the sender wants to close the channel. + This may be due to internal conditions (e.g. a forced shut-down) or + due to an error handling a specific method, i.e. an exception. When + a close is due to an exception, the sender provides the class and + method id of the method which caused the exception. + </doc> + <rule implement="MUST"> + After sending this method any received method except + Channel.Close-OK MUST be discarded. + </rule> + <rule implement="MAY"> + The peer sending this method MAY use a counter or timeout to detect + failure of the other peer to respond correctly with Channel.Close-OK.. + </rule> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <response name="close-ok"/> + <field name="reply code" domain="reply code"/> + <field name="reply text" domain="reply text"/> + <field name="class id" domain="class id"> + failing method class + <doc> + When the close is provoked by a method exception, this is the + class of the method. + </doc> + </field> + <field name="method id" domain="method id"> + failing method ID + <doc> + When the close is provoked by a method exception, this is the + ID of the method. + </doc> + </field> + </method> + <method name="close-ok" synchronous="1" index="41"> + confirm a channel close + <doc> + This method confirms a Channel.Close method and tells the recipient + that it is safe to release resources for the channel and close the + socket. + </doc> + <rule implement="SHOULD"> + A peer that detects a socket closure without having received a + Channel.Close-Ok handshake method SHOULD log the error. + </rule> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + </method> + </class> + <class name="access" handler="connection" index="30"> + <!-- +====================================================== +== ACCESS CONTROL +====================================================== +--> + work with access tickets +<doc> + The protocol control access to server resources using access tickets. + A client must explicitly request access tickets before doing work. + An access ticket grants a client the right to use a specific set of + resources - called a "realm" - in specific ways. +</doc> + <doc name="grammar"> + access = C:REQUEST S:REQUEST-OK +</doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="request" synchronous="1" index="10"> + request an access ticket + <doc> + This method requests an access ticket for an access realm. + The server responds by granting the access ticket. If the + client does not have access rights to the requested realm + this causes a connection exception. Access tickets are a + per-channel resource. + </doc> + <rule implement="MUST"> + The realm name MUST start with either "/data" (for application + resources) or "/admin" (for server administration resources). + If the realm starts with any other path, the server MUST raise + a connection exception with reply code 403 (access refused). + </rule> + <rule implement="MUST"> + The server MUST implement the /data realm and MAY implement the + /admin realm. The mapping of resources to realms is not + defined in the protocol - this is a server-side configuration + issue. + </rule> + <chassis name="server" implement="MUST"/> + <response name="request-ok"/> + <field name="realm" domain="path"> + name of requested realm + <rule implement="MUST"> + If the specified realm is not known to the server, the server + must raise a channel exception with reply code 402 (invalid + path). + </rule> + </field> + <field name="exclusive" type="bit"> + request exclusive access + <doc> + Request exclusive access to the realm. If the server cannot grant + this - because there are other active tickets for the realm - it + raises a channel exception. + </doc> + </field> + <field name="passive" type="bit"> + request passive access + <doc> + Request message passive access to the specified access realm. + Passive access lets a client get information about resources in + the realm but not to make any changes to them. + </doc> + </field> + <field name="active" type="bit"> + request active access + <doc> + Request message active access to the specified access realm. + Acvtive access lets a client get create and delete resources in + the realm. + </doc> + </field> + <field name="write" type="bit"> + request write access + <doc> + Request write access to the specified access realm. Write access + lets a client publish messages to all exchanges in the realm. + </doc> + </field> + <field name="read" type="bit"> + request read access + <doc> + Request read access to the specified access realm. Read access + lets a client consume messages from queues in the realm. + </doc> + </field> + </method> + <method name="request-ok" synchronous="1" index="11"> + grant access to server resources + <doc> + This method provides the client with an access ticket. The access + ticket is valid within the current channel and for the lifespan of + the channel. + </doc> + <rule implement="MUST"> + The client MUST NOT use access tickets except within the same + channel as originally granted. + </rule> + <rule implement="MUST"> + The server MUST isolate access tickets per channel and treat an + attempt by a client to mix these as a connection exception. + </rule> + <chassis name="client" implement="MUST"/> + <field name="ticket" domain="access ticket"/> + </method> + </class> + <class name="exchange" handler="channel" index="40"> + <!-- +====================================================== +== EXCHANGES (or "routers", if you prefer) +== (Or matchers, plugins, extensions, agents,... Routing is just one of +== the many fun things an exchange can do.) +====================================================== +--> + work with exchanges +<doc> + Exchanges match and distribute messages across queues. Exchanges can be + configured in the server or created at runtime. +</doc> + <doc name="grammar"> + exchange = C:DECLARE S:DECLARE-OK + / C:DELETE S:DELETE-OK +</doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + <rule implement="MUST"> + <test>amq_exchange_19</test> + The server MUST implement the direct and fanout exchange types, and + predeclare the corresponding exchanges named amq.direct and amq.fanout + in each virtual host. The server MUST also predeclare a direct + exchange to act as the default exchange for content Publish methods + and for default queue bindings. +</rule> + <rule implement="SHOULD"> + <test>amq_exchange_20</test> + The server SHOULD implement the topic exchange type, and predeclare + the corresponding exchange named amq.topic in each virtual host. +</rule> + <rule implement="MAY"> + <test>amq_exchange_21</test> + The server MAY implement the system exchange type, and predeclare the + corresponding exchanges named amq.system in each virtual host. If the + client attempts to bind a queue to the system exchange, the server + MUST raise a connection exception with reply code 507 (not allowed). +</rule> + <rule implement="MUST"> + <test>amq_exchange_22</test> + The default exchange MUST be defined as internal, and be inaccessible + to the client except by specifying an empty exchange name in a content + Publish method. That is, the server MUST NOT let clients make explicit + bindings to this exchange. +</rule> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="declare" synchronous="1" index="10"> + declare exchange, create if needed + <doc> + This method creates an exchange if it does not already exist, and if the + exchange exists, verifies that it is of the correct and expected class. + </doc> + <rule implement="SHOULD"> + <test>amq_exchange_23</test> + The server SHOULD support a minimum of 16 exchanges per virtual host + and ideally, impose no limit except as defined by available resources. + </rule> + <chassis name="server" implement="MUST"/> + <response name="declare-ok"/> + <field name="ticket" domain="access ticket"> + <doc> + When a client defines a new exchange, this belongs to the access realm + of the ticket used. All further work done with that exchange must be + done with an access ticket for the same realm. + </doc> + <rule implement="MUST"> + The client MUST provide a valid access ticket giving "active" access + to the realm in which the exchange exists or will be created, or + "passive" access if the if-exists flag is set. + </rule> + </field> + <field name="exchange" domain="exchange name"> + <rule implement="MUST"> + <test>amq_exchange_15</test> + Exchange names starting with "amq." are reserved for predeclared + and standardised exchanges. If the client attempts to create an + exchange starting with "amq.", the server MUST raise a channel + exception with reply code 403 (access refused). + </rule> + <assert check="regexp" value="^[a-zA-Z0-9-_.:]+$"/> + </field> + <field name="type" type="shortstr"> + exchange type + <doc> + Each exchange belongs to one of a set of exchange types implemented + by the server. The exchange types define the functionality of the + exchange - i.e. how messages are routed through it. It is not valid + or meaningful to attempt to change the type of an existing exchange. + </doc> + <rule implement="MUST"> + <test>amq_exchange_16</test> + If the exchange already exists with a different type, the server + MUST raise a connection exception with a reply code 507 (not allowed). + </rule> + <rule implement="MUST"> + <test>amq_exchange_18</test> + If the server does not support the requested exchange type it MUST + raise a connection exception with a reply code 503 (command invalid). + </rule> + <assert check="regexp" value="^[a-zA-Z0-9-_.:]+$"/> + </field> + <field name="passive" type="bit"> + do not create exchange + <doc> + If set, the server will not create the exchange. The client can use + this to check whether an exchange exists without modifying the server + state. + </doc> + <rule implement="MUST"> + <test>amq_exchange_05</test> + If set, and the exchange does not already exist, the server MUST + raise a channel exception with reply code 404 (not found). + </rule> + </field> + <field name="durable" type="bit"> + request a durable exchange + <doc> + If set when creating a new exchange, the exchange will be marked as + durable. Durable exchanges remain active when a server restarts. + Non-durable exchanges (transient exchanges) are purged if/when a + server restarts. + </doc> + <rule implement="MUST"> + <test>amq_exchange_24</test> + The server MUST support both durable and transient exchanges. + </rule> + <rule implement="MUST"> + The server MUST ignore the durable field if the exchange already + exists. + </rule> + </field> + <field name="auto delete" type="bit"> + auto-delete when unused + <doc> + If set, the exchange is deleted when all queues have finished + using it. + </doc> + <rule implement="SHOULD"> + <test>amq_exchange_02</test> + The server SHOULD allow for a reasonable delay between the point + when it determines that an exchange is not being used (or no longer + used), and the point when it deletes the exchange. At the least it + must allow a client to create an exchange and then bind a queue to + it, with a small but non-zero delay between these two actions. + </rule> + <rule implement="MUST"> + <test>amq_exchange_25</test> + The server MUST ignore the auto-delete field if the exchange already + exists. + </rule> + </field> + <field name="internal" type="bit"> + create internal exchange + <doc> + If set, the exchange may not be used directly by publishers, but + only when bound to other exchanges. Internal exchanges are used to + construct wiring that is not visible to applications. + </doc> + </field> + + <field name = "nowait" type = "bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The client should + not wait for a reply method. If the server could not complete the + method it will raise a channel or connection exception. + </doc> + </field> + + <field name="arguments" type="table"> + arguments for declaration + <doc> + A set of arguments for the declaration. The syntax and semantics + of these arguments depends on the server implementation. This + field is ignored if passive is 1. + </doc> + </field> + </method> + <method name="declare-ok" synchronous="1" index="11"> + confirms an exchange declaration + <doc> + This method confirms a Declare method and confirms the name of the + exchange, essential for automatically-named exchanges. + </doc> + <chassis name="client" implement="MUST"/> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="delete" synchronous="1" index="20"> + delete an exchange + <doc> + This method deletes an exchange. When an exchange is deleted all queue + bindings on the exchange are cancelled. + </doc> + <chassis name="server" implement="MUST"/> + <response name="delete-ok"/> + <field name="ticket" domain="access ticket"> + <rule implement="MUST"> + The client MUST provide a valid access ticket giving "active" + access rights to the exchange's access realm. + </rule> + </field> + <field name="exchange" domain="exchange name"> + <rule implement="MUST"> + <test>amq_exchange_11</test> + The exchange MUST exist. Attempting to delete a non-existing exchange + causes a channel exception. + </rule> + <assert check="notnull"/> + </field> + <field name="if unused" type="bit"> + delete only if unused + <doc> + If set, the server will only delete the exchange if it has no queue + bindings. If the exchange has queue bindings the server does not + delete it but raises a channel exception instead. + </doc> + <rule implement="SHOULD"> + <test>amq_exchange_12</test> + If set, the server SHOULD delete the exchange but only if it has + no queue bindings. + </rule> + <rule implement="SHOULD"> + <test>amq_exchange_13</test> + If set, the server SHOULD raise a channel exception if the exchange is in + use. + </rule> + </field> + + <field name = "nowait" type = "bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The client should + not wait for a reply method. If the server could not complete the + method it will raise a channel or connection exception. + </doc> + </field> + + </method> + <method name="delete-ok" synchronous="1" index="21"> + confirm deletion of an exchange + <doc> + This method confirms the deletion of an exchange. + </doc> + <chassis name="client" implement="MUST"/> + </method> + </class> + <class name="queue" handler="channel" index="50"> + <!-- +====================================================== +== QUEUES +====================================================== +--> + work with queues + +<doc> + Queues store and forward messages. Queues can be configured in the server + or created at runtime. Queues must be attached to at least one exchange + in order to receive messages from publishers. +</doc> + <doc name="grammar"> + queue = C:DECLARE S:DECLARE-OK + / C:BIND S:BIND-OK + / C:PURGE S:PURGE-OK + / C:DELETE S:DELETE-OK +</doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + <rule implement="MUST"> + <test>amq_queue_33</test> + A server MUST allow any content class to be sent to any queue, in any + mix, and queue and delivery these content classes independently. Note + that all methods that fetch content off queues are specific to a given + content class. +</rule> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="declare" synchronous="1" index="10"> + declare queue, create if needed + <doc> + This method creates or checks a queue. When creating a new queue + the client can specify various properties that control the durability + of the queue and its contents, and the level of sharing for the queue. + </doc> + <rule implement="MUST"> + <test>amq_queue_34</test> + The server MUST create a default binding for a newly-created queue + to the default exchange, which is an exchange of type 'direct'. + </rule> + <rule implement="SHOULD"> + <test>amq_queue_35</test> + The server SHOULD support a minimum of 256 queues per virtual host + and ideally, impose no limit except as defined by available resources. + </rule> + <chassis name="server" implement="MUST"/> + <response name="declare-ok"/> + <field name="ticket" domain="access ticket"> + <doc> + When a client defines a new queue, this belongs to the access realm + of the ticket used. All further work done with that queue must be + done with an access ticket for the same realm. + </doc> + <doc> + The client provides a valid access ticket giving "active" access + to the realm in which the queue exists or will be created, or + "passive" access if the if-exists flag is set. + </doc> + </field> + <field name="queue" domain="queue name"> + <rule implement="MAY"> + <test>amq_queue_10</test> + The queue name MAY be empty, in which case the server MUST create + a new queue with a unique generated name and return this to the + client in the Declare-Ok method. + </rule> + <rule implement="MUST"> + <test>amq_queue_32</test> + Queue names starting with "amq." are reserved for predeclared and + standardised server queues. If the queue name starts with "amq." + and the passive option is zero, the server MUST raise a connection + exception with reply code 403 (access refused). + </rule> + <assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/> + </field> + <field name="passive" type="bit"> + do not create queue + <doc> + If set, the server will not create the queue. The client can use + this to check whether a queue exists without modifying the server + state. + </doc> + <rule implement="MUST"> + <test>amq_queue_05</test> + If set, and the queue does not already exist, the server MUST + respond with a reply code 404 (not found) and raise a channel + exception. + </rule> + </field> + <field name="durable" type="bit"> + request a durable queue + <doc> + If set when creating a new queue, the queue will be marked as + durable. Durable queues remain active when a server restarts. + Non-durable queues (transient queues) are purged if/when a + server restarts. Note that durable queues do not necessarily + hold persistent messages, although it does not make sense to + send persistent messages to a transient queue. + </doc> + <rule implement="MUST"> + <test>amq_queue_03</test> + The server MUST recreate the durable queue after a restart. + </rule> + <rule implement="MUST"> + <test>amq_queue_36</test> + The server MUST support both durable and transient queues. + </rule> + <rule implement="MUST"> + <test>amq_queue_37</test> + The server MUST ignore the durable field if the queue already + exists. + </rule> + </field> + <field name="exclusive" type="bit"> + request an exclusive queue + <doc> + Exclusive queues may only be consumed from by the current connection. + Setting the 'exclusive' flag always implies 'auto-delete'. + </doc> + <rule implement="MUST"> + <test>amq_queue_38</test> + The server MUST support both exclusive (private) and non-exclusive + (shared) queues. + </rule> + <rule implement="MUST"> + <test>amq_queue_04</test> + The server MUST raise a channel exception if 'exclusive' is specified + and the queue already exists and is owned by a different connection. + </rule> + </field> + <field name="auto delete" type="bit"> + auto-delete queue when unused + <doc> + If set, the queue is deleted when all consumers have finished + using it. Last consumer can be cancelled either explicitly or because + its channel is closed. If there was no consumer ever on the queue, it + won't be deleted. + </doc> + <rule implement="SHOULD"> + <test>amq_queue_02</test> + The server SHOULD allow for a reasonable delay between the point + when it determines that a queue is not being used (or no longer + used), and the point when it deletes the queue. At the least it + must allow a client to create a queue and then create a consumer + to read from it, with a small but non-zero delay between these + two actions. The server should equally allow for clients that may + be disconnected prematurely, and wish to re-consume from the same + queue without losing messages. We would recommend a configurable + timeout, with a suitable default value being one minute. + </rule> + <rule implement="MUST"> + <test>amq_queue_31</test> + The server MUST ignore the auto-delete field if the queue already + exists. + </rule> + </field> + <field name = "nowait" type = "bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The client should + not wait for a reply method. If the server could not complete the + method it will raise a channel or connection exception. + </doc> + </field> + + <field name="arguments" type="table"> + arguments for declaration + <doc> + A set of arguments for the declaration. The syntax and semantics + of these arguments depends on the server implementation. This + field is ignored if passive is 1. + </doc> + </field> + </method> + <method name="declare-ok" synchronous="1" index="11"> + confirms a queue definition + <doc> + This method confirms a Declare method and confirms the name of the + queue, essential for automatically-named queues. + </doc> + <chassis name="client" implement="MUST"/> + <field name="queue" domain="queue name"> + <doc> + Reports the name of the queue. If the server generated a queue + name, this field contains that name. + </doc> + <assert check="notnull"/> + </field> + <field name="message count" type="long"> + number of messages in queue + <doc> + Reports the number of messages in the queue, which will be zero + for newly-created queues. + </doc> + </field> + <field name="consumer count" type="long"> + number of consumers + <doc> + Reports the number of active consumers for the queue. Note that + consumers can suspend activity (Channel.Flow) in which case they + do not appear in this count. + </doc> + </field> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="bind" synchronous="1" index="20"> + bind queue to an exchange + <doc> + This method binds a queue to an exchange. Until a queue is + bound it will not receive any messages. In a classic messaging + model, store-and-forward queues are bound to a dest exchange + and subscription queues are bound to a dest_wild exchange. + </doc> + <rule implement="MUST"> + <test>amq_queue_25</test> + A server MUST allow ignore duplicate bindings - that is, two or + more bind methods for a specific queue, with identical arguments + - without treating these as an error. + </rule> + <rule implement="MUST"> + <test>amq_queue_39</test> + If a bind fails, the server MUST raise a connection exception. + </rule> + <rule implement="MUST"> + <test>amq_queue_12</test> + The server MUST NOT allow a durable queue to bind to a transient + exchange. If the client attempts this the server MUST raise a + channel exception. + </rule> + <rule implement="SHOULD"> + <test>amq_queue_13</test> + Bindings for durable queues are automatically durable and the + server SHOULD restore such bindings after a server restart. + </rule> + <rule implement="MUST"> + <test>amq_queue_17</test> + If the client attempts to an exchange that was declared as internal, + the server MUST raise a connection exception with reply code 530 + (not allowed). + </rule> + <rule implement="SHOULD"> + <test>amq_queue_40</test> + The server SHOULD support at least 4 bindings per queue, and + ideally, impose no limit except as defined by available resources. + </rule> + <chassis name="server" implement="MUST"/> + <response name="bind-ok"/> + <field name="ticket" domain="access ticket"> + <doc> + The client provides a valid access ticket giving "active" + access rights to the queue's access realm. + </doc> + </field> + + <field name = "queue" domain = "queue name"> + <doc> + Specifies the name of the queue to bind. If the queue name is + empty, refers to the current queue for the channel, which is + the last declared queue. + </doc> + <doc name = "rule"> + If the client did not previously declare a queue, and the queue + name in this method is empty, the server MUST raise a connection + exception with reply code 530 (not allowed). + </doc> + <doc name = "rule" test = "amq_queue_26"> + If the queue does not exist the server MUST raise a channel exception + with reply code 404 (not found). + </doc> + </field> + + <field name="exchange" domain="exchange name"> + The name of the exchange to bind to. + <rule implement="MUST"> + <test>amq_queue_14</test> + If the exchange does not exist the server MUST raise a channel + exception with reply code 404 (not found). + </rule> + </field> + <field name="routing key" type="shortstr"> + message routing key + <doc> + Specifies the routing key for the binding. The routing key is + used for routing messages depending on the exchange configuration. + Not all exchanges use a routing key - refer to the specific + exchange documentation. If the routing key is empty and the queue + name is empty, the routing key will be the current queue for the + channel, which is the last declared queue. + </doc> + </field> + + <field name = "nowait" type = "bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The client should + not wait for a reply method. If the server could not complete the + method it will raise a channel or connection exception. + </doc> + </field> + + <field name="arguments" type="table"> + arguments for binding + <doc> + A set of arguments for the binding. The syntax and semantics of + these arguments depends on the exchange class. + </doc> + </field> + </method> + <method name="bind-ok" synchronous="1" index="21"> + confirm bind successful + <doc> + This method confirms that the bind was successful. + </doc> + <chassis name="client" implement="MUST"/> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="purge" synchronous="1" index="30"> + purge a queue + <doc> + This method removes all messages from a queue. It does not cancel + consumers. Purged messages are deleted without any formal "undo" + mechanism. + </doc> + <rule implement="MUST"> + <test>amq_queue_15</test> + A call to purge MUST result in an empty queue. + </rule> + <rule implement="MUST"> + <test>amq_queue_41</test> + On transacted channels the server MUST not purge messages that have + already been sent to a client but not yet acknowledged. + </rule> + <rule implement="MAY"> + <test>amq_queue_42</test> + The server MAY implement a purge queue or log that allows system + administrators to recover accidentally-purged messages. The server + SHOULD NOT keep purged messages in the same storage spaces as the + live messages since the volumes of purged messages may get very + large. + </rule> + <chassis name="server" implement="MUST"/> + <response name="purge-ok"/> + <field name="ticket" domain="access ticket"> + <doc> + The access ticket must be for the access realm that holds the + queue. + </doc> + <rule implement="MUST"> + The client MUST provide a valid access ticket giving "read" access + rights to the queue's access realm. Note that purging a queue is + equivalent to reading all messages and discarding them. + </rule> + </field> + <field name = "queue" domain = "queue name"> + <doc> + Specifies the name of the queue to purge. If the queue name is + empty, refers to the current queue for the channel, which is + the last declared queue. + </doc> + <doc name = "rule"> + If the client did not previously declare a queue, and the queue + name in this method is empty, the server MUST raise a connection + exception with reply code 530 (not allowed). + </doc> + <doc name = "rule" test = "amq_queue_16"> + The queue must exist. Attempting to purge a non-existing queue + causes a channel exception. + </doc> + </field> + + <field name = "nowait" type = "bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The client should + not wait for a reply method. If the server could not complete the + method it will raise a channel or connection exception. + </doc> + </field> + </method> + <method name="purge-ok" synchronous="1" index="31"> + confirms a queue purge + <doc> + This method confirms the purge of a queue. + </doc> + <chassis name="client" implement="MUST"/> + <field name="message count" type="long"> + number of messages purged + <doc> + Reports the number of messages purged. + </doc> + </field> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="delete" synchronous="1" index="40"> + delete a queue + <doc> + This method deletes a queue. When a queue is deleted any pending + messages are sent to a dead-letter queue if this is defined in the + server configuration, and all consumers on the queue are cancelled. + </doc> + <rule implement="SHOULD"> + <test>amq_queue_43</test> + The server SHOULD use a dead-letter queue to hold messages that + were pending on a deleted queue, and MAY provide facilities for + a system administrator to move these messages back to an active + queue. + </rule> + <chassis name="server" implement="MUST"/> + <response name="delete-ok"/> + <field name="ticket" domain="access ticket"> + <doc> + The client provides a valid access ticket giving "active" + access rights to the queue's access realm. + </doc> + </field> + + <field name = "queue" domain = "queue name"> + <doc> + Specifies the name of the queue to delete. If the queue name is + empty, refers to the current queue for the channel, which is the + last declared queue. + </doc> + <doc name = "rule"> + If the client did not previously declare a queue, and the queue + name in this method is empty, the server MUST raise a connection + exception with reply code 530 (not allowed). + </doc> + <doc name = "rule" test = "amq_queue_21"> + The queue must exist. Attempting to delete a non-existing queue + causes a channel exception. + </doc> + </field> + + <field name="if unused" type="bit"> + delete only if unused + <doc> + If set, the server will only delete the queue if it has no + consumers. If the queue has consumers the server does does not + delete it but raises a channel exception instead. + </doc> + <rule implement="MUST"> + <test>amq_queue_29</test> + <test>amq_queue_30</test> + The server MUST respect the if-unused flag when deleting a queue. + </rule> + </field> + <field name="if empty" type="bit"> + delete only if empty + <test>amq_queue_27</test> + <doc> + If set, the server will only delete the queue if it has no + messages. If the queue is not empty the server raises a channel + exception. + </doc> + </field> + <field name = "nowait" type = "bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The client should + not wait for a reply method. If the server could not complete the + method it will raise a channel or connection exception. + </doc> + </field> + </method> + + <method name="delete-ok" synchronous="1" index="41"> + confirm deletion of a queue + <doc> + This method confirms the deletion of a queue. + </doc> + <chassis name="client" implement="MUST"/> + <field name="message count" type="long"> + number of messages purged + <doc> + Reports the number of messages purged. + </doc> + </field> + </method> + </class> + <class name="basic" handler="channel" index="60"> + <!-- +====================================================== +== BASIC MIDDLEWARE +====================================================== +--> + work with basic content +<doc> + The Basic class provides methods that support an industry-standard + messaging model. +</doc> + +<doc name = "grammar"> + basic = C:QOS S:QOS-OK + / C:CONSUME S:CONSUME-OK + / C:CANCEL S:CANCEL-OK + / C:PUBLISH content + / S:RETURN content + / S:DELIVER content + / C:GET ( S:GET-OK content / S:GET-EMPTY ) + / C:ACK + / C:REJECT +</doc> + +<chassis name = "server" implement = "MUST" /> +<chassis name = "client" implement = "MAY" /> + +<doc name = "rule" test = "amq_basic_08"> + The server SHOULD respect the persistent property of basic messages + and SHOULD make a best-effort to hold persistent basic messages on a + reliable storage mechanism. +</doc> +<doc name = "rule" test = "amq_basic_09"> + The server MUST NOT discard a persistent basic message in case of a + queue overflow. The server MAY use the Channel.Flow method to slow + or stop a basic message publisher when necessary. +</doc> +<doc name = "rule" test = "amq_basic_10"> + The server MAY overflow non-persistent basic messages to persistent + storage and MAY discard or dead-letter non-persistent basic messages + on a priority basis if the queue size exceeds some configured limit. +</doc> +<doc name = "rule" test = "amq_basic_11"> + The server MUST implement at least 2 priority levels for basic + messages, where priorities 0-4 and 5-9 are treated as two distinct + levels. The server MAY implement up to 10 priority levels. +</doc> +<doc name = "rule" test = "amq_basic_12"> + The server MUST deliver messages of the same priority in order + irrespective of their individual persistence. +</doc> +<doc name = "rule" test = "amq_basic_13"> + The server MUST support both automatic and explicit acknowledgements + on Basic content. +</doc> + +<!-- These are the properties for a Basic content --> + +<field name = "content type" type = "shortstr"> + MIME content type +</field> +<field name = "content encoding" type = "shortstr"> + MIME content encoding +</field> +<field name = "headers" type = "table"> + Message header field table +</field> +<field name = "delivery mode" type = "octet"> + Non-persistent (1) or persistent (2) +</field> +<field name = "priority" type = "octet"> + The message priority, 0 to 9 +</field> +<field name = "correlation id" type = "shortstr"> + The application correlation identifier +</field> +<field name = "reply to" type = "shortstr"> + The destination to reply to +</field> +<field name = "expiration" type = "shortstr"> + Message expiration specification +</field> +<field name = "message id" type = "shortstr"> + The application message identifier +</field> +<field name = "timestamp" type = "timestamp"> + The message timestamp +</field> +<field name = "type" type = "shortstr"> + The message type name +</field> +<field name = "user id" type = "shortstr"> + The creating user id +</field> +<field name = "app id" type = "shortstr"> + The creating application id +</field> +<field name = "cluster id" type = "shortstr"> + Intra-cluster routing identifier +</field> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "qos" synchronous = "1" index = "10"> + specify quality of service + <doc> + This method requests a specific quality of service. The QoS can + be specified for the current channel or for all channels on the + connection. The particular properties and semantics of a qos method + always depend on the content class semantics. Though the qos method + could in principle apply to both peers, it is currently meaningful + only for the server. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "qos-ok" /> + + <field name = "prefetch size" type = "long"> + prefetch window in octets + <doc> + The client can request that messages be sent in advance so that + when the client finishes processing a message, the following + message is already held locally, rather than needing to be sent + down the channel. Prefetching gives a performance improvement. + This field specifies the prefetch window size in octets. The + server will send a message in advance if it is equal to or + smaller in size than the available prefetch size (and also falls + into other prefetch limits). May be set to zero, meaning "no + specific limit", although other prefetch limits may still apply. + The prefetch-size is ignored if the no-ack option is set. + </doc> + <doc name = "rule" test = "amq_basic_17"> + The server MUST ignore this setting when the client is not + processing any messages - i.e. the prefetch size does not limit + the transfer of single messages to a client, only the sending in + advance of more messages while the client still has one or more + unacknowledged messages. + </doc> + </field> + + <field name = "prefetch count" type = "short"> + prefetch window in messages + <doc> + Specifies a prefetch window in terms of whole messages. This + field may be used in combination with the prefetch-size field; + a message will only be sent in advance if both prefetch windows + (and those at the channel and connection level) allow it. + The prefetch-count is ignored if the no-ack option is set. + </doc> + <doc name = "rule" test = "amq_basic_18"> + The server MAY send less data in advance than allowed by the + client's specified prefetch windows but it MUST NOT send more. + </doc> + </field> + + <field name = "global" type = "bit"> + apply to entire connection + <doc> + By default the QoS settings apply to the current channel only. If + this field is set, they are applied to the entire connection. + </doc> + </field> +</method> + +<method name = "qos-ok" synchronous = "1" index = "11"> + confirm the requested qos + <doc> + This method tells the client that the requested QoS levels could + be handled by the server. The requested QoS applies to all active + consumers until a new QoS is defined. + </doc> + <chassis name = "client" implement = "MUST" /> +</method> + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "consume" synchronous = "1" index = "20"> + start a queue consumer + <doc> + This method asks the server to start a "consumer", which is a + transient request for messages from a specific queue. Consumers + last as long as the channel they were created on, or until the + client cancels them. + </doc> + <doc name = "rule" test = "amq_basic_01"> + The server SHOULD support at least 16 consumers per queue, unless + the queue was declared as private, and ideally, impose no limit + except as defined by available resources. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "consume-ok" /> + + <field name = "ticket" domain = "access ticket"> + <doc name = "rule"> + The client MUST provide a valid access ticket giving "read" access + rights to the realm for the queue. + </doc> + </field> + + <field name = "queue" domain = "queue name"> + <doc> + Specifies the name of the queue to consume from. If the queue name + is null, refers to the current queue for the channel, which is the + last declared queue. + </doc> + <doc name = "rule"> + If the client did not previously declare a queue, and the queue name + in this method is empty, the server MUST raise a connection exception + with reply code 530 (not allowed). + </doc> + </field> + + <field name = "consumer tag" domain = "consumer tag"> + <doc> + Specifies the identifier for the consumer. The consumer tag is + local to a connection, so two clients can use the same consumer + tags. If this field is empty the server will generate a unique + tag. + </doc> + <doc name = "rule" test = "todo"> + The tag MUST NOT refer to an existing consumer. If the client + attempts to create two consumers with the same non-empty tag + the server MUST raise a connection exception with reply code + 530 (not allowed). + </doc> + </field> + + <field name = "no local" domain = "no local" /> + + <field name = "no ack" domain = "no ack" /> + + <field name = "exclusive" type = "bit"> + request exclusive access + <doc> + Request exclusive consumer access, meaning only this consumer can + access the queue. + </doc> + <doc name = "rule" test = "amq_basic_02"> + If the server cannot grant exclusive access to the queue when asked, + - because there are other consumers active - it MUST raise a channel + exception with return code 403 (access refused). + </doc> + </field> + + <field name = "nowait" type = "bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The client should + not wait for a reply method. If the server could not complete the + method it will raise a channel or connection exception. + </doc> + </field> +</method> + +<method name = "consume-ok" synchronous = "1" index = "21"> + confirm a new consumer + <doc> + The server provides the client with a consumer tag, which is used + by the client for methods called on the consumer at a later stage. + </doc> + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer tag" domain = "consumer tag"> + <doc> + Holds the consumer tag specified by the client or provided by + the server. + </doc> + </field> +</method> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "cancel" synchronous = "1" index = "30"> + end a queue consumer + <doc test = "amq_basic_04"> + This method cancels a consumer. This does not affect already + delivered messages, but it does mean the server will not send any + more messages for that consumer. The client may receive an + abitrary number of messages in between sending the cancel method + and receiving the cancel-ok reply. + </doc> + <doc name = "rule" test = "todo"> + If the queue no longer exists when the client sends a cancel command, + or the consumer has been cancelled for other reasons, this command + has no effect. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "cancel-ok" /> + + <field name = "consumer tag" domain = "consumer tag" /> + + <field name = "nowait" type = "bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The client should + not wait for a reply method. If the server could not complete the + method it will raise a channel or connection exception. + </doc> + </field> +</method> + +<method name = "cancel-ok" synchronous = "1" index = "31"> + confirm a cancelled consumer + <doc> + This method confirms that the cancellation was completed. + </doc> + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer tag" domain = "consumer tag" /> +</method> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "publish" content = "1" index = "40"> + publish a message + <doc> + This method publishes a message to a specific exchange. The message + will be routed to queues as defined by the exchange configuration + and distributed to any active consumers when the transaction, if any, + is committed. + </doc> + <chassis name = "server" implement = "MUST" /> + + <field name = "ticket" domain = "access ticket"> + <doc name = "rule"> + The client MUST provide a valid access ticket giving "write" + access rights to the access realm for the exchange. + </doc> + </field> + + <field name = "exchange" domain = "exchange name"> + <doc> + Specifies the name of the exchange to publish to. The exchange + name can be empty, meaning the default exchange. If the exchange + name is specified, and that exchange does not exist, the server + will raise a channel exception. + </doc> + <doc name = "rule" test = "amq_basic_06"> + The server MUST accept a blank exchange name to mean the default + exchange. + </doc> + <doc name = "rule" test = "amq_basic_14"> + If the exchange was declared as an internal exchange, the server + MUST raise a channel exception with a reply code 403 (access + refused). + </doc> + <doc name = "rule" test = "amq_basic_15"> + The exchange MAY refuse basic content in which case it MUST raise + a channel exception with reply code 540 (not implemented). + </doc> + </field> + + <field name = "routing key" type = "shortstr"> + Message routing key + <doc> + Specifies the routing key for the message. The routing key is + used for routing messages depending on the exchange configuration. + </doc> + </field> + + <field name = "mandatory" type = "bit"> + indicate mandatory routing + <doc> + This flag tells the server how to react if the message cannot be + routed to a queue. If this flag is set, the server will return an + unroutable message with a Return method. If this flag is zero, the + server silently drops the message. + </doc> + <doc name = "rule" test = "amq_basic_07"> + The server SHOULD implement the mandatory flag. + </doc> + </field> + + <field name = "immediate" type = "bit"> + request immediate delivery + <doc> + This flag tells the server how to react if the message cannot be + routed to a queue consumer immediately. If this flag is set, the + server will return an undeliverable message with a Return method. + If this flag is zero, the server will queue the message, but with + no guarantee that it will ever be consumed. + </doc> + <doc name = "rule" test = "amq_basic_16"> + The server SHOULD implement the immediate flag. + </doc> + </field> +</method> + +<method name = "return" content = "1" index = "50"> + return a failed message + <doc> + This method returns an undeliverable message that was published + with the "immediate" flag set, or an unroutable message published + with the "mandatory" flag set. The reply code and text provide + information about the reason that the message was undeliverable. + </doc> + <chassis name = "client" implement = "MUST" /> + + <field name = "reply code" domain = "reply code" /> + <field name = "reply text" domain = "reply text" /> + + <field name = "exchange" domain = "exchange name"> + <doc> + Specifies the name of the exchange that the message was + originally published to. + </doc> + </field> + + <field name = "routing key" type = "shortstr"> + Message routing key + <doc> + Specifies the routing key name specified when the message was + published. + </doc> + </field> +</method> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "deliver" content = "1" index = "60"> + notify the client of a consumer message + <doc> + This method delivers a message to the client, via a consumer. In + the asynchronous message delivery model, the client starts a + consumer using the Consume method, then the server responds with + Deliver methods as and when messages arrive for that consumer. + </doc> + <doc name = "rule" test = "amq_basic_19"> + The server SHOULD track the number of times a message has been + delivered to clients and when a message is redelivered a certain + number of times - e.g. 5 times - without being acknowledged, the + server SHOULD consider the message to be unprocessable (possibly + causing client applications to abort), and move the message to a + dead letter queue. + </doc> + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer tag" domain = "consumer tag" /> + + <field name = "delivery tag" domain = "delivery tag" /> + + <field name = "redelivered" domain = "redelivered" /> + + <field name = "exchange" domain = "exchange name"> + <doc> + Specifies the name of the exchange that the message was + originally published to. + </doc> + </field> + + <field name = "routing key" type = "shortstr"> + Message routing key + <doc> + Specifies the routing key name specified when the message was + published. + </doc> + </field> +</method> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "get" synchronous = "1" index = "70"> + direct access to a queue + <doc> + This method provides a direct access to the messages in a queue + using a synchronous dialogue that is designed for specific types of + application where synchronous functionality is more important than + performance. + </doc> + <response name = "get-ok" /> + <response name = "get-empty" /> + <chassis name = "server" implement = "MUST" /> + + <field name = "ticket" domain = "access ticket"> + <doc name = "rule"> + The client MUST provide a valid access ticket giving "read" + access rights to the realm for the queue. + </doc> + </field> + + <field name = "queue" domain = "queue name"> + <doc> + Specifies the name of the queue to consume from. If the queue name + is null, refers to the current queue for the channel, which is the + last declared queue. + </doc> + <doc name = "rule"> + If the client did not previously declare a queue, and the queue name + in this method is empty, the server MUST raise a connection exception + with reply code 530 (not allowed). + </doc> + </field> + + <field name = "no ack" domain = "no ack" /> +</method> + +<method name = "get-ok" synchronous = "1" content = "1" index = "71"> + provide client with a message + <doc> + This method delivers a message to the client following a get + method. A message delivered by 'get-ok' must be acknowledged + unless the no-ack option was set in the get method. + </doc> + <chassis name = "client" implement = "MAY" /> + + <field name = "delivery tag" domain = "delivery tag" /> + + <field name = "redelivered" domain = "redelivered" /> + + <field name = "exchange" domain = "exchange name"> + <doc> + Specifies the name of the exchange that the message was originally + published to. If empty, the message was published to the default + exchange. + </doc> + </field> + + <field name = "routing key" type = "shortstr"> + Message routing key + <doc> + Specifies the routing key name specified when the message was + published. + </doc> + </field> + + <field name = "message count" type = "long" > + number of messages pending + <doc> + This field reports the number of messages pending on the queue, + excluding the message being delivered. Note that this figure is + indicative, not reliable, and can change arbitrarily as messages + are added to the queue and removed by other clients. + </doc> + </field> +</method> + + +<method name = "get-empty" synchronous = "1" index = "72"> + indicate no messages available + <doc> + This method tells the client that the queue has no messages + available for the client. + </doc> + <chassis name = "client" implement = "MAY" /> + + <field name = "cluster id" type = "shortstr"> + Cluster id + <doc> + For use by cluster applications, should not be used by + client applications. + </doc> + </field> +</method> + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "ack" index = "80"> + acknowledge one or more messages + <doc> + This method acknowledges one or more messages delivered via the + Deliver or Get-Ok methods. The client can ask to confirm a + single message or a set of messages up to and including a specific + message. + </doc> + <chassis name = "server" implement = "MUST" /> + <field name = "delivery tag" domain = "delivery tag" /> + + <field name = "multiple" type = "bit"> + acknowledge multiple messages + <doc> + If set to 1, the delivery tag is treated as "up to and including", + so that the client can acknowledge multiple messages with a single + method. If set to zero, the delivery tag refers to a single + message. If the multiple field is 1, and the delivery tag is zero, + tells the server to acknowledge all outstanding mesages. + </doc> + <doc name = "rule" test = "amq_basic_20"> + The server MUST validate that a non-zero delivery-tag refers to an + delivered message, and raise a channel exception if this is not the + case. + </doc> + </field> +</method> + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "reject" index = "90"> + reject an incoming message + <doc> + This method allows a client to reject a message. It can be used to + interrupt and cancel large incoming messages, or return untreatable + messages to their original queue. + </doc> + <doc name = "rule" test = "amq_basic_21"> + The server SHOULD be capable of accepting and process the Reject + method while sending message content with a Deliver or Get-Ok + method. I.e. the server should read and process incoming methods + while sending output frames. To cancel a partially-send content, + the server sends a content body frame of size 1 (i.e. with no data + except the frame-end octet). + </doc> + <doc name = "rule" test = "amq_basic_22"> + The server SHOULD interpret this method as meaning that the client + is unable to process the message at this time. + </doc> + <doc name = "rule"> + A client MUST NOT use this method as a means of selecting messages + to process. A rejected message MAY be discarded or dead-lettered, + not necessarily passed to another client. + </doc> + <chassis name = "server" implement = "MUST" /> + + <field name = "delivery tag" domain = "delivery tag" /> + + <field name = "requeue" type = "bit"> + requeue the message + <doc> + If this field is zero, the message will be discarded. If this bit + is 1, the server will attempt to requeue the message. + </doc> + <doc name = "rule" test = "amq_basic_23"> + The server MUST NOT deliver the message to the same client within + the context of the current channel. The recommended strategy is + to attempt to deliver the message to an alternative consumer, and + if that is not possible, to move the message to a dead-letter + queue. The server MAY use more sophisticated tracking to hold + the message on the queue and redeliver it to the same client at + a later stage. + </doc> + </field> +</method> + +<method name = "recover" index = "100"> + redeliver unacknowledged messages + <doc> + This method asks the broker to redeliver all unacknowledged messages on a + specified channel. Zero or more messages may be redelivered. This method + is only allowed on non-transacted channels. + </doc> + <chassis name = "server" implement = "MUST" /> + + <field name = "requeue" type = "bit"> + requeue the message + <doc> + If this field is zero, the message will be redelivered to the original + recipient. If this bit is 1, the server will attempt to requeue the + message, potentially then delivering it to an alternative subscriber. + </doc> + </field> + <doc name="rule"> + The server MUST set the redelivered flag on all messages that are resent. + </doc> + <doc name="rule"> + The server MUST raise a channel exception if this is called on a + transacted channel. + </doc> +</method> + +</class> + + + <class name="file" handler="channel" index="70"> + <!-- +====================================================== +== FILE TRANSFER +====================================================== +--> + work with file content +<doc> + The file class provides methods that support reliable file transfer. + File messages have a specific set of properties that are required for + interoperability with file transfer applications. File messages and + acknowledgements are subject to channel transactions. Note that the + file class does not provide message browsing methods; these are not + compatible with the staging model. Applications that need browsable + file transfer should use Basic content and the Basic class. +</doc> + +<doc name = "grammar"> + file = C:QOS S:QOS-OK + / C:CONSUME S:CONSUME-OK + / C:CANCEL S:CANCEL-OK + / C:OPEN S:OPEN-OK C:STAGE content + / S:OPEN C:OPEN-OK S:STAGE content + / C:PUBLISH + / S:DELIVER + / S:RETURN + / C:ACK + / C:REJECT +</doc> + +<chassis name = "server" implement = "MAY" /> +<chassis name = "client" implement = "MAY" /> + +<doc name = "rule"> + The server MUST make a best-effort to hold file messages on a + reliable storage mechanism. +</doc> +<doc name = "rule"> + The server MUST NOT discard a file message in case of a queue + overflow. The server MUST use the Channel.Flow method to slow or stop + a file message publisher when necessary. +</doc> +<doc name = "rule"> + The server MUST implement at least 2 priority levels for file + messages, where priorities 0-4 and 5-9 are treated as two distinct + levels. The server MAY implement up to 10 priority levels. +</doc> +<doc name = "rule"> + The server MUST support both automatic and explicit acknowledgements + on file content. +</doc> + +<!-- These are the properties for a File content --> + +<field name = "content type" type = "shortstr"> + MIME content type +</field> +<field name = "content encoding" type = "shortstr"> + MIME content encoding +</field> +<field name = "headers" type = "table"> + Message header field table +</field> +<field name = "priority" type = "octet"> + The message priority, 0 to 9 +</field> +<field name = "reply to" type = "shortstr"> + The destination to reply to +</field> +<field name = "message id" type = "shortstr"> + The application message identifier +</field> +<field name = "filename" type = "shortstr"> + The message filename +</field> +<field name = "timestamp" type = "timestamp"> + The message timestamp +</field> +<field name = "cluster id" type = "shortstr"> + Intra-cluster routing identifier +</field> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "qos" synchronous = "1" index = "10"> + specify quality of service + <doc> + This method requests a specific quality of service. The QoS can + be specified for the current channel or for all channels on the + connection. The particular properties and semantics of a qos method + always depend on the content class semantics. Though the qos method + could in principle apply to both peers, it is currently meaningful + only for the server. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "qos-ok" /> + + <field name = "prefetch size" type = "long"> + prefetch window in octets + <doc> + The client can request that messages be sent in advance so that + when the client finishes processing a message, the following + message is already held locally, rather than needing to be sent + down the channel. Prefetching gives a performance improvement. + This field specifies the prefetch window size in octets. May be + set to zero, meaning "no specific limit". Note that other + prefetch limits may still apply. The prefetch-size is ignored + if the no-ack option is set. + </doc> + </field> + + <field name = "prefetch count" type = "short"> + prefetch window in messages + <doc> + Specifies a prefetch window in terms of whole messages. This + is compatible with some file API implementations. This field + may be used in combination with the prefetch-size field; a + message will only be sent in advance if both prefetch windows + (and those at the channel and connection level) allow it. + The prefetch-count is ignored if the no-ack option is set. + </doc> + <doc name = "rule"> + The server MAY send less data in advance than allowed by the + client's specified prefetch windows but it MUST NOT send more. + </doc> + </field> + + <field name = "global" type = "bit"> + apply to entire connection + <doc> + By default the QoS settings apply to the current channel only. If + this field is set, they are applied to the entire connection. + </doc> + </field> +</method> + +<method name = "qos-ok" synchronous = "1" index = "11"> + confirm the requested qos + <doc> + This method tells the client that the requested QoS levels could + be handled by the server. The requested QoS applies to all active + consumers until a new QoS is defined. + </doc> + <chassis name = "client" implement = "MUST" /> +</method> + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "consume" synchronous = "1" index = "20"> + start a queue consumer + <doc> + This method asks the server to start a "consumer", which is a + transient request for messages from a specific queue. Consumers + last as long as the channel they were created on, or until the + client cancels them. + </doc> + <doc name = "rule"> + The server SHOULD support at least 16 consumers per queue, unless + the queue was declared as private, and ideally, impose no limit + except as defined by available resources. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "consume-ok" /> + + <field name = "ticket" domain = "access ticket"> + <doc name = "rule"> + The client MUST provide a valid access ticket giving "read" access + rights to the realm for the queue. + </doc> + </field> + + <field name = "queue" domain = "queue name"> + <doc> + Specifies the name of the queue to consume from. If the queue name + is null, refers to the current queue for the channel, which is the + last declared queue. + </doc> + <doc name = "rule"> + If the client did not previously declare a queue, and the queue name + in this method is empty, the server MUST raise a connection exception + with reply code 530 (not allowed). + </doc> + </field> + + <field name = "consumer tag" domain = "consumer tag"> + <doc> + Specifies the identifier for the consumer. The consumer tag is + local to a connection, so two clients can use the same consumer + tags. If this field is empty the server will generate a unique + tag. + </doc> + <doc name = "rule" test = "todo"> + The tag MUST NOT refer to an existing consumer. If the client + attempts to create two consumers with the same non-empty tag + the server MUST raise a connection exception with reply code + 530 (not allowed). + </doc> + </field> + + <field name = "no local" domain = "no local" /> + + <field name = "no ack" domain = "no ack" /> + + <field name = "exclusive" type = "bit"> + request exclusive access + <doc> + Request exclusive consumer access, meaning only this consumer can + access the queue. + </doc> + <doc name = "rule" test = "amq_file_00"> + If the server cannot grant exclusive access to the queue when asked, + - because there are other consumers active - it MUST raise a channel + exception with return code 405 (resource locked). + </doc> + </field> + + <field name = "nowait" type = "bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The client should + not wait for a reply method. If the server could not complete the + method it will raise a channel or connection exception. + </doc> + </field> +</method> + +<method name = "consume-ok" synchronous = "1" index = "21"> + confirm a new consumer + <doc> + This method provides the client with a consumer tag which it MUST + use in methods that work with the consumer. + </doc> + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer tag" domain = "consumer tag"> + <doc> + Holds the consumer tag specified by the client or provided by + the server. + </doc> + </field> +</method> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "cancel" synchronous = "1" index = "30"> + end a queue consumer + <doc> + This method cancels a consumer. This does not affect already + delivered messages, but it does mean the server will not send any + more messages for that consumer. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "cancel-ok" /> + + <field name = "consumer tag" domain = "consumer tag" /> + + <field name = "nowait" type = "bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The client should + not wait for a reply method. If the server could not complete the + method it will raise a channel or connection exception. + </doc> + </field> +</method> + +<method name = "cancel-ok" synchronous = "1" index = "31"> + confirm a cancelled consumer + <doc> + This method confirms that the cancellation was completed. + </doc> + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer tag" domain = "consumer tag" /> +</method> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "open" synchronous = "1" index = "40"> + request to start staging + <doc> + This method requests permission to start staging a message. Staging + means sending the message into a temporary area at the recipient end + and then delivering the message by referring to this temporary area. + Staging is how the protocol handles partial file transfers - if a + message is partially staged and the connection breaks, the next time + the sender starts to stage it, it can restart from where it left off. + </doc> + <response name = "open-ok" /> + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <field name = "identifier" type = "shortstr"> + staging identifier + <doc> + This is the staging identifier. This is an arbitrary string chosen + by the sender. For staging to work correctly the sender must use + the same staging identifier when staging the same message a second + time after recovery from a failure. A good choice for the staging + identifier would be the SHA1 hash of the message properties data + (including the original filename, revised time, etc.). + </doc> + </field> + + <field name = "content size" type = "longlong"> + message content size + <doc> + The size of the content in octets. The recipient may use this + information to allocate or check available space in advance, to + avoid "disk full" errors during staging of very large messages. + </doc> + <doc name = "rule"> + The sender MUST accurately fill the content-size field. + Zero-length content is permitted. + </doc> + </field> +</method> + +<method name = "open-ok" synchronous = "1" index = "41"> + confirm staging ready + <doc> + This method confirms that the recipient is ready to accept staged + data. If the message was already partially-staged at a previous + time the recipient will report the number of octets already staged. + </doc> + <response name = "stage" /> + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <field name = "staged size" type = "longlong"> + already staged amount + <doc> + The amount of previously-staged content in octets. For a new + message this will be zero. + </doc> + <doc name = "rule"> + The sender MUST start sending data from this octet offset in the + message, counting from zero. + </doc> + <doc name = "rule"> + The recipient MAY decide how long to hold partially-staged content + and MAY implement staging by always discarding partially-staged + content. However if it uses the file content type it MUST support + the staging methods. + </doc> + </field> +</method> + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "stage" content = "1" index = "50"> + stage message content + <doc> + This method stages the message, sending the message content to the + recipient from the octet offset specified in the Open-Ok method. + </doc> + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> +</method> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "publish" index = "60"> + publish a message + <doc> + This method publishes a staged file message to a specific exchange. + The file message will be routed to queues as defined by the exchange + configuration and distributed to any active consumers when the + transaction, if any, is committed. + </doc> + <chassis name = "server" implement = "MUST" /> + + <field name = "ticket" domain = "access ticket"> + <doc name = "rule"> + The client MUST provide a valid access ticket giving "write" + access rights to the access realm for the exchange. + </doc> + </field> + + <field name = "exchange" domain = "exchange name"> + <doc> + Specifies the name of the exchange to publish to. The exchange + name can be empty, meaning the default exchange. If the exchange + name is specified, and that exchange does not exist, the server + will raise a channel exception. + </doc> + <doc name = "rule"> + The server MUST accept a blank exchange name to mean the default + exchange. + </doc> + <doc name = "rule"> + If the exchange was declared as an internal exchange, the server + MUST respond with a reply code 403 (access refused) and raise a + channel exception. + </doc> + <doc name = "rule"> + The exchange MAY refuse file content in which case it MUST respond + with a reply code 540 (not implemented) and raise a channel + exception. + </doc> + </field> + + <field name = "routing key" type = "shortstr"> + Message routing key + <doc> + Specifies the routing key for the message. The routing key is + used for routing messages depending on the exchange configuration. + </doc> + </field> + + <field name = "mandatory" type = "bit"> + indicate mandatory routing + <doc> + This flag tells the server how to react if the message cannot be + routed to a queue. If this flag is set, the server will return an + unroutable message with a Return method. If this flag is zero, the + server silently drops the message. + </doc> + <doc name = "rule" test = "amq_file_00"> + The server SHOULD implement the mandatory flag. + </doc> + </field> + + <field name = "immediate" type = "bit"> + request immediate delivery + <doc> + This flag tells the server how to react if the message cannot be + routed to a queue consumer immediately. If this flag is set, the + server will return an undeliverable message with a Return method. + If this flag is zero, the server will queue the message, but with + no guarantee that it will ever be consumed. + </doc> + <doc name = "rule" test = "amq_file_00"> + The server SHOULD implement the immediate flag. + </doc> + </field> + + <field name = "identifier" type = "shortstr"> + staging identifier + <doc> + This is the staging identifier of the message to publish. The + message must have been staged. Note that a client can send the + Publish method asynchronously without waiting for staging to + finish. + </doc> + </field> +</method> + +<method name = "return" content = "1" index = "70"> + return a failed message + <doc> + This method returns an undeliverable message that was published + with the "immediate" flag set, or an unroutable message published + with the "mandatory" flag set. The reply code and text provide + information about the reason that the message was undeliverable. + </doc> + <chassis name = "client" implement = "MUST" /> + + <field name = "reply code" domain = "reply code" /> + <field name = "reply text" domain = "reply text" /> + + <field name = "exchange" domain = "exchange name"> + <doc> + Specifies the name of the exchange that the message was + originally published to. + </doc> + </field> + + <field name = "routing key" type = "shortstr"> + Message routing key + <doc> + Specifies the routing key name specified when the message was + published. + </doc> + </field> +</method> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "deliver" index = "80"> + notify the client of a consumer message + <doc> + This method delivers a staged file message to the client, via a + consumer. In the asynchronous message delivery model, the client + starts a consumer using the Consume method, then the server + responds with Deliver methods as and when messages arrive for + that consumer. + </doc> + <doc name = "rule"> + The server SHOULD track the number of times a message has been + delivered to clients and when a message is redelivered a certain + number of times - e.g. 5 times - without being acknowledged, the + server SHOULD consider the message to be unprocessable (possibly + causing client applications to abort), and move the message to a + dead letter queue. + </doc> + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer tag" domain = "consumer tag" /> + + <field name = "delivery tag" domain = "delivery tag" /> + + <field name = "redelivered" domain = "redelivered" /> + + <field name = "exchange" domain = "exchange name"> + <doc> + Specifies the name of the exchange that the message was originally + published to. + </doc> + </field> + + <field name = "routing key" type = "shortstr"> + Message routing key + <doc> + Specifies the routing key name specified when the message was + published. + </doc> + </field> + + <field name = "identifier" type = "shortstr"> + staging identifier + <doc> + This is the staging identifier of the message to deliver. The + message must have been staged. Note that a server can send the + Deliver method asynchronously without waiting for staging to + finish. + </doc> + </field> +</method> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "ack" index = "90"> + acknowledge one or more messages + <doc> + This method acknowledges one or more messages delivered via the + Deliver method. The client can ask to confirm a single message or + a set of messages up to and including a specific message. + </doc> + <chassis name = "server" implement = "MUST" /> + <field name = "delivery tag" domain = "delivery tag" /> + + <field name = "multiple" type = "bit"> + acknowledge multiple messages + <doc> + If set to 1, the delivery tag is treated as "up to and including", + so that the client can acknowledge multiple messages with a single + method. If set to zero, the delivery tag refers to a single + message. If the multiple field is 1, and the delivery tag is zero, + tells the server to acknowledge all outstanding mesages. + </doc> + <doc name = "rule"> + The server MUST validate that a non-zero delivery-tag refers to an + delivered message, and raise a channel exception if this is not the + case. + </doc> + </field> +</method> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "reject" index = "100"> + reject an incoming message + <doc> + This method allows a client to reject a message. It can be used to + return untreatable messages to their original queue. Note that file + content is staged before delivery, so the client will not use this + method to interrupt delivery of a large message. + </doc> + <doc name = "rule"> + The server SHOULD interpret this method as meaning that the client + is unable to process the message at this time. + </doc> + <doc name = "rule"> + A client MUST NOT use this method as a means of selecting messages + to process. A rejected message MAY be discarded or dead-lettered, + not necessarily passed to another client. + </doc> + <chassis name = "server" implement = "MUST" /> + + <field name = "delivery tag" domain = "delivery tag" /> + + <field name = "requeue" type = "bit"> + requeue the message + <doc> + If this field is zero, the message will be discarded. If this bit + is 1, the server will attempt to requeue the message. + </doc> + <doc name = "rule"> + The server MUST NOT deliver the message to the same client within + the context of the current channel. The recommended strategy is + to attempt to deliver the message to an alternative consumer, and + if that is not possible, to move the message to a dead-letter + queue. The server MAY use more sophisticated tracking to hold + the message on the queue and redeliver it to the same client at + a later stage. + </doc> + </field> +</method> + +</class> + + <class name="stream" handler="channel" index="80"> + <!-- +====================================================== +== STREAMING +====================================================== +--> + work with streaming content + +<doc> + The stream class provides methods that support multimedia streaming. + The stream class uses the following semantics: one message is one + packet of data; delivery is unacknowleged and unreliable; the consumer + can specify quality of service parameters that the server can try to + adhere to; lower-priority messages may be discarded in favour of high + priority messages. +</doc> + +<doc name = "grammar"> + stream = C:QOS S:QOS-OK + / C:CONSUME S:CONSUME-OK + / C:CANCEL S:CANCEL-OK + / C:PUBLISH content + / S:RETURN + / S:DELIVER content +</doc> + +<chassis name = "server" implement = "MAY" /> +<chassis name = "client" implement = "MAY" /> + +<doc name = "rule"> + The server SHOULD discard stream messages on a priority basis if + the queue size exceeds some configured limit. +</doc> +<doc name = "rule"> + The server MUST implement at least 2 priority levels for stream + messages, where priorities 0-4 and 5-9 are treated as two distinct + levels. The server MAY implement up to 10 priority levels. +</doc> +<doc name = "rule"> + The server MUST implement automatic acknowledgements on stream + content. That is, as soon as a message is delivered to a client + via a Deliver method, the server must remove it from the queue. +</doc> + + +<!-- These are the properties for a Stream content --> + +<field name = "content type" type = "shortstr"> + MIME content type +</field> +<field name = "content encoding" type = "shortstr"> + MIME content encoding +</field> +<field name = "headers" type = "table"> + Message header field table +</field> +<field name = "priority" type = "octet"> + The message priority, 0 to 9 +</field> +<field name = "timestamp" type = "timestamp"> + The message timestamp +</field> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "qos" synchronous = "1" index = "10"> + specify quality of service + <doc> + This method requests a specific quality of service. The QoS can + be specified for the current channel or for all channels on the + connection. The particular properties and semantics of a qos method + always depend on the content class semantics. Though the qos method + could in principle apply to both peers, it is currently meaningful + only for the server. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "qos-ok" /> + + <field name = "prefetch size" type = "long"> + prefetch window in octets + <doc> + The client can request that messages be sent in advance so that + when the client finishes processing a message, the following + message is already held locally, rather than needing to be sent + down the channel. Prefetching gives a performance improvement. + This field specifies the prefetch window size in octets. May be + set to zero, meaning "no specific limit". Note that other + prefetch limits may still apply. + </doc> + </field> + + <field name = "prefetch count" type = "short"> + prefetch window in messages + <doc> + Specifies a prefetch window in terms of whole messages. This + field may be used in combination with the prefetch-size field; + a message will only be sent in advance if both prefetch windows + (and those at the channel and connection level) allow it. + </doc> + </field> + + <field name = "consume rate" type = "long"> + transfer rate in octets/second + <doc> + Specifies a desired transfer rate in octets per second. This is + usually determined by the application that uses the streaming + data. A value of zero means "no limit", i.e. as rapidly as + possible. + </doc> + <doc name = "rule"> + The server MAY ignore the prefetch values and consume rates, + depending on the type of stream and the ability of the server + to queue and/or reply it. The server MAY drop low-priority + messages in favour of high-priority messages. + </doc> + </field> + + <field name = "global" type = "bit"> + apply to entire connection + <doc> + By default the QoS settings apply to the current channel only. If + this field is set, they are applied to the entire connection. + </doc> + </field> +</method> + +<method name = "qos-ok" synchronous = "1" index = "11"> + confirm the requested qos + <doc> + This method tells the client that the requested QoS levels could + be handled by the server. The requested QoS applies to all active + consumers until a new QoS is defined. + </doc> + <chassis name = "client" implement = "MUST" /> +</method> + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "consume" synchronous = "1" index = "20"> + start a queue consumer + <doc> + This method asks the server to start a "consumer", which is a + transient request for messages from a specific queue. Consumers + last as long as the channel they were created on, or until the + client cancels them. + </doc> + <doc name = "rule"> + The server SHOULD support at least 16 consumers per queue, unless + the queue was declared as private, and ideally, impose no limit + except as defined by available resources. + </doc> + <doc name = "rule"> + Streaming applications SHOULD use different channels to select + different streaming resolutions. AMQP makes no provision for + filtering and/or transforming streams except on the basis of + priority-based selective delivery of individual messages. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "consume-ok" /> + + <field name = "ticket" domain = "access ticket"> + <doc name = "rule"> + The client MUST provide a valid access ticket giving "read" access + rights to the realm for the queue. + </doc> + </field> + + <field name = "queue" domain = "queue name"> + <doc> + Specifies the name of the queue to consume from. If the queue name + is null, refers to the current queue for the channel, which is the + last declared queue. + </doc> + <doc name = "rule"> + If the client did not previously declare a queue, and the queue name + in this method is empty, the server MUST raise a connection exception + with reply code 530 (not allowed). + </doc> + </field> + + <field name = "consumer tag" domain = "consumer tag"> + <doc> + Specifies the identifier for the consumer. The consumer tag is + local to a connection, so two clients can use the same consumer + tags. If this field is empty the server will generate a unique + tag. + </doc> + <doc name = "rule" test = "todo"> + The tag MUST NOT refer to an existing consumer. If the client + attempts to create two consumers with the same non-empty tag + the server MUST raise a connection exception with reply code + 530 (not allowed). + </doc> + </field> + + <field name = "no local" domain = "no local" /> + + <field name = "exclusive" type = "bit"> + request exclusive access + <doc> + Request exclusive consumer access, meaning only this consumer can + access the queue. + </doc> + <doc name = "rule" test = "amq_file_00"> + If the server cannot grant exclusive access to the queue when asked, + - because there are other consumers active - it MUST raise a channel + exception with return code 405 (resource locked). + </doc> + </field> + + <field name = "nowait" type = "bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The client should + not wait for a reply method. If the server could not complete the + method it will raise a channel or connection exception. + </doc> + </field> +</method> + + +<method name = "consume-ok" synchronous = "1" index = "21"> + confirm a new consumer + <doc> + This method provides the client with a consumer tag which it may + use in methods that work with the consumer. + </doc> + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer tag" domain = "consumer tag"> + <doc> + Holds the consumer tag specified by the client or provided by + the server. + </doc> + </field> +</method> + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "cancel" synchronous = "1" index = "30"> + end a queue consumer + <doc> + This method cancels a consumer. Since message delivery is + asynchronous the client may continue to receive messages for + a short while after canceling a consumer. It may process or + discard these as appropriate. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "cancel-ok" /> + + <field name = "consumer tag" domain = "consumer tag" /> + + <field name = "nowait" type = "bit"> + do not send a reply method + <doc> + If set, the server will not respond to the method. The client should + not wait for a reply method. If the server could not complete the + method it will raise a channel or connection exception. + </doc> + </field> +</method> + +<method name = "cancel-ok" synchronous = "1" index = "31"> + confirm a cancelled consumer + <doc> + This method confirms that the cancellation was completed. + </doc> + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer tag" domain = "consumer tag" /> +</method> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "publish" content = "1" index = "40"> + publish a message + <doc> + This method publishes a message to a specific exchange. The message + will be routed to queues as defined by the exchange configuration + and distributed to any active consumers as appropriate. + </doc> + <chassis name = "server" implement = "MUST" /> + + <field name = "ticket" domain = "access ticket"> + <doc name = "rule"> + The client MUST provide a valid access ticket giving "write" + access rights to the access realm for the exchange. + </doc> + </field> + + <field name = "exchange" domain = "exchange name"> + <doc> + Specifies the name of the exchange to publish to. The exchange + name can be empty, meaning the default exchange. If the exchange + name is specified, and that exchange does not exist, the server + will raise a channel exception. + </doc> + <doc name = "rule"> + The server MUST accept a blank exchange name to mean the default + exchange. + </doc> + <doc name = "rule"> + If the exchange was declared as an internal exchange, the server + MUST respond with a reply code 403 (access refused) and raise a + channel exception. + </doc> + <doc name = "rule"> + The exchange MAY refuse stream content in which case it MUST + respond with a reply code 540 (not implemented) and raise a + channel exception. + </doc> + </field> + + <field name = "routing key" type = "shortstr"> + Message routing key + <doc> + Specifies the routing key for the message. The routing key is + used for routing messages depending on the exchange configuration. + </doc> + </field> + + <field name = "mandatory" type = "bit"> + indicate mandatory routing + <doc> + This flag tells the server how to react if the message cannot be + routed to a queue. If this flag is set, the server will return an + unroutable message with a Return method. If this flag is zero, the + server silently drops the message. + </doc> + <doc name = "rule" test = "amq_stream_00"> + The server SHOULD implement the mandatory flag. + </doc> + </field> + + <field name = "immediate" type = "bit"> + request immediate delivery + <doc> + This flag tells the server how to react if the message cannot be + routed to a queue consumer immediately. If this flag is set, the + server will return an undeliverable message with a Return method. + If this flag is zero, the server will queue the message, but with + no guarantee that it will ever be consumed. + </doc> + <doc name = "rule" test = "amq_stream_00"> + The server SHOULD implement the immediate flag. + </doc> + </field> +</method> + +<method name = "return" content = "1" index = "50"> + return a failed message + <doc> + This method returns an undeliverable message that was published + with the "immediate" flag set, or an unroutable message published + with the "mandatory" flag set. The reply code and text provide + information about the reason that the message was undeliverable. + </doc> + <chassis name = "client" implement = "MUST" /> + + <field name = "reply code" domain = "reply code" /> + <field name = "reply text" domain = "reply text" /> + + <field name = "exchange" domain = "exchange name"> + <doc> + Specifies the name of the exchange that the message was + originally published to. + </doc> + </field> + + <field name = "routing key" type = "shortstr"> + Message routing key + <doc> + Specifies the routing key name specified when the message was + published. + </doc> + </field> +</method> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + +<method name = "deliver" content = "1" index = "60"> + notify the client of a consumer message + <doc> + This method delivers a message to the client, via a consumer. In + the asynchronous message delivery model, the client starts a + consumer using the Consume method, then the server responds with + Deliver methods as and when messages arrive for that consumer. + </doc> + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer tag" domain = "consumer tag" /> + + <field name = "delivery tag" domain = "delivery tag" /> + + <field name = "exchange" domain = "exchange name"> + <doc> + Specifies the name of the exchange that the message was originally + published to. + </doc> + </field> + + <field name = "queue" domain = "queue name"> + <doc> + Specifies the name of the queue that the message came from. Note + that a single channel can start many consumers on different + queues. + </doc> + <assert check = "notnull" /> + </field> +</method> + </class> + + <class name="tx" handler="channel" index="90"> + <!-- +====================================================== +== TRANSACTIONS +====================================================== +--> + work with standard transactions + +<doc> + Standard transactions provide so-called "1.5 phase commit". We can + ensure that work is never lost, but there is a chance of confirmations + being lost, so that messages may be resent. Applications that use + standard transactions must be able to detect and ignore duplicate + messages. +</doc> + <rule implement="SHOULD"> + An client using standard transactions SHOULD be able to track all + messages received within a reasonable period, and thus detect and + reject duplicates of the same message. It SHOULD NOT pass these to + the application layer. +</rule> + <doc name="grammar"> + tx = C:SELECT S:SELECT-OK + / C:COMMIT S:COMMIT-OK + / C:ROLLBACK S:ROLLBACK-OK +</doc> + <chassis name="server" implement="SHOULD"/> + <chassis name="client" implement="MAY"/> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="select" synchronous="1" index="10"> +select standard transaction mode + <doc> + This method sets the channel to use standard transactions. The + client must use this method at least once on a channel before + using the Commit or Rollback methods. + </doc> + <chassis name="server" implement="MUST"/> + <response name="select-ok"/> + </method> + <method name="select-ok" synchronous="1" index="11"> +confirm transaction mode + <doc> + This method confirms to the client that the channel was successfully + set to use standard transactions. + </doc> + <chassis name="client" implement="MUST"/> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="commit" synchronous="1" index="20"> +commit the current transaction + <doc> + This method commits all messages published and acknowledged in + the current transaction. A new transaction starts immediately + after a commit. + </doc> + <chassis name="server" implement="MUST"/> + <response name="commit-ok"/> + </method> + <method name="commit-ok" synchronous="1" index="21"> +confirm a successful commit + <doc> + This method confirms to the client that the commit succeeded. + Note that if a commit fails, the server raises a channel exception. + </doc> + <chassis name="client" implement="MUST"/> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="rollback" synchronous="1" index="30"> +abandon the current transaction + <doc> + This method abandons all messages published and acknowledged in + the current transaction. A new transaction starts immediately + after a rollback. + </doc> + <chassis name="server" implement="MUST"/> + <response name="rollback-ok"/> + </method> + <method name="rollback-ok" synchronous="1" index="31"> +confirm a successful rollback + <doc> + This method confirms to the client that the rollback succeeded. + Note that if an rollback fails, the server raises a channel exception. + </doc> + <chassis name="client" implement="MUST"/> + </method> + </class> + <class name="dtx" handler="channel" index="100"> + <!-- +====================================================== +== DISTRIBUTED TRANSACTIONS +====================================================== +--> + work with distributed transactions + +<doc> + Distributed transactions provide so-called "2-phase commit". The + AMQP distributed transaction model supports the X-Open XA + architecture and other distributed transaction implementations. + The Dtx class assumes that the server has a private communications + channel (not AMQP) to a distributed transaction coordinator. +</doc> + <doc name="grammar"> + dtx = C:SELECT S:SELECT-OK + C:START S:START-OK +</doc> + <chassis name="server" implement="MAY"/> + <chassis name="client" implement="MAY"/> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="select" synchronous="1" index="10"> +select standard transaction mode + <doc> + This method sets the channel to use distributed transactions. The + client must use this method at least once on a channel before + using the Start method. + </doc> + <chassis name="server" implement="MUST"/> + <response name="select-ok"/> + </method> + <method name="select-ok" synchronous="1" index="11"> +confirm transaction mode + <doc> + This method confirms to the client that the channel was successfully + set to use distributed transactions. + </doc> + <chassis name="client" implement="MUST"/> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="start" synchronous="1" index="20"> + start a new distributed transaction + <doc> + This method starts a new distributed transaction. This must be + the first method on a new channel that uses the distributed + transaction mode, before any methods that publish or consume + messages. + </doc> + <chassis name="server" implement="MAY"/> + <response name="start-ok"/> + <field name="dtx identifier" type="shortstr"> + transaction identifier + <doc> + The distributed transaction key. This identifies the transaction + so that the AMQP server can coordinate with the distributed + transaction coordinator. + </doc> + <assert check="notnull"/> + </field> + </method> + <method name="start-ok" synchronous="1" index="21"> + confirm the start of a new distributed transaction + <doc> + This method confirms to the client that the transaction started. + Note that if a start fails, the server raises a channel exception. + </doc> + <chassis name="client" implement="MUST"/> + </method> + </class> + <class name="tunnel" handler="tunnel" index="110"> + <!-- +====================================================== +== TUNNEL +====================================================== +--> + methods for protocol tunneling. + +<doc> + The tunnel methods are used to send blocks of binary data - which + can be serialised AMQP methods or other protocol frames - between + AMQP peers. +</doc> + <doc name="grammar"> + tunnel = C:REQUEST + / S:REQUEST +</doc> + <chassis name="server" implement="MAY"/> + <chassis name="client" implement="MAY"/> + <field name="headers" type="table"> + Message header field table +</field> + <field name="proxy name" type="shortstr"> + The identity of the tunnelling proxy +</field> + <field name="data name" type="shortstr"> + The name or type of the message being tunnelled +</field> + <field name="durable" type="octet"> + The message durability indicator +</field> + <field name="broadcast" type="octet"> + The message broadcast mode +</field> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="request" content="1" index="10"> + sends a tunnelled method + <doc> + This method tunnels a block of binary data, which can be an + encoded AMQP method or other data. The binary data is sent + as the content for the Tunnel.Request method. + </doc> + <chassis name="server" implement="MUST"/> + <field name="meta data" type="table"> + meta data for the tunnelled block + <doc> + This field table holds arbitrary meta-data that the sender needs + to pass to the recipient. + </doc> + </field> + </method> + </class> + <class name="test" handler="channel" index="120"> + <!-- +====================================================== +== TEST - CHECK FUNCTIONAL CAPABILITIES OF AN IMPLEMENTATION +====================================================== +--> + test functional primitives of the implementation + +<doc> + The test class provides methods for a peer to test the basic + operational correctness of another peer. The test methods are + intended to ensure that all peers respect at least the basic + elements of the protocol, such as frame and content organisation + and field types. We assume that a specially-designed peer, a + "monitor client" would perform such tests. +</doc> + <doc name="grammar"> + test = C:INTEGER S:INTEGER-OK + / S:INTEGER C:INTEGER-OK + / C:STRING S:STRING-OK + / S:STRING C:STRING-OK + / C:TABLE S:TABLE-OK + / S:TABLE C:TABLE-OK + / C:CONTENT S:CONTENT-OK + / S:CONTENT C:CONTENT-OK +</doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="SHOULD"/> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="integer" synchronous="1" index="10"> + test integer handling + <doc> + This method tests the peer's capability to correctly marshal integer + data. + </doc> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <response name="integer-ok"/> + <field name="integer 1" type="octet"> + octet test value + <doc> + An octet integer test value. + </doc> + </field> + <field name="integer 2" type="short"> + short test value + <doc> + A short integer test value. + </doc> + </field> + <field name="integer 3" type="long"> + long test value + <doc> + A long integer test value. + </doc> + </field> + <field name="integer 4" type="longlong"> + long-long test value + <doc> + A long long integer test value. + </doc> + </field> + <field name="operation" type="octet"> + operation to test + <doc> + The client must execute this operation on the provided integer + test fields and return the result. + </doc> + <assert check="enum"> + <value name="add">return sum of test values</value> + <value name="min">return lowest of test values</value> + <value name="max">return highest of test values</value> + </assert> + </field> + </method> + <method name="integer-ok" synchronous="1" index="11"> + report integer test result + <doc> + This method reports the result of an Integer method. + </doc> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <field name="result" type="longlong"> + result value + <doc> + The result of the tested operation. + </doc> + </field> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="string" synchronous="1" index="20"> + test string handling + <doc> + This method tests the peer's capability to correctly marshal string + data. + </doc> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <response name="string-ok"/> + <field name="string 1" type="shortstr"> + short string test value + <doc> + An short string test value. + </doc> + </field> + <field name="string 2" type="longstr"> + long string test value + <doc> + A long string test value. + </doc> + </field> + <field name="operation" type="octet"> + operation to test + <doc> + The client must execute this operation on the provided string + test fields and return the result. + </doc> + <assert check="enum"> + <value name="add">return concatentation of test strings</value> + <value name="min">return shortest of test strings</value> + <value name="max">return longest of test strings</value> + </assert> + </field> + </method> + <method name="string-ok" synchronous="1" index="21"> + report string test result + <doc> + This method reports the result of a String method. + </doc> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <field name="result" type="longstr"> + result value + <doc> + The result of the tested operation. + </doc> + </field> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="table" synchronous="1" index="30"> + test field table handling + <doc> + This method tests the peer's capability to correctly marshal field + table data. + </doc> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <response name="table-ok"/> + <field name="table" type="table"> + field table of test values + <doc> + A field table of test values. + </doc> + </field> + <field name="integer op" type="octet"> + operation to test on integers + <doc> + The client must execute this operation on the provided field + table integer values and return the result. + </doc> + <assert check="enum"> + <value name="add">return sum of numeric field values</value> + <value name="min">return min of numeric field values</value> + <value name="max">return max of numeric field values</value> + </assert> + </field> + <field name="string op" type="octet"> + operation to test on strings + <doc> + The client must execute this operation on the provided field + table string values and return the result. + </doc> + <assert check="enum"> + <value name="add">return concatenation of string field values</value> + <value name="min">return shortest of string field values</value> + <value name="max">return longest of string field values</value> + </assert> + </field> + </method> + <method name="table-ok" synchronous="1" index="31"> + report table test result + <doc> + This method reports the result of a Table method. + </doc> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <field name="integer result" type="longlong"> + integer result value + <doc> + The result of the tested integer operation. + </doc> + </field> + <field name="string result" type="longstr"> + string result value + <doc> + The result of the tested string operation. + </doc> + </field> + </method> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <method name="content" synchronous="1" content="1" index="40"> + test content handling + <doc> + This method tests the peer's capability to correctly marshal content. + </doc> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <response name="content-ok"/> + </method> + <method name="content-ok" synchronous="1" content="1" index="41"> + report content test result + <doc> + This method reports the result of a Content method. It contains the + content checksum and echoes the original content as provided. + </doc> + <chassis name="client" implement="MUST"/> + <chassis name="server" implement="MUST"/> + <field name="content checksum" type="long"> + content hash + <doc> + The 32-bit checksum of the content, calculated by adding the + content into a 32-bit accumulator. + </doc> + </field> + </method> + </class> +</amqp> diff --git a/qpid/cpp-0-9/gentools/xml-src/amqp-0.9.test.xml b/qpid/cpp-0-9/gentools/xml-src/amqp-0.9.test.xml new file mode 100644 index 0000000000..e12e9c787a --- /dev/null +++ b/qpid/cpp-0-9/gentools/xml-src/amqp-0.9.test.xml @@ -0,0 +1,4282 @@ +<?xml version = "1.0"?> + +<!-- + EDITORS: (PH) Pieter Hintjens <ph@imatix.com> + (KvdR) Kim van der Riet <kim.vdriet@redhat.com> + + These editors have been assigned by the AMQP working group. + Please do not edit/commit this file without consulting with + one of the above editors. + ======================================================== + + TODOs + - see TODO comments in the text +--> + +<!-- + Copyright Notice + ================ + (c) Copyright JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc., + iMatix Corporation, IONA\ufffd Technologies, Red Hat, Inc., + TWIST Process Innovations, and 29West Inc. 2006. All rights reserved. + + License + ======= + JPMorgan Chase Bank & Co., Cisco Systems, Inc., Envoy Technologies Inc., iMatix + Corporation, IONA\ufffd Technologies, Red Hat, Inc., TWIST Process Innovations, and + 29West Inc. (collectively, the "Authors") each hereby grants to you a worldwide, + perpetual, royalty-free, nontransferable, nonexclusive license to + (i) copy, display, and implement the Advanced Messaging Queue Protocol + ("AMQP") Specification and (ii) the Licensed Claims that are held by + the Authors, all for the purpose of implementing the Advanced Messaging + Queue Protocol Specification. Your license and any rights under this + Agreement will terminate immediately without notice from + any Author if you bring any claim, suit, demand, or action related to + the Advanced Messaging Queue Protocol Specification against any Author. + Upon termination, you shall destroy all copies of the Advanced Messaging + Queue Protocol Specification in your possession or control. + + As used hereunder, "Licensed Claims" means those claims of a patent or + patent application, throughout the world, excluding design patents and + design registrations, owned or controlled, or that can be sublicensed + without fee and in compliance with the requirements of this + Agreement, by an Author or its affiliates now or at any + future time and which would necessarily be infringed by implementation + of the Advanced Messaging Queue Protocol Specification. A claim is + necessarily infringed hereunder only when it is not possible to avoid + infringing it because there is no plausible non-infringing alternative + for implementing the required portions of the Advanced Messaging Queue + Protocol Specification. Notwithstanding the foregoing, Licensed Claims + shall not include any claims other than as set forth above even if + contained in the same patent as Licensed Claims; or that read solely + on any implementations of any portion of the Advanced Messaging Queue + Protocol Specification that are not required by the Advanced Messaging + Queue Protocol Specification, or that, if licensed, would require a + payment of royalties by the licensor to unaffiliated third parties. + Moreover, Licensed Claims shall not include (i) any enabling technologies + that may be necessary to make or use any Licensed Product but are not + themselves expressly set forth in the Advanced Messaging Queue Protocol + Specification (e.g., semiconductor manufacturing technology, compiler + technology, object oriented technology, networking technology, operating + system technology, and the like); or (ii) the implementation of other + published standards developed elsewhere and merely referred to in the + body of the Advanced Messaging Queue Protocol Specification, or + (iii) any Licensed Product and any combinations thereof the purpose or + function of which is not required for compliance with the Advanced + Messaging Queue Protocol Specification. For purposes of this definition, + the Advanced Messaging Queue Protocol Specification shall be deemed to + include both architectural and interconnection requirements essential + for interoperability and may also include supporting source code artifacts + where such architectural, interconnection requirements and source code + artifacts are expressly identified as being required or documentation to + achieve compliance with the Advanced Messaging Queue Protocol Specification. + + As used hereunder, "Licensed Products" means only those specific portions + of products (hardware, software or combinations thereof) that implement + and are compliant with all relevant portions of the Advanced Messaging + Queue Protocol Specification. + + The following disclaimers, which you hereby also acknowledge as to any + use you may make of the Advanced Messaging Queue Protocol Specification: + + THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION IS PROVIDED "AS IS," + AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE + CONTENTS OF THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION ARE + SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF THE ADVANCED + MESSAGING QUEUE PROTOCOL SPECIFICATION WILL NOT INFRINGE ANY THIRD PARTY + PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + + THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, + INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO ANY + USE, IMPLEMENTATION OR DISTRIBUTION OF THE ADVANCED MESSAGING QUEUE + PROTOCOL SPECIFICATION. + + The name and trademarks of the Authors may NOT be used in any manner, + including advertising or publicity pertaining to the Advanced Messaging + Queue Protocol Specification or its contents without specific, written + prior permission. Title to copyright in the Advanced Messaging Queue + Protocol Specification will at all times remain with the Authors. + + No other rights are granted by implication, estoppel or otherwise. + + Upon termination of your license or rights under this Agreement, you + shall destroy all copies of the Advanced Messaging Queue Protocol + Specification in your possession or control. + + Trademarks + ========== + "JPMorgan", "JPMorgan Chase", "Chase", the JPMorgan Chase logo and the + Octagon Symbol are trademarks of JPMorgan Chase & Co. + + IMATIX and the iMatix logo are trademarks of iMatix Corporation sprl. + + IONA, IONA Technologies, and the IONA logos are trademarks of IONA + Technologies PLC and/or its subsidiaries. + + LINUX is a trademark of Linus Torvalds. RED HAT and JBOSS are registered + trademarks of Red Hat, Inc. in the US and other countries. + + Java, all Java-based trademarks and OpenOffice.org are trademarks of + Sun Microsystems, Inc. in the United States, other countries, or both. + + Other company, product, or service names may be trademarks or service + marks of others. + + Links to full AMQP specification: + ================================= + http://www.envoytech.org/spec/amq/ + http://www.iona.com/opensource/amqp/ + http://www.redhat.com/solutions/specifications/amqp/ + http://www.twiststandards.org/tiki-index.php?page=AMQ + http://www.imatix.com/amqp +--> + +<!-- + <!DOCTYPE amqp SYSTEM "amqp.dtd"> +--> + +<!-- XML Notes + + We use entities to indicate repetition; attributes to indicate properties. + + We use the 'name' attribute as an identifier, usually within the context + of the surrounding entities. + + We use spaces to seperate words in names, so that we can print names in + their natural form depending on the context - underlines for source code, + hyphens for written text, etc. + + We do not enforce any particular validation mechanism but we support all + mechanisms. The protocol definition conforms to a formal grammar that is + published seperately in several technologies. + + --> + +<amqp major = "0" minor = "9" port = "5672" comment = "AMQ Protocol"> + <!-- + ====================================================== + == CONSTANTS + ====================================================== + --> + <!-- Frame types --> + <constant name = "frame-method" value = "1" /> + <constant name = "frame-header" value = "2" /> + <constant name = "frame-body" value = "3" /> + <constant name = "frame-oob-method" value = "4" /> + <constant name = "frame-oob-header" value = "5" /> + <constant name = "frame-oob-body" value = "6" /> + <constant name = "frame-trace" value = "7" /> + <constant name = "frame-heartbeat" value = "8" /> + + <!-- Protocol constants --> + <constant name = "frame-min-size" value = "4096" /> + <constant name = "frame-end" value = "206" /> + + <!-- Reply codes --> + <constant name = "reply-success" value = "200"> + <doc> + Indicates that the method completed successfully. This reply code is + reserved for future use - the current protocol design does not use positive + confirmation and reply codes are sent only in case of an error. + </doc> + </constant> + + <constant name = "not-delivered" value = "310" class = "soft-error"> + <doc> + The client asked for a specific message that is no longer available. + The message was delivered to another client, or was purged from the queue + for some other reason. + </doc> + </constant> + + <constant name = "content-too-large" value = "311" class = "soft-error"> + <doc> + The client attempted to transfer content larger than the server could accept + at the present time. The client may retry at a later time. + </doc> + </constant> + + <constant name = "connection-forced" value = "320" class = "hard-error"> + <doc> + An operator intervened to close the connection for some reason. The client + may retry at some later date. + </doc> + </constant> + + <constant name = "invalid-path" value = "402" class = "hard-error"> + <doc> + The client tried to work with an unknown virtual host. + </doc> + </constant> + + <constant name = "access-refused" value = "403" class = "soft-error"> + <doc> + The client attempted to work with a server entity to which it has no + access due to security settings. + </doc> + </constant> + + <constant name = "not-found" value = "404" class = "soft-error"> + <doc>The client attempted to work with a server entity that does not exist.</doc> + </constant> + + <constant name = "resource-locked" value = "405" class = "soft-error"> + <doc> + The client attempted to work with a server entity to which it has no + access because another client is working with it. + </doc> + </constant> + + <constant name = "precondition-failed" value = "406" class = "soft-error"> + <doc> + The client requested a method that was not allowed because some precondition + failed. + </doc> + </constant> + + <constant name = "frame-error" value = "501" class = "hard-error"> + <doc> + The client sent a malformed frame that the server could not decode. This + strongly implies a programming error in the client. + </doc> + </constant> + + <constant name = "syntax-error" value = "502" class = "hard-error"> + <doc> + The client sent a frame that contained illegal values for one or more + fields. This strongly implies a programming error in the client. + </doc> + </constant> + + <constant name = "command-invalid" value = "503" class = "hard-error"> + <doc> + The client sent an invalid sequence of frames, attempting to perform an + operation that was considered invalid by the server. This usually implies + a programming error in the client. + </doc> + </constant> + + <constant name = "channel-error" value = "504" class = "hard-error"> + <doc> + The client attempted to work with a channel that had not been correctly + opened. This most likely indicates a fault in the client layer. + </doc> + </constant> + + <constant name = "resource-error" value = "506" class = "hard-error"> + <doc> + The server could not complete the method because it lacked sufficient + resources. This may be due to the client creating too many of some type + of entity. + </doc> + </constant> + + <constant name = "not-allowed" value = "530" class = "hard-error"> + <doc> + The client tried to work with some entity in a manner that is prohibited + by the server, due to security settings or by some other criteria. + </doc> + </constant> + + <constant name = "not-implemented" value = "540" class = "hard-error"> + <doc> + The client tried to use functionality that is not implemented in the + server. + </doc> + </constant> + + <constant name = "internal-error" value = "541" class = "hard-error"> + <doc> + The server could not complete the method because of an internal error. + The server may require intervention by an operator in order to resume + normal operations. + </doc> + </constant> + + <constant name = "test-str2" value = "1.2.3.3"/> + + <!-- + ====================================================== + == DOMAIN TYPES + ====================================================== + --> + + <domain name = "access-ticket" type = "short" label = "access ticket granted by server"> + <doc> + An access ticket granted by the server for a certain set of access rights + within a specific realm. Access tickets are valid within the channel where + they were created, and expire when the channel closes. + </doc> + <assert check = "ne" value = "0" /> + </domain> + + <domain name = "class-id" type = "short" /> + + <domain name = "consumer-tag" type = "shortstr" label = "consumer tag"> + <doc> + Identifier for the consumer, valid within the current connection. + </doc> + </domain> + + <domain name = "delivery-tag" type = "longlong" label = "server-assigned delivery tag"> + <doc> + The server-assigned and channel-specific delivery tag + </doc> + <rule name = "channel-local"> + <doc> + The delivery tag is valid only within the channel from which the message was + received. I.e. a client MUST NOT receive a message on one channel and then + acknowledge it on another. + </doc> + </rule> + <rule name = "non-zero"> + <doc> + The server MUST NOT use a zero value for delivery tags. Zero is reserved + for client use, meaning "all messages so far received". + </doc> + </rule> + </domain> + + <domain name = "exchange-name" type = "shortstr" label = "exchange name"> + <doc> + The exchange name is a client-selected string that identifies the exchange for publish + methods. Exchange names may consist of any mixture of digits, letters, and underscores. + Exchange names are scoped by the virtual host. + </doc> + <assert check = "length" value = "127" /> + </domain> + + <domain name = "known-hosts" type = "shortstr" label = "list of known hosts"> + <doc> + Specifies the list of equivalent or alternative hosts that the server knows about, + which will normally include the current server itself. Clients can cache this + information and use it when reconnecting to a server after a failure. This field + may be empty. + </doc> + </domain> + + <domain name = "method-id" type = "short" /> + + <domain name = "no-ack" type = "bit" label = "no acknowledgement needed"> + <doc> + If this field is set the server does not expect acknowledgments for + messages. That is, when a message is delivered to the client the server + automatically and silently acknowledges it on behalf of the client. This + functionality increases performance but at the cost of reliability. + Messages can get lost if a client dies before it can deliver them to the + application. + </doc> + </domain> + + <domain name = "no-local" type = "bit" label = "do not deliver own messages"> + <doc> + If the no-local field is set the server will not send messages to the client that + published them. + </doc> + </domain> + + <domain name = "path" type = "shortstr"> + <doc> + Must start with a slash "/" and continue with path names separated by slashes. A path + name consists of any combination of at least one of [A-Za-z0-9] plus zero or more of + [.-_+!=:]. + </doc> + + <assert check = "notnull" /> + <assert check = "syntax" rule = "path" /> + <assert check = "length" value = "127" /> + </domain> + + <domain name = "peer-properties" type = "table"> + <doc> + This string provides a set of peer properties, used for identification, debugging, and + general information. + </doc> + </domain> + + <domain name = "queue-name" type = "shortstr" label = "queue name"> + <doc> + The queue name identifies the queue within the vhost. Queue names may consist of any + mixture of digits, letters, and underscores. + </doc> + <assert check = "length" value = "127" /> + </domain> + + <domain name = "redelivered" type = "bit" label = "message is being redelivered"> + <doc> + This indicates that the message has been previously delivered to this or + another client. + </doc> + <rule name = "implementation"> + <doc> + The server SHOULD try to signal redelivered messages when it can. When + redelivering a message that was not successfully acknowledged, the server + SHOULD deliver it to the original client if possible. + </doc> + <doc type = "scenario"> + Create a shared queue and publish a message to the queue. Consume the + message using explicit acknowledgements, but do not acknowledge the + message. Close the connection, reconnect, and consume from the queue + again. The message should arrive with the redelivered flag set. + </doc> + </rule> + <rule name = "hinting"> + <doc> + The client MUST NOT rely on the redelivered field but should take it as a + hint that the message may already have been processed. A fully robust + client must be able to track duplicate received messages on non-transacted, + and locally-transacted channels. + </doc> + </rule> + </domain> + + <domain name = "reply-code" type = "short" label = "reply code from server"> + <doc> + The reply code. The AMQ reply codes are defined as constants at the start + of this formal specification. + </doc> + <assert check = "notnull" /> + </domain> + + <domain name = "reply-text" type = "shortstr" label = "localised reply text"> + <doc> + The localised reply text. This text can be logged as an aid to resolving + issues. + </doc> + <assert check = "notnull" /> + </domain> + + <!-- Elementary domains --> + <domain name = "bit" type = "bit" label = "single bit" /> + <domain name = "octet" type = "octet" label = "single octet" /> + <domain name = "short" type = "short" label = "16-bit integer" /> + <domain name = "long" type = "long" label = "32-bit integer" /> + <domain name = "longlong" type = "longlong" label = "64-bit integer" /> + <domain name = "shortstr" type = "shortstr" label = "short string" /> + <domain name = "longstr" type = "longstr" label = "long string" /> + <domain name = "timestamp" type = "timestamp" label = "64-bit timestamp" /> + <domain name = "table" type = "table" label = "field table" /> + + <!-- == CONNECTION ======================================================= --> + + <!-- TODO 0.81 - the 'handler' attribute of methods needs to be reviewed, and if + no current implementations use it, removed. /PH 2006/07/20 + --> + + <class name = "connection" handler = "connection" index = "10" label = "work with socket connections"> + <doc> + The connection class provides methods for a client to establish a network connection to + a server, and for both peers to operate the connection thereafter. + </doc> + + <doc type = "grammar"> + connection = open-connection *use-connection close-connection + open-connection = C:protocol-header + S:START C:START-OK + *challenge + S:TUNE C:TUNE-OK + C:OPEN S:OPEN-OK | S:REDIRECT + challenge = S:SECURE C:SECURE-OK + use-connection = *channel + close-connection = C:CLOSE S:CLOSE-OK + / S:CLOSE C:CLOSE-OK + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "start" synchronous = "1" index = "10" label = "start connection negotiation"> + <doc> + This method starts the connection negotiation process by telling the client the + protocol version that the server proposes, along with a list of security mechanisms + which the client can use for authentication. + </doc> + + <rule name = "protocol-name"> + <doc> + If the server cannot support the protocol specified in the protocol header, + it MUST close the socket connection without sending any response method. + </doc> + <doc type = "scenario"> + The client sends a protocol header containing an invalid protocol name. + The server must respond by closing the connection. + </doc> + </rule> + <rule name = "server-support"> + <doc> + The server MUST provide a protocol version that is lower than or equal to + that requested by the client in the protocol header. + </doc> + <doc type = "scenario"> + The client requests a protocol version that is higher than any valid + implementation, e.g. 9.0. The server must respond with a current + protocol version, e.g. 1.0. + </doc> + </rule> + <rule name = "client-support"> + <doc> + If the client cannot handle the protocol version suggested by the server + it MUST close the socket connection. + </doc> + <doc type = "scenario"> + The server sends a protocol version that is lower than any valid + implementation, e.g. 0.1. The client must respond by closing the + connection. + </doc> + </rule> + + <chassis name = "client" implement = "MUST" /> + <response name = "start-ok" /> + + <field name = "version-major" domain = "octet" label = "protocol major version"> + <doc> + The version of the protocol, expressed in protocol units of 0.1 public + versions and properly printed as two digits with a leading zero. I.e. a + protocol version of "09" represents a public version "0.9". The decimal + shift allows the correct expression of pre-1.0 protocol releases. + </doc> + <doc type = "todo"> + This field should be renamed to "protocol version". + </doc> + </field> + + <field name = "version-minor" domain = "octet" label = "protocol major version"> + <doc> + The protocol revision, expressed as an integer from 0 to 9. The use of more + than ten revisions is discouraged. The public version string is constructed + from the protocol version and revision as follows: we print the protocol + version with one decimal position, and we append the protocol revision. A + version=10 and revision=2 are printed as "1.02". + </doc> + <doc type = "todo"> + This field should be renamed to "protocol revision". + </doc> + </field> + + <field name = "server-properties" domain = "peer-properties" label = "server properties"> + <rule name = "required-fields"> + <doc> + The properties SHOULD contain at least these fields: "host", specifying the + server host name or address, "product", giving the name of the server product, + "version", giving the name of the server version, "platform", giving the name + of the operating system, "copyright", if appropriate, and "information", giving + other general information. + </doc> + <doc type = "scenario"> + Client connects to server and inspects the server properties. It checks for + the presence of the required fields. + </doc> + </rule> + </field> + + <field name = "mechanisms" domain = "longstr" label = "available security mechanisms"> + <doc> + A list of the security mechanisms that the server supports, delimited by spaces. + Currently ASL supports these mechanisms: PLAIN. + </doc> + <assert check = "notnull" /> + </field> + + <field name = "locales" domain = "longstr" label = "available message locales"> + <doc> + A list of the message locales that the server supports, delimited by spaces. The + locale defines the language in which the server will send reply texts. + </doc> + <rule name = "required-support"> + <doc> + The server MUST support at least the en_US locale. + </doc> + <doc type = "scenario"> + Client connects to server and inspects the locales field. It checks for + the presence of the required locale(s). + </doc> + </rule> + <assert check = "notnull" /> + </field> + </method> + + <method name = "start-ok" synchronous = "1" index = "11" + label = "select security mechanism and locale"> + <doc> + This method selects a SASL security mechanism. ASL uses SASL (RFC2222) to + negotiate authentication and encryption. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "client-properties" domain = "peer-properties" label = "client properties"> + <rule name = "required-fields"> + <!-- This rule is not testable from the client side --> + <doc> + The properties SHOULD contain at least these fields: "product", giving the name + of the client product, "version", giving the name of the client version, "platform", + giving the name of the operating system, "copyright", if appropriate, and + "information", giving other general information. + </doc> + </rule> + </field> + + <field name = "mechanism" domain = "shortstr" label = "selected security mechanism"> + <doc> + A single security mechanisms selected by the client, which must be one of those + specified by the server. + </doc> + <rule name = "security"> + <doc> + The client SHOULD authenticate using the highest-level security profile it + can handle from the list provided by the server. + </doc> + </rule> + <rule name = "validity"> + <doc> + If the mechanism field does not contain one of the security mechanisms + proposed by the server in the Start method, the server MUST close the + connection without sending any further data. + </doc> + <doc type = "scenario"> + Client connects to server and sends an invalid security mechanism. The + server must respond by closing the connection (a socket close, with no + connection close negotiation). + </doc> + </rule> + <assert check = "notnull" /> + </field> + + <field name = "response" domain = "longstr" label = "security response data"> + <doc> + A block of opaque data passed to the security mechanism. The contents of this + data are defined by the SASL security mechanism. + </doc> + <assert check = "notnull" /> + </field> + + <field name = "locale" domain = "shortstr" label = "selected message locale"> + <doc> + A single message local selected by the client, which must be one of those + specified by the server. + </doc> + <assert check = "notnull" /> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "secure" synchronous = "1" index = "20" label = "security mechanism challenge"> + <doc> + The SASL protocol works by exchanging challenges and responses until both peers have + received sufficient information to authenticate each other. This method challenges + the client to provide more information. + </doc> + + <chassis name = "client" implement = "MUST" /> + <response name = "secure-ok" /> + + <field name = "challenge" domain = "longstr" label = "security challenge data"> + <doc> + Challenge information, a block of opaque binary data passed to the security + mechanism. + </doc> + </field> + </method> + + <method name = "secure-ok" synchronous = "1" index = "21" label = "security mechanism response"> + <doc> + This method attempts to authenticate, passing a block of SASL data for the security + mechanism at the server side. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "response" domain = "longstr" label = "security response data"> + <doc> + A block of opaque data passed to the security mechanism. The contents of this + data are defined by the SASL security mechanism. + </doc> + <assert check = "notnull" /> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "tune" synchronous = "1" index = "30" + label = "propose connection tuning parameters"> + <doc> + This method proposes a set of connection configuration values to the client. The + client can accept and/or adjust these. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <response name = "tune-ok" /> + + <field name = "channel-max" domain = "short" label = "proposed maximum channels"> + <doc> + The maximum total number of channels that the server allows per connection. Zero + means that the server does not impose a fixed limit, but the number of allowed + channels may be limited by available server resources. + </doc> + </field> + + <field name = "frame-max" domain = "long" label = "proposed maximum frame size"> + <doc> + The largest frame size that the server proposes for the connection. The client + can negotiate a lower value. Zero means that the server does not impose any + specific limit but may reject very large frames if it cannot allocate resources + for them. + </doc> + <rule name = "minimum"> + <doc> + Until the frame-max has been negotiated, both peers MUST accept frames of up + to frame-min-size octets large, and the minimum negotiated value for frame-max + is also frame-min-size. + </doc> + <doc type = "scenario"> + Client connects to server and sends a large properties field, creating a frame + of frame-min-size octets. The server must accept this frame. + </doc> + </rule> + </field> + + <field name = "heartbeat" domain = "short" label = "desired heartbeat delay"> + <!-- TODO 0.82 - the heartbeat negotiation mechanism was changed during + implementation because the model documented here does not actually + work properly. The best model we found is that the server proposes + a heartbeat value to the client; the client can reply with zero, meaning + 'do not use heartbeats (as documented here), or can propose its own + heartbeat value, which the server should then accept. This is different + from the model here which is disconnected - e.g. each side requests a + heartbeat independently. Basically a connection is heartbeated in + both ways, or not at all, depending on whether both peers support + heartbeating or not, and the heartbeat value should itself be chosen + by the client so that remote links can get a higher value. Also, the + actual heartbeat mechanism needs documentation, and is as follows: so + long as there is activity on a connection - in or out - both peers + assume the connection is active. When there is no activity, each peer + must send heartbeat frames. When no heartbeat frame is received after + N cycles (where N is at least 2), the connection can be considered to + have died. /PH 2006/07/19 + --> + <doc> + The delay, in seconds, of the connection heartbeat that the server wants. + Zero means the server does not want a heartbeat. + </doc> + </field> + </method> + + <method name = "tune-ok" synchronous = "1" index = "31" + label = "negotiate connection tuning parameters"> + <doc> + This method sends the client's connection tuning parameters to the server. + Certain fields are negotiated, others provide capability information. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "channel-max" domain = "short" label = "negotiated maximum channels"> + <doc> + The maximum total number of channels that the client will use per connection. + </doc> + <rule name = "upper-limit"> + <doc> + If the client specifies a channel max that is higher than the value provided + by the server, the server MUST close the connection without attempting a + negotiated close. The server may report the error in some fashion to assist + implementors. + </doc> + </rule> + <assert check = "notnull" /> + <assert check = "le" method = "tune" field = "channel-max" /> + </field> + + <field name = "frame-max" domain = "long" label = "negotiated maximum frame size"> + <doc> + The largest frame size that the client and server will use for the connection. + Zero means that the client does not impose any specific limit but may reject + very large frames if it cannot allocate resources for them. Note that the + frame-max limit applies principally to content frames, where large contents can + be broken into frames of arbitrary size. + </doc> + <rule name = "minimum"> + <doc> + Until the frame-max has been negotiated, both peers MUST accept frames of up + to frame-min-size octets large, and the minimum negotiated value for frame-max + is also frame-min-size. + </doc> + </rule> + <rule name = "upper-limit"> + <doc> + If the client specifies a frame max that is higher than the value provided + by the server, the server MUST close the connection without attempting a + negotiated close. The server may report the error in some fashion to assist + implementors. + </doc> + </rule> + </field> + + <field name = "heartbeat" domain = "short" label = "desired heartbeat delay"> + <doc> + The delay, in seconds, of the connection heartbeat that the client wants. Zero + means the client does not want a heartbeat. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "open" synchronous = "1" index = "40" label = "open connection to virtual host"> + <doc> + This method opens a connection to a virtual host, which is a collection of + resources, and acts to separate multiple application domains within a server. + The server may apply arbitrary limits per virtual host, such as the number + of each type of entity that may be used, per connection and/or in total. + </doc> + + <chassis name = "server" implement = "MUST" /> + <response name = "open-ok" /> + <response name = "redirect" /> + + <field name = "virtual-host" domain = "path" label = "virtual host name"> + <!-- TODO 0.82 - the entire vhost model needs review. This concept was + prompted by the HTTP vhost concept but does not fit very well into + AMQP. Currently we use the vhost as a "cluster identifier" which is + inaccurate usage. /PH 2006/07/19 + --> + <assert check = "regexp" value = "^[a-zA-Z0-9/-_]+$" /> + <doc> + The name of the virtual host to work with. + </doc> + <rule name = "separation"> + <doc> + If the server supports multiple virtual hosts, it MUST enforce a full + separation of exchanges, queues, and all associated entities per virtual + host. An application, connected to a specific virtual host, MUST NOT be able + to access resources of another virtual host. + </doc> + </rule> + <rule name = "security"> + <doc> + The server SHOULD verify that the client has permission to access the + specified virtual host. + </doc> + </rule> + </field> + + <field name = "capabilities" domain = "shortstr" label = "required capabilities"> + <doc> + The client can specify zero or more capability names, delimited by spaces. + The server can use this string to how to process the client's connection + request. + </doc> + </field> + + <field name = "insist" domain = "bit" label = "insist on connecting to server"> + <doc> + In a configuration with multiple collaborating servers, the server may respond + to a Connection.Open method with a Connection.Redirect. The insist option tells + the server that the client is insisting on a connection to the specified server. + </doc> + <rule name = "behaviour"> + <doc> + When the client uses the insist option, the server MUST NOT respond with a + Connection.Redirect method. If it cannot accept the client's connection + request it should respond by closing the connection with a suitable reply + code. + </doc> + </rule> + </field> + </method> + + <method name = "open-ok" synchronous = "1" index = "41" label = "signal that connection is ready"> + <doc> + This method signals to the client that the connection is ready for use. + </doc> + <chassis name = "client" implement = "MUST" /> + <field name = "known-hosts" domain = "known-hosts" /> + </method> + + <method name = "redirect" synchronous = "1" index = "42" label = "redirects client to other server"> + <doc> + This method redirects the client to another server, based on the requested virtual + host and/or capabilities. + </doc> + <rule name = "usage"> + <doc> + When getting the Connection.Redirect method, the client SHOULD reconnect to + the host specified, and if that host is not present, to any of the hosts + specified in the known-hosts list. + </doc> + </rule> + <chassis name = "client" implement = "MUST" /> + <field name = "host" domain = "shortstr" label = "server to connect to"> + <doc> + Specifies the server to connect to. This is an IP address or a DNS name, + optionally followed by a colon and a port number. If no port number is + specified, the client should use the default port number for the protocol. + </doc> + <assert check = "notnull" /> + </field> + <field name = "known-hosts" domain = "known-hosts" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "close" synchronous = "1" index = "50" label = "request a connection close"> + <doc> + This method indicates that the sender wants to close the connection. This may be + due to internal conditions (e.g. a forced shut-down) or due to an error handling + a specific method, i.e. an exception. When a close is due to an exception, the + sender provides the class and method id of the method which caused the exception. + </doc> + <!-- TODO: the connection close mechanism needs to be reviewed from the ODF + documentation and better expressed as rules here. /PH 2006/07/20 + --> + <rule name = "stability"> + <doc> + After sending this method any received method except the Close-OK method MUST + be discarded. + </doc> + </rule> + + <chassis name = "client" implement = "MUST" /> + <chassis name = "server" implement = "MUST" /> + <response name = "close-ok" /> + + <field name = "reply-code" domain = "reply-code" /> + <field name = "reply-text" domain = "reply-text" /> + + <field name = "class-id" domain = "class-id" label = "failing method class"> + <doc> + When the close is provoked by a method exception, this is the class of the + method. + </doc> + </field> + + <field name = "method-id" domain = "method-id" label = "failing method ID"> + <doc> + When the close is provoked by a method exception, this is the ID of the method. + </doc> + </field> + </method> + + <method name = "close-ok" synchronous = "1" index = "51" label = "confirm a connection close"> + <doc> + This method confirms a Connection.Close method and tells the recipient that it is + safe to release resources for the connection and close the socket. + </doc> + <rule name = "reporting"> + <doc> + A peer that detects a socket closure without having received a Close-Ok + handshake method SHOULD log the error. + </doc> + </rule> + <chassis name = "client" implement = "MUST" /> + <chassis name = "server" implement = "MUST" /> + </method> + </class> + + <!-- == CHANNEL ========================================================== --> + + <class name = "channel" handler = "channel" index = "20" label = "work with channels"> + <doc> + The channel class provides methods for a client to establish a channel to a + server and for both peers to operate the channel thereafter. + </doc> + + <doc type = "grammar"> + channel = open-channel *use-channel close-channel + open-channel = C:OPEN S:OPEN-OK + use-channel = C:FLOW S:FLOW-OK + / S:FLOW C:FLOW-OK + / S:ALERT + / functional-class + close-channel = C:CLOSE S:CLOSE-OK + / S:CLOSE C:CLOSE-OK + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "open" synchronous = "1" index = "10" label = "open a channel for use"> + <doc> + This method opens a channel to the server. + </doc> + <rule name = "state" on-failure = "channel-error"> + <doc> + The client MUST NOT use this method on an alread-opened channel. + </doc> + <doc type = "scenario"> + Client opens a channel and then reopens the same channel. + </doc> + </rule> + <chassis name = "server" implement = "MUST" /> + <response name = "open-ok" /> + <field name = "out of band" domain = "shortstr" label = "out-of-band settings"> + <doc> + Configures out-of-band transfers on this channel. The syntax and meaning of this + field will be formally defined at a later date. + </doc> + <assert check = "null" /> + </field> + </method> + + <method name = "open-ok" synchronous = "1" index = "11" label = "signal that the channel is ready"> + <doc> + This method signals to the client that the channel is ready for use. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "flow" synchronous = "1" index = "20" label = "enable/disable flow from peer"> + <doc> + This method asks the peer to pause or restart the flow of content data. This is a + simple flow-control mechanism that a peer can use to avoid oveflowing its queues or + otherwise finding itself receiving more messages than it can process. Note that this + method is not intended for window control. The peer that receives a disable flow + method should finish sending the current content frame, if any, then pause. + </doc> + + <rule name = "initial-state"> + <doc> + When a new channel is opened, it is active (flow is active). Some applications + assume that channels are inactive until started. To emulate this behaviour a + client MAY open the channel, then pause it. + </doc> + </rule> + + <rule name = "bidirectional"> + <doc> + When sending content frames, a peer SHOULD monitor the channel for incoming + methods and respond to a Channel.Flow as rapidly as possible. + </doc> + </rule> + + <rule name = "throttling"> + <doc> + A peer MAY use the Channel.Flow method to throttle incoming content data for + internal reasons, for example, when exchanging data over a slower connection. + </doc> + </rule> + + <rule name = "expected-behaviour"> + <doc> + The peer that requests a Channel.Flow method MAY disconnect and/or ban a peer + that does not respect the request. This is to prevent badly-behaved clients + from overwhelming a broker. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <response name = "flow-ok" /> + + <field name = "active" domain = "bit" label = "start/stop content frames"> + <doc> + If 1, the peer starts sending content frames. If 0, the peer stops sending + content frames. + </doc> + </field> + </method> + + <method name = "flow-ok" index = "21" label = "confirm a flow method"> + <doc> + Confirms to the peer that a flow command was received and processed. + </doc> + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + <field name = "active" domain = "bit" label = "current flow setting"> + <doc> + Confirms the setting of the processed flow method: 1 means the peer will start + sending or continue to send content frames; 0 means it will not. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <!-- TODO 0.82 - remove this method entirely + /PH 2006/07/20 + --> + <method name = "alert" index = "30" label = "send a non-fatal warning message"> + <doc> + This method allows the server to send a non-fatal warning to the client. This is + used for methods that are normally asynchronous and thus do not have confirmations, + and for which the server may detect errors that need to be reported. Fatal errors + are handled as channel or connection exceptions; non-fatal errors are sent through + this method. + </doc> + <chassis name = "client" implement = "MUST" /> + <field name = "reply-code" domain = "reply-code" /> + <field name = "reply-text" domain = "reply-text" /> + <field name = "details" domain = "table" label = "detailed information for warning"> + <doc> + A set of fields that provide more information about the problem. The meaning of + these fields are defined on a per-reply-code basis (TO BE DEFINED). + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "close" synchronous = "1" index = "40" label = "request a channel close"> + <doc> + This method indicates that the sender wants to close the channel. This may be due to + internal conditions (e.g. a forced shut-down) or due to an error handling a specific + method, i.e. an exception. When a close is due to an exception, the sender provides + the class and method id of the method which caused the exception. + </doc> + + <!-- TODO: the channel close behaviour needs to be reviewed from the ODF + documentation and better expressed as rules here. /PH 2006/07/20 + --> + <rule name = "stability"> + <doc> + After sending this method any received method except the Close-OK method MUST + be discarded. + </doc> + </rule> + + <chassis name = "client" implement = "MUST" /> + <chassis name = "server" implement = "MUST" /> + <response name = "close-ok" /> + + <field name = "reply-code" domain = "reply-code" /> + <field name = "reply-text" domain = "reply-text" /> + + <field name = "class-id" domain = "class-id" label = "failing method class"> + <doc> + When the close is provoked by a method exception, this is the class of the + method. + </doc> + </field> + + <field name = "method-id" domain = "method-id" label = "failing method ID"> + <doc> + When the close is provoked by a method exception, this is the ID of the method. + </doc> + </field> + </method> + + <method name = "close-ok" synchronous = "1" index = "41" label = "confirm a channel close"> + <doc> + This method confirms a Channel.Close method and tells the recipient that it is safe + to release resources for the channel and close the socket. + </doc> + <rule name = "reporting"> + <doc> + A peer that detects a socket closure without having received a Channel.Close-Ok + handshake method SHOULD log the error. + </doc> + </rule> + <chassis name = "client" implement = "MUST" /> + <chassis name = "server" implement = "MUST" /> + </method> + </class> + + <!-- == ACCESS =========================================================== --> + + <!-- TODO 0.82 - this class must be implemented by two teams before we can + consider it matured. + --> + + <class name = "access" handler = "connection" index = "30" label = "work with access tickets"> + <doc> + The protocol control access to server resources using access tickets. A + client must explicitly request access tickets before doing work. An access + ticket grants a client the right to use a specific set of resources - + called a "realm" - in specific ways. + </doc> + + <doc type = "grammar"> + access = C:REQUEST S:REQUEST-OK + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "request" synchronous = "1" index = "10" label = "request an access ticket"> + <doc> + This method requests an access ticket for an access realm. The server + responds by granting the access ticket. If the client does not have + access rights to the requested realm this causes a connection exception. + Access tickets are a per-channel resource. + </doc> + + <chassis name = "server" implement = "MUST" /> + <response name = "request-ok" /> + + <field name = "realm" domain = "shortstr" label = "name of requested realm"> + <doc> + Specifies the name of the realm to which the client is requesting access. + The realm is a configured server-side object that collects a set of + resources (exchanges, queues, etc.). If the channel has already requested + an access ticket onto this realm, the previous ticket is destroyed and a + new ticket is created with the requested access rights, if allowed. + </doc> + <rule name = "validity" on-failure = "access-refused"> + <doc> + The client MUST specify a realm that is known to the server. The server + makes an identical response for undefined realms as it does for realms + that are defined but inaccessible to this client. + </doc> + <doc type = "scenario"> + Client specifies an undefined realm. + </doc> + </rule> + </field> + + <field name = "exclusive" domain = "bit" label = "request exclusive access"> + <doc> + Request exclusive access to the realm, meaning that this will be the only + channel that uses the realm's resources. + </doc> + <rule name = "validity" on-failure = "access-refused"> + <doc> + The client MAY NOT request exclusive access to a realm that has active + access tickets, unless the same channel already had the only access + ticket onto that realm. + </doc> + <doc type = "scenario"> + Client opens two channels and requests exclusive access to the same realm. + </doc> + </rule> + </field> + <field name = "passive" domain = "bit" label = "request passive access"> + <doc> + Request message passive access to the specified access realm. Passive + access lets a client get information about resources in the realm but + not to make any changes to them. + </doc> + </field> + <field name = "active" domain = "bit" label = "request active access"> + <doc> + Request message active access to the specified access realm. Active access lets + a client get create and delete resources in the realm. + </doc> + </field> + <field name = "write" domain = "bit" label = "request write access"> + <doc> + Request write access to the specified access realm. Write access lets a client + publish messages to all exchanges in the realm. + </doc> + </field> + <field name = "read" domain = "bit" label = "request read access"> + <doc> + Request read access to the specified access realm. Read access lets a client + consume messages from queues in the realm. + </doc> + </field> + </method> + + <method name = "request-ok" synchronous = "1" index = "11" label = "grant access to server resources"> + <doc> + This method provides the client with an access ticket. The access ticket is valid + within the current channel and for the lifespan of the channel. + </doc> + <rule name = "per-channel" on-failure = "not-allowed"> + <doc> + The client MUST NOT use access tickets except within the same channel as + originally granted. + </doc> + <doc type = "scenario"> + Client opens two channels, requests a ticket on one channel, and then + tries to use that ticket in a seconc channel. + </doc> + </rule> + <chassis name = "client" implement = "MUST" /> + <field name = "ticket" domain = "access-ticket" /> + </method> + </class> + + <!-- == EXCHANGE ========================================================= --> + + <class name = "exchange" handler = "channel" index = "40" label = "work with exchanges"> + <doc> + Exchanges match and distribute messages across queues. Exchanges can be configured in + the server or created at runtime. + </doc> + + <doc type = "grammar"> + exchange = C:DECLARE S:DECLARE-OK + / C:DELETE S:DELETE-OK + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <rule name = "required-types"> + <doc> + The server MUST implement these standard exchange types: fanout, direct. + </doc> + <doc type = "scenario"> + Client attempts to declare an exchange with each of these standard types. + </doc> + </rule> + <rule name = "recommended-types"> + <doc> + The server SHOULD implement these standard exchange types: topic, headers. + </doc> + <doc type = "scenario"> + Client attempts to declare an exchange with each of these standard types. + </doc> + </rule> + <rule name = "required-instances"> + <doc> + The server MUST, in each virtual host, pre-declare an exchange instance + for each standard exchange type that it implements, where the name of the + exchange instance is "amq." followed by the exchange type name. + </doc> + <doc type = "scenario"> + Client creates a temporary queue and attempts to bind to each required + exchange instance (amq.fanout, amq.direct, and amq.topic, amq.headers if + those types are defined). + </doc> + </rule> + <rule name = "default-exchange"> + <doc> + The server MUST predeclare a direct exchange to act as the default exchange + for content Publish methods and for default queue bindings. + </doc> + <doc type = "scenario"> + Client checks that the default exchange is active by specifying a queue + binding with no exchange name, and publishing a message with a suitable + routing key but without specifying the exchange name, then ensuring that + the message arrives in the queue correctly. + </doc> + </rule> + <rule name = "default-access"> + <doc> + The server MUST NOT allow clients to access the default exchange except + by specifying an empty exchange name in the Queue.Bind and content Publish + methods. + </doc> + </rule> + <rule name = "extensions"> + <doc> + The server MAY implement other exchange types as wanted. + </doc> + </rule> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "declare" synchronous = "1" index = "10" label = "declare exchange, create if needed"> + <doc> + This method creates an exchange if it does not already exist, and if the exchange + exists, verifies that it is of the correct and expected class. + </doc> + <rule name = "minimum"> + <doc> + The server SHOULD support a minimum of 16 exchanges per virtual host and + ideally, impose no limit except as defined by available resources. + </doc> + <doc type = "scenario"> + The client creates as many exchanges as it can until the server reports + an error; the number of exchanges successfuly created must be at least + sixteen. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + <response name = "declare-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <doc> + When a client defines a new exchange, this belongs to the access realm of the + ticket used. All further work done with that exchange must be done with an + access ticket for the same realm. + </doc> + <rule name = "validity" on-failure = "access-refused"> + <doc> + The client MUST provide a valid access ticket giving "active" access to + the realm in which the exchange exists or will be created, or "passive" + access if the if-exists flag is set. + </doc> + <doc type = "scenario"> + Client creates access ticket with wrong access rights and attempts to use + in this method. + </doc> + </rule> + </field> + + <field name = "exchange" domain = "exchange-name"> + <rule name = "reserved" on-failure = "access-refused"> + <doc> + Exchange names starting with "amq." are reserved for predeclared and + standardised exchanges. The client MUST NOT attempt to create an exchange + starting with "amq.". + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + <assert check = "regexp" value = "^[a-zA-Z0-9-_.:]+$" /> + </field> + + <field name = "type" domain = "shortstr" label = "exchange type"> + <doc> + Each exchange belongs to one of a set of exchange types implemented by the + server. The exchange types define the functionality of the exchange - i.e. how + messages are routed through it. It is not valid or meaningful to attempt to + change the type of an existing exchange. + </doc> + <rule name = "typed" on-failure = "not-allowed"> + <doc> + Exchanges cannot be redeclared with different types. The client MUST not + attempt to redeclare an existing exchange with a different type than used + in the original Exchange.Declare method. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + <rule name = "support" on-failure = "command-invalid"> + <doc> + The client MUST NOT attempt to create an exchange with a type that the + server does not support. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + <assert check = "regexp" value = "^[a-zA-Z0-9-_.:]+$" /> + </field> + + <field name = "passive" domain = "bit" label = "do not create exchange"> + <doc> + If set, the server will not create the exchange. The client can use this to + check whether an exchange exists without modifying the server state. + </doc> + <rule name = "not-found"> + <doc> + If set, and the exchange does not already exist, the server MUST raise a + channel exception with reply code 404 (not found). + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "durable" domain = "bit" label = "request a durable exchange"> + <doc> + If set when creating a new exchange, the exchange will be marked as durable. + Durable exchanges remain active when a server restarts. Non-durable exchanges + (transient exchanges) are purged if/when a server restarts. + </doc> + <rule name = "support"> + <doc> + The server MUST support both durable and transient exchanges. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + <rule name = "sticky"> + <doc> + The server MUST ignore the durable field if the exchange already exists. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <!-- TODO 0.82 - clarify how this works; there is no way to cancel a binding + except by deleting a queue. + --> + <field name = "auto-delete" domain = "bit" label = "auto-delete when unused"> + <doc> + If set, the exchange is deleted when all queues have finished using it. + </doc> + <rule name = "sticky"> + <doc> + The server MUST ignore the auto-delete field if the exchange already + exists. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "internal" domain = "bit" label = "create internal exchange"> + <doc> + If set, the exchange may not be used directly by publishers, but only when bound + to other exchanges. Internal exchanges are used to construct wiring that is not + visible to applications. + </doc> + </field> + + <field name = "nowait" domain = "bit" label = "do not send reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise a + channel or connection exception. + </doc> + </field> + + <field name = "arguments" domain = "table" label = "arguments for declaration"> + <doc> + A set of arguments for the declaration. The syntax and semantics of these + arguments depends on the server implementation. This field is ignored if passive + is 1. + </doc> + </field> + </method> + + <method name = "declare-ok" synchronous = "1" index = "11" label = "confirm exchange declaration"> + <doc> + This method confirms a Declare method and confirms the name of the exchange, + essential for automatically-named exchanges. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "delete" synchronous = "1" index = "20" label = "delete an exchange"> + <doc> + This method deletes an exchange. When an exchange is deleted all queue bindings on + the exchange are cancelled. + </doc> + + <chassis name = "server" implement = "MUST" /> + <response name = "delete-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "validity" on-failure = "access-refused"> + <doc> + The client MUST provide a valid access ticket giving "active" access + rights to the exchange's access realm. + </doc> + <doc type = "scenario"> + Client creates access ticket with wrong access rights and attempts to use + in this method. + </doc> + </rule> + </field> + + <field name = "exchange" domain = "exchange-name"> + <rule name = "exists" on-failure = "not-found"> + <doc> + The client MUST NOT attempt to delete an exchange that does not exist. + </doc> + </rule> + <assert check = "notnull" /> + </field> + + <!-- TODO 0.82 - discuss whether this option is useful or not. I don't have + any real use case for it. /PH 2006-07-23. + --> + <field name = "if-unused" domain = "bit" label = "delete only if unused"> + <doc> + If set, the server will only delete the exchange if it has no queue bindings. If + the exchange has queue bindings the server does not delete it but raises a + channel exception instead. + </doc> + </field> + + <field name = "nowait" domain = "bit" label = "do not send a reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise a + channel or connection exception. + </doc> + </field> + </method> + + <method name = "delete-ok" synchronous = "1" index = "21" + label = "confirm deletion of an exchange"> + <doc>This method confirms the deletion of an exchange.</doc> + <chassis name = "client" implement = "MUST" /> + </method> + </class> + + <!-- == QUEUE ============================================================ --> + + <class name = "queue" handler = "channel" index = "50" label = "work with queues"> + <doc> + Queues store and forward messages. Queues can be configured in the server or created at + runtime. Queues must be attached to at least one exchange in order to receive messages + from publishers. + </doc> + + <doc type = "grammar"> + queue = C:DECLARE S:DECLARE-OK + / C:BIND S:BIND-OK + / C:PURGE S:PURGE-OK + / C:DELETE S:DELETE-OK + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <rule name = "any-content"> + <doc> + A server MUST allow any content class to be sent to any queue, in any mix, and + queue and deliver these content classes independently. Note that all methods + that fetch content off queues are specific to a given content class. + </doc> + <doc type = "scenario"> + Client creates an exchange of each standard type and several queues that + it binds to each exchange. It must then sucessfully send each of the standard + content types to each of the available queues. + </doc> + </rule> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "declare" synchronous = "1" index = "10" label = "declare queue, create if needed"> + <doc> + This method creates or checks a queue. When creating a new queue the client can + specify various properties that control the durability of the queue and its + contents, and the level of sharing for the queue. + </doc> + + <rule name = "default-binding"> + <doc> + The server MUST create a default binding for a newly-created queue to the + default exchange, which is an exchange of type 'direct'. + </doc> + <doc type = "scenario"> + Client creates a new queue, and then without explicitly binding it to an + exchange, attempts to send a message through the default exchange binding, + i.e. publish a message to the empty exchange, with the queue name as routing + key. + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_35" --> + <rule name = "minimum-queues"> + <doc> + The server SHOULD support a minimum of 256 queues per virtual host and ideally, + impose no limit except as defined by available resources. + </doc> + <doc type = "scenario"> + Client attempts to create as many queues as it can until the server reports + an error. The resulting count must at least be 256. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + <response name = "declare-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <doc> + When a client defines a new queue, this belongs to the access realm of the + ticket used. All further work done with that queue must be done with an access + ticket for the same realm. + </doc> + <rule name = "validity" on-failure = "access-refused"> + <doc> + The client MUST provide a valid access ticket giving "active" access to + the realm in which the queue exists or will be created. + </doc> + <doc type = "scenario"> + Client creates access ticket with wrong access rights and attempts to use + in this method. + </doc> + </rule> + </field> + + <field name = "queue" domain = "queue-name"> + <rule name = "default-name"> + <doc> + The queue name MAY be empty, in which case the server MUST create a new + queue with a unique generated name and return this to the client in the + Declare-Ok method. + </doc> + <doc type = "scenario"> + Client attempts to create several queues with an empty name. The client then + verifies that the server-assigned names are unique and different. + </doc> + </rule> + <rule name = "reserved-prefix" on-failure = "not-allowed"> + <doc> + Queue names starting with "amq." are reserved for predeclared and + standardised server queues. A client MAY NOT attempt to declare a queue with a + name that starts with "amq." and the passive option set to zero. + </doc> + <doc type = "scenario"> + A client attempts to create a queue with a name starting with "amq." and with + the passive option set to zero. + </doc> + </rule> + <assert check = "regexp" value = "^[a-zA-Z0-9-_.:]*$" /> + </field> + + <field name = "passive" domain = "bit" label = "do not create queue"> + <doc> + If set, the server will not create the queue. This field allows the client + to assert the presence of a queue without modifying the server state. + </doc> + <rule name = "passive" on-failure = "not-found"> + <doc> + The client MAY ask the server to assert that a queue exists without + creating the queue if not. If the queue does not exist, the server + treats this as a failure. + </doc> + <doc type = "scenario"> + Client declares an existing queue with the passive option and expects + the server to respond with a declare-ok. Client then attempts to declare + a non-existent queue with the passive option, and the server must close + the channel with the correct reply-code. + </doc> + </rule> + </field> + + <field name = "durable" domain = "bit" label = "request a durable queue"> + <doc> + If set when creating a new queue, the queue will be marked as durable. Durable + queues remain active when a server restarts. Non-durable queues (transient + queues) are purged if/when a server restarts. Note that durable queues do not + necessarily hold persistent messages, although it does not make sense to send + persistent messages to a transient queue. + </doc> + <!-- Rule test name: was "amq_queue_03" --> + <rule name = "persistence"> + <doc>The server MUST recreate the durable queue after a restart.</doc> + + <!-- TODO: use 'client does something' rather than 'a client does something'. --> + <doc type = "scenario"> + A client creates a durable queue. The server is then restarted. The client + then attempts to send a message to the queue. The message should be successfully + delivered. + </doc> + </rule> + <!-- Rule test name: was "amq_queue_36" --> + <rule name = "types"> + <doc>The server MUST support both durable and transient queues.</doc> + <doc type = "scenario"> + A client creates two named queues, one durable and one transient. + </doc> + </rule> + <!-- Rule test name: was "amq_queue_37" --> + <rule name = "pre-existence"> + <doc>The server MUST ignore the durable field if the queue already exists.</doc> + <doc type = "scenario"> + A client creates two named queues, one durable and one transient. The client + then attempts to declare the two queues using the same names again, but reversing + the value of the durable flag in each case. Verify that the queues still exist + with the original durable flag values. + <!-- TODO: but how? --> + </doc> + </rule> + </field> + + <field name = "exclusive" domain = "bit" label = "request an exclusive queue"> + <doc> + Exclusive queues may only be consumed from by the current connection. Setting + the 'exclusive' flag always implies 'auto-delete'. + </doc> + + <!-- Rule test name: was "amq_queue_38" --> + <rule name = "types"> + <doc> + The server MUST support both exclusive (private) and non-exclusive (shared) + queues. + </doc> + <doc type = "scenario"> + A client creates two named queues, one exclusive and one non-exclusive. + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_04" --> + <rule name = "02" on-failure = "channel-error"> + <doc> + The client MAY NOT attempt to declare any existing and exclusive queue + on multiple connections. + </doc> + <doc type = "scenario"> + A client declares an exclusive named queue. A second client on a different + connection attempts to declare a queue of the same name. + </doc> + </rule> + </field> + + <field name = "auto-delete" domain = "bit" label = "auto-delete queue when unused"> + <doc> + If set, the queue is deleted when all consumers have finished using it. Last + consumer can be cancelled either explicitly or because its channel is closed. If + there was no consumer ever on the queue, it won't be deleted. + </doc> + + <!-- Rule test name: was "amq_queue_31" --> + <rule name = "pre-existence"> + <doc> + The server MUST ignore the auto-delete field if the queue already exists. + </doc> + <doc type = "scenario"> + A client creates two named queues, one as auto-delete and one explicit-delete. + The client then attempts to declare the two queues using the same names again, + but reversing the value of the auto-delete field in each case. Verify that the + queues still exist with the original auto-delete flag values. + <!-- TODO: but how? --> + </doc> + </rule> + </field> + + <field name = "nowait" domain = "bit" label = "do not send a reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise a + channel or connection exception. + </doc> + </field> + + <field name = "arguments" domain = "table" label = "arguments for declaration"> + <doc> + A set of arguments for the declaration. The syntax and semantics of these + arguments depends on the server implementation. This field is ignored if passive + is 1. + </doc> + </field> + </method> + + <method name = "declare-ok" synchronous = "1" index = "11" label = "confirms a queue definition"> + <doc> + This method confirms a Declare method and confirms the name of the queue, essential + for automatically-named queues. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "queue" domain = "queue-name"> + <doc> + Reports the name of the queue. If the server generated a queue name, this field + contains that name. + </doc> + <assert check = "notnull" /> + </field> + + <field name = "message-count" domain = "long" label = "number of messages in queue"> + <doc> + Reports the number of messages in the queue, which will be zero for + newly-created queues. + </doc> + </field> + + <field name = "consumer-count" domain = "long" label = "number of consumers"> + <doc> + Reports the number of active consumers for the queue. Note that consumers can + suspend activity (Channel.Flow) in which case they do not appear in this count. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "bind" synchronous = "1" index = "20" label = "bind queue to an exchange"> + <doc> + This method binds a queue to an exchange. Until a queue is bound it will not receive + any messages. In a classic messaging model, store-and-forward queues are bound to a + dest exchange and subscription queues are bound to a dest_wild exchange. + </doc> + + <!-- Rule test name: was "amq_queue_25" --> + <rule name = "duplicates"> + <doc> + A server MUST allow ignore duplicate bindings - that is, two or more bind + methods for a specific queue, with identical arguments - without treating these + as an error. + </doc> + <doc type = "scenario"> + A client binds a named queue to an exchange. The client then repeats the bind + (with identical arguments). + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_39" --> + <rule name = "failure" on-failure = "??????"> + <!-- + TODO: Find correct code. The on-failure code returned should depend on why the bind + failed. Assuming that failures owing to bad parameters are covered in the rules relating + to those parameters, the only remaining reason for a failure would be the lack of + server resorces or some internal error - such as too many queues open. Would these + cases qualify as "resource error" 506 or "internal error" 541? + --> + <doc>If a bind fails, the server MUST raise a connection exception.</doc> + <doc type = "scenario"> + TODO + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_12" --> + <rule name = "transient-exchange" on-failure = "not-allowed"> + <doc> + The server MUST NOT allow a durable queue to bind to a transient exchange. + </doc> + <doc type = "scenario"> + A client creates a transient exchange. The client then declares a named durable + queue and then attempts to bind the transient exchange to the durable queue. + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_13" --> + <rule name = "durable-exchange"> + <doc> + Bindings for durable queues are automatically durable and the server SHOULD + restore such bindings after a server restart. + </doc> + <doc type = "scenario"> + A server creates a named durable queue and binds it to a durable exchange. The + server is restarted. The client then attempts to use the queue/exchange combination. + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_17" --> + <rule name = "internal-exchange"> + <doc> + If the client attempts to bind to an exchange that was declared as internal, the server + MUST raise a connection exception with reply code 530 (not allowed). + </doc> + <doc type = "scenario"> + A client attempts to bind a named queue to an internal exchange. + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_40" --> + <rule name = "binding-count"> + <doc> + The server SHOULD support at least 4 bindings per queue, and ideally, impose no + limit except as defined by available resources. + </doc> + <doc type = "scenario"> + A client creates a named queue and attempts to bind it to 4 different non-internal + exchanges. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <response name = "bind-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <doc> + The client provides a valid access ticket giving "active" access rights to the + queue's access realm. + </doc> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to bind. If the queue name is empty, refers to + the current queue for the channel, which is the last declared queue. + </doc> + + <rule name = "empty-queue" on-failure = "not-allowed"> + <doc> + A client MUST NOT be allowed to bind a non-existent and unnamed queue (i.e. + empty queue name) to an exchange. + </doc> + <doc type = "scenario"> + A client attempts to bind with an unnamed (empty) queue name to an exchange. + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_26" --> + <rule name = "queue-existence" on-failure = "not-found"> + <doc> + A client MUST NOT be allowed to bind a non-existent queue (i.e. not previously + declared) to an exchange. + </doc> + <doc type = "scenario"> + A client attempts to bind an undeclared queue name to an exchange. + </doc> + </rule> + </field> + + <field name = "exchange" domain = "exchange-name" label = "name of the exchange to bind to"> + <!-- Rule test name: was "amq_queue_14" --> + <rule name = "exchange-existence" on-failure = "not-found"> + <doc> + A client MUST NOT be allowed to bind a queue to a non-existent exchange. + </doc> + <doc type = "scenario"> + A client attempts to bind an named queue to a undeclared exchange. + </doc> + </rule> + </field> + + <field name = "routing-key" domain = "shortstr" label = "message routing key"> + <doc> + Specifies the routing key for the binding. The routing key is used for routing + messages depending on the exchange configuration. Not all exchanges use a + routing key - refer to the specific exchange documentation. If the queue name + is empty, the server uses the last queue declared on the channel. If the + routing key is also empty, the server uses this queue name for the routing + key as well. If the queue name is provided but the routing key is empty, the + server does the binding with that empty routing key. The meaning of empty + routing keys depends on the exchange implementation. + </doc> + </field> + + <field name = "nowait" domain = "bit" label = "do not send a reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise a + channel or connection exception. + </doc> + </field> + + <field name = "arguments" domain = "table" label = "arguments for binding"> + <doc> + A set of arguments for the binding. The syntax and semantics of these arguments + depends on the exchange class. + </doc> + </field> + </method> + + <method name = "bind-ok" synchronous = "1" index = "21" label = "confirm bind successful"> + <doc>This method confirms that the bind was successful.</doc> + + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "purge" synchronous = "1" index = "30" label = "purge a queue"> + <doc> + This method removes all messages from a queue. It does not cancel consumers. Purged + messages are deleted without any formal "undo" mechanism. + </doc> + + <!-- Rule test name: was "amq_queue_15" --> + <rule name = "01"> + <doc>A call to purge MUST result in an empty queue.</doc> + </rule> + + <!-- Rule test name: was "amq_queue_41" --> + <rule name = "02"> + <doc> + On transacted channels the server MUST not purge messages that have already been + sent to a client but not yet acknowledged. + </doc> + </rule> + + <!-- TODO: Rule split? --> + + <!-- Rule test name: was "amq_queue_42" --> + <rule name = "03"> + <doc> + The server MAY implement a purge queue or log that allows system administrators + to recover accidentally-purged messages. The server SHOULD NOT keep purged + messages in the same storage spaces as the live messages since the volumes of + purged messages may get very large. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <response name = "purge-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <doc>The access ticket must be for the access realm that holds the queue.</doc> + + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "read" access rights to + the queue's access realm. Note that purging a queue is equivalent to reading + all messages and discarding them. + </doc> + </rule> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to purge. If the queue name is empty, refers to + the current queue for the channel, which is the last declared queue. + </doc> + + <rule name = "01"> + <doc> + If the client did not previously declare a queue, and the queue name in this + method is empty, the server MUST raise a connection exception with reply + code 530 (not allowed). + </doc> + </rule> + + <!-- TODO Rule split? --> + + <!-- Rule test name: was "amq_queue_16" --> + <rule name = "02"> + <doc> + The queue MUST exist. Attempting to purge a non-existing queue MUST cause a + channel exception. + </doc> + </rule> + </field> + + <field name = "nowait" domain = "bit" label = "do not send a reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise a + channel or connection exception. + </doc> + </field> + </method> + + <method name = "purge-ok" synchronous = "1" index = "31" label = "confirms a queue purge"> + <doc>This method confirms the purge of a queue.</doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "message-count" domain = "long" label = "number of messages purged"> + <doc>Reports the number of messages purged.</doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "delete" synchronous = "1" index = "40" label = "delete a queue"> + <doc> + This method deletes a queue. When a queue is deleted any pending messages are sent + to a dead-letter queue if this is defined in the server configuration, and all + consumers on the queue are cancelled. + </doc> + + <!-- TODO: Rule split? --> + + <!-- Rule test name: was "amq_queue_43" --> + <rule name = "01"> + <doc> + The server SHOULD use a dead-letter queue to hold messages that were pending on + a deleted queue, and MAY provide facilities for a system administrator to move + these messages back to an active queue. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <response name = "delete-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <doc> + The client provides a valid access ticket giving "active" access rights to the + queue's access realm. + </doc> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to delete. If the queue name is empty, refers to + the current queue for the channel, which is the last declared queue. + </doc> + + <rule name = "01"> + <doc> + If the client did not previously declare a queue, and the queue name in this + method is empty, the server MUST raise a connection exception with reply + code 530 (not allowed). + </doc> + </rule> + + <!-- Rule test name: was "amq_queue_21" --> + <rule name = "02"> + <doc> + The queue must exist. If the client attempts to delete a non-existing queue + the server MUST raise a channel exception with reply code 404 (not found). + </doc> + </rule> + </field> + + <field name = "if-unused" domain = "bit" label = "delete only if unused"> + <doc> + If set, the server will only delete the queue if it has no consumers. If the + queue has consumers the server does does not delete it but raises a channel + exception instead. + </doc> + + <!-- Rule test name: was "amq_queue_29" and "amq_queue_30" --> + <rule name = "01"> + <doc>The server MUST respect the if-unused flag when deleting a queue.</doc> + </rule> + </field> + + <field name = "if-empty" domain = "bit" label = "delete only if empty"> + <doc> + If set, the server will only delete the queue if it has no messages. + </doc> + <rule name = "01"> + <doc> + If the queue is not empty the server MUST raise a channel exception with + reply code 406 (precondition failed). + </doc> + </rule> + </field> + + <field name = "nowait" domain = "bit" label = "do not send a reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise a + channel or connection exception. + </doc> + </field> + </method> + + <method name = "delete-ok" synchronous = "1" index = "41" label = "confirm deletion of a queue"> + <doc>This method confirms the deletion of a queue.</doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "message-count" domain = "long" label = "number of messages purged"> + <doc>Reports the number of messages purged.</doc> + </field> + </method> + </class> + + <!-- == BASIC ============================================================ --> + + <class name = "basic" handler = "channel" index = "60" label = "work with basic content"> + <doc> + The Basic class provides methods that support an industry-standard messaging model. + </doc> + + <doc type = "grammar"> + basic = C:QOS S:QOS-OK + / C:CONSUME S:CONSUME-OK + / C:CANCEL S:CANCEL-OK + / C:PUBLISH content + / S:RETURN content + / S:DELIVER content + / C:GET ( S:GET-OK content / S:GET-EMPTY ) + / C:ACK + / C:REJECT + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MAY" /> + + <!-- Rule test name: was "amq_basic_08" --> + <rule name = "01"> + <doc> + The server SHOULD respect the persistent property of basic messages and + SHOULD make a best-effort to hold persistent basic messages on a reliable + storage mechanism. + </doc> + <doc type = "scenario"> + Send a persistent message to queue, stop server, restart server and then + verify whether message is still present. Assumes that queues are durable. + Persistence without durable queues makes no sense. + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_09" --> + <rule name = "02"> + <doc> + The server MUST NOT discard a persistent basic message in case of a queue + overflow. + </doc> + <doc type = "scenario"> + Create a queue overflow situation with persistent messages and verify that + messages do not get lost (presumably the server will write them to disk). + </doc> + </rule> + + <rule name = "03"> + <doc> + The server MAY use the Channel.Flow method to slow or stop a basic message + publisher when necessary. + </doc> + <doc type = "scenario"> + Create a queue overflow situation with non-persistent messages and verify + whether the server responds with Channel.Flow or not. Repeat with persistent + messages. + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_10" --> + <rule name = "04"> + <doc> + The server MAY overflow non-persistent basic messages to persistent + storage. + </doc> + <!-- Test scenario: untestable --> + </rule> + + <rule name = "05"> + <doc> + The server MAY discard or dead-letter non-persistent basic messages on a + priority basis if the queue size exceeds some configured limit. + </doc> + <!-- Test scenario: untestable --> + </rule> + + <!-- Rule test name: was "amq_basic_11" --> + <rule name = "06"> + <doc> + The server MUST implement at least 2 priority levels for basic messages, + where priorities 0-4 and 5-9 are treated as two distinct levels. + </doc> + <doc type = "scenario"> + Send a number of priority 0 messages to a queue. Send one priority 9 + message. Consume messages from the queue and verify that the first message + received was priority 9. + </doc> + </rule> + + <rule name = "07"> + <doc> + The server MAY implement up to 10 priority levels. + </doc> + <doc type = "scenario"> + Send a number of messages with mixed priorities to a queue, so that all + priority values from 0 to 9 are exercised. A good scenario would be ten + messages in low-to-high priority. Consume from queue and verify how many + priority levels emerge. + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_12" --> + <rule name = "08"> + <doc> + The server MUST deliver messages of the same priority in order irrespective of + their individual persistence. + </doc> + <doc type = "scenario"> + Send a set of messages with the same priority but different persistence + settings to a queue. Consume and verify that messages arrive in same order + as originally published. + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_13" --> + <rule name = "09"> + <doc> + The server MUST support automatic acknowledgements on Basic content, i.e. + consumers with the no-ack field set to FALSE. + </doc> + <doc type = "scenario"> + Create a queue and a consumer using automatic acknowledgements. Publish + a set of messages to the queue. Consume the messages and verify that all + messages are received. + </doc> + </rule> + + <rule name = "10"> + <doc> + The server MUST support explicit acknowledgements on Basic content, i.e. + consumers with the no-ack field set to TRUE. + </doc> + <doc type = "scenario"> + Create a queue and a consumer using explicit acknowledgements. Publish a + set of messages to the queue. Consume the messages but acknowledge only + half of them. Disconnect and reconnect, and consume from the queue. + Verify that the remaining messages are received. + </doc> + </rule> + + <!-- These are the properties for a Basic content --> + + <field name = "content-type" domain = "shortstr" label = "MIME content type" /> + <field name = "content-encoding" domain = "shortstr" label = "MIME content encoding" /> + <field name = "headers" domain = "table" label = "message header field table" /> + <field name = "delivery-mode" domain = "octet" label = "non-persistent (1) or persistent (2)" /> + <field name = "priority" domain = "octet" label = "message priority, 0 to 9" /> + <field name = "correlation-id" domain = "shortstr" label = "application correlation identifier" /> + <field name = "reply-to" domain = "shortstr" label = "destination to reply to" /> + <field name = "expiration" domain = "shortstr" label = "message expiration specification" /> + <field name = "message-id" domain = "shortstr" label = "application message identifier" /> + <field name = "timestamp" domain = "timestamp" label = "message timestamp" /> + <field name = "type" domain = "shortstr" label = "message type name" /> + <field name = "user-id" domain = "shortstr" label = "creating user id" /> + <field name = "app-id" domain = "shortstr" label = "creating application id" /> + <!-- This field is deprecated pending review --> + <field name = "cluster-id" domain = "shortstr" label = "intra-cluster routing identifier" /> + + <field name = "property-one" domain = "shortstr" label = "Extra property for testing only" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "qos" synchronous = "1" index = "10" label = "specify quality of service"> + <doc> + This method requests a specific quality of service. The QoS can be specified for the + current channel or for all channels on the connection. The particular properties and + semantics of a qos method always depend on the content class semantics. Though the + qos method could in principle apply to both peers, it is currently meaningful only + for the server. + </doc> + + <chassis name = "server" implement = "MUST" /> + <response name = "qos-ok" /> + + <field name = "prefetch-size" domain = "long" label = "prefetch window in octets"> + <doc> + The client can request that messages be sent in advance so that when the client + finishes processing a message, the following message is already held locally, + rather than needing to be sent down the channel. Prefetching gives a performance + improvement. This field specifies the prefetch window size in octets. The server + will send a message in advance if it is equal to or smaller in size than the + available prefetch size (and also falls into other prefetch limits). May be set + to zero, meaning "no specific limit", although other prefetch limits may still + apply. The prefetch-size is ignored if the no-ack option is set. + </doc> + <!-- Rule test name: was "amq_basic_17" --> + <rule name = "01"> + <doc> + The server MUST ignore this setting when the client is not processing any + messages - i.e. the prefetch size does not limit the transfer of single + messages to a client, only the sending in advance of more messages while + the client still has one or more unacknowledged messages. + </doc> + <doc type = "scenario"> + Define a QoS prefetch-size limit and send a single message that exceeds + that limit. Verify that the message arrives correctly. + </doc> + </rule> + </field> + + <field name = "prefetch-count" domain = "short" label = "prefetch window in messages"> + <doc> + Specifies a prefetch window in terms of whole messages. This field may be used + in combination with the prefetch-size field; a message will only be sent in + advance if both prefetch windows (and those at the channel and connection level) + allow it. The prefetch-count is ignored if the no-ack option is set. + </doc> + <!-- Rule test name: was "amq_basic_18" --> + <rule name = "01"> + <doc> + The server may send less data in advance than allowed by the client's + specified prefetch windows but it MUST NOT send more. + </doc> + <doc type = "scenario"> + Define a QoS prefetch-size limit and a prefetch-count limit greater than + one. Send multiple messages that exceed the prefetch size. Verify that + no more than one message arrives at once. + </doc> + </rule> + </field> + + <field name = "global" domain = "bit" label = "apply to entire connection"> + <doc> + By default the QoS settings apply to the current channel only. If this field is + set, they are applied to the entire connection. + </doc> + </field> + </method> + + <method name = "qos-ok" synchronous = "1" index = "11" label = "confirm the requested qos"> + <doc> + This method tells the client that the requested QoS levels could be handled by the + server. The requested QoS applies to all active consumers until a new QoS is + defined. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "consume" synchronous = "1" index = "30" label = "start a queue consumer"> + <doc> + This method asks the server to start a "consumer", which is a transient request for + messages from a specific queue. Consumers last as long as the channel they were + created on, or until the client cancels them. + </doc> + + <!-- Rule test name: was "amq_basic_01" --> + <rule name = "01"> + <doc> + The server SHOULD support at least 16 consumers per queue, and ideally, impose + no limit except as defined by available resources. + </doc> + <doc type = "scenario"> + Create a queue and create consumers on that queue until the server closes the + connection. Verify that the number of consumers created was at least sixteen + and report the total number. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + <response name = "consume-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01" on-failure = "access-refused"> + <doc> + The client MUST provide a valid access ticket giving "read" access rights to + the realm for the queue. + </doc> + <doc type = "scenario"> + Attempt to create a consumer with an invalid (non-zero) access ticket. + </doc> + </rule> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to consume from. If the queue name is null, + refers to the current queue for the channel, which is the last declared queue. + </doc> + <rule name = "01" on-failure = "not-allowed"> + <doc> + If the queue name is empty the client MUST have previously declared a + queue using this channel. + </doc> + <doc type = "scenario"> + Attempt to create a consumer with an empty queue name and no previously + declared queue on the channel. + </doc> + </rule> + </field> + + <field name = "consumer-tag" domain = "consumer-tag"> + <doc> + Specifies the identifier for the consumer. The consumer tag is local to a + connection, so two clients can use the same consumer tags. If this field is + empty the server will generate a unique tag. + </doc> + <rule name = "01" on-failure = "not-allowed"> + <doc> + The client MUST NOT specify a tag that refers to an existing consumer. + </doc> + <doc type = "scenario"> + Attempt to create two consumers with the same non-empty tag. + </doc> + </rule> + <rule name = "02" on-failure = "not-allowed"> + <doc> + The consumer tag is valid only within the channel from which the + consumer was created. I.e. a client MUST NOT create a consumer in one + channel and then use it in another. + </doc> + <doc type = "scenario"> + Attempt to create a consumer in one channel, then use in another channel, + in which consumers have also been created (to test that the server uses + unique consumer tags). + </doc> + </rule> + </field> + + <field name = "no-local" domain = "no-local" /> + + <field name = "no-ack" domain = "no-ack" /> + + <field name = "exclusive" domain = "bit" label = "request exclusive access"> + <doc> + Request exclusive consumer access, meaning only this consumer can access the + queue. + </doc> + <!-- Rule test name: was "amq_basic_02" --> + <rule name = "01" on-failure = "access-refused"> + <doc> + The client MAY NOT gain exclusive access to a queue that already has + active consumers. + </doc> + <doc type = "scenario"> + Open two connections to a server, and in one connection create a shared + (non-exclusive) queue and then consume from the queue. In the second + connection attempt to consume from the same queue using the exclusive + option. + </doc> + </rule> + </field> + + <field name = "nowait" domain = "bit" label = "do not send a reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise + a channel or connection exception. + </doc> + </field> + </method> + + <method name = "consume-ok" synchronous = "1" index = "31" label = "confirm a new consumer"> + <doc> + The server provides the client with a consumer tag, which is used by the client + for methods called on the consumer at a later stage. + </doc> + <chassis name = "client" implement = "MUST" /> + <field name = "consumer-tag" domain = "consumer-tag"> + <doc> + Holds the consumer tag specified by the client or provided by the server. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "cancel" synchronous = "1" index = "20" label = "end a queue consumer"> + <doc> + This method cancels a consumer. This does not affect already delivered + messages, but it does mean the server will not send any more messages for + that consumer. The client may receive an abitrary number of messages in + between sending the cancel method and receiving the cancel-ok reply. + </doc> + + <rule name = "01"> + <doc> + If the queue does not exist the server MUST ignore the cancel method, so + long as the consumer tag is valid for that channel. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + <response name = "cancel-ok" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + + <field name = "nowait" domain = "bit" label = "do not send a reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise a + channel or connection exception. + </doc> + </field> + </method> + + <method name = "cancel-ok" synchronous = "1" index = "21" label = "confirm a cancelled consumer"> + <doc> + This method confirms that the cancellation was completed. + </doc> + <chassis name = "client" implement = "MUST" /> + <field name = "consumer-tag" domain = "consumer-tag" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "publish" content = "1" index = "40" label = "publish a message"> + <doc> + This method publishes a message to a specific exchange. The message will be routed + to queues as defined by the exchange configuration and distributed to any active + consumers when the transaction, if any, is committed. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "write" access rights + to the access realm for the exchange. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange to publish to. The exchange name can be + empty, meaning the default exchange. If the exchange name is specified, and that + exchange does not exist, the server will raise a channel exception. + </doc> + + <!-- Rule test name: was "amq_basic_06" --> + <rule name = "01"> + <doc> + The server MUST accept a blank exchange name to mean the default exchange. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_14" --> + <rule name = "02"> + <doc> + If the exchange was declared as an internal exchange, the server MUST raise + a channel exception with a reply code 403 (access refused). + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_15" --> + <rule name = "03"> + <doc> + The exchange MAY refuse basic content in which case it MUST raise a channel + exception with reply code 540 (not implemented). + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc> + Specifies the routing key for the message. The routing key is used for routing + messages depending on the exchange configuration. + </doc> + </field> + + <field name = "mandatory" domain = "bit" label = "indicate mandatory routing"> + <doc> + This flag tells the server how to react if the message cannot be routed to a + queue. If this flag is set, the server will return an unroutable message with a + Return method. If this flag is zero, the server silently drops the message. + </doc> + <!-- Rule test name: was "amq_basic_07" --> + <rule name = "01"> + <doc> + The server SHOULD implement the mandatory flag. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "immediate" domain = "bit" label = "request immediate delivery"> + <doc> + This flag tells the server how to react if the message cannot be routed to a + queue consumer immediately. If this flag is set, the server will return an + undeliverable message with a Return method. If this flag is zero, the server + will queue the message, but with no guarantee that it will ever be consumed. + </doc> + <!-- Rule test name: was "amq_basic_16" --> + <rule name = "01"> + <doc> + The server SHOULD implement the immediate flag. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + <method name = "return" content = "1" index = "50" label = "return a failed message"> + <doc> + This method returns an undeliverable message that was published with the "immediate" + flag set, or an unroutable message published with the "mandatory" flag set. The + reply code and text provide information about the reason that the message was + undeliverable. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "reply-code" domain = "reply-code" /> + + <field name = "reply-text" domain = "reply-text" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + </doc> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc> + Specifies the routing key name specified when the message was published. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "deliver" content = "1" index = "60" + label = "notify the client of a consumer message"> + <doc> + This method delivers a message to the client, via a consumer. In the asynchronous + message delivery model, the client starts a consumer using the Consume method, then + the server responds with Deliver methods as and when messages arrive for that + consumer. + </doc> + + <!-- Rule test name: was "amq_basic_19" --> + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The server SHOULD track the number of times a message has been delivered to + clients and when a message is redelivered a certain number of times - e.g. 5 + times - without being acknowledged, the server SHOULD consider the message to be + unprocessable (possibly causing client applications to abort), and move the + message to a dead letter queue. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "redelivered" domain = "redelivered" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + </doc> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc>Specifies the routing key name specified when the message was published.</doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "get" synchronous = "1" index = "70" label = "direct access to a queue"> + <doc> + This method provides a direct access to the messages in a queue using a synchronous + dialogue that is designed for specific types of application where synchronous + functionality is more important than performance. + </doc> + + <response name = "get-ok" /> + <response name = "get-empty" /> + <chassis name = "server" implement = "MUST" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "read" access rights to + the realm for the queue. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to consume from. If the queue name is null, + refers to the current queue for the channel, which is the last declared queue. + </doc> + <rule name = "01"> + <doc> + If the client did not previously declare a queue, and the queue name in this + method is empty, the server MUST raise a connection exception with reply + code 530 (not allowed). + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + + <field name = "no-ack" domain = "no-ack" /> + </method> + + <method name = "get-ok" synchronous = "1" content = "1" index = "71" + label = "provide client with a message"> + <doc> + This method delivers a message to the client following a get method. A message + delivered by 'get-ok' must be acknowledged unless the no-ack option was set in the + get method. + </doc> + + <chassis name = "client" implement = "MAY" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "redelivered" domain = "redelivered" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + If empty, the message was published to the default exchange. + </doc> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc>Specifies the routing key name specified when the message was published.</doc> + </field> + + <field name = "message-count" domain = "long" label = "number of messages pending"> + <doc> + This field reports the number of messages pending on the queue, excluding the + message being delivered. Note that this figure is indicative, not reliable, and + can change arbitrarily as messages are added to the queue and removed by other + clients. + </doc> + </field> + </method> + + <method name = "get-empty" synchronous = "1" index = "72" + label = "indicate no messages available"> + <doc> + This method tells the client that the queue has no messages available for the + client. + </doc> + + <chassis name = "client" implement = "MAY" /> + + <!-- This field is deprecated pending review --> + <field name = "cluster-id" domain = "shortstr" label = "Cluster id"> + <doc> + For use by cluster applications, should not be used by client applications. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "ack" index = "80" label = "acknowledge one or more messages"> + <doc> + This method acknowledges one or more messages delivered via the Deliver or Get-Ok + methods. The client can ask to confirm a single message or a set of messages up to + and including a specific message. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "multiple" domain = "bit" label = "acknowledge multiple messages"> + <doc> + If set to 1, the delivery tag is treated as "up to and including", so that the + client can acknowledge multiple messages with a single method. If set to zero, + the delivery tag refers to a single message. If the multiple field is 1, and the + delivery tag is zero, tells the server to acknowledge all outstanding mesages. + </doc> + + <!-- Rule test name: was "amq_basic_20" --> + <rule name = "01"> + <doc> + The server MUST validate that a non-zero delivery-tag refers to an delivered + message, and raise a channel exception if this is not the case. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "reject" index = "90" label = "reject an incoming message"> + <doc> + This method allows a client to reject a message. It can be used to interrupt and + cancel large incoming messages, or return untreatable messages to their original + queue. + </doc> + + <!-- Rule test name: was "amq_basic_21" --> + <rule name = "01"> + <doc> + The server SHOULD be capable of accepting and process the Reject method while + sending message content with a Deliver or Get-Ok method. I.e. the server should + read and process incoming methods while sending output frames. To cancel a + partially-send content, the server sends a content body frame of size 1 (i.e. + with no data except the frame-end octet). + </doc> + </rule> + + <!-- Rule test name: was "amq_basic_22" --> + <rule name = "02"> + <doc> + The server SHOULD interpret this method as meaning that the client is unable to + process the message at this time. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <rule name = "03"> + <!-- TODO: Rule split? --> + <doc> + A client MUST NOT use this method as a means of selecting messages to process. A + rejected message MAY be discarded or dead-lettered, not necessarily passed to + another client. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "requeue" domain = "bit" label = "requeue the message"> + <doc> + If this field is zero, the message will be discarded. If this bit is 1, the + server will attempt to requeue the message. + </doc> + + <!-- Rule test name: was "amq_basic_23" --> + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The server MUST NOT deliver the message to the same client within the + context of the current channel. The recommended strategy is to attempt to + deliver the message to an alternative consumer, and if that is not possible, + to move the message to a dead-letter queue. The server MAY use more + sophisticated tracking to hold the message on the queue and redeliver it to + the same client at a later stage. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + </field> + </method> + + <method name = "recover" index = "100" label = "redeliver unacknowledged messages"> + <doc> + This method asks the broker to redeliver all unacknowledged messages on a specified + channel. Zero or more messages may be redelivered. This method is only allowed on + non-transacted channels. + </doc> + + <rule name = "01"> + <doc> + The server MUST set the redelivered flag on all messages that are resent. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <rule name = "02"> + <doc> + The server MUST raise a channel exception if this is called on a transacted + channel. + </doc> + <doc type = "scenario"> + TODO. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <field name = "requeue" domain = "bit" label = "requeue the message"> + <doc> + If this field is zero, the message will be redelivered to the original + recipient. If this bit is 1, the server will attempt to requeue the message, + potentially then delivering it to an alternative subscriber. + </doc> + </field> + </method> + </class> + + <!-- == FILE ============================================================= --> + + <class name = "file" handler = "channel" index = "70" label = "work with file content"> + <doc> + The file class provides methods that support reliable file transfer. File + messages have a specific set of properties that are required for interoperability + with file transfer applications. File messages and acknowledgements are subject to + channel transactions. Note that the file class does not provide message browsing + methods; these are not compatible with the staging model. Applications that need + browsable file transfer should use Basic content and the Basic class. + </doc> + + <doc type = "grammar"> + file = C:QOS S:QOS-OK + / C:CONSUME S:CONSUME-OK + / C:CANCEL S:CANCEL-OK + / C:OPEN S:OPEN-OK C:STAGE content + / S:OPEN C:OPEN-OK S:STAGE content + / C:PUBLISH + / S:DELIVER + / S:RETURN + / C:ACK + / C:REJECT + </doc> + + <chassis name = "server" implement = "MAY" /> + <chassis name = "client" implement = "MAY" /> + + <rule name = "01"> + <doc> + The server MUST make a best-effort to hold file messages on a reliable storage + mechanism. + </doc> + </rule> + + <!-- TODO Rule implement attr inverse? --> + + <!-- TODO: Rule split? --> + + <rule name = "02"> + <doc> + The server MUST NOT discard a file message in case of a queue overflow. The server + MUST use the Channel.Flow method to slow or stop a file message publisher when + necessary. + </doc> + </rule> + + <!-- TODO: Rule split? --> + + <rule name = "03"> + <doc> + The server MUST implement at least 2 priority levels for file messages, where + priorities 0-4 and 5-9 are treated as two distinct levels. The server MAY implement + up to 10 priority levels. + </doc> + </rule> + + <rule name = "04"> + <doc> + The server MUST support both automatic and explicit acknowledgements on file + content. + </doc> + </rule> + + <!-- These are the properties for a File content --> + + <field name = "content-type" domain = "shortstr" label = "MIME content type" /> + <field name = "content-encoding" domain = "shortstr" label = "MIME content encoding" /> + <field name = "headers" domain = "table" label = "message header field table" /> + <field name = "priority" domain = "octet" label = "message priority, 0 to 9" /> + <field name = "reply-to" domain = "shortstr" label = "destination to reply to" /> + <field name = "message-id" domain = "shortstr" label = "application message identifier" /> + <field name = "filename" domain = "shortstr" label = "message filename" /> + <field name = "timestamp" domain = "timestamp" label = "message timestamp" /> + <!-- This field is deprecated pending review --> + <field name = "cluster-id" domain = "shortstr" label = "intra-cluster routing identifier" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "qos" synchronous = "1" index = "10" label = "specify quality of service"> + <doc> + This method requests a specific quality of service. The QoS can be specified for the + current channel or for all channels on the connection. The particular properties and + semantics of a qos method always depend on the content class semantics. Though the + qos method could in principle apply to both peers, it is currently meaningful only + for the server. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <response name = "qos-ok" /> + + <field name = "prefetch-size" domain = "long" label = "prefetch window in octets"> + <doc> + The client can request that messages be sent in advance so that when the client + finishes processing a message, the following message is already held locally, + rather than needing to be sent down the channel. Prefetching gives a performance + improvement. This field specifies the prefetch window size in octets. May be set + to zero, meaning "no specific limit". Note that other prefetch limits may still + apply. The prefetch-size is ignored if the no-ack option is set. + </doc> + </field> + + <field name = "prefetch-count" domain = "short" label = "prefetch window in messages"> + <doc> + Specifies a prefetch window in terms of whole messages. This is compatible with + some file API implementations. This field may be used in combination with the + prefetch-size field; a message will only be sent in advance if both prefetch + windows (and those at the channel and connection level) allow it. The + prefetch-count is ignored if the no-ack option is set. + </doc> + + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The server MAY send less data in advance than allowed by the client's + specified prefetch windows but it MUST NOT send more. + </doc> + </rule> + </field> + + <field name = "global" domain = "bit" label = "apply to entire connection"> + <doc> + By default the QoS settings apply to the current channel only. If this field is + set, they are applied to the entire connection. + </doc> + </field> + </method> + + <method name = "qos-ok" synchronous = "1" index = "11" label = "confirm the requested qos"> + <doc> + This method tells the client that the requested QoS levels could be handled by the + server. The requested QoS applies to all active consumers until a new QoS is + defined. + </doc> + + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "consume" synchronous = "1" index = "20" label = "start a queue consumer"> + <doc> + This method asks the server to start a "consumer", which is a transient request for + messages from a specific queue. Consumers last as long as the channel they were + created on, or until the client cancels them. + </doc> + + <rule name = "01"> + <doc> + The server SHOULD support at least 16 consumers per queue, unless the queue was + declared as private, and ideally, impose no limit except as defined by available + resources. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <response name = "consume-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "read" access rights to + the realm for the queue. + </doc> + </rule> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to consume from. If the queue name is null, + refers to the current queue for the channel, which is the last declared queue. + </doc> + + <rule name = "01"> + <doc> + If the client did not previously declare a queue, and the queue name in this + method is empty, the server MUST raise a connection exception with reply + code 530 (not allowed). + </doc> + </rule> + </field> + + <field name = "consumer-tag" domain = "consumer-tag"> + <doc> + Specifies the identifier for the consumer. The consumer tag is local to a + connection, so two clients can use the same consumer tags. If this field is + empty the server will generate a unique tag. + </doc> + + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The tag MUST NOT refer to an existing consumer. If the client attempts to + create two consumers with the same non-empty tag the server MUST raise a + connection exception with reply code 530 (not allowed). + </doc> + </rule> + </field> + + <field name = "no-local" domain = "no-local" /> + + <field name = "no-ack" domain = "no-ack" /> + + <field name = "exclusive" domain = "bit" label = "request exclusive access"> + <doc> + Request exclusive consumer access, meaning only this consumer can access the + queue. + </doc> + + <!-- Rule test name: was "amq_file_00" --> + <rule name = "01"> + <doc> + If the server cannot grant exclusive access to the queue when asked, - + because there are other consumers active - it MUST raise a channel exception + with return code 405 (resource locked). + </doc> + </rule> + </field> + + <field name = "nowait" domain = "bit" label = "do not send a reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise a + channel or connection exception. + </doc> + </field> + </method> + + <method name = "consume-ok" synchronous = "1" index = "21" label = "confirm a new consumer"> + <doc> + This method provides the client with a consumer tag which it MUST use in methods + that work with the consumer. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag"> + <doc>Holds the consumer tag specified by the client or provided by the server.</doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "cancel" synchronous = "1" index = "30" label = "end a queue consumer"> + <doc> + This method cancels a consumer. This does not affect already delivered messages, but + it does mean the server will not send any more messages for that consumer. + </doc> + + <response name = "cancel-ok" /> + + <chassis name = "server" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + + <field name = "nowait" domain = "bit" label = "do not send a reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise a + channel or connection exception. + </doc> + </field> + </method> + + <method name = "cancel-ok" synchronous = "1" index = "31" label = "confirm a cancelled consumer"> + <doc>This method confirms that the cancellation was completed.</doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "open" synchronous = "1" index = "40" label = "request to start staging"> + <doc> + This method requests permission to start staging a message. Staging means sending + the message into a temporary area at the recipient end and then delivering the + message by referring to this temporary area. Staging is how the protocol handles + partial file transfers - if a message is partially staged and the connection breaks, + the next time the sender starts to stage it, it can restart from where it left off. + </doc> + + <response name = "open-ok" /> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <field name = "identifier" domain = "shortstr" label = "staging identifier"> + <doc> + This is the staging identifier. This is an arbitrary string chosen by the + sender. For staging to work correctly the sender must use the same staging + identifier when staging the same message a second time after recovery from a + failure. A good choice for the staging identifier would be the SHA1 hash of the + message properties data (including the original filename, revised time, etc.). + </doc> + </field> + + <field name = "content-size" domain = "longlong" label = "message content size"> + <doc> + The size of the content in octets. The recipient may use this information to + allocate or check available space in advance, to avoid "disk full" errors during + staging of very large messages. + </doc> + + <rule name = "01"> + <doc> + The sender MUST accurately fill the content-size field. Zero-length content + is permitted. + </doc> + </rule> + </field> + </method> + + <method name = "open-ok" synchronous = "1" index = "41" label = "confirm staging ready"> + <doc> + This method confirms that the recipient is ready to accept staged data. If the + message was already partially-staged at a previous time the recipient will report + the number of octets already staged. + </doc> + + <response name = "stage" /> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + + <field name = "staged-size" domain = "longlong" label = "already staged amount"> + <doc> + The amount of previously-staged content in octets. For a new message this will + be zero. + </doc> + + <rule name = "01"> + <doc> + The sender MUST start sending data from this octet offset in the message, + counting from zero. + </doc> + </rule> + + <rule name = "02"> + <!-- TODO: Rule split? --> + <doc> + The recipient MAY decide how long to hold partially-staged content and MAY + implement staging by always discarding partially-staged content. However if + it uses the file content type it MUST support the staging methods. + </doc> + </rule> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "stage" content = "1" index = "50" label = "stage message content"> + <doc> + This method stages the message, sending the message content to the recipient from + the octet offset specified in the Open-Ok method. + </doc> + + <chassis name = "server" implement = "MUST" /> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "publish" index = "60" label = "publish a message"> + <doc> + This method publishes a staged file message to a specific exchange. The file message + will be routed to queues as defined by the exchange configuration and distributed to + any active consumers when the transaction, if any, is committed. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "write" access rights + to the access realm for the exchange. + </doc> + </rule> + </field> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange to publish to. The exchange name can be + empty, meaning the default exchange. If the exchange name is specified, and that + exchange does not exist, the server will raise a channel exception. + </doc> + + <rule name = "01"> + <doc> + The server MUST accept a blank exchange name to mean the default exchange. + </doc> + </rule> + + <rule name = "02"> + <doc> + If the exchange was declared as an internal exchange, the server MUST + respond with a reply code 403 (access refused) and raise a channel + exception. + </doc> + </rule> + + <!-- TODO: Rule split? --> + + <rule name = "03"> + <doc> + The exchange MAY refuse file content in which case it MUST respond with a + reply code 540 (not implemented) and raise a channel exception. + </doc> + </rule> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc> + Specifies the routing key for the message. The routing key is used for routing + messages depending on the exchange configuration. + </doc> + </field> + + <field name = "mandatory" domain = "bit" label = "indicate mandatory routing"> + <doc> + This flag tells the server how to react if the message cannot be routed to a + queue. If this flag is set, the server will return an unroutable message with a + Return method. If this flag is zero, the server silently drops the message. + </doc> + + <!-- Rule test name: was "amq_file_00" --> + <rule name = "01"> + <doc>The server SHOULD implement the mandatory flag.</doc> + </rule> + </field> + + <field name = "immediate" domain = "bit" label = "request immediate delivery"> + <doc> + This flag tells the server how to react if the message cannot be routed to a + queue consumer immediately. If this flag is set, the server will return an + undeliverable message with a Return method. If this flag is zero, the server + will queue the message, but with no guarantee that it will ever be consumed. + </doc> + + <!-- Rule test name: was "amq_file_00" --> + <rule name = "01"> + <doc>The server SHOULD implement the immediate flag.</doc> + </rule> + </field> + + <field name = "identifier" domain = "shortstr" label = "staging identifier"> + <doc> + This is the staging identifier of the message to publish. The message must have + been staged. Note that a client can send the Publish method asynchronously + without waiting for staging to finish. + </doc> + </field> + </method> + + <method name = "return" content = "1" index = "70" label = "return a failed message"> + <doc> + This method returns an undeliverable message that was published with the "immediate" + flag set, or an unroutable message published with the "mandatory" flag set. The + reply code and text provide information about the reason that the message was + undeliverable. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "reply-code" domain = "reply-code" /> + + <field name = "reply-text" domain = "reply-text" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + </doc> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc>Specifies the routing key name specified when the message was published.</doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "deliver" index = "80" label = "notify the client of a consumer message"> + <doc> + This method delivers a staged file message to the client, via a consumer. In the + asynchronous message delivery model, the client starts a consumer using the Consume + method, then the server responds with Deliver methods as and when messages arrive + for that consumer. + </doc> + + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The server SHOULD track the number of times a message has been delivered to + clients and when a message is redelivered a certain number of times - e.g. 5 + times - without being acknowledged, the server SHOULD consider the message to be + unprocessable (possibly causing client applications to abort), and move the + message to a dead letter queue. + </doc> + </rule> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "redelivered" domain = "redelivered" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + </doc> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc>Specifies the routing key name specified when the message was published.</doc> + </field> + + <field name = "identifier" domain = "shortstr" label = "staging identifier"> + <doc> + This is the staging identifier of the message to deliver. The message must have + been staged. Note that a server can send the Deliver method asynchronously + without waiting for staging to finish. + </doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "ack" index = "90" label = "acknowledge one or more messages"> + <doc> + This method acknowledges one or more messages delivered via the Deliver method. The + client can ask to confirm a single message or a set of messages up to and including + a specific message. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "multiple" domain = "bit" label = "acknowledge multiple messages"> + <doc> + If set to 1, the delivery tag is treated as "up to and including", so that the + client can acknowledge multiple messages with a single method. If set to zero, + the delivery tag refers to a single message. If the multiple field is 1, and the + delivery tag is zero, tells the server to acknowledge all outstanding mesages. + </doc> + + <rule name = "01"> + <doc> + The server MUST validate that a non-zero delivery-tag refers to an delivered + message, and raise a channel exception if this is not the case. + </doc> + </rule> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "reject" index = "100" label = "reject an incoming message"> + <doc> + This method allows a client to reject a message. It can be used to return + untreatable messages to their original queue. Note that file content is staged + before delivery, so the client will not use this method to interrupt delivery of a + large message. + </doc> + + <rule name = "01"> + <doc> + The server SHOULD interpret this method as meaning that the client is unable to + process the message at this time. + </doc> + </rule> + + <!-- TODO: Rule split? --> + + <rule name = "02"> + <doc> + A client MUST NOT use this method as a means of selecting messages to process. A + rejected message MAY be discarded or dead-lettered, not necessarily passed to + another client. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "requeue" domain = "bit" label = "requeue the message"> + <doc> + If this field is zero, the message will be discarded. If this bit is 1, the + server will attempt to requeue the message. + </doc> + + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The server MUST NOT deliver the message to the same client within the + context of the current channel. The recommended strategy is to attempt to + deliver the message to an alternative consumer, and if that is not possible, + to move the message to a dead-letter queue. The server MAY use more + sophisticated tracking to hold the message on the queue and redeliver it to + the same client at a later stage. + </doc> + </rule> + </field> + </method> + </class> + + <!-- == STREAM =========================================================== --> + + <class name = "stream" handler = "channel" index = "80" label = "work with streaming content"> + <doc> + The stream class provides methods that support multimedia streaming. The stream class + uses the following semantics: one message is one packet of data; delivery is + unacknowleged and unreliable; the consumer can specify quality of service parameters + that the server can try to adhere to; lower-priority messages may be discarded in favour + of high priority messages. + </doc> + + <doc type = "grammar"> + stream = C:QOS S:QOS-OK + / C:CONSUME S:CONSUME-OK + / C:CANCEL S:CANCEL-OK + / C:PUBLISH content + / S:RETURN + / S:DELIVER content + </doc> + + <chassis name = "server" implement = "MAY" /> + <chassis name = "client" implement = "MAY" /> + + <rule name = "01"> + <doc> + The server SHOULD discard stream messages on a priority basis if the queue size + exceeds some configured limit. + </doc> + </rule> + + <rule name = "02"> + <!-- TODO: Rule split? --> + <doc> + The server MUST implement at least 2 priority levels for stream messages, where + priorities 0-4 and 5-9 are treated as two distinct levels. The server MAY implement + up to 10 priority levels. + </doc> + </rule> + + <rule name = "03"> + <doc> + The server MUST implement automatic acknowledgements on stream content. That is, as + soon as a message is delivered to a client via a Deliver method, the server must + remove it from the queue. + </doc> + </rule> + + <!-- These are the properties for a Stream content --> + + <field name = "content-type" domain = "shortstr" label = "MIME content type" /> + <field name = "content-encoding" domain = "shortstr" label = "MIME content encoding" /> + <field name = "headers" domain = "table" label = "message header field table" /> + <field name = "priority" domain = "octet" label = "message priority, 0 to 9" /> + <field name = "timestamp" domain = "timestamp" label = "message timestamp" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "qos" synchronous = "1" index = "10" label = "specify quality of service"> + <doc> + This method requests a specific quality of service. The QoS can be specified for the + current channel or for all channels on the connection. The particular properties and + semantics of a qos method always depend on the content class semantics. Though the + qos method could in principle apply to both peers, it is currently meaningful only + for the server. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <response name = "qos-ok" /> + + <field name = "prefetch-size" domain = "long" label = "prefetch window in octets"> + <doc> + The client can request that messages be sent in advance so that when the client + finishes processing a message, the following message is already held locally, + rather than needing to be sent down the channel. Prefetching gives a performance + improvement. This field specifies the prefetch window size in octets. May be set + to zero, meaning "no specific limit". Note that other prefetch limits may still + apply. + </doc> + </field> + + <field name = "prefetch-count" domain = "short" label = "prefetch window in messages"> + <doc> + Specifies a prefetch window in terms of whole messages. This field may be used + in combination with the prefetch-size field; a message will only be sent in + advance if both prefetch windows (and those at the channel and connection level) + allow it. + </doc> + </field> + + <field name = "consume-rate" domain = "long" label = "transfer rate in octets/second"> + <doc> + Specifies a desired transfer rate in octets per second. This is usually + determined by the application that uses the streaming data. A value of zero + means "no limit", i.e. as rapidly as possible. + </doc> + + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The server MAY ignore the prefetch values and consume rates, depending on + the type of stream and the ability of the server to queue and/or reply it. + The server MAY drop low-priority messages in favour of high-priority + messages. + </doc> + </rule> + </field> + + <field name = "global" domain = "bit" label = "apply to entire connection"> + <doc> + By default the QoS settings apply to the current channel only. If this field is + set, they are applied to the entire connection. + </doc> + </field> + </method> + + <method name = "qos-ok" synchronous = "1" index = "11" label = "confirm the requested qos"> + <doc> + This method tells the client that the requested QoS levels could be handled by the + server. The requested QoS applies to all active consumers until a new QoS is + defined. + </doc> + + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "consume" synchronous = "1" index = "20" label = "start a queue consumer"> + <doc> + This method asks the server to start a "consumer", which is a transient request for + messages from a specific queue. Consumers last as long as the channel they were + created on, or until the client cancels them. + </doc> + + <rule name = "01"> + <doc> + The server SHOULD support at least 16 consumers per queue, unless the queue was + declared as private, and ideally, impose no limit except as defined by available + resources. + </doc> + </rule> + + <rule name = "02"> + <doc> + Streaming applications SHOULD use different channels to select different + streaming resolutions. AMQP makes no provision for filtering and/or transforming + streams except on the basis of priority-based selective delivery of individual + messages. + </doc> + </rule> + + <chassis name = "server" implement = "MUST" /> + <response name = "consume-ok" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "read" access rights to + the realm for the queue. + </doc> + </rule> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue to consume from. If the queue name is null, + refers to the current queue for the channel, which is the last declared queue. + </doc> + + <rule name = "01"> + <doc> + If the client did not previously declare a queue, and the queue name in this + method is empty, the server MUST raise a connection exception with reply + code 530 (not allowed). + </doc> + </rule> + </field> + + <field name = "consumer-tag" domain = "consumer-tag"> + <doc> + Specifies the identifier for the consumer. The consumer tag is local to a + connection, so two clients can use the same consumer tags. If this field is + empty the server will generate a unique tag. + </doc> + + <rule name = "01"> + <!-- TODO: Rule split? --> + <doc> + The tag MUST NOT refer to an existing consumer. If the client attempts to + create two consumers with the same non-empty tag the server MUST raise a + connection exception with reply code 530 (not allowed). + </doc> + </rule> + </field> + + <field name = "no-local" domain = "no-local" /> + + <field name = "exclusive" domain = "bit" label = "request exclusive access"> + <doc> + Request exclusive consumer access, meaning only this consumer can access the + queue. + </doc> + + + <!-- Rule test name: was "amq_file_00" --> + <rule name = "01"> + <doc> + If the server cannot grant exclusive access to the queue when asked, - + because there are other consumers active - it MUST raise a channel exception + with return code 405 (resource locked). + </doc> + </rule> + </field> + + <field name = "nowait" domain = "bit" label = "do not send a reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise a + channel or connection exception. + </doc> + </field> + </method> + + <method name = "consume-ok" synchronous = "1" index = "21" label = "confirm a new consumer"> + <doc> + This method provides the client with a consumer tag which it may use in methods that + work with the consumer. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag"> + <doc>Holds the consumer tag specified by the client or provided by the server.</doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "cancel" synchronous = "1" index = "30" label = "end a queue consumer"> + <doc> + This method cancels a consumer. Since message delivery is asynchronous the client + may continue to receive messages for a short while after canceling a consumer. It + may process or discard these as appropriate. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <response name = "cancel-ok" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + + <field name = "nowait" domain = "bit" label = "do not send a reply method"> + <doc> + If set, the server will not respond to the method. The client should not wait + for a reply method. If the server could not complete the method it will raise a + channel or connection exception. + </doc> + </field> + </method> + + <method name = "cancel-ok" synchronous = "1" index = "31" label = "confirm a cancelled consumer"> + <doc>This method confirms that the cancellation was completed.</doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "publish" content = "1" index = "40" label = "publish a message"> + <doc> + This method publishes a message to a specific exchange. The message will be routed + to queues as defined by the exchange configuration and distributed to any active + consumers as appropriate. + </doc> + + <chassis name = "server" implement = "MUST" /> + + <field name = "ticket" domain = "access-ticket"> + <rule name = "01"> + <doc> + The client MUST provide a valid access ticket giving "write" access rights + to the access realm for the exchange. + </doc> + </rule> + </field> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange to publish to. The exchange name can be + empty, meaning the default exchange. If the exchange name is specified, and that + exchange does not exist, the server will raise a channel exception. + </doc> + + <rule name = "01"> + <doc> + The server MUST accept a blank exchange name to mean the default exchange. + </doc> + </rule> + + <rule name = "02"> + <doc> + If the exchange was declared as an internal exchange, the server MUST + respond with a reply code 403 (access refused) and raise a channel + exception. + </doc> + </rule> + + <rule name = "03"> + <doc> + The exchange MAY refuse stream content in which case it MUST respond with a + reply code 540 (not implemented) and raise a channel exception. + </doc> + </rule> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc> + Specifies the routing key for the message. The routing key is used for routing + messages depending on the exchange configuration. + </doc> + </field> + + <field name = "mandatory" domain = "bit" label = "indicate mandatory routing"> + <doc> + This flag tells the server how to react if the message cannot be routed to a + queue. If this flag is set, the server will return an unroutable message with a + Return method. If this flag is zero, the server silently drops the message. + </doc> + + <!-- Rule test name: was "amq_stream_00" --> + <rule name = "01"> + <doc>The server SHOULD implement the mandatory flag.</doc> + </rule> + </field> + + <field name = "immediate" domain = "bit" label = "request immediate delivery"> + <doc> + This flag tells the server how to react if the message cannot be routed to a + queue consumer immediately. If this flag is set, the server will return an + undeliverable message with a Return method. If this flag is zero, the server + will queue the message, but with no guarantee that it will ever be consumed. + </doc> + + <!-- Rule test name: was "amq_stream_00" --> + <rule name = "01"> + <doc>The server SHOULD implement the immediate flag.</doc> + </rule> + </field> + </method> + + <method name = "return" content = "1" index = "50" label = "return a failed message"> + <doc> + This method returns an undeliverable message that was published with the "immediate" + flag set, or an unroutable message published with the "mandatory" flag set. The + reply code and text provide information about the reason that the message was + undeliverable. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "reply-code" domain = "reply-code" /> + + <field name = "reply-text" domain = "reply-text" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + </doc> + </field> + + <field name = "routing-key" domain = "shortstr" label = "Message routing key"> + <doc>Specifies the routing key name specified when the message was published.</doc> + </field> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "deliver" content = "1" index = "60" + label = "notify the client of a consumer message"> + <doc> + This method delivers a message to the client, via a consumer. In the asynchronous + message delivery model, the client starts a consumer using the Consume method, then + the server responds with Deliver methods as and when messages arrive for that + consumer. + </doc> + + <chassis name = "client" implement = "MUST" /> + + <field name = "consumer-tag" domain = "consumer-tag" /> + + <field name = "delivery-tag" domain = "delivery-tag" /> + + <field name = "exchange" domain = "exchange-name"> + <doc> + Specifies the name of the exchange that the message was originally published to. + </doc> + </field> + + <field name = "queue" domain = "queue-name"> + <doc> + Specifies the name of the queue that the message came from. Note that a single + channel can start many consumers on different queues. + </doc> + <assert check = "notnull" /> + </field> + </method> + </class> + + <!-- == TX =============================================================== --> + + <class name = "tx" handler = "channel" index = "90" label = "work with standard transactions"> + <doc> + Standard transactions provide so-called "1.5 phase commit". We can ensure that work is + never lost, but there is a chance of confirmations being lost, so that messages may be + resent. Applications that use standard transactions must be able to detect and ignore + duplicate messages. + </doc> + + <!-- TODO: Rule split? --> + + <rule name = "01"> + <doc> + An client using standard transactions SHOULD be able to track all messages received + within a reasonable period, and thus detect and reject duplicates of the same + message. It SHOULD NOT pass these to the application layer. + </doc> + </rule> + + <doc type = "grammar"> + tx = C:SELECT S:SELECT-OK + / C:COMMIT S:COMMIT-OK + / C:ROLLBACK S:ROLLBACK-OK + </doc> + + <chassis name = "server" implement = "SHOULD" /> + <chassis name = "client" implement = "MAY" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "select" synchronous = "1" index = "10" label = "select standard transaction mode"> + <doc> + This method sets the channel to use standard transactions. The client must use this + method at least once on a channel before using the Commit or Rollback methods. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "select-ok" /> + </method> + + <method name = "select-ok" synchronous = "1" index = "11" label = "confirm transaction mode"> + <doc> + This method confirms to the client that the channel was successfully set to use + standard transactions. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "commit" synchronous = "1" index = "20" label = "commit the current transaction"> + <doc> + This method commits all messages published and acknowledged in the current + transaction. A new transaction starts immediately after a commit. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "commit-ok" /> + </method> + + <method name = "commit-ok" synchronous = "1" index = "21" label = "confirm a successful commit"> + <doc> + This method confirms to the client that the commit succeeded. Note that if a commit + fails, the server raises a channel exception. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "rollback" synchronous = "1" index = "30" + label = "abandon the current transaction"> + <doc> + This method abandons all messages published and acknowledged in the current + transaction. A new transaction starts immediately after a rollback. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "rollback-ok" /> + </method> + + <method name = "rollback-ok" synchronous = "1" index = "31" label = "confirm successful rollback"> + <doc> + This method confirms to the client that the rollback succeeded. Note that if an + rollback fails, the server raises a channel exception. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + </class> + + <!-- == DTX ============================================================== --> + + <class name = "dtx" handler = "channel" index = "100" label = "work with distributed transactions"> + <doc> + Distributed transactions provide so-called "2-phase commit". The AMQP distributed + transaction model supports the X-Open XA architecture and other distributed transaction + implementations. The Dtx class assumes that the server has a private communications + channel (not AMQP) to a distributed transaction coordinator. + </doc> + + <doc type = "grammar"> + dtx = C:SELECT S:SELECT-OK + C:START S:START-OK + </doc> + + <chassis name = "server" implement = "MAY" /> + <chassis name = "client" implement = "MAY" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "select" synchronous = "1" index = "10" label = "select standard transaction mode"> + <doc> + This method sets the channel to use distributed transactions. The client must use + this method at least once on a channel before using the Start method. + </doc> + <chassis name = "server" implement = "MUST" /> + <response name = "select-ok" /> + </method> + + <method name = "select-ok" synchronous = "1" index = "11" label = "confirm transaction mode"> + <doc> + This method confirms to the client that the channel was successfully set to use + distributed transactions. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "start" synchronous = "1" index = "20" + label = "start a new distributed transaction"> + <doc> + This method starts a new distributed transaction. This must be the first method on a + new channel that uses the distributed transaction mode, before any methods that + publish or consume messages. + </doc> + <chassis name = "server" implement = "MAY" /> + <response name = "start-ok" /> + <field name = "dtx-identifier" domain = "shortstr" label = "transaction identifier"> + <doc> + The distributed transaction key. This identifies the transaction so that the + AMQP server can coordinate with the distributed transaction coordinator. + </doc> + <assert check = "notnull" /> + </field> + </method> + + <method name = "start-ok" synchronous = "1" index = "21" + label = "confirm the start of a new distributed transaction"> + <doc> + This method confirms to the client that the transaction started. Note that if a + start fails, the server raises a channel exception. + </doc> + <chassis name = "client" implement = "MUST" /> + </method> + </class> + + <!-- == TUNNEL =========================================================== --> + + <class name = "tunnel" handler = "tunnel" index = "110" label = "methods for protocol tunneling"> + <doc> + The tunnel methods are used to send blocks of binary data - which can be serialised AMQP + methods or other protocol frames - between AMQP peers. + </doc> + + <doc type = "grammar"> + tunnel = C:REQUEST + / S:REQUEST + </doc> + + <chassis name = "server" implement = "MAY" /> + <chassis name = "client" implement = "MAY" /> + + <field name = "headers" domain = "table" label = "message header field table" /> + <field name = "proxy-name" domain = "shortstr" label = "identity of tunnelling proxy" /> + <field name = "data-name" domain = "shortstr" label = "name or type of message being tunnelled" /> + <field name = "durable" domain = "octet" label = "message durability indicator" /> + <field name = "broadcast" domain = "octet" label = "message broadcast mode" /> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name = "request" content = "1" index = "10" label = "sends a tunnelled method"> + <doc> + This method tunnels a block of binary data, which can be an encoded + AMQP method or other data. The binary data is sent as the content for + the Tunnel.Request method. + </doc> + <chassis name = "server" implement = "MUST" /> + <field name = "meta-data" domain = "table" label = "meta data for the tunnelled block"> + <doc> + This field table holds arbitrary meta-data that the sender needs to + pass to the recipient. + </doc> + </field> + </method> + </class> +</amqp> diff --git a/qpid/cpp-0-9/gentools/xml-src/cluster-0.9.test.xml b/qpid/cpp-0-9/gentools/xml-src/cluster-0.9.test.xml new file mode 100644 index 0000000000..142e6c9380 --- /dev/null +++ b/qpid/cpp-0-9/gentools/xml-src/cluster-0.9.test.xml @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<!-- + - + - Licensed to the Apache Software Foundation (ASF) under one + - or more contributor license agreements. See the NOTICE file + - distributed with this work for additional information + - regarding copyright ownership. The ASF licenses this file + - to you under the Apache License, Version 2.0 (the + - "License"); you may not use this file except in compliance + - with the License. You may obtain a copy of the License at + - + - http://www.apache.org/licenses/LICENSE-2.0 + - + - Unless required by applicable law or agreed to in writing, + - software distributed under the License is distributed on an + - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + - KIND, either express or implied. See the License for the + - specific language governing permissions and limitations + - under the License. + - + --> + +<amqp major="0" minor="9" port="5672" comment="AMQ protocol 0.80"> + +<class name = "cluster" index = "101"> + +<doc> + An extension that allows brokers to communicate in order to + provide a clustered service to clients. +</doc> + +<method name = "join" index="10"> + <field name = "broker" type = "shortstr" /> +</method> + +<method name = "membership" index="20"> + <field name = "members" type = "longstr" /> +</method> + +<method name = "synch" index="30"> +</method> + +<method name = "leave" index="40"> + <field name = "broker" type = "shortstr" /> +</method> + +<method name = "suspect" index="50"> + <field name = "broker" type = "shortstr" /> +</method> + +<method name = "ping" index="60"> + <field name = "broker" type = "shortstr" /> + <field name = "load" type = "long" /> + <field name = "response required" type = "bit" /> +</method> + +</class> + +</amqp> diff --git a/qpid/cpp-0-9/lib/Makefile.am b/qpid/cpp-0-9/lib/Makefile.am new file mode 100644 index 0000000000..09a689bc76 --- /dev/null +++ b/qpid/cpp-0-9/lib/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = common broker client diff --git a/qpid/cpp-0-9/lib/broker/AccumulatedAck.cpp b/qpid/cpp-0-9/lib/broker/AccumulatedAck.cpp new file mode 100644 index 0000000000..ff471b0287 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/AccumulatedAck.cpp @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "AccumulatedAck.h" + +#include <assert.h> + +using std::less_equal; +using std::bind2nd; +using namespace qpid::broker; + +void AccumulatedAck::update(uint64_t firstTag, uint64_t lastTag){ + assert(firstTag<=lastTag); + if (firstTag <= range + 1) { + if (lastTag > range) range = lastTag; + } else { + for (uint64_t tag = firstTag; tag<=lastTag; tag++) + individual.push_back(tag); + } +} + +void AccumulatedAck::consolidate(){ + individual.sort(); + //remove any individual tags that are covered by range + individual.remove_if(bind2nd(less_equal<uint64_t>(), range)); + //update range if possible (using <= allows for duplicates from overlapping ranges) + while (individual.front() <= range + 1) { + range = individual.front(); + individual.pop_front(); + } +} + +void AccumulatedAck::clear(){ + range = 0; + individual.clear(); +} + +bool AccumulatedAck::covers(uint64_t tag) const{ + return tag <= range || find(individual.begin(), individual.end(), tag) != individual.end(); +} diff --git a/qpid/cpp-0-9/lib/broker/AccumulatedAck.h b/qpid/cpp-0-9/lib/broker/AccumulatedAck.h new file mode 100644 index 0000000000..c4a6e3b79b --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/AccumulatedAck.h @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _AccumulatedAck_ +#define _AccumulatedAck_ + +#include <algorithm> +#include <functional> +#include <list> + +namespace qpid { + namespace broker { + /** + * Keeps an accumulated record of acked messages (by delivery + * tag). + */ + class AccumulatedAck { + public: + /** + * If not zero, then everything up to this value has been + * acked. + */ + uint64_t range; + /** + * List of individually acked messages that are not + * included in the range marked by 'range'. + */ + std::list<uint64_t> individual; + + AccumulatedAck(uint64_t r) : range(r) {} + void update(uint64_t firstTag, uint64_t lastTag); + void consolidate(); + void clear(); + bool covers(uint64_t tag) const; + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/AutoDelete.cpp b/qpid/cpp-0-9/lib/broker/AutoDelete.cpp new file mode 100644 index 0000000000..2037a9c71c --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/AutoDelete.cpp @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <AutoDelete.h> +#include <sys/Time.h> + +using namespace qpid::broker; +using namespace qpid::sys; + +AutoDelete::AutoDelete(QueueRegistry* const _registry, uint32_t _period) + : registry(_registry), period(_period), stopped(true) { } + +void AutoDelete::add(Queue::shared_ptr const queue){ + Mutex::ScopedLock l(lock); + queues.push(queue); +} + +Queue::shared_ptr const AutoDelete::pop(){ + Queue::shared_ptr next; + Mutex::ScopedLock l(lock); + if(!queues.empty()){ + next = queues.front(); + queues.pop(); + } + return next; +} + +void AutoDelete::process(){ + Queue::shared_ptr seen; + for(Queue::shared_ptr q = pop(); q; q = pop()){ + if(seen == q){ + add(q); + break; + }else if(q->canAutoDelete()){ + std::string name(q->getName()); + registry->destroy(name); + std::cout << "INFO: Auto-deleted queue named " << name << std::endl; + }else{ + add(q); + if(!seen) seen = q; + } + } +} + +void AutoDelete::run(){ + Monitor::ScopedLock l(monitor); + while(!stopped){ + process(); + monitor.wait(period*TIME_MSEC); + } +} + +void AutoDelete::start(){ + Monitor::ScopedLock l(monitor); + if(stopped){ + stopped = false; + runner = Thread(this); + } +} + +void AutoDelete::stop(){ + { + Monitor::ScopedLock l(monitor); + if(stopped) return; + stopped = true; + } + monitor.notify(); + runner.join(); +} diff --git a/qpid/cpp-0-9/lib/broker/AutoDelete.h b/qpid/cpp-0-9/lib/broker/AutoDelete.h new file mode 100644 index 0000000000..9034de1730 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/AutoDelete.h @@ -0,0 +1,55 @@ +#ifndef _AutoDelete_ +#define _AutoDelete_ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <queue> +#include <sys/Monitor.h> +#include <BrokerQueue.h> +#include <QueueRegistry.h> +#include <sys/Thread.h> + +namespace qpid { + namespace broker{ + class AutoDelete : private qpid::sys::Runnable { + qpid::sys::Mutex lock; + qpid::sys::Monitor monitor; + std::queue<Queue::shared_ptr> queues; + QueueRegistry* const registry; + uint32_t period; + volatile bool stopped; + qpid::sys::Thread runner; + + Queue::shared_ptr const pop(); + void process(); + virtual void run(); + + public: + AutoDelete(QueueRegistry* const registry, uint32_t period); + void add(Queue::shared_ptr const); + void start(); + void stop(); + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/Binding.h b/qpid/cpp-0-9/lib/broker/Binding.h new file mode 100644 index 0000000000..16ca223208 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Binding.h @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _Binding_ +#define _Binding_ + +#include <FieldTable.h> + +namespace qpid { + namespace broker { + class Binding{ + public: + virtual void cancel() = 0; + virtual ~Binding(){} + }; + } +} + + +#endif + diff --git a/qpid/cpp-0-9/lib/broker/Broker.cpp b/qpid/cpp-0-9/lib/broker/Broker.cpp new file mode 100644 index 0000000000..f650452e33 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Broker.cpp @@ -0,0 +1,118 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <memory> + +#include "AMQFrame.h" +#include "DirectExchange.h" +#include "TopicExchange.h" +#include "FanOutExchange.h" +#include "HeadersExchange.h" +#include "MessageStoreModule.h" +#include "NullMessageStore.h" +#include "ProtocolInitiation.h" +#include "Connection.h" +#include "sys/ConnectionInputHandler.h" +#include "sys/ConnectionInputHandlerFactory.h" +#include "sys/TimeoutHandler.h" + +#include "Broker.h" + +namespace qpid { +namespace broker { + +const std::string empty; +const std::string amq_direct("amq.direct"); +const std::string amq_topic("amq.topic"); +const std::string amq_fanout("amq.fanout"); +const std::string amq_match("amq.match"); + +Broker::Broker(const Configuration& conf) : + config(conf), + queues(store.get()), + timeout(30000), + stagingThreshold(0), + cleaner(&queues, timeout/10), + factory(*this) +{ + if (config.getStore().empty()) + store.reset(new NullMessageStore(config.isTrace())); + else + store.reset(new MessageStoreModule(config.getStore())); + + exchanges.declare(empty, DirectExchange::typeName); // Default exchange. + exchanges.declare(amq_direct, DirectExchange::typeName); + exchanges.declare(amq_topic, TopicExchange::typeName); + exchanges.declare(amq_fanout, FanOutExchange::typeName); + exchanges.declare(amq_match, HeadersExchange::typeName); + + if(store.get()) { + RecoveryManager recoverer(queues, exchanges); + MessageStoreSettings storeSettings = { getStagingThreshold() }; + store->recover(recoverer, &storeSettings); + } + + cleaner.start(); +} + + +Broker::shared_ptr Broker::create(int16_t port) +{ + Configuration config; + config.setPort(port); + return create(config); +} + +Broker::shared_ptr Broker::create(const Configuration& config) { + return Broker::shared_ptr(new Broker(config)); +} + +void Broker::run() { + getAcceptor().run(&factory); +} + +void Broker::shutdown() { + if (acceptor) + acceptor->shutdown(); +} + +Broker::~Broker() { + shutdown(); +} + +int16_t Broker::getPort() const { return getAcceptor().getPort(); } + +Acceptor& Broker::getAcceptor() const { + if (!acceptor) + const_cast<Acceptor::shared_ptr&>(acceptor) = + Acceptor::create(config.getPort(), + config.getConnectionBacklog(), + config.getWorkerThreads(), + config.isTrace()); + return *acceptor; +} + + +const int16_t Broker::DEFAULT_PORT(5672); + + +}} // namespace qpid::broker + diff --git a/qpid/cpp-0-9/lib/broker/Broker.h b/qpid/cpp-0-9/lib/broker/Broker.h new file mode 100644 index 0000000000..7c21e90b18 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Broker.h @@ -0,0 +1,106 @@ +#ifndef _Broker_ +#define _Broker_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <Configuration.h> +#include <ConnectionFactory.h> +#include <sys/Runnable.h> +#include <sys/Acceptor.h> +#include <SharedObject.h> +#include <MessageStore.h> +#include <AutoDelete.h> +#include <ExchangeRegistry.h> +#include <ConnectionToken.h> +#include <DirectExchange.h> +#include <OutputHandler.h> +#include <ProtocolInitiation.h> +#include <QueueRegistry.h> + +namespace qpid { +namespace broker { +/** + * A broker instance. + */ +class Broker : public sys::Runnable, + public SharedObject<Broker> +{ + public: + static const int16_t DEFAULT_PORT; + + virtual ~Broker(); + + /** + * Create a broker. + * @param port Port to listen on or 0 to pick a port dynamically. + */ + static shared_ptr create(int16_t port = DEFAULT_PORT); + + /** + * Create a broker using a Configuration. + */ + static shared_ptr create(const Configuration& config); + + /** + * Return listening port. If called before bind this is + * the configured port. If called after it is the actual + * port, which will be different if the configured port is + * 0. + */ + virtual int16_t getPort() const; + + /** + * Run the broker. Implements Runnable::run() so the broker + * can be run in a separate thread. + */ + virtual void run(); + + /** Shut down the broker */ + virtual void shutdown(); + + MessageStore& getStore() { return *store; } + QueueRegistry& getQueues() { return queues; } + ExchangeRegistry& getExchanges() { return exchanges; } + uint32_t getTimeout() { return timeout; } + uint64_t getStagingThreshold() { return stagingThreshold; } + AutoDelete& getCleaner() { return cleaner; } + + private: + Broker(const Configuration& config); + sys::Acceptor& getAcceptor() const; + + Configuration config; + sys::Acceptor::shared_ptr acceptor; + std::auto_ptr<MessageStore> store; + QueueRegistry queues; + ExchangeRegistry exchanges; + uint32_t timeout; + uint64_t stagingThreshold; + AutoDelete cleaner; + ConnectionFactory factory; +}; + +}} + + + +#endif /*!_Broker_*/ diff --git a/qpid/cpp-0-9/lib/broker/BrokerAdapter.cpp b/qpid/cpp-0-9/lib/broker/BrokerAdapter.cpp new file mode 100644 index 0000000000..981801c40e --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerAdapter.cpp @@ -0,0 +1,388 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include <boost/format.hpp> + +#include "BrokerAdapter.h" +#include "BrokerChannel.h" +#include "Connection.h" +#include "AMQMethodBody.h" +#include "Exception.h" + +namespace qpid { +namespace broker { + +using boost::format; +using namespace qpid; +using namespace qpid::framing; + +typedef std::vector<Queue::shared_ptr> QueueVector; + + +BrokerAdapter::BrokerAdapter(Channel& ch, Connection& c, Broker& b) : + CoreRefs(ch, c, b), + connection(c), + basicHandler(*this), + channelHandler(*this), + connectionHandler(*this), + exchangeHandler(*this), + messageHandler(*this), + queueHandler(*this), + txHandler(*this) +{} + + +ProtocolVersion BrokerAdapter::getVersion() const { + return connection.getVersion(); +} + +void BrokerAdapter::ConnectionHandlerImpl::startOk( + const MethodContext&, const FieldTable& /*clientProperties*/, + const string& /*mechanism*/, + const string& /*response*/, const string& /*locale*/) +{ + client.tune( + 100, connection.getFrameMax(), connection.getHeartbeat()); +} + +void BrokerAdapter::ConnectionHandlerImpl::secureOk( + const MethodContext&, const string& /*response*/){} + +void BrokerAdapter::ConnectionHandlerImpl::tuneOk( + const MethodContext&, uint16_t /*channelmax*/, + uint32_t framemax, uint16_t heartbeat) +{ + connection.setFrameMax(framemax); + connection.setHeartbeat(heartbeat); +} + +void BrokerAdapter::ConnectionHandlerImpl::open( + const MethodContext& context, const string& /*virtualHost*/, + const string& /*capabilities*/, bool /*insist*/) +{ + string knownhosts; + client.openOk( + knownhosts, context.getRequestId()); +} + +void BrokerAdapter::ConnectionHandlerImpl::close( + const MethodContext& context, uint16_t /*replyCode*/, const string& /*replyText*/, + uint16_t /*classId*/, uint16_t /*methodId*/) +{ + client.closeOk(context.getRequestId()); + connection.getOutput().close(); +} + +void BrokerAdapter::ConnectionHandlerImpl::closeOk(const MethodContext&){ + connection.getOutput().close(); +} + +void BrokerAdapter::ChannelHandlerImpl::open( + const MethodContext& context, const string& /*outOfBand*/){ + channel.open(); + // FIXME aconway 2007-01-04: provide valid ID as per ampq 0-9 + client.openOk( + std::string()/* ID */, context.getRequestId()); +} + +void BrokerAdapter::ChannelHandlerImpl::flow(const MethodContext&, bool /*active*/){} +void BrokerAdapter::ChannelHandlerImpl::flowOk(const MethodContext&, bool /*active*/){} + +void BrokerAdapter::ChannelHandlerImpl::close( + const MethodContext& context, uint16_t /*replyCode*/, + const string& /*replyText*/, + uint16_t /*classId*/, uint16_t /*methodId*/) +{ + client.closeOk(context.getRequestId()); + // FIXME aconway 2007-01-18: Following line will "delete this". Ugly. + connection.closeChannel(channel.getId()); +} + +void BrokerAdapter::ChannelHandlerImpl::closeOk(const MethodContext&){} + + + +void BrokerAdapter::ExchangeHandlerImpl::declare(const MethodContext& context, uint16_t /*ticket*/, const string& exchange, const string& type, + bool passive, bool /*durable*/, bool /*autoDelete*/, bool /*internal*/, bool nowait, + const FieldTable& /*arguments*/){ + + if(passive){ + if(!broker.getExchanges().get(exchange)) { + throw ChannelException(404, "Exchange not found: " + exchange); + } + }else{ + try{ + std::pair<Exchange::shared_ptr, bool> response = broker.getExchanges().declare(exchange, type); + if(!response.second && response.first->getType() != type){ + throw ConnectionException( + 530, + "Exchange already declared to be of type " + + response.first->getType() + ", requested " + type); + } + }catch(UnknownExchangeTypeException& e){ + throw ConnectionException( + 503, "Exchange type not implemented: " + type); + } + } + if(!nowait){ + client.declareOk(context.getRequestId()); + } +} + +void BrokerAdapter::ExchangeHandlerImpl::delete_(const MethodContext& context, uint16_t /*ticket*/, + const string& exchange, bool /*ifUnused*/, bool nowait){ + + //TODO: implement unused + broker.getExchanges().destroy(exchange); + if(!nowait) client.deleteOk(context.getRequestId()); +} + +void BrokerAdapter::QueueHandlerImpl::declare(const MethodContext& context, uint16_t /*ticket*/, const string& name, + bool passive, bool durable, bool exclusive, + bool autoDelete, bool nowait, const qpid::framing::FieldTable& arguments){ + Queue::shared_ptr queue; + if (passive && !name.empty()) { + queue = connection.getQueue(name, channel.getId()); + } else { + std::pair<Queue::shared_ptr, bool> queue_created = + broker.getQueues().declare( + name, durable, + autoDelete ? connection.getTimeout() : 0, + exclusive ? &connection : 0); + queue = queue_created.first; + assert(queue); + if (queue_created.second) { // This is a new queue + channel.setDefaultQueue(queue); + + //apply settings & create persistent record if required + queue_created.first->create(arguments); + + //add default binding: + broker.getExchanges().getDefault()->bind(queue, name, 0); + if (exclusive) { + connection.exclusiveQueues.push_back(queue); + } else if(autoDelete){ + broker.getCleaner().add(queue); + } + } + } + if (exclusive && !queue->isExclusiveOwner(&connection)) + throw ChannelException( + 405, + format("Cannot grant exclusive access to queue '%s'") + % queue->getName()); + if (!nowait) { + string queueName = queue->getName(); + client.declareOk( + queueName, queue->getMessageCount(), queue->getConsumerCount(), + context.getRequestId()); + } +} + +void BrokerAdapter::QueueHandlerImpl::bind(const MethodContext& context, uint16_t /*ticket*/, const string& queueName, + const string& exchangeName, const string& routingKey, bool nowait, + const FieldTable& arguments){ + + Queue::shared_ptr queue = connection.getQueue(queueName, channel.getId()); + Exchange::shared_ptr exchange = broker.getExchanges().get(exchangeName); + if(exchange){ + string exchangeRoutingKey = routingKey.empty() && queueName.empty() ? queue->getName() : routingKey; + exchange->bind(queue, exchangeRoutingKey, &arguments); + if(!nowait) client.bindOk(context.getRequestId()); + }else{ + throw ChannelException( + 404, "Bind failed. No such exchange: " + exchangeName); + } +} + +void +BrokerAdapter::QueueHandlerImpl::unbind( + const MethodContext& context, + uint16_t /*ticket*/, + const string& queueName, + const string& exchangeName, + const string& routingKey, + const qpid::framing::FieldTable& arguments ) +{ + Queue::shared_ptr queue = connection.getQueue(queueName, channel.getId()); + if (!queue.get()) throw ChannelException(404, "Unbind failed. No such exchange: " + exchangeName); + + Exchange::shared_ptr exchange = broker.getExchanges().get(exchangeName); + if (!exchange.get()) throw ChannelException(404, "Unbind failed. No such exchange: " + exchangeName); + + exchange->unbind(queue, routingKey, &arguments); + + client.unbindOk(context.getRequestId()); +} + +void BrokerAdapter::QueueHandlerImpl::purge(const MethodContext& context, uint16_t /*ticket*/, const string& queueName, bool nowait){ + + Queue::shared_ptr queue = connection.getQueue(queueName, channel.getId()); + int count = queue->purge(); + if(!nowait) client.purgeOk( count, context.getRequestId()); +} + +void BrokerAdapter::QueueHandlerImpl::delete_(const MethodContext& context, uint16_t /*ticket*/, const string& queue, + bool ifUnused, bool ifEmpty, bool nowait){ + ChannelException error(0, ""); + int count(0); + Queue::shared_ptr q = connection.getQueue(queue, channel.getId()); + if(ifEmpty && q->getMessageCount() > 0){ + throw ChannelException(406, "Queue not empty."); + }else if(ifUnused && q->getConsumerCount() > 0){ + throw ChannelException(406, "Queue in use."); + }else{ + //remove the queue from the list of exclusive queues if necessary + if(q->isExclusiveOwner(&connection)){ + QueueVector::iterator i = find(connection.exclusiveQueues.begin(), connection.exclusiveQueues.end(), q); + if(i < connection.exclusiveQueues.end()) connection.exclusiveQueues.erase(i); + } + count = q->getMessageCount(); + q->destroy(); + broker.getQueues().destroy(queue); + } + + if(!nowait) + client.deleteOk(count, context.getRequestId()); +} + + + + +void BrokerAdapter::BasicHandlerImpl::qos(const MethodContext& context, uint32_t prefetchSize, uint16_t prefetchCount, bool /*global*/){ + //TODO: handle global + channel.setPrefetchSize(prefetchSize); + channel.setPrefetchCount(prefetchCount); + client.qosOk(context.getRequestId()); +} + +void BrokerAdapter::BasicHandlerImpl::consume( + const MethodContext& context, uint16_t /*ticket*/, + const string& queueName, const string& consumerTag, + bool noLocal, bool noAck, bool exclusive, + bool nowait, const FieldTable& fields) +{ + + Queue::shared_ptr queue = connection.getQueue(queueName, channel.getId()); + if(!consumerTag.empty() && channel.exists(consumerTag)){ + throw ConnectionException(530, "Consumer tags must be unique"); + } + + string newTag = consumerTag; + channel.consume( + newTag, queue, !noAck, exclusive, noLocal ? &connection : 0, &fields); + + if(!nowait) client.consumeOk(newTag, context.getRequestId()); + + //allow messages to be dispatched if required as there is now a consumer: + queue->dispatch(); +} + +void BrokerAdapter::BasicHandlerImpl::cancel(const MethodContext& context, const string& consumerTag, bool nowait){ + channel.cancel(consumerTag); + + if(!nowait) client.cancelOk(consumerTag, context.getRequestId()); +} + +void BrokerAdapter::BasicHandlerImpl::publish( + const MethodContext& context, uint16_t /*ticket*/, + const string& exchangeName, const string& routingKey, + bool mandatory, bool immediate) +{ + + Exchange::shared_ptr exchange = exchangeName.empty() ? broker.getExchanges().getDefault() : broker.getExchanges().get(exchangeName); + if(exchange){ + BasicMessage* msg = new BasicMessage( + &connection, exchangeName, routingKey, mandatory, immediate, + context.methodBody); + channel.handlePublish(msg); + }else{ + throw ChannelException( + 404, "Exchange not found '" + exchangeName + "'"); + } +} + +void BrokerAdapter::BasicHandlerImpl::get(const MethodContext& context, uint16_t /*ticket*/, const string& queueName, bool noAck){ + Queue::shared_ptr queue = connection.getQueue(queueName, channel.getId()); + if(!connection.getChannel(channel.getId()).get(queue, "", !noAck)){ + string clusterId;//not used, part of an imatix hack + + client.getEmpty(clusterId, context.getRequestId()); + } +} + +void BrokerAdapter::BasicHandlerImpl::ack(const MethodContext&, uint64_t deliveryTag, bool multiple){ + channel.ack(deliveryTag, multiple); +} + +void BrokerAdapter::BasicHandlerImpl::reject(const MethodContext&, uint64_t /*deliveryTag*/, bool /*requeue*/){} + +void BrokerAdapter::BasicHandlerImpl::recover(const MethodContext&, bool requeue){ + channel.recover(requeue); +} + +void BrokerAdapter::TxHandlerImpl::select(const MethodContext& context){ + channel.begin(); + client.selectOk(context.getRequestId()); +} + +void BrokerAdapter::TxHandlerImpl::commit(const MethodContext& context){ + channel.commit(); + client.commitOk(context.getRequestId()); +} + +void BrokerAdapter::TxHandlerImpl::rollback(const MethodContext& context){ + + channel.rollback(); + client.rollbackOk(context.getRequestId()); + channel.recover(false); +} + +void +BrokerAdapter::ChannelHandlerImpl::ok( const MethodContext& ) +{ + //no specific action required, generic response handling should be sufficient +} + + +// +// Message class method handlers +// +void +BrokerAdapter::ChannelHandlerImpl::ping( const MethodContext& context) +{ + client.ok(context.getRequestId()); + client.pong(); +} + + +void +BrokerAdapter::ChannelHandlerImpl::pong( const MethodContext& context) +{ + client.ok(context.getRequestId()); +} + +void +BrokerAdapter::ChannelHandlerImpl::resume( + const MethodContext&, + const string& /*channel*/ ) +{ + assert(0); // FIXME aconway 2007-01-04: 0-9 feature +} + +}} // namespace qpid::broker + diff --git a/qpid/cpp-0-9/lib/broker/BrokerAdapter.h b/qpid/cpp-0-9/lib/broker/BrokerAdapter.h new file mode 100644 index 0000000000..2fafbcc180 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerAdapter.h @@ -0,0 +1,222 @@ +#ifndef _broker_BrokerAdapter_h +#define _broker_BrokerAdapter_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "AMQP_ServerOperations.h" +#include "HandlerImpl.h" +#include "MessageHandlerImpl.h" +#include "Exception.h" + +namespace qpid { +namespace broker { + +class Channel; +class Connection; +class Broker; +class ChannelHandler; +class ConnectionHandler; +class BasicHandler; +class ExchangeHandler; +class QueueHandler; +class TxHandler; +class MessageHandler; +class AccessHandler; +class FileHandler; +class StreamHandler; +class DtxHandler; +class TunnelHandler; +class MessageHandlerImpl; + +/** + * Per-channel protocol adapter. + * + * A container for a collection of AMQP-class adapters that translate + * AMQP method bodies into calls on the core Channel, Connection and + * Broker objects. Each adapter class also provides a client proxy + * to send methods to the peer. + * + */ +class BrokerAdapter : public CoreRefs, public framing::AMQP_ServerOperations +{ + public: + BrokerAdapter(Channel& ch, Connection& c, Broker& b); + + framing::ProtocolVersion getVersion() const; + ChannelHandler* getChannelHandler() { return &channelHandler; } + ConnectionHandler* getConnectionHandler() { return &connectionHandler; } + BasicHandler* getBasicHandler() { return &basicHandler; } + ExchangeHandler* getExchangeHandler() { return &exchangeHandler; } + QueueHandler* getQueueHandler() { return &queueHandler; } + TxHandler* getTxHandler() { return &txHandler; } + MessageHandler* getMessageHandler() { return &messageHandler; } + AccessHandler* getAccessHandler() { + throw ConnectionException(540, "Access class not implemented"); } + FileHandler* getFileHandler() { + throw ConnectionException(540, "File class not implemented"); } + StreamHandler* getStreamHandler() { + throw ConnectionException(540, "Stream class not implemented"); } + DtxHandler* getDtxHandler() { + throw ConnectionException(540, "Dtx class not implemented"); } + TunnelHandler* getTunnelHandler() { + throw ConnectionException(540, "Tunnel class not implemented"); } + + framing::AMQP_ClientProxy& getProxy() { return proxy; } + + private: + + class ConnectionHandlerImpl : + public ConnectionHandler, + public HandlerImpl<framing::AMQP_ClientProxy::Connection> + { + public: + ConnectionHandlerImpl(BrokerAdapter& parent) : HandlerImplType(parent) {} + + void startOk(const framing::MethodContext& context, + const qpid::framing::FieldTable& clientProperties, + const std::string& mechanism, const std::string& response, + const std::string& locale); + void secureOk(const framing::MethodContext& context, + const std::string& response); + void tuneOk(const framing::MethodContext& context, + uint16_t channelMax, + uint32_t frameMax, uint16_t heartbeat); + void open(const framing::MethodContext& context, + const std::string& virtualHost, + const std::string& capabilities, bool insist); + void close(const framing::MethodContext& context, uint16_t replyCode, + const std::string& replyText, + uint16_t classId, uint16_t methodId); + void closeOk(const framing::MethodContext& context); + }; + + class ChannelHandlerImpl : + public ChannelHandler, + public HandlerImpl<framing::AMQP_ClientProxy::Channel> + { + public: + ChannelHandlerImpl(BrokerAdapter& parent) : HandlerImplType(parent) {} + + void open(const framing::MethodContext& context, const std::string& outOfBand); + void flow(const framing::MethodContext& context, bool active); + void flowOk(const framing::MethodContext& context, bool active); + void ok( const framing::MethodContext& context ); + void ping( const framing::MethodContext& context ); + void pong( const framing::MethodContext& context ); + void resume( const framing::MethodContext& context, const std::string& channelId ); + void close(const framing::MethodContext& context, uint16_t replyCode, const + std::string& replyText, uint16_t classId, uint16_t methodId); + void closeOk(const framing::MethodContext& context); + }; + + class ExchangeHandlerImpl : + public ExchangeHandler, + public HandlerImpl<framing::AMQP_ClientProxy::Exchange> + { + public: + ExchangeHandlerImpl(BrokerAdapter& parent) : HandlerImplType(parent) {} + + void declare(const framing::MethodContext& context, uint16_t ticket, + const std::string& exchange, const std::string& type, + bool passive, bool durable, bool autoDelete, + bool internal, bool nowait, + const qpid::framing::FieldTable& arguments); + void delete_(const framing::MethodContext& context, uint16_t ticket, + const std::string& exchange, bool ifUnused, bool nowait); + }; + + class QueueHandlerImpl : + public QueueHandler, + public HandlerImpl<framing::AMQP_ClientProxy::Queue> + { + public: + QueueHandlerImpl(BrokerAdapter& parent) : HandlerImplType(parent) {} + + void declare(const framing::MethodContext& context, uint16_t ticket, const std::string& queue, + bool passive, bool durable, bool exclusive, + bool autoDelete, bool nowait, + const qpid::framing::FieldTable& arguments); + void bind(const framing::MethodContext& context, uint16_t ticket, const std::string& queue, + const std::string& exchange, const std::string& routingKey, + bool nowait, const qpid::framing::FieldTable& arguments); + void unbind(const framing::MethodContext& context, + uint16_t ticket, + const std::string& queue, + const std::string& exchange, + const std::string& routingKey, + const qpid::framing::FieldTable& arguments ); + void purge(const framing::MethodContext& context, uint16_t ticket, const std::string& queue, + bool nowait); + void delete_(const framing::MethodContext& context, uint16_t ticket, const std::string& queue, + bool ifUnused, bool ifEmpty, + bool nowait); + }; + + class BasicHandlerImpl : + public BasicHandler, + public HandlerImpl<framing::AMQP_ClientProxy::Basic> + { + public: + BasicHandlerImpl(BrokerAdapter& parent) : HandlerImplType(parent) {} + + void qos(const framing::MethodContext& context, uint32_t prefetchSize, + uint16_t prefetchCount, bool global); + void consume( + const framing::MethodContext& context, uint16_t ticket, const std::string& queue, + const std::string& consumerTag, bool noLocal, bool noAck, + bool exclusive, bool nowait, + const qpid::framing::FieldTable& fields); + void cancel(const framing::MethodContext& context, const std::string& consumerTag, + bool nowait); + void publish(const framing::MethodContext& context, uint16_t ticket, + const std::string& exchange, const std::string& routingKey, + bool mandatory, bool immediate); + void get(const framing::MethodContext& context, uint16_t ticket, const std::string& queue, + bool noAck); + void ack(const framing::MethodContext& context, uint64_t deliveryTag, bool multiple); + void reject(const framing::MethodContext& context, uint64_t deliveryTag, bool requeue); + void recover(const framing::MethodContext& context, bool requeue); + }; + + class TxHandlerImpl : + public TxHandler, + public HandlerImpl<framing::AMQP_ClientProxy::Tx> + { + public: + TxHandlerImpl(BrokerAdapter& parent) : HandlerImplType(parent) {} + + void select(const framing::MethodContext& context); + void commit(const framing::MethodContext& context); + void rollback(const framing::MethodContext& context); + }; + + Connection& connection; + BasicHandlerImpl basicHandler; + ChannelHandlerImpl channelHandler; + ConnectionHandlerImpl connectionHandler; + ExchangeHandlerImpl exchangeHandler; + MessageHandlerImpl messageHandler; + QueueHandlerImpl queueHandler; + TxHandlerImpl txHandler; + +}; +}} // namespace qpid::broker + + + +#endif /*!_broker_BrokerAdapter_h*/ diff --git a/qpid/cpp-0-9/lib/broker/BrokerChannel.cpp b/qpid/cpp-0-9/lib/broker/BrokerChannel.cpp new file mode 100644 index 0000000000..5673a2c42a --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerChannel.cpp @@ -0,0 +1,346 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <assert.h> + +#include <iostream> +#include <sstream> +#include <algorithm> +#include <functional> + +#include <boost/bind.hpp> + +#include "BrokerChannel.h" +#include "DeletingTxOp.h" +#include "framing/ChannelAdapter.h" +#include <QpidError.h> +#include <DeliverableMessage.h> +#include <BrokerQueue.h> +#include <BrokerMessage.h> +#include <MessageStore.h> +#include <TxAck.h> +#include <TxPublish.h> +#include "BrokerAdapter.h" +#include "Connection.h" + +using std::mem_fun_ref; +using std::bind2nd; +using namespace qpid::broker; +using namespace qpid::framing; +using namespace qpid::sys; + + +Channel::Channel( + Connection& con, ChannelId id, + uint32_t _framesize, MessageStore* const _store, + uint64_t _stagingThreshold +) : + ChannelAdapter(id, &con.getOutput(), con.getVersion()), + connection(con), + currentDeliveryTag(1), + transactional(false), + prefetchSize(0), + prefetchCount(0), + framesize(_framesize), + tagGenerator("sgen"), + accumulatedAck(0), + store(_store), + messageBuilder(this, _store, _stagingThreshold), + opened(id == 0),//channel 0 is automatically open, other must be explicitly opened + adapter(new BrokerAdapter(*this, con, con.broker)) +{ + outstanding.reset(); +} + +Channel::~Channel(){ + close(); +} + +bool Channel::exists(const string& consumerTag){ + return consumers.find(consumerTag) != consumers.end(); +} + +// TODO aconway 2007-02-12: Why is connection token passed in instead +// of using the channel's parent connection? +void Channel::consume(string& tagInOut, Queue::shared_ptr queue, bool acks, + bool exclusive, ConnectionToken* const connection, + const FieldTable*) +{ + if(tagInOut.empty()) + tagInOut = tagGenerator.generate(); + std::auto_ptr<ConsumerImpl> c( + new ConsumerImpl(this, tagInOut, queue, connection, acks)); + queue->consume(c.get(), exclusive);//may throw exception + consumers.insert(tagInOut, c.release()); +} + +void Channel::cancel(const string& tag){ + // consumers is a ptr_map so erase will delete the consumer + // which will call cancel. + ConsumerImplMap::iterator i = consumers.find(tag); + if (i != consumers.end()) + consumers.erase(i); +} + +void Channel::close(){ + opened = false; + consumers.clear(); + recover(true); +} + +void Channel::begin(){ + transactional = true; +} + +void Channel::commit(){ + TxAck txAck(accumulatedAck, unacked); + txBuffer.enlist(&txAck); + if(txBuffer.prepare(store)){ + txBuffer.commit(); + } + accumulatedAck.clear(); +} + +void Channel::rollback(){ + txBuffer.rollback(); + accumulatedAck.clear(); +} + +void Channel::deliver( + Message::shared_ptr& msg, const string& consumerTag, + Queue::shared_ptr& queue, bool ackExpected) +{ + Mutex::ScopedLock locker(deliveryLock); + + // Key the delivered messages to the id of the request in which they're sent + uint64_t deliveryTag = getNextSendRequestId(); + + if(ackExpected){ + unacked.push_back(DeliveryRecord(msg, queue, consumerTag, deliveryTag)); + outstanding.size += msg->contentSize(); + outstanding.count++; + } + //send deliver method, header and content(s) + msg->deliver(*this, consumerTag, deliveryTag, framesize); +} + +bool Channel::checkPrefetch(Message::shared_ptr& msg){ + Mutex::ScopedLock locker(deliveryLock); + bool countOk = !prefetchCount || prefetchCount > unacked.size(); + bool sizeOk = !prefetchSize || prefetchSize > msg->contentSize() + outstanding.size || unacked.empty(); + return countOk && sizeOk; +} + +Channel::ConsumerImpl::ConsumerImpl(Channel* _parent, const string& _tag, + Queue::shared_ptr _queue, + ConnectionToken* const _connection, bool ack +) : parent(_parent), tag(_tag), queue(_queue), connection(_connection), + ackExpected(ack), blocked(false) {} + +bool Channel::ConsumerImpl::deliver(Message::shared_ptr& msg){ + if(!connection || connection != msg->getPublisher()){//check for no_local + if(ackExpected && !parent->checkPrefetch(msg)){ + blocked = true; + }else{ + blocked = false; + parent->deliver(msg, tag, queue, ackExpected); + return true; + } + } + return false; +} + +Channel::ConsumerImpl::~ConsumerImpl() { + cancel(); +} + +void Channel::ConsumerImpl::cancel(){ + if(queue) + queue->cancel(this); +} + +void Channel::ConsumerImpl::requestDispatch(){ + if(blocked) + queue->dispatch(); +} + +void Channel::handleInlineTransfer(Message::shared_ptr msg) +{ + Exchange::shared_ptr exchange = + connection.broker.getExchanges().get(msg->getExchange()); + if(transactional){ + TxPublish* deliverable = new TxPublish(msg); + exchange->route( + *deliverable, msg->getRoutingKey(), + &(msg->getApplicationHeaders())); + txBuffer.enlist(new DeletingTxOp(deliverable)); + }else{ + DeliverableMessage deliverable(msg); + exchange->route( + deliverable, msg->getRoutingKey(), + &(msg->getApplicationHeaders())); + } +} + +void Channel::handlePublish(Message* _message){ + Message::shared_ptr message(_message); + messageBuilder.initialise(message); +} + +void Channel::handleHeader(AMQHeaderBody::shared_ptr header){ + messageBuilder.setHeader(header); + //at this point, decide based on the size of the message whether we want + //to stage it by saving content directly to disk as it arrives +} + +void Channel::handleContent(AMQContentBody::shared_ptr content){ + messageBuilder.addContent(content); +} + +void Channel::handleHeartbeat(boost::shared_ptr<AMQHeartbeatBody>) { + // TODO aconway 2007-01-17: Implement heartbeating. +} + +void Channel::complete(Message::shared_ptr msg) { + Exchange::shared_ptr exchange = + connection.broker.getExchanges().get(msg->getExchange()); + assert(exchange.get()); + if(transactional) { + std::auto_ptr<TxPublish> deliverable(new TxPublish(msg)); + exchange->route(*deliverable, msg->getRoutingKey(), + &(msg->getApplicationHeaders())); + txBuffer.enlist(new DeletingTxOp(deliverable.release())); + } else { + DeliverableMessage deliverable(msg); + exchange->route(deliverable, msg->getRoutingKey(), + &(msg->getApplicationHeaders())); + } +} + +void Channel::ack(){ + ack(getFirstAckRequest(), getLastAckRequest()); +} + +// Used by Basic +void Channel::ack(uint64_t deliveryTag, bool multiple){ + if (multiple) + ack(0, deliveryTag); + else + ack(deliveryTag, deliveryTag); +} + +void Channel::ack(uint64_t firstTag, uint64_t lastTag){ + if(transactional){ + accumulatedAck.update(firstTag, lastTag); + + //TODO: I think the outstanding prefetch size & count should be updated at this point... + //TODO: ...this may then necessitate dispatching to consumers + }else{ + Mutex::ScopedLock locker(deliveryLock);//need to synchronize with possible concurrent delivery + + ack_iterator i = find_if(unacked.begin(), unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::matches), lastTag)); + ack_iterator j = (firstTag == 0) ? + unacked.begin() : + find_if(unacked.begin(), unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::matches), firstTag)); + + if(i == unacked.end()){ + throw ConnectionException(530, "Received ack for unrecognised delivery tag"); + }else if(i!=j){ + ack_iterator end = ++i; + for_each(j, end, mem_fun_ref(&DeliveryRecord::discard)); + unacked.erase(unacked.begin(), end); + + //recalculate the prefetch: + outstanding.reset(); + for_each(unacked.begin(), unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::addTo), &outstanding)); + }else{ + i->discard(); + i->subtractFrom(&outstanding); + unacked.erase(i); + } + + //if the prefetch limit had previously been reached, there may + //be messages that can be now be delivered + std::for_each(consumers.begin(), consumers.end(), + boost::bind(&ConsumerImpl::requestDispatch, _1)); + } +} + +void Channel::recover(bool requeue){ + Mutex::ScopedLock locker(deliveryLock);//need to synchronize with possible concurrent delivery + + if(requeue){ + outstanding.reset(); + std::list<DeliveryRecord> copy = unacked; + unacked.clear(); + for_each(copy.begin(), copy.end(), mem_fun_ref(&DeliveryRecord::requeue)); + }else{ + for_each(unacked.begin(), unacked.end(), bind2nd(mem_fun_ref(&DeliveryRecord::redeliver), this)); + } +} + +bool Channel::get(Queue::shared_ptr queue, const string& destination, bool ackExpected){ + Message::shared_ptr msg = queue->dequeue(); + if(msg){ + Mutex::ScopedLock locker(deliveryLock); + uint64_t myDeliveryTag = getNextSendRequestId(); + msg->sendGetOk(MethodContext(this, msg->getRespondTo()), + destination, + queue->getMessageCount() + 1, myDeliveryTag, + framesize); + if(ackExpected){ + unacked.push_back(DeliveryRecord(msg, queue, myDeliveryTag)); + } + return true; + }else{ + return false; + } +} + +void Channel::deliver(Message::shared_ptr& msg, const string& consumerTag, + uint64_t deliveryTag) +{ + msg->deliver(*this, consumerTag, deliveryTag, framesize); +} + +void Channel::handleMethodInContext( + boost::shared_ptr<qpid::framing::AMQMethodBody> method, + const MethodContext& context +) +{ + try{ + if(getId() != 0 && !method->isA<ChannelOpenBody>() && !isOpen()) { + std::stringstream out; + out << "Attempt to use unopened channel: " << getId(); + throw ConnectionException(504, out.str()); + } else { + method->invoke(*adapter, context); + } + }catch(ChannelException& e){ + adapter->getProxy().getChannel().close( + e.code, e.toString(), + method->amqpClassId(), method->amqpMethodId()); + connection.closeChannel(getId()); + }catch(ConnectionException& e){ + connection.close(e.code, e.toString(), method->amqpClassId(), method->amqpMethodId()); + }catch(std::exception& e){ + connection.close(541/*internal error*/, e.what(), method->amqpClassId(), method->amqpMethodId()); + } +} diff --git a/qpid/cpp-0-9/lib/broker/BrokerChannel.h b/qpid/cpp-0-9/lib/broker/BrokerChannel.h new file mode 100644 index 0000000000..5085783685 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerChannel.h @@ -0,0 +1,159 @@ +#ifndef _broker_BrokerChannel_h +#define _broker_BrokerChannel_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <list> + +#include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/ptr_container/ptr_map.hpp> + +#include <AccumulatedAck.h> +#include <Consumer.h> +#include <DeliveryRecord.h> +#include <MessageBuilder.h> +#include <NameGenerator.h> +#include <Prefetch.h> +#include <TxBuffer.h> +#include "framing/ChannelAdapter.h" +#include "ChannelOpenBody.h" +#include "CompletionHandler.h" + +namespace qpid { +namespace broker { + +class ConnectionToken; +class Connection; +class Queue; +class BrokerAdapter; + +using framing::string; + +/** + * Maintains state for an AMQP channel. Handles incoming and + * outgoing messages for that channel. + */ +class Channel : public framing::ChannelAdapter, + public CompletionHandler +{ + class ConsumerImpl : public Consumer + { + Channel* parent; + const string tag; + Queue::shared_ptr queue; + ConnectionToken* const connection; + const bool ackExpected; + bool blocked; + + public: + ConsumerImpl(Channel* parent, const string& tag, + Queue::shared_ptr queue, + ConnectionToken* const connection, bool ack); + ~ConsumerImpl(); + virtual bool deliver(Message::shared_ptr& msg); + void cancel(); + void requestDispatch(); + }; + + typedef boost::ptr_map<string,ConsumerImpl> ConsumerImplMap; + + Connection& connection; + uint64_t currentDeliveryTag; + Queue::shared_ptr defaultQueue; + bool transactional; + ConsumerImplMap consumers; + uint32_t prefetchSize; + uint16_t prefetchCount; + Prefetch outstanding; + uint32_t framesize; + NameGenerator tagGenerator; + std::list<DeliveryRecord> unacked; + sys::Mutex deliveryLock; + TxBuffer txBuffer; + AccumulatedAck accumulatedAck; + MessageStore* const store; + MessageBuilder messageBuilder;//builder for in-progress message + bool opened; + boost::scoped_ptr<BrokerAdapter> adapter; + + // completion handler for MessageBuilder + void complete(Message::shared_ptr msg); + + void deliver(Message::shared_ptr& msg, const string& tag, + Queue::shared_ptr& queue, bool ackExpected); + bool checkPrefetch(Message::shared_ptr& msg); + + public: + Channel(Connection& parent, + framing::ChannelId id, + uint32_t framesize, + MessageStore* const _store = 0, + uint64_t stagingThreshold = 0); + + ~Channel(); + + bool isOpen() const { return opened; } + BrokerAdapter& getAdatper() { return *adapter; } + + void open() { opened = true; } + void setDefaultQueue(Queue::shared_ptr queue){ defaultQueue = queue; } + Queue::shared_ptr getDefaultQueue() const { return defaultQueue; } + uint32_t setPrefetchSize(uint32_t size){ return prefetchSize = size; } + uint16_t setPrefetchCount(uint16_t n){ return prefetchCount = n; } + + bool exists(const string& consumerTag); + + /** + *@param tagInOut - if empty it is updated with the generated token. + */ + void consume(string& tagInOut, Queue::shared_ptr queue, bool acks, + bool exclusive, ConnectionToken* const connection = 0, + const framing::FieldTable* = 0); + void cancel(const string& tag); + bool get(Queue::shared_ptr queue, const std::string& destination, bool ackExpected); + void begin(); + void close(); + void commit(); + void rollback(); + void ack(); + void ack(uint64_t deliveryTag, bool multiple); + void ack(uint64_t deliveryTag, uint64_t endTag); + void recover(bool requeue); + void deliver(Message::shared_ptr& msg, const string& consumerTag, uint64_t deliveryTag); + void handlePublish(Message* msg); + void handleHeader(boost::shared_ptr<framing::AMQHeaderBody>); + void handleContent(boost::shared_ptr<framing::AMQContentBody>); + void handleHeartbeat(boost::shared_ptr<framing::AMQHeartbeatBody>); + + void handleInlineTransfer(Message::shared_ptr msg); + + // For ChannelAdapter + void handleMethodInContext( + boost::shared_ptr<framing::AMQMethodBody> method, + const framing::MethodContext& context); +}; + +}} // namespace broker + + +#endif /*!_broker_BrokerChannel_h*/ diff --git a/qpid/cpp-0-9/lib/broker/BrokerExchange.h b/qpid/cpp-0-9/lib/broker/BrokerExchange.h new file mode 100644 index 0000000000..6f4e9e6671 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerExchange.h @@ -0,0 +1,51 @@ +#ifndef _broker_BrokerExchange_h +#define _broker_BrokerExchange_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <boost/shared_ptr.hpp> +#include <Deliverable.h> +#include <BrokerQueue.h> +#include <FieldTable.h> + +namespace qpid { + namespace broker { + using std::string; + + class Exchange{ + const string name; + public: + typedef boost::shared_ptr<Exchange> shared_ptr; + + explicit Exchange(const string& _name) : name(_name){} + virtual ~Exchange(){} + string getName() { return name; } + virtual string getType() = 0; + virtual void bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args) = 0; + virtual void unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args) = 0; + virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args) = 0; + }; + } +} + + +#endif /*!_broker_BrokerExchange_h*/ diff --git a/qpid/cpp-0-9/lib/broker/BrokerMessage.cpp b/qpid/cpp-0-9/lib/broker/BrokerMessage.cpp new file mode 100644 index 0000000000..91ba3dfec0 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerMessage.cpp @@ -0,0 +1,245 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <boost/cast.hpp> + +#include <BrokerMessage.h> +#include <iostream> + +#include <InMemoryContent.h> +#include <LazyLoadedContent.h> +#include <MessageStore.h> +#include <BasicDeliverBody.h> +#include <BasicGetOkBody.h> +#include <AMQContentBody.h> +#include <AMQHeaderBody.h> +#include "AMQMethodBody.h" +#include "AMQFrame.h" +#include "framing/ChannelAdapter.h" + +using namespace boost; +using namespace qpid::broker; +using namespace qpid::framing; +using namespace qpid::sys; + +BasicMessage::BasicMessage( + const ConnectionToken* const _publisher, + const string& _exchange, const string& _routingKey, + bool _mandatory, bool _immediate, framing::AMQMethodBody::shared_ptr respondTo +) : + Message(_publisher, _exchange, _routingKey, _mandatory, + _immediate, respondTo), + size(0) +{} + +// FIXME aconway 2007-02-01: remove. +// BasicMessage::BasicMessage(Buffer& buffer, bool headersOnly, uint32_t contentChunkSize) : +// publisher(0), size(0) +// { + +// decode(buffer, headersOnly, contentChunkSize); +// } + +// For tests only. +BasicMessage::BasicMessage() : size(0) +{} + +BasicMessage::~BasicMessage(){} + +void BasicMessage::setHeader(AMQHeaderBody::shared_ptr _header){ + this->header = _header; +} + +void BasicMessage::addContent(AMQContentBody::shared_ptr data){ + if (!content.get()) { + content = std::auto_ptr<Content>(new InMemoryContent()); + } + content->add(data); + size += data->size(); +} + +bool BasicMessage::isComplete(){ + return header.get() && (header->getContentSize() == contentSize()); +} + +void BasicMessage::deliver(ChannelAdapter& channel, + const string& consumerTag, uint64_t deliveryTag, + uint32_t framesize) +{ + // CCT -- TODO - Update code generator to take pointer/ not + // instance to avoid extra contruction + channel.send( + new BasicDeliverBody( + channel.getVersion(), consumerTag, deliveryTag, + getRedelivered(), getExchange(), getRoutingKey())); + sendContent(channel, framesize); +} + +void BasicMessage::sendGetOk(const MethodContext& context, + const std::string& /*destination*/, + uint32_t messageCount, + uint64_t deliveryTag, + uint32_t framesize) +{ + // CCT -- TODO - Update code generator to take pointer/ not + // instance to avoid extra contruction + context.channel->send( + new BasicGetOkBody( + context.channel->getVersion(), + context.methodBody->getRequestId(), + deliveryTag, getRedelivered(), getExchange(), + getRoutingKey(), messageCount)); + sendContent(*context.channel, framesize); +} + +void BasicMessage::sendContent( + ChannelAdapter& channel, uint32_t framesize) +{ + channel.send(header); + Mutex::ScopedLock locker(contentLock); + if (content.get()) + content->send(channel, framesize); +} + +BasicHeaderProperties* BasicMessage::getHeaderProperties(){ + return boost::polymorphic_downcast<BasicHeaderProperties*>( + header->getProperties()); +} + +const FieldTable& BasicMessage::getApplicationHeaders(){ + return getHeaderProperties()->getHeaders(); +} + +bool BasicMessage::isPersistent() +{ + if(!header) return false; + BasicHeaderProperties* props = getHeaderProperties(); + return props && props->getDeliveryMode() == PERSISTENT; +} + +void BasicMessage::decode(Buffer& buffer, bool headersOnly, uint32_t contentChunkSize) +{ + decodeHeader(buffer); + if (!headersOnly) decodeContent(buffer, contentChunkSize); +} + +void BasicMessage::decodeHeader(Buffer& buffer) +{ + string exchange; + string routingKey; + + buffer.getShortString(exchange); + buffer.getShortString(routingKey); + setRouting(exchange, routingKey); + + uint32_t headerSize = buffer.getLong(); + AMQHeaderBody::shared_ptr headerBody(new AMQHeaderBody()); + headerBody->decode(buffer, headerSize); + setHeader(headerBody); +} + +void BasicMessage::decodeContent(Buffer& buffer, uint32_t chunkSize) +{ + uint64_t expected = expectedContentSize(); + if (expected != buffer.available()) { + std::cout << "WARN: Expected " << expectedContentSize() << " bytes, got " << buffer.available() << std::endl; + throw Exception("Cannot decode content, buffer not large enough."); + } + + if (!chunkSize || chunkSize > expected) { + chunkSize = expected; + } + + uint64_t total = 0; + while (total < expectedContentSize()) { + uint64_t remaining = expected - total; + AMQContentBody::shared_ptr contentBody(new AMQContentBody()); + contentBody->decode(buffer, remaining < chunkSize ? remaining : chunkSize); + addContent(contentBody); + total += chunkSize; + } +} + +void BasicMessage::encode(Buffer& buffer) +{ + encodeHeader(buffer); + encodeContent(buffer); +} + +void BasicMessage::encodeHeader(Buffer& buffer) +{ + buffer.putShortString(getExchange()); + buffer.putShortString(getRoutingKey()); + buffer.putLong(header->size()); + header->encode(buffer); +} + +void BasicMessage::encodeContent(Buffer& buffer) +{ + Mutex::ScopedLock locker(contentLock); + if (content.get()) content->encode(buffer); +} + +uint32_t BasicMessage::encodedSize() +{ + return encodedHeaderSize() + encodedContentSize(); +} + +uint32_t BasicMessage::encodedContentSize() +{ + Mutex::ScopedLock locker(contentLock); + return content.get() ? content->size() : 0; +} + +uint32_t BasicMessage::encodedHeaderSize() +{ + return getExchange().size() + 1 + + getRoutingKey().size() + 1 + + header->size() + 4;//4 extra bytes for size +} + +uint64_t BasicMessage::expectedContentSize() +{ + return header.get() ? header->getContentSize() : 0; +} + +void BasicMessage::releaseContent(MessageStore* store) +{ + Mutex::ScopedLock locker(contentLock); + if (!isPersistent() && getPersistenceId() == 0) { + store->stage(this); + } + if (!content.get() || content->size() > 0) { + // FIXME aconway 2007-02-07: handle MessageMessage. + //set content to lazy loading mode (but only if there is stored content): + + //Note: the LazyLoadedContent instance contains a raw pointer to the message, however it is + // then set as a member of that message so its lifetime is guaranteed to be no longer than + // that of the message itself + content = std::auto_ptr<Content>( + new LazyLoadedContent(store, this, expectedContentSize())); + } +} + +void BasicMessage::setContent(std::auto_ptr<Content>& _content) +{ + Mutex::ScopedLock locker(contentLock); + content = _content; +} diff --git a/qpid/cpp-0-9/lib/broker/BrokerMessage.h b/qpid/cpp-0-9/lib/broker/BrokerMessage.h new file mode 100644 index 0000000000..fcb104edbb --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerMessage.h @@ -0,0 +1,137 @@ +#ifndef _broker_BrokerMessage_h +#define _broker_BrokerMessage_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <memory> +#include <boost/shared_ptr.hpp> + +#include <BrokerMessageBase.h> +#include <BasicHeaderProperties.h> +#include <ConnectionToken.h> +#include <Content.h> +#include <Mutex.h> +#include <TxBuffer.h> + +namespace qpid { + +namespace framing { +class MethodContext; +class ChannelAdapter; +class AMQHeaderBody; +} + +namespace broker { + +class MessageStore; +using framing::string; + +/** + * Represents an AMQP message, i.e. a header body, a list of + * content bodies and some details about the publication + * request. + */ +class BasicMessage : public Message { + boost::shared_ptr<framing::AMQHeaderBody> header; + std::auto_ptr<Content> content; + sys::Mutex contentLock; + uint64_t size; + + void sendContent(framing::ChannelAdapter&, uint32_t framesize); + + public: + typedef boost::shared_ptr<BasicMessage> shared_ptr; + + BasicMessage(const ConnectionToken* const publisher, + const string& exchange, const string& routingKey, + bool mandatory, bool immediate, + boost::shared_ptr<framing::AMQMethodBody> respondTo); + BasicMessage(); + ~BasicMessage(); + void setHeader(boost::shared_ptr<framing::AMQHeaderBody> header); + void addContent(framing::AMQContentBody::shared_ptr data); + bool isComplete(); + + void deliver(framing::ChannelAdapter&, + const string& consumerTag, + uint64_t deliveryTag, + uint32_t framesize); + + void sendGetOk(const framing::MethodContext&, + const std::string& destination, + uint32_t messageCount, + uint64_t deliveryTag, + uint32_t framesize); + + framing::BasicHeaderProperties* getHeaderProperties(); + const framing::FieldTable& getApplicationHeaders(); + bool isPersistent(); + uint64_t contentSize() const { return size; } + + void decode(framing::Buffer& buffer, bool headersOnly = false, + uint32_t contentChunkSize = 0); + void decodeHeader(framing::Buffer& buffer); + void decodeContent(framing::Buffer& buffer, uint32_t contentChunkSize = 0); + + void encode(framing::Buffer& buffer); + void encodeHeader(framing::Buffer& buffer); + void encodeContent(framing::Buffer& buffer); + /** + * @returns the size of the buffer needed to encode this + * message in its entirety + */ + uint32_t encodedSize(); + /** + * @returns the size of the buffer needed to encode the + * 'header' of this message (not just the header frame, + * but other meta data e.g.routing key and exchange) + */ + uint32_t encodedHeaderSize(); + /** + * @returns the size of the buffer needed to encode the + * (possibly partial) content held by this message + */ + uint32_t encodedContentSize(); + /** + * Releases the in-memory content data held by this + * message. Must pass in a store from which the data can + * be reloaded. + */ + void releaseContent(MessageStore* store); + /** + * If headers have been received, returns the expected + * content size else returns 0. + */ + uint64_t expectedContentSize(); + /** + * Sets the 'content' implementation of this message (the + * message controls the lifecycle of the content instance + * it uses). + */ + void setContent(std::auto_ptr<Content>& content); +}; + +} +} + + +#endif /*!_broker_BrokerMessage_h*/ diff --git a/qpid/cpp-0-9/lib/broker/BrokerMessageBase.h b/qpid/cpp-0-9/lib/broker/BrokerMessageBase.h new file mode 100644 index 0000000000..709369ae2f --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerMessageBase.h @@ -0,0 +1,184 @@ +#ifndef _broker_BrokerMessageBase_h +#define _broker_BrokerMessageBase_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <string> +#include <boost/shared_ptr.hpp> +#include "Content.h" +#include "framing/amqp_types.h" + +namespace qpid { + +namespace framing { +class MethodContext; +class ChannelAdapter; +class BasicHeaderProperties; +class FieldTable; +class AMQMethodBody; +class AMQContentBody; +class AMQHeaderBody; +} + + +namespace broker { +class ConnectionToken; +class MessageStore; + +/** + * Base class for all types of internal broker messages + * abstracting away the operations + * TODO; AMS: for the moment this is mostly a placeholder + */ +class Message { + public: + typedef boost::shared_ptr<Message> shared_ptr; + typedef boost::shared_ptr<framing::AMQMethodBody> AMQMethodBodyPtr; + + + Message(const ConnectionToken* publisher_, + const std::string& _exchange, + const std::string& _routingKey, + bool _mandatory, bool _immediate, + AMQMethodBodyPtr respondTo_) : + publisher(publisher_), + exchange(_exchange), + routingKey(_routingKey), + mandatory(_mandatory), + immediate(_immediate), + persistenceId(0), + redelivered(false), + respondTo(respondTo_) + {} + + Message() : + mandatory(false), + immediate(false), + persistenceId(0), + redelivered(false) + {} + + virtual ~Message() {}; + + // Accessors + const std::string& getRoutingKey() const { return routingKey; } + const std::string& getExchange() const { return exchange; } + uint64_t getPersistenceId() const { return persistenceId; } + bool getRedelivered() const { return redelivered; } + AMQMethodBodyPtr getRespondTo() const { return respondTo; } + + void setRouting(const std::string& _exchange, const std::string& _routingKey) + { exchange = _exchange; routingKey = _routingKey; } + void setPersistenceId(uint64_t _persistenceId) { persistenceId = _persistenceId; } // XXXX: Only used in tests? + void redeliver() { redelivered = true; } + + /** + * Used to deliver the message from the queue + */ + virtual void deliver(framing::ChannelAdapter& channel, + const std::string& consumerTag, + uint64_t deliveryTag, + uint32_t framesize) = 0; + /** + * Used to return a message in response to a get from a queue + */ + virtual void sendGetOk(const framing::MethodContext& context, + const std::string& destination, + uint32_t messageCount, + uint64_t deliveryTag, + uint32_t framesize) = 0; + + virtual bool isComplete() = 0; + + virtual uint64_t contentSize() const = 0; + // FIXME aconway 2007-02-06: Get rid of BasicHeaderProperties + // at this level. Expose only generic properties available from both + // message types (e.g. getApplicationHeaders below). + // + virtual framing::BasicHeaderProperties* getHeaderProperties() = 0; + virtual const framing::FieldTable& getApplicationHeaders() = 0; + virtual bool isPersistent() = 0; + virtual const ConnectionToken* getPublisher() const { + return publisher; + } + + virtual void encode(framing::Buffer& /*buffer*/) {}; // XXXX: Only used in tests? + virtual void encodeHeader(framing::Buffer& /*buffer*/) {}; // XXXX: Only used in tests? + + /** + * @returns the size of the buffer needed to encode this + * message in its entirety + * + * XXXX: Only used in tests? + */ + virtual uint32_t encodedSize() = 0; + /** + * @returns the size of the buffer needed to encode the + * 'header' of this message (not just the header frame, + * but other meta data e.g.routing key and exchange) + * + * XXXX: Only used in tests? + */ + virtual uint32_t encodedHeaderSize() = 0; + /** + * @returns the size of the buffer needed to encode the + * (possibly partial) content held by this message + */ + virtual uint32_t encodedContentSize() = 0; + /** + * If headers have been received, returns the expected + * content size else returns 0. + */ + virtual uint64_t expectedContentSize() = 0; + + // TODO: AMS 29/1/2007 Don't think these are really part of base class + + /** + * Sets the 'content' implementation of this message (the + * message controls the lifecycle of the content instance + * it uses). + */ + virtual void setContent(std::auto_ptr<Content>& /*content*/) {}; + virtual void setHeader(boost::shared_ptr<framing::AMQHeaderBody>) {}; + virtual void addContent(boost::shared_ptr<framing::AMQContentBody>) {}; + /** + * Releases the in-memory content data held by this + * message. Must pass in a store from which the data can + * be reloaded. + */ + virtual void releaseContent(MessageStore* /*store*/) {}; + + private: + const ConnectionToken* publisher; + std::string exchange; + std::string routingKey; + const bool mandatory; + const bool immediate; + uint64_t persistenceId; + bool redelivered; + AMQMethodBodyPtr respondTo; +}; + +}} + + +#endif /*!_broker_BrokerMessage_h*/ diff --git a/qpid/cpp-0-9/lib/broker/BrokerMessageMessage.cpp b/qpid/cpp-0-9/lib/broker/BrokerMessageMessage.cpp new file mode 100644 index 0000000000..3449078d70 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerMessageMessage.cpp @@ -0,0 +1,239 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "QpidError.h" +#include "BrokerMessageMessage.h" +#include "ChannelAdapter.h" +#include "MessageTransferBody.h" +#include "MessageOpenBody.h" +#include "MessageCloseBody.h" +#include "MessageAppendBody.h" +#include "Reference.h" +#include "framing/FieldTable.h" +#include "framing/BasicHeaderProperties.h" + +#include <algorithm> + +using namespace std; +using namespace qpid::framing; + +namespace qpid { +namespace broker { + +MessageMessage::MessageMessage( + ConnectionToken* publisher, RequestId requestId_, TransferPtr transfer_ +) : Message(publisher, transfer_->getDestination(), + transfer_->getRoutingKey(), + transfer_->getMandatory(), + transfer_->getImmediate(), + transfer_), + requestId(requestId_), + transfer(transfer_) +{} + +MessageMessage::MessageMessage( + ConnectionToken* publisher, RequestId requestId_, TransferPtr transfer_, + ReferencePtr reference_ +) : Message(publisher, transfer_->getDestination(), + transfer_->getRoutingKey(), + transfer_->getMandatory(), + transfer_->getImmediate(), + transfer_), + requestId(requestId_), + transfer(transfer_), + reference(reference_) +{} + +// TODO: astitcher 1-Mar-2007: This code desperately needs better factoring +void MessageMessage::transferMessage( + framing::ChannelAdapter& channel, + const std::string& consumerTag, + uint32_t framesize) +{ + const framing::Content& body = transfer->getBody(); + + // Send any reference data + if (!body.isInline()){ + // Open + channel.send(new MessageOpenBody(channel.getVersion(), reference->getId())); + // Appends + for(Reference::Appends::const_iterator a = reference->getAppends().begin(); + a != reference->getAppends().end(); + ++a) { + uint32_t sizeleft = (*a)->size(); + const string& content = (*a)->getBytes(); + // Calculate overhead bytes + // Assume that the overhead is constant as the reference name doesn't change + uint32_t overhead = sizeleft - content.size(); + string::size_type contentStart = 0; + while (sizeleft) { + string::size_type contentSize = sizeleft <= framesize ? sizeleft : framesize-overhead; + channel.send(new MessageAppendBody(channel.getVersion(), reference->getId(), + string(content, contentStart, contentSize))); + sizeleft -= contentSize; + contentStart += contentSize; + } + } + } + + // The transfer + if ( transfer->size()<=framesize ) { + channel.send( + new MessageTransferBody(channel.getVersion(), + transfer->getTicket(), + consumerTag, + getRedelivered(), + transfer->getImmediate(), + transfer->getTtl(), + transfer->getPriority(), + transfer->getTimestamp(), + transfer->getDeliveryMode(), + transfer->getExpiration(), + getExchange(), + getRoutingKey(), + transfer->getMessageId(), + transfer->getCorrelationId(), + transfer->getReplyTo(), + transfer->getContentType(), + transfer->getContentEncoding(), + transfer->getUserId(), + transfer->getAppId(), + transfer->getTransactionId(), + transfer->getSecurityToken(), + transfer->getApplicationHeaders(), + body, + transfer->getMandatory())); + } else { + // Thing to do here is to construct a simple reference message then deliver that instead + // fragmentation will be taken care of in the delivery if necessary; + string content = body.getValue(); + string refname = "dummy"; + TransferPtr newTransfer( + new MessageTransferBody(channel.getVersion(), + transfer->getTicket(), + consumerTag, + getRedelivered(), + transfer->getImmediate(), + transfer->getTtl(), + transfer->getPriority(), + transfer->getTimestamp(), + transfer->getDeliveryMode(), + transfer->getExpiration(), + getExchange(), + getRoutingKey(), + transfer->getMessageId(), + transfer->getCorrelationId(), + transfer->getReplyTo(), + transfer->getContentType(), + transfer->getContentEncoding(), + transfer->getUserId(), + transfer->getAppId(), + transfer->getTransactionId(), + transfer->getSecurityToken(), + transfer->getApplicationHeaders(), + framing::Content(REFERENCE, refname), + transfer->getMandatory())); + ReferencePtr newRef(new Reference(refname)); + Reference::AppendPtr newAppend(new MessageAppendBody(channel.getVersion(), refname, content)); + newRef->append(newAppend); + MessageMessage newMsg(const_cast<ConnectionToken*>(getPublisher()), 0, newTransfer, newRef); + newMsg.transferMessage(channel, consumerTag, framesize); + return; + } + // Close any reference data + if (!body.isInline()){ + // Close + channel.send(new MessageCloseBody(channel.getVersion(), reference->getId())); + } +} + +void MessageMessage::deliver( + framing::ChannelAdapter& channel, + const std::string& consumerTag, + uint64_t /*deliveryTag*/, + uint32_t framesize) +{ + transferMessage(channel, consumerTag, framesize); +} + +void MessageMessage::sendGetOk( + const framing::MethodContext& context, + const std::string& destination, + uint32_t /*messageCount*/, + uint64_t /*deliveryTag*/, + uint32_t framesize) +{ + framing::ChannelAdapter* channel = context.channel; + transferMessage(*channel, destination, framesize); +} + +bool MessageMessage::isComplete() +{ + return true; +} + +uint64_t MessageMessage::contentSize() const +{ + if (transfer->getBody().isInline()) + return transfer->getBody().getValue().size(); + else + return reference->getSize(); +} + +qpid::framing::BasicHeaderProperties* MessageMessage::getHeaderProperties() +{ + return 0; // FIXME aconway 2007-02-05: +} + +const FieldTable& MessageMessage::getApplicationHeaders() +{ + return transfer->getApplicationHeaders(); +} +bool MessageMessage::isPersistent() +{ + return transfer->getDeliveryMode() == PERSISTENT; +} + +uint32_t MessageMessage::encodedSize() +{ + THROW_QPID_ERROR(INTERNAL_ERROR, "Unfinished"); + return 0; // FIXME aconway 2007-02-05: +} + +uint32_t MessageMessage::encodedHeaderSize() +{ + THROW_QPID_ERROR(INTERNAL_ERROR, "Unfinished"); + return 0; // FIXME aconway 2007-02-05: +} + +uint32_t MessageMessage::encodedContentSize() +{ + THROW_QPID_ERROR(INTERNAL_ERROR, "Unfinished"); + return 0; // FIXME aconway 2007-02-05: +} + +uint64_t MessageMessage::expectedContentSize() +{ + THROW_QPID_ERROR(INTERNAL_ERROR, "Unfinished"); + return 0; // FIXME aconway 2007-02-05: +} + + +}} // namespace qpid::broker diff --git a/qpid/cpp-0-9/lib/broker/BrokerMessageMessage.h b/qpid/cpp-0-9/lib/broker/BrokerMessageMessage.h new file mode 100644 index 0000000000..8a2ff3a063 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerMessageMessage.h @@ -0,0 +1,91 @@ +#ifndef _broker_BrokerMessageMessage_h +#define _broker_BrokerMessageMessage_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "BrokerMessageBase.h" +#include "MessageTransferBody.h" +#include "amqp_types.h" + +#include <vector> + +namespace qpid { + +namespace framing { +class MessageTransferBody; +} + +namespace broker { +class ConnectionToken; +class Reference; + +class MessageMessage: public Message{ + public: + typedef boost::shared_ptr<MessageMessage> shared_ptr; + typedef boost::shared_ptr<framing::MessageTransferBody> TransferPtr; + typedef boost::shared_ptr<Reference> ReferencePtr; + + MessageMessage(ConnectionToken* publisher, framing::RequestId, TransferPtr transfer); + MessageMessage(ConnectionToken* publisher, framing::RequestId, TransferPtr transfer, ReferencePtr reference); + + // Default destructor okay + + framing::RequestId getRequestId() {return requestId; } + TransferPtr getTransfer() { return transfer; } + ReferencePtr getReference() { return reference; } + + void deliver(framing::ChannelAdapter& channel, + const std::string& consumerTag, + uint64_t deliveryTag, + uint32_t framesize); + + void sendGetOk(const framing::MethodContext& context, + const std::string& destination, + uint32_t messageCount, + uint64_t deliveryTag, + uint32_t framesize); + + bool isComplete(); + + uint64_t contentSize() const; + framing::BasicHeaderProperties* getHeaderProperties(); + const framing::FieldTable& getApplicationHeaders(); + bool isPersistent(); + + uint32_t encodedSize(); + uint32_t encodedHeaderSize(); + uint32_t encodedContentSize(); + uint64_t expectedContentSize(); + + private: + void transferMessage(framing::ChannelAdapter& channel, + const std::string& consumerTag, + uint32_t framesize); + + framing::RequestId requestId; + const TransferPtr transfer; + const ReferencePtr reference; +}; + +}} + + +#endif /*!_broker_BrokerMessage_h*/ diff --git a/qpid/cpp-0-9/lib/broker/BrokerQueue.cpp b/qpid/cpp-0-9/lib/broker/BrokerQueue.cpp new file mode 100644 index 0000000000..31309bd6c5 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerQueue.cpp @@ -0,0 +1,258 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <boost/format.hpp> + +#include <BrokerQueue.h> +#include <MessageStore.h> +#include <sys/Monitor.h> +#include <sys/Time.h> +#include <iostream> + +using namespace qpid::broker; +using namespace qpid::sys; +using namespace qpid::framing; +using boost::format; + +Queue::Queue(const string& _name, uint32_t _autodelete, + MessageStore* const _store, + const ConnectionToken* const _owner) : + + name(_name), + autodelete(_autodelete), + store(_store), + owner(_owner), + queueing(false), + dispatching(false), + next(0), + lastUsed(0), + exclusive(0), + persistenceId(0) +{ + if(autodelete) lastUsed = now()/TIME_MSEC; +} + +Queue::~Queue(){ + for(Binding* b = bindings.front(); !bindings.empty(); b = bindings.front()){ + b->cancel(); + bindings.pop(); + } +} + +void Queue::bound(Binding* b){ + bindings.push(b); +} + +void Queue::deliver(Message::shared_ptr& msg){ + enqueue(0, msg, 0); + process(msg); +} + +void Queue::recover(Message::shared_ptr& msg){ + push(msg); + if (store && msg->expectedContentSize() != msg->encodedContentSize()) { + //content has not been loaded, need to ensure that lazy loading mode is set: + //TODO: find a nicer way to do this + msg->releaseContent(store); + } +} + +void Queue::process(Message::shared_ptr& msg){ + Mutex::ScopedLock locker(lock); + if(queueing || !dispatch(msg)){ + push(msg); + } +} + +bool Queue::dispatch(Message::shared_ptr& msg){ + if(consumers.empty()){ + return false; + }else if(exclusive){ + if(!exclusive->deliver(msg)){ + std::cout << "WARNING: Dropping undeliverable message from queue with exclusive consumer." << std::endl; + } + return true; + }else{ + //deliver to next consumer + next = next % consumers.size(); + Consumer* c = consumers[next]; + int start = next; + while(c){ + next++; + if(c->deliver(msg)) return true; + + next = next % consumers.size(); + c = next == start ? 0 : consumers[next]; + } + return false; + } +} + +bool Queue::startDispatching(){ + Mutex::ScopedLock locker(lock); + if(queueing && !dispatching){ + dispatching = true; + return true; + }else{ + return false; + } +} + +void Queue::dispatch(){ + bool proceed = startDispatching(); + while(proceed){ + Mutex::ScopedLock locker(lock); + if(!messages.empty() && dispatch(messages.front())){ + pop(); + }else{ + dispatching = false; + proceed = false; + queueing = !messages.empty(); + } + } +} + +void Queue::consume(Consumer* c, bool requestExclusive){ + Mutex::ScopedLock locker(lock); + if(exclusive) + throw ChannelException( + 403, format("Queue '%s' has an exclusive consumer." + " No more consumers allowed.") % getName()); + if(requestExclusive) { + if(!consumers.empty()) + throw ChannelException( + 403, format("Queue '%s' already has conumers." + "Exclusive access denied.") %getName()); + exclusive = c; + } + if(autodelete && consumers.empty()) lastUsed = 0; + consumers.push_back(c); +} + +void Queue::cancel(Consumer* c){ + Mutex::ScopedLock locker(lock); + Consumers::iterator i = std::find(consumers.begin(), consumers.end(), c); + if (i != consumers.end()) + consumers.erase(i); + if(autodelete && consumers.empty()) lastUsed = now()*TIME_MSEC; + if(exclusive == c) exclusive = 0; +} + +Message::shared_ptr Queue::dequeue(){ + Mutex::ScopedLock locker(lock); + Message::shared_ptr msg; + if(!messages.empty()){ + msg = messages.front(); + pop(); + } + return msg; +} + +uint32_t Queue::purge(){ + Mutex::ScopedLock locker(lock); + int count = messages.size(); + while(!messages.empty()) pop(); + return count; +} + +void Queue::pop(){ + if (policy.get()) policy->dequeued(messages.front()->contentSize()); + messages.pop(); +} + +void Queue::push(Message::shared_ptr& msg){ + queueing = true; + messages.push(msg); + if (policy.get()) { + policy->enqueued(msg->contentSize()); + if (policy->limitExceeded()) { + msg->releaseContent(store); + } + } +} + +uint32_t Queue::getMessageCount() const{ + Mutex::ScopedLock locker(lock); + return messages.size(); +} + +uint32_t Queue::getConsumerCount() const{ + Mutex::ScopedLock locker(lock); + return consumers.size(); +} + +bool Queue::canAutoDelete() const{ + Mutex::ScopedLock locker(lock); + return lastUsed && (now()*TIME_MSEC - lastUsed > autodelete); +} + +void Queue::enqueue(TransactionContext* ctxt, Message::shared_ptr& msg, const string * const xid) +{ + if (msg->isPersistent() && store) { + store->enqueue(ctxt, msg.get(), *this, xid); + } +} + +void Queue::dequeue(TransactionContext* ctxt, Message::shared_ptr& msg, const string * const xid) +{ + if (msg->isPersistent() && store) { + store->dequeue(ctxt, msg.get(), *this, xid); + } +} + +namespace +{ + const std::string qpidMaxSize("qpid.max_size"); + const std::string qpidMaxCount("qpid.max_count"); +} + +void Queue::create(const FieldTable& settings) +{ + if (store) { + store->create(*this, settings); + } + configure(settings); +} + +void Queue::configure(const FieldTable& settings) +{ + QueuePolicy* _policy = new QueuePolicy(settings); + if (_policy->getMaxCount() || _policy->getMaxSize()) { + setPolicy(std::auto_ptr<QueuePolicy>(_policy)); + } +} + +void Queue::destroy() +{ + if (store) { + store->destroy(*this); + } +} + +void Queue::setPolicy(std::auto_ptr<QueuePolicy> _policy) +{ + policy = _policy; +} + +const QueuePolicy* const Queue::getPolicy() +{ + return policy.get(); +} diff --git a/qpid/cpp-0-9/lib/broker/BrokerQueue.h b/qpid/cpp-0-9/lib/broker/BrokerQueue.h new file mode 100644 index 0000000000..12f5815027 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerQueue.h @@ -0,0 +1,151 @@ +#ifndef _broker_BrokerQueue_h +#define _broker_BrokerQueue_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <vector> +#include <memory> +#include <queue> +#include <boost/shared_ptr.hpp> +#include <amqp_types.h> +#include <Binding.h> +#include <ConnectionToken.h> +#include <Consumer.h> +#include <BrokerMessage.h> +#include <FieldTable.h> +#include <sys/Monitor.h> +#include <QueuePolicy.h> + +// TODO aconway 2007-02-06: Use auto_ptr and boost::ptr_vector to +// enforce ownership of Consumers. + +namespace qpid { + namespace broker { + class MessageStore; + + /** + * Thrown when exclusive access would be violated. + */ + using std::string; + + /** + * The brokers representation of an amqp queue. Messages are + * delivered to a queue from where they can be dispatched to + * registered consumers or be stored until dequeued or until one + * or more consumers registers. + */ + class Queue{ + typedef std::vector<Consumer*> Consumers; + typedef std::queue<Binding*> Bindings; + typedef std::queue<Message::shared_ptr> Messages; + + const string name; + const uint32_t autodelete; + MessageStore* const store; + const ConnectionToken* const owner; + Consumers consumers; + Bindings bindings; + Messages messages; + bool queueing; + bool dispatching; + int next; + mutable qpid::sys::Mutex lock; + int64_t lastUsed; + Consumer* exclusive; + mutable uint64_t persistenceId; + std::auto_ptr<QueuePolicy> policy; + + void pop(); + void push(Message::shared_ptr& msg); + bool startDispatching(); + bool dispatch(Message::shared_ptr& msg); + void setPolicy(std::auto_ptr<QueuePolicy> policy); + + public: + + typedef boost::shared_ptr<Queue> shared_ptr; + + typedef std::vector<shared_ptr> vector; + + Queue(const string& name, uint32_t autodelete = 0, + MessageStore* const store = 0, + const ConnectionToken* const owner = 0); + ~Queue(); + + void create(const qpid::framing::FieldTable& settings); + void configure(const qpid::framing::FieldTable& settings); + void destroy(); + /** + * Informs the queue of a binding that should be cancelled on + * destruction of the queue. + */ + void bound(Binding* b); + /** + * Delivers a message to the queue. Will record it as + * enqueued if persistent then process it. + */ + void deliver(Message::shared_ptr& msg); + /** + * Dispatches the messages immediately to a consumer if + * one is available or stores it for later if not. + */ + void process(Message::shared_ptr& msg); + /** + * Used during recovery to add stored messages back to the queue + */ + void recover(Message::shared_ptr& msg); + /** + * Dispatch any queued messages providing there are + * consumers for them. Only one thread can be dispatching + * at any time, but this method (rather than the caller) + * is responsible for ensuring that. + */ + void dispatch(); + void consume(Consumer* c, bool exclusive = false); + void cancel(Consumer* c); + uint32_t purge(); + uint32_t getMessageCount() const; + uint32_t getConsumerCount() const; + inline const string& getName() const { return name; } + inline const bool isExclusiveOwner(const ConnectionToken* const o) const { return o == owner; } + inline bool hasExclusiveConsumer() const { return exclusive; } + inline uint64_t getPersistenceId() const { return persistenceId; } + inline void setPersistenceId(uint64_t _persistenceId) const { persistenceId = _persistenceId; } + + bool canAutoDelete() const; + + void enqueue(TransactionContext* ctxt, Message::shared_ptr& msg, const string * const xid); + /** + * dequeue from store (only done once messages is acknowledged) + */ + void dequeue(TransactionContext* ctxt, Message::shared_ptr& msg, const string * const xid); + /** + * dequeues from memory only + */ + Message::shared_ptr dequeue(); + + const QueuePolicy* const getPolicy(); + }; + } +} + + +#endif /*!_broker_BrokerQueue_h*/ diff --git a/qpid/cpp-0-9/lib/broker/BrokerSingleton.cpp b/qpid/cpp-0-9/lib/broker/BrokerSingleton.cpp new file mode 100644 index 0000000000..4571764850 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerSingleton.cpp @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "BrokerSingleton.h" + +namespace qpid { +namespace broker { + +BrokerSingleton::BrokerSingleton() { + if (broker.get() == 0) + broker = Broker::create(); + Broker::shared_ptr::operator=(broker); +} + +BrokerSingleton::~BrokerSingleton() { + broker->shutdown(); +} + +Broker::shared_ptr BrokerSingleton::broker; + +}} // namespace qpid::broker diff --git a/qpid/cpp-0-9/lib/broker/BrokerSingleton.h b/qpid/cpp-0-9/lib/broker/BrokerSingleton.h new file mode 100644 index 0000000000..139e02a5fd --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/BrokerSingleton.h @@ -0,0 +1,52 @@ +#ifndef _broker_BrokerSingleton_h +#define _broker_BrokerSingleton_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "Broker.h" + +namespace qpid { +namespace broker { + +/** + * BrokerSingleton is a smart pointer to a process-wide singleton broker + * started on an os-chosen port. The broker starts the first time + * an instance of BrokerSingleton is created and runs untill the process exits. + * + * Useful for unit tests that want to share a broker between multiple + * tests to reduce overhead of starting/stopping a broker for every test. + * + * Tests that need a new broker can call Broker::create directly. + * + * THREAD UNSAFE. + */ +class BrokerSingleton : public Broker::shared_ptr +{ + public: + BrokerSingleton(); + ~BrokerSingleton(); + private: + static Broker::shared_ptr broker; +}; + +}} // namespace qpid::broker + + + +#endif /*!_broker_BrokerSingleton_h*/ diff --git a/qpid/cpp-0-9/lib/broker/CompletionHandler.h b/qpid/cpp-0-9/lib/broker/CompletionHandler.h new file mode 100644 index 0000000000..9d51656282 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/CompletionHandler.h @@ -0,0 +1,39 @@ +#ifndef _broker_CompletionHandler_h +#define _broker_CompletionHandler_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace qpid { +namespace broker { + +/** + * Callback interface to handle completion of a message. + */ +class CompletionHandler +{ + public: + virtual ~CompletionHandler(){} + virtual void complete(Message::shared_ptr) = 0; +}; + +}} // namespace qpid::broker + + + +#endif /*!_broker_CompletionHandler_h*/ diff --git a/qpid/cpp-0-9/lib/broker/Configuration.cpp b/qpid/cpp-0-9/lib/broker/Configuration.cpp new file mode 100644 index 0000000000..e83c359f2d --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Configuration.cpp @@ -0,0 +1,252 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <Configuration.h> +#include <string.h> +#include <config.h> + +using namespace qpid::broker; +using namespace std; + +Configuration::Configuration() : + daemon('d', "daemon", "Run as system daemon, detached from terminal.", false), + trace('t', "trace", "Print incoming & outgoing frames to the console", false), + port('p', "port", "Set the port to listen on (default=5672)", 5672), + workerThreads("worker-threads", "Set the number of worker threads to use (default=5).", 5), + maxConnections("max-connections", "Set the maximum number of connections the broker can accept (default=500).", 500), + connectionBacklog("connection-backlog", "Set the connection backlog for the servers socket (default=10)", 10), + store('s', "store", "Set the message store module to use (default='' which implies no store)", ""), + stagingThreshold("staging-threshold", "Set the message size threshold above which messages will be written to disk as they arrive (default=5,000,000)", 5000000), + help("help", "Print usage information", false), + version("version", "Print version information", false) +{ + options.push_back(&daemon); + options.push_back(&trace); + options.push_back(&port); + options.push_back(&workerThreads); + options.push_back(&maxConnections); + options.push_back(&connectionBacklog); + options.push_back(&store); + options.push_back(&stagingThreshold); + options.push_back(&help); + options.push_back(&version); +} + +Configuration::~Configuration(){} + +void Configuration::parse(char const *progName, int argc, char** argv){ + programName = progName; + int position = 1; + while(position < argc){ + bool matched(false); + for(op_iterator i = options.begin(); i < options.end() && !matched; i++){ + matched = (*i)->parse(position, argv, argc); + } + if(!matched) { + throw BadOptionException( + std::string("Unrecognised option: ")+argv[position]); + } + } +} + +void Configuration::usage(){ + std::cout << "Usage: " << programName << " [OPTION]..." << std::endl + << "Start the Qpid AMQP broker daemon." << std::endl << std::endl + << "Options:" << std::endl; + for(op_iterator i = options.begin(); i < options.end(); i++){ + (*i)->print(std::cout); + } + + std::cout << std::endl << "Report bugs to <" << PACKAGE_BUGREPORT << ">." + << std::endl; +} + +bool Configuration::isHelp() const { + return help.getValue(); +} + +bool Configuration::isVersion() const { + return version.getValue(); +} + +bool Configuration::isDaemon() const { + return daemon.getValue(); +} + +bool Configuration::isTrace() const { + return trace.getValue(); +} + +int Configuration::getPort() const { + return port.getValue(); +} + +int Configuration::getWorkerThreads() const { + return workerThreads.getValue(); +} + +int Configuration::getMaxConnections() const { + return maxConnections.getValue(); +} + +int Configuration::getConnectionBacklog() const { + return connectionBacklog.getValue(); +} + +const std::string& Configuration::getStore() const { + return store.getValue(); +} + +long Configuration::getStagingThreshold() const { + return stagingThreshold.getValue(); +} + + +Configuration::Option::Option(const char _flag, const string& _name, const string& _desc) : + flag(string("-") + _flag), name("--" +_name), desc(_desc) {} + +Configuration::Option::Option(const string& _name, const string& _desc) : + flag(""), name("--" + _name), desc(_desc) {} + +Configuration::Option::~Option(){} + +bool Configuration::Option::match(const string& arg){ + return flag == arg || name == arg; +} + +bool Configuration::Option::parse(int& i, char** argv, int argc){ + const string arg(argv[i]); + if(match(arg)){ + if(needsValue()){ + if(++i < argc) setValue(argv[i]); + else throw ParseException("Argument " + arg + " requires a value!"); + }else{ + setValue(""); + } + i++; + return true; + }else{ + return false; + } +} + +void Configuration::Option::print(ostream& out) const { + out << " "; + if(flag.length() > 0){ + out << flag << ", "; + } else { + out << " "; + } + out << name; + if(needsValue()) out << " <value>"; + out << std::endl; + out << " " << desc << std::endl; +} + + +// String Option: + +Configuration::StringOption::StringOption(const char _flag, const string& _name, const string& _desc, const string _value) : + Option(_flag,_name,_desc), defaultValue(_value), value(_value) {} + +Configuration::StringOption::StringOption(const string& _name, const string& _desc, const string _value) : + Option(_name,_desc), defaultValue(_value), value(_value) {} + +Configuration::StringOption::~StringOption(){} + +const string& Configuration::StringOption::getValue() const { + return value; +} + +bool Configuration::StringOption::needsValue() const { + return true; +} + +void Configuration::StringOption::setValue(const std::string& _value){ + value = _value; +} + +// Int Option: + +Configuration::IntOption::IntOption(const char _flag, const string& _name, const string& _desc, const int _value) : + Option(_flag,_name,_desc), defaultValue(_value), value(_value) {} + +Configuration::IntOption::IntOption(const string& _name, const string& _desc, const int _value) : + Option(_name,_desc), defaultValue(_value), value(_value) {} + +Configuration::IntOption::~IntOption(){} + +int Configuration::IntOption::getValue() const { + return value; +} + +bool Configuration::IntOption::needsValue() const { + return true; +} + +void Configuration::IntOption::setValue(const std::string& _value){ + value = atoi(_value.c_str()); +} + +// Long Option: + +Configuration::LongOption::LongOption(const char _flag, const string& _name, const string& _desc, const long _value) : + Option(_flag,_name,_desc), defaultValue(_value), value(_value) {} + +Configuration::LongOption::LongOption(const string& _name, const string& _desc, const long _value) : + Option(_name,_desc), defaultValue(_value), value(_value) {} + +Configuration::LongOption::~LongOption(){} + +long Configuration::LongOption::getValue() const { + return value; +} + +bool Configuration::LongOption::needsValue() const { + return true; +} + +void Configuration::LongOption::setValue(const std::string& _value){ + value = atol(_value.c_str()); +} + +// Bool Option: + +Configuration::BoolOption::BoolOption(const char _flag, const string& _name, const string& _desc, const bool _value) : + Option(_flag,_name,_desc), defaultValue(_value), value(_value) {} + +Configuration::BoolOption::BoolOption(const string& _name, const string& _desc, const bool _value) : + Option(_name,_desc), defaultValue(_value), value(_value) {} + +Configuration::BoolOption::~BoolOption(){} + +bool Configuration::BoolOption::getValue() const { + return value; +} + +bool Configuration::BoolOption::needsValue() const { + return false; +} + +void Configuration::BoolOption::setValue(const std::string& /*not required*/){ + //BoolOptions have no value. The fact that the option is specified + //implies the value is true. + value = true; +} diff --git a/qpid/cpp-0-9/lib/broker/Configuration.h b/qpid/cpp-0-9/lib/broker/Configuration.h new file mode 100644 index 0000000000..27c743c8f0 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Configuration.h @@ -0,0 +1,171 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _Configuration_ +#define _Configuration_ + +#include <cstdlib> +#include <iostream> +#include <vector> +#include <Exception.h> + +namespace qpid { +namespace broker { +class Configuration{ + + class Option { + const std::string flag; + const std::string name; + const std::string desc; + + bool match(const std::string& arg); + + protected: + virtual bool needsValue() const = 0; + virtual void setValue(const std::string& value) = 0; + + public: + Option(const char flag, const std::string& name, const std::string& desc); + Option(const std::string& name, const std::string& desc); + virtual ~Option(); + + bool parse(int& i, char** argv, int argc); + void print(std::ostream& out) const; + }; + + class IntOption : public Option{ + const int defaultValue; + int value; + public: + IntOption(char flag, const std::string& name, const std::string& desc, const int value = 0); + IntOption(const std::string& name, const std::string& desc, const int value = 0); + virtual ~IntOption(); + + int getValue() const; + virtual bool needsValue() const; + virtual void setValue(const std::string& value); + virtual void setValue(int _value) { value = _value; } + }; + + class LongOption : public Option{ + const long defaultValue; + int value; + public: + LongOption(char flag, const std::string& name, const std::string& desc, const long value = 0); + LongOption(const std::string& name, const std::string& desc, const long value = 0); + virtual ~LongOption(); + + long getValue() const; + virtual bool needsValue() const; + virtual void setValue(const std::string& value); + virtual void setValue(int _value) { value = _value; } + }; + + class StringOption : public Option{ + const std::string defaultValue; + std::string value; + public: + StringOption(char flag, const std::string& name, const std::string& desc, const std::string value = ""); + StringOption(const std::string& name, const std::string& desc, const std::string value = ""); + virtual ~StringOption(); + + const std::string& getValue() const; + virtual bool needsValue() const; + virtual void setValue(const std::string& value); + }; + + class BoolOption : public Option{ + const bool defaultValue; + bool value; + public: + BoolOption(char flag, const std::string& name, const std::string& desc, const bool value = 0); + BoolOption(const std::string& name, const std::string& desc, const bool value = 0); + virtual ~BoolOption(); + + bool getValue() const; + virtual bool needsValue() const; + virtual void setValue(const std::string& value); + virtual void setValue(bool _value) { value = _value; } + }; + + BoolOption daemon; + BoolOption trace; + IntOption port; + IntOption workerThreads; + IntOption maxConnections; + IntOption connectionBacklog; + StringOption store; + LongOption stagingThreshold; + BoolOption help; + BoolOption version; + char const *programName; + + typedef std::vector<Option*>::iterator op_iterator; + std::vector<Option*> options; + + public: + + struct BadOptionException : public Exception { + template<class T> + BadOptionException(const T& msg) : Exception(msg) {} + }; + + + class ParseException : public Exception { + public: + template <class T> + ParseException(const T& msg) : Exception(msg) {} + }; + + + Configuration(); + ~Configuration(); + + void parse(char const*, int argc, char** argv); + + bool isHelp() const; + bool isVersion() const; + bool isDaemon() const; + bool isTrace() const; + int getPort() const; + int getWorkerThreads() const; + int getMaxConnections() const; + int getConnectionBacklog() const; + const std::string& getStore() const; + long getStagingThreshold() const; + + void setHelp(bool b) { help.setValue(b); } + void setVersion(bool b) { version.setValue(b); } + void setDaemon(bool b) { daemon.setValue(b); } + void setTrace(bool b) { trace.setValue(b); } + void setPort(int i) { port.setValue(i); } + void setWorkerThreads(int i) { workerThreads.setValue(i); } + void setMaxConnections(int i) { maxConnections.setValue(i); } + void setConnectionBacklog(int i) { connectionBacklog.setValue(i); } + void setStore(const std::string& s) { store.setValue(s); } + void setStagingThreshold(long l) { stagingThreshold.setValue(l); } + + void usage(); +}; +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/Connection.cpp b/qpid/cpp-0-9/lib/broker/Connection.cpp new file mode 100644 index 0000000000..ae0114cba9 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Connection.cpp @@ -0,0 +1,128 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <assert.h> + +#include "Connection.h" +#include "BrokerChannel.h" +#include "AMQP_ClientProxy.h" +#include "BrokerAdapter.h" + +using namespace boost; +using namespace qpid::sys; +using namespace qpid::framing; +using namespace qpid::sys; + +namespace qpid { +namespace broker { + +Connection::Connection(ConnectionOutputHandler* out_, Broker& broker_) : + broker(broker_), + out(out_), + framemax(65536), + heartbeat(0), + client(0), + timeout(broker.getTimeout()), + stagingThreshold(broker.getStagingThreshold()) +{} + + +Queue::shared_ptr Connection::getQueue(const string& name, uint16_t channel){ + Queue::shared_ptr queue; + if (name.empty()) { + queue = getChannel(channel).getDefaultQueue(); + if (!queue) throw ConnectionException( 530, "Queue must be specified or previously declared" ); + } else { + queue = broker.getQueues().find(name); + if (queue == 0) { + throw ChannelException( 404, "Queue not found: " + name); + } + } + return queue; +} + + +Exchange::shared_ptr Connection::findExchange(const string& name){ + return broker.getExchanges().get(name); +} + + +void Connection::received(framing::AMQFrame* frame){ + getChannel(frame->getChannel()).handleBody(frame->getBody()); +} + +void Connection::close( + ReplyCode code, const string& text, ClassId classId, MethodId methodId) +{ + client->close(code, text, classId, methodId); + getOutput().close(); +} + +void Connection::initiated(framing::ProtocolInitiation* header) { + version = ProtocolVersion(header->getMajor(), header->getMinor()); + FieldTable properties; + string mechanisms("PLAIN"); + string locales("en_US"); + getChannel(0).init(0, *out, getVersion()); + client = &getChannel(0).getAdatper().getProxy().getConnection(); + client->start( + header->getMajor(), header->getMinor(), + properties, mechanisms, locales); +} + +void Connection::idleOut(){} + +void Connection::idleIn(){} + +void Connection::closed(){ + try { + while (!exclusiveQueues.empty()) { + broker.getQueues().destroy(exclusiveQueues.front()->getName()); + exclusiveQueues.erase(exclusiveQueues.begin()); + } + } catch(std::exception& e) { + std::cout << "Caught unhandled exception while closing session: " << + e.what() << std::endl; + assert(0); + } +} + +void Connection::closeChannel(uint16_t id) { + ChannelMap::iterator i = channels.find(id); + if (i != channels.end()) + i->close(); +} + + +Channel& Connection::getChannel(ChannelId id) { + ChannelMap::iterator i = channels.find(id); + if (i == channels.end()) { + i = channels.insert( + id, new Channel( + *this, id, framemax, broker.getQueues().getStore(), + broker.getStagingThreshold())).first; + } + return *i; +} + + +}} + diff --git a/qpid/cpp-0-9/lib/broker/Connection.h b/qpid/cpp-0-9/lib/broker/Connection.h new file mode 100644 index 0000000000..1314ccbd97 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Connection.h @@ -0,0 +1,108 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _Connection_ +#define _Connection_ + +#include <sstream> +#include <vector> + +#include <boost/ptr_container/ptr_map.hpp> + +#include <AMQFrame.h> +#include <AMQP_ServerOperations.h> +#include <AMQP_ClientProxy.h> +#include <sys/ConnectionOutputHandler.h> +#include <sys/ConnectionInputHandler.h> +#include <sys/TimeoutHandler.h> +#include "framing/ProtocolVersion.h" +#include "Broker.h" +#include "Exception.h" +#include "BrokerChannel.h" + +namespace qpid { +namespace broker { + +class Channel; + +class Connection : public sys::ConnectionInputHandler, + public ConnectionToken +{ + public: + Connection(sys::ConnectionOutputHandler* out, Broker& broker); + + /** Get a channel. Create if it does not already exist */ + Channel& getChannel(framing::ChannelId channel); + + /** Close a channel */ + void closeChannel(framing::ChannelId channel); + + /** Close the connection */ + void close(framing::ReplyCode code, const string& text, framing::ClassId classId, framing::MethodId methodId); + + sys::ConnectionOutputHandler& getOutput() const { return *out; } + framing::ProtocolVersion getVersion() const { return version; } + + uint32_t getFrameMax() const { return framemax; } + uint16_t getHeartbeat() const { return heartbeat; } + uint32_t getTimeout() const { return timeout; } + uint64_t getStagingThreshold() const { return stagingThreshold; } + + void setFrameMax(uint32_t fm) { framemax = fm; } + void setHeartbeat(uint16_t hb) { heartbeat = hb; } + + /** + * Get named queue, never returns 0. + * @return: named queue or default queue for channel if name="" + * @exception: ChannelException if no queue of that name is found. + * @exception: ConnectionException if name="" and channel has no default. + */ + Queue::shared_ptr getQueue(const string& name, uint16_t channel); + + Broker& broker; + std::vector<Queue::shared_ptr> exclusiveQueues; + + // ConnectionInputHandler methods + void received(framing::AMQFrame* frame); + void initiated(framing::ProtocolInitiation* header); + void idleOut(); + void idleIn(); + void closed(); + + private: + typedef boost::ptr_map<framing::ChannelId, Channel> ChannelMap; + + typedef std::vector<Queue::shared_ptr>::iterator queue_iterator; + Exchange::shared_ptr findExchange(const string& name); + + framing::ProtocolVersion version; + ChannelMap channels; + sys::ConnectionOutputHandler* out; + uint32_t framemax; + uint16_t heartbeat; + framing::AMQP_ClientProxy::Connection* client; + const uint32_t timeout; //timeout for auto-deleted queues (in ms) + const uint64_t stagingThreshold; + +}; + +}} + +#endif diff --git a/qpid/cpp-0-9/lib/broker/ConnectionFactory.cpp b/qpid/cpp-0-9/lib/broker/ConnectionFactory.cpp new file mode 100644 index 0000000000..20485dd0e1 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/ConnectionFactory.cpp @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <ConnectionFactory.h> +#include <Connection.h> + +namespace qpid { +namespace broker { + + +ConnectionFactory::ConnectionFactory(Broker& b) : broker(b) +{} + + +ConnectionFactory::~ConnectionFactory() +{ + broker.getCleaner().stop(); +} + +qpid::sys::ConnectionInputHandler* +ConnectionFactory::create(qpid::sys::ConnectionOutputHandler* out) +{ + return new Connection(out, broker); +} + +}} // namespace qpid::broker diff --git a/qpid/cpp-0-9/lib/broker/ConnectionFactory.h b/qpid/cpp-0-9/lib/broker/ConnectionFactory.h new file mode 100644 index 0000000000..9147384b2a --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/ConnectionFactory.h @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _ConnectionFactory_ +#define _ConnectionFactory_ + +#include "ConnectionInputHandlerFactory.h" + +namespace qpid { +namespace broker { +class Broker; + +class ConnectionFactory : public qpid::sys::ConnectionInputHandlerFactory +{ + public: + ConnectionFactory(Broker& b); + + virtual qpid::sys::ConnectionInputHandler* create( + qpid::sys::ConnectionOutputHandler* ctxt); + + virtual ~ConnectionFactory(); + + private: + Broker& broker; +}; + +}} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/ConnectionToken.h b/qpid/cpp-0-9/lib/broker/ConnectionToken.h new file mode 100644 index 0000000000..7e7f813d0e --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/ConnectionToken.h @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _ConnectionToken_ +#define _ConnectionToken_ + +namespace qpid { + namespace broker { + /** + * An empty interface allowing opaque implementations of some + * form of token to identify a connection. + */ + class ConnectionToken{ + public: + virtual ~ConnectionToken(){} + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/Consumer.h b/qpid/cpp-0-9/lib/broker/Consumer.h new file mode 100644 index 0000000000..26deef4a26 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Consumer.h @@ -0,0 +1,37 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _Consumer_ +#define _Consumer_ + +#include <BrokerMessage.h> + +namespace qpid { + namespace broker { + class Consumer{ + public: + virtual bool deliver(Message::shared_ptr& msg) = 0; + virtual ~Consumer(){} + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/Content.h b/qpid/cpp-0-9/lib/broker/Content.h new file mode 100644 index 0000000000..b65a454778 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Content.h @@ -0,0 +1,64 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _Content_ +#define _Content_ + +#include <boost/function.hpp> + +#include <AMQContentBody.h> +#include <Buffer.h> +#include <OutputHandler.h> + +namespace qpid { + +namespace framing { +class ChannelAdapter; +} + +namespace broker { +class Content{ + public: + typedef std::string DataBlock; + typedef boost::function1<void, const DataBlock&> SendFn; + + virtual ~Content(){} + + /** Add a block of data to the content */ + virtual void add(framing::AMQContentBody::shared_ptr data) = 0; + + /** Total size of content in bytes */ + virtual uint32_t size() = 0; + + /** + * Iterate over the content calling SendFn for each block. + * Subdivide blocks if necessary to ensure each block is + * <= framesize bytes long. + */ + virtual void send(framing::ChannelAdapter& channel, uint32_t framesize) = 0; + + //FIXME aconway 2007-02-07: This is inconsistently implemented + //find out what is needed. + virtual void encode(qpid::framing::Buffer& buffer) = 0; +}; +}} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/DeletingTxOp.cpp b/qpid/cpp-0-9/lib/broker/DeletingTxOp.cpp new file mode 100644 index 0000000000..25fe9c98db --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/DeletingTxOp.cpp @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <DeletingTxOp.h> + +using namespace qpid::broker; + +DeletingTxOp::DeletingTxOp(TxOp* const _delegate) : delegate(_delegate){} + +bool DeletingTxOp::prepare(TransactionContext* ctxt) throw(){ + return delegate && delegate->prepare(ctxt); +} + +void DeletingTxOp::commit() throw(){ + if(delegate){ + delegate->commit(); + delete delegate; + delegate = 0; + } +} + +void DeletingTxOp::rollback() throw(){ + if(delegate){ + delegate->rollback(); + delete delegate; + delegate = 0; + } +} diff --git a/qpid/cpp-0-9/lib/broker/DeletingTxOp.h b/qpid/cpp-0-9/lib/broker/DeletingTxOp.h new file mode 100644 index 0000000000..3e026cd4ca --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/DeletingTxOp.h @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _DeletingTxOp_ +#define _DeletingTxOp_ + +#include <TxOp.h> + +namespace qpid { + namespace broker { + /** + * TxOp wrapper that will delegate calls & delete the object + * to which it delegates after completion of the transaction. + */ + class DeletingTxOp : public virtual TxOp{ + TxOp* delegate; + public: + DeletingTxOp(TxOp* const delegate); + virtual bool prepare(TransactionContext* ctxt) throw(); + virtual void commit() throw(); + virtual void rollback() throw(); + virtual ~DeletingTxOp(){} + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/Deliverable.h b/qpid/cpp-0-9/lib/broker/Deliverable.h new file mode 100644 index 0000000000..e33443555d --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Deliverable.h @@ -0,0 +1,37 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _Deliverable_ +#define _Deliverable_ + +#include <BrokerQueue.h> + +namespace qpid { + namespace broker { + class Deliverable{ + public: + virtual void deliverTo(Queue::shared_ptr& queue) = 0; + virtual ~Deliverable(){} + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/DeliverableMessage.cpp b/qpid/cpp-0-9/lib/broker/DeliverableMessage.cpp new file mode 100644 index 0000000000..b9c89da690 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/DeliverableMessage.cpp @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <DeliverableMessage.h> + +using namespace qpid::broker; + +DeliverableMessage::DeliverableMessage(Message::shared_ptr& _msg) : msg(_msg) +{ +} + +void DeliverableMessage::deliverTo(Queue::shared_ptr& queue) +{ + queue->deliver(msg); +} + diff --git a/qpid/cpp-0-9/lib/broker/DeliverableMessage.h b/qpid/cpp-0-9/lib/broker/DeliverableMessage.h new file mode 100644 index 0000000000..962f0da640 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/DeliverableMessage.h @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _DeliverableMessage_ +#define _DeliverableMessage_ + +#include <Deliverable.h> +#include <BrokerMessage.h> +#include <BrokerQueue.h> + +namespace qpid { + namespace broker { + class DeliverableMessage : public Deliverable{ + Message::shared_ptr msg; + public: + DeliverableMessage(Message::shared_ptr& msg); + virtual void deliverTo(Queue::shared_ptr& queue); + virtual ~DeliverableMessage(){} + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/DeliveryRecord.cpp b/qpid/cpp-0-9/lib/broker/DeliveryRecord.cpp new file mode 100644 index 0000000000..0d2e5325c5 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/DeliveryRecord.cpp @@ -0,0 +1,91 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <DeliveryRecord.h> +#include <BrokerChannel.h> + +using namespace qpid::broker; +using std::string; + +DeliveryRecord::DeliveryRecord(Message::shared_ptr _msg, + Queue::shared_ptr _queue, + const string _consumerTag, + const uint64_t _deliveryTag) : msg(_msg), + queue(_queue), + consumerTag(_consumerTag), + deliveryTag(_deliveryTag), + pull(false){} + +DeliveryRecord::DeliveryRecord(Message::shared_ptr _msg, + Queue::shared_ptr _queue, + const uint64_t _deliveryTag) : msg(_msg), + queue(_queue), + consumerTag(""), + deliveryTag(_deliveryTag), + pull(true){} + + +void DeliveryRecord::discard(TransactionContext* ctxt, const std::string* const xid) const{ + queue->dequeue(ctxt, msg, xid); +} + +void DeliveryRecord::discard() const{ + discard(0, 0); +} + +bool DeliveryRecord::matches(uint64_t tag) const{ + return deliveryTag == tag; +} + +bool DeliveryRecord::coveredBy(const AccumulatedAck* const range) const{ + return range->covers(deliveryTag); +} + +void DeliveryRecord::redeliver(Channel* const channel) const{ + if(pull){ + //if message was originally sent as response to get, we must requeue it + requeue(); + }else{ + channel->deliver(msg, consumerTag, deliveryTag); + } +} + +void DeliveryRecord::requeue() const{ + msg->redeliver(); + queue->process(msg); +} + +void DeliveryRecord::addTo(Prefetch* const prefetch) const{ + if(!pull){ + //ignore 'pulled' messages (i.e. those that were sent in + //response to get) when calculating prefetch + prefetch->size += msg->contentSize(); + prefetch->count++; + } +} + +void DeliveryRecord::subtractFrom(Prefetch* const prefetch) const{ + if(!pull){ + //ignore 'pulled' messages (i.e. those that were sent in + //response to get) when calculating prefetch + prefetch->size -= msg->contentSize(); + prefetch->count--; + } +} diff --git a/qpid/cpp-0-9/lib/broker/DeliveryRecord.h b/qpid/cpp-0-9/lib/broker/DeliveryRecord.h new file mode 100644 index 0000000000..bda2c2ec90 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/DeliveryRecord.h @@ -0,0 +1,64 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _DeliveryRecord_ +#define _DeliveryRecord_ + +#include <algorithm> +#include <list> +#include <AccumulatedAck.h> +#include <BrokerMessage.h> +#include <Prefetch.h> +#include <BrokerQueue.h> + +namespace qpid { + namespace broker { + class Channel; + + /** + * Record of a delivery for which an ack is outstanding. + */ + class DeliveryRecord{ + mutable Message::shared_ptr msg; + mutable Queue::shared_ptr queue; + std::string consumerTag; + uint64_t deliveryTag; + bool pull; + + public: + DeliveryRecord(Message::shared_ptr msg, Queue::shared_ptr queue, const std::string consumerTag, const uint64_t deliveryTag); + DeliveryRecord(Message::shared_ptr msg, Queue::shared_ptr queue, const uint64_t deliveryTag); + + void discard() const; + void discard(TransactionContext* ctxt, const std::string* const xid) const; + bool matches(uint64_t tag) const; + bool coveredBy(const AccumulatedAck* const range) const; + void requeue() const; + void redeliver(Channel* const) const; + void addTo(Prefetch* const prefetch) const; + void subtractFrom(Prefetch* const prefetch) const; + }; + + typedef std::list<DeliveryRecord>::iterator ack_iterator; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/DirectExchange.cpp b/qpid/cpp-0-9/lib/broker/DirectExchange.cpp new file mode 100644 index 0000000000..c898ae8d7e --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/DirectExchange.cpp @@ -0,0 +1,73 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <DirectExchange.h> +#include <ExchangeBinding.h> +#include <iostream> + +using namespace qpid::broker; +using namespace qpid::framing; +using namespace qpid::sys; + +DirectExchange::DirectExchange(const string& _name) : Exchange(_name) { + +} + +void DirectExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args){ + Mutex::ScopedLock l(lock); + std::vector<Queue::shared_ptr>& queues(bindings[routingKey]); + std::vector<Queue::shared_ptr>::iterator i = find(queues.begin(), queues.end(), queue); + if(i == queues.end()){ + bindings[routingKey].push_back(queue); + queue->bound(new ExchangeBinding(this, queue, routingKey, args)); + } +} + +void DirectExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/){ + Mutex::ScopedLock l(lock); + std::vector<Queue::shared_ptr>& queues(bindings[routingKey]); + + std::vector<Queue::shared_ptr>::iterator i = find(queues.begin(), queues.end(), queue); + if(i < queues.end()){ + queues.erase(i); + if(queues.empty()){ + bindings.erase(routingKey); + } + } +} + +void DirectExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/){ + Mutex::ScopedLock l(lock); + std::vector<Queue::shared_ptr>& queues(bindings[routingKey]); + int count(0); + for(std::vector<Queue::shared_ptr>::iterator i = queues.begin(); i != queues.end(); i++, count++){ + msg.deliverTo(*i); + } + if(!count){ + std::cout << "WARNING: DirectExchange " << getName() << " could not route message with key " << routingKey << std::endl; + } +} + +DirectExchange::~DirectExchange(){ + +} + + +const std::string DirectExchange::typeName("direct"); diff --git a/qpid/cpp-0-9/lib/broker/DirectExchange.h b/qpid/cpp-0-9/lib/broker/DirectExchange.h new file mode 100644 index 0000000000..a7ef5aca9e --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/DirectExchange.h @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _DirectExchange_ +#define _DirectExchange_ + +#include <map> +#include <vector> +#include <BrokerExchange.h> +#include <FieldTable.h> +#include <BrokerMessage.h> +#include <sys/Monitor.h> +#include <BrokerQueue.h> + +namespace qpid { +namespace broker { + class DirectExchange : public virtual Exchange{ + std::map<string, std::vector<Queue::shared_ptr> > bindings; + qpid::sys::Mutex lock; + + public: + static const std::string typeName; + + DirectExchange(const std::string& name); + + virtual std::string getType(){ return typeName; } + + virtual void bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args); + + virtual void unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args); + + virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args); + + virtual ~DirectExchange(); + }; +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/ExchangeBinding.cpp b/qpid/cpp-0-9/lib/broker/ExchangeBinding.cpp new file mode 100644 index 0000000000..bf2102414d --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/ExchangeBinding.cpp @@ -0,0 +1,35 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <ExchangeBinding.h> +#include <BrokerExchange.h> + +using namespace qpid::broker; +using namespace qpid::framing; + +ExchangeBinding::ExchangeBinding(Exchange* _e, Queue::shared_ptr _q, const string& _key, const FieldTable* _args) : e(_e), q(_q), key(_key), args(_args){} + +void ExchangeBinding::cancel(){ + e->unbind(q, key, args); + delete this; +} + +ExchangeBinding::~ExchangeBinding(){ +} diff --git a/qpid/cpp-0-9/lib/broker/ExchangeBinding.h b/qpid/cpp-0-9/lib/broker/ExchangeBinding.h new file mode 100644 index 0000000000..2afaa89552 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/ExchangeBinding.h @@ -0,0 +1,48 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _ExchangeBinding_ +#define _ExchangeBinding_ + +#include <Binding.h> +#include <FieldTable.h> +#include <BrokerQueue.h> + +namespace qpid { + namespace broker { + class Exchange; + class Queue; + + class ExchangeBinding : public virtual Binding{ + Exchange* e; + Queue::shared_ptr q; + const string key; + const qpid::framing::FieldTable* args; + public: + ExchangeBinding(Exchange* _e, Queue::shared_ptr _q, const string& _key, const qpid::framing::FieldTable* _args); + virtual void cancel(); + virtual ~ExchangeBinding(); + }; + } +} + + +#endif + diff --git a/qpid/cpp-0-9/lib/broker/ExchangeRegistry.cpp b/qpid/cpp-0-9/lib/broker/ExchangeRegistry.cpp new file mode 100644 index 0000000000..3e5ed89b54 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/ExchangeRegistry.cpp @@ -0,0 +1,76 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <ExchangeRegistry.h> +#include <DirectExchange.h> +#include <FanOutExchange.h> +#include <HeadersExchange.h> +#include <TopicExchange.h> + +using namespace qpid::broker; +using namespace qpid::sys; +using std::pair; + +pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, const string& type) throw(UnknownExchangeTypeException){ + Mutex::ScopedLock locker(lock); + ExchangeMap::iterator i = exchanges.find(name); + if (i == exchanges.end()) { + Exchange::shared_ptr exchange; + + if(type == TopicExchange::typeName){ + exchange = Exchange::shared_ptr(new TopicExchange(name)); + }else if(type == DirectExchange::typeName){ + exchange = Exchange::shared_ptr(new DirectExchange(name)); + }else if(type == FanOutExchange::typeName){ + exchange = Exchange::shared_ptr(new FanOutExchange(name)); + }else if (type == HeadersExchange::typeName) { + exchange = Exchange::shared_ptr(new HeadersExchange(name)); + }else{ + throw UnknownExchangeTypeException(); + } + exchanges[name] = exchange; + return std::pair<Exchange::shared_ptr, bool>(exchange, true); + } else { + return std::pair<Exchange::shared_ptr, bool>(i->second, false); + } +} + +void ExchangeRegistry::destroy(const string& name){ + Mutex::ScopedLock locker(lock); + exchanges.erase(name); +} + +Exchange::shared_ptr ExchangeRegistry::get(const string& name){ + Mutex::ScopedLock locker(lock); + Exchange::shared_ptr exchange =exchanges[name]; + if (!exchange) + throw ChannelException(404, "Exchange not found:" + name); + return exchange; +} + +namespace +{ +const std::string empty; +} + +Exchange::shared_ptr ExchangeRegistry::getDefault() +{ + return get(empty); +} diff --git a/qpid/cpp-0-9/lib/broker/ExchangeRegistry.h b/qpid/cpp-0-9/lib/broker/ExchangeRegistry.h new file mode 100644 index 0000000000..aeb32753df --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/ExchangeRegistry.h @@ -0,0 +1,47 @@ +#ifndef _broker_ExchangeRegistry_h +#define _broker_ExchangeRegistry_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <map> +#include <BrokerExchange.h> +#include <sys/Monitor.h> + +namespace qpid { +namespace broker { + struct UnknownExchangeTypeException{}; + + class ExchangeRegistry{ + typedef std::map<std::string, Exchange::shared_ptr> ExchangeMap; + ExchangeMap exchanges; + qpid::sys::Mutex lock; + public: + std::pair<Exchange::shared_ptr, bool> declare(const std::string& name, const std::string& type) throw(UnknownExchangeTypeException); + void destroy(const std::string& name); + Exchange::shared_ptr get(const std::string& name); + Exchange::shared_ptr getDefault(); + }; +} +} + + +#endif /*!_broker_ExchangeRegistry_h*/ diff --git a/qpid/cpp-0-9/lib/broker/FanOutExchange.cpp b/qpid/cpp-0-9/lib/broker/FanOutExchange.cpp new file mode 100644 index 0000000000..48afcc20d5 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/FanOutExchange.cpp @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <FanOutExchange.h> +#include <ExchangeBinding.h> +#include <algorithm> + +using namespace qpid::broker; +using namespace qpid::framing; +using namespace qpid::sys; + +FanOutExchange::FanOutExchange(const std::string& _name) : Exchange(_name) {} + +void FanOutExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args){ + Mutex::ScopedLock locker(lock); + // Add if not already present. + Queue::vector::iterator i = std::find(bindings.begin(), bindings.end(), queue); + if (i == bindings.end()) { + bindings.push_back(queue); + queue->bound(new ExchangeBinding(this, queue, routingKey, args)); + } +} + +void FanOutExchange::unbind(Queue::shared_ptr queue, const string& /*routingKey*/, const FieldTable* /*args*/){ + Mutex::ScopedLock locker(lock); + Queue::vector::iterator i = std::find(bindings.begin(), bindings.end(), queue); + if (i != bindings.end()) { + bindings.erase(i); + // TODO aconway 2006-09-14: What about the ExchangeBinding object? + // Don't we have to verify routingKey/args match? + } +} + +void FanOutExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* /*args*/){ + Mutex::ScopedLock locker(lock); + for(Queue::vector::iterator i = bindings.begin(); i != bindings.end(); ++i){ + msg.deliverTo(*i); + } +} + +FanOutExchange::~FanOutExchange() {} + +const std::string FanOutExchange::typeName("fanout"); diff --git a/qpid/cpp-0-9/lib/broker/FanOutExchange.h b/qpid/cpp-0-9/lib/broker/FanOutExchange.h new file mode 100644 index 0000000000..6dc70e69bb --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/FanOutExchange.h @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _FanOutExchange_ +#define _FanOutExchange_ + +#include <map> +#include <vector> +#include <BrokerExchange.h> +#include <FieldTable.h> +#include <BrokerMessage.h> +#include <sys/Monitor.h> +#include <BrokerQueue.h> + +namespace qpid { +namespace broker { + +class FanOutExchange : public virtual Exchange { + std::vector<Queue::shared_ptr> bindings; + qpid::sys::Mutex lock; + + public: + static const std::string typeName; + + FanOutExchange(const std::string& name); + + virtual std::string getType(){ return typeName; } + + virtual void bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args); + + virtual void unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args); + + virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args); + + virtual ~FanOutExchange(); +}; + +} +} + + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/HandlerImpl.h b/qpid/cpp-0-9/lib/broker/HandlerImpl.h new file mode 100644 index 0000000000..c55a36da45 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/HandlerImpl.h @@ -0,0 +1,71 @@ +#ifndef _broker_HandlerImpl_h +#define _broker_HandlerImpl_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "BrokerChannel.h" +#include "AMQP_ClientProxy.h" + +namespace qpid { + +namespace framing { +class AMQP_ClientProxy; +} + +namespace broker { + +class Broker; +class Channel; +class Connection; + +/** + * A collection of references to the core objects required by an adapter, + * and a client proxy. + */ +struct CoreRefs +{ + CoreRefs(Channel& ch, Connection& c, Broker& b) + : channel(ch), connection(c), broker(b), proxy(ch) {} + + Channel& channel; + Connection& connection; + Broker& broker; + framing::AMQP_ClientProxy proxy; +}; + + +/** + * Base template for protocol handler implementations. + * Provides the core references and appropriate AMQP class proxy. + */ +template <class ProxyType> +struct HandlerImpl : public CoreRefs { + typedef HandlerImpl<ProxyType> HandlerImplType; + HandlerImpl(CoreRefs& parent) + : CoreRefs(parent), client(ProxyType::get(proxy)) {} + ProxyType client; +}; + + + +}} // namespace qpid::broker + + + +#endif /*!_broker_HandlerImpl_h*/ diff --git a/qpid/cpp-0-9/lib/broker/HeadersExchange.cpp b/qpid/cpp-0-9/lib/broker/HeadersExchange.cpp new file mode 100644 index 0000000000..acd344725a --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/HeadersExchange.cpp @@ -0,0 +1,121 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <HeadersExchange.h> +#include <ExchangeBinding.h> +#include <Value.h> +#include <QpidError.h> +#include <algorithm> + + +using namespace qpid::broker; +using namespace qpid::framing; +using namespace qpid::sys; + +// TODO aconway 2006-09-20: More efficient matching algorithm. +// The current search algorithm really sucks. +// Fieldtables are heavy, maybe use shared_ptr to do handle-body. + +using namespace qpid::broker; + +namespace { + const std::string all("all"); + const std::string any("any"); + const std::string x_match("x-match"); +} + +HeadersExchange::HeadersExchange(const string& _name) : Exchange(_name) { } + +void HeadersExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args){ + Mutex::ScopedLock locker(lock); + std::string what = args->getString("x-match"); + if (what != all && what != any) { + THROW_QPID_ERROR(PROTOCOL_ERROR, "Invalid x-match value binding to headers exchange."); + } + bindings.push_back(Binding(*args, queue)); + queue->bound(new ExchangeBinding(this, queue, routingKey, args)); +} + +void HeadersExchange::unbind(Queue::shared_ptr queue, const string& /*routingKey*/, const FieldTable* args){ + Mutex::ScopedLock locker(lock); + Bindings::iterator i = + std::find(bindings.begin(),bindings.end(), Binding(*args, queue)); + if (i != bindings.end()) bindings.erase(i); +} + + +void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* args){ + Mutex::ScopedLock locker(lock);; + for (Bindings::iterator i = bindings.begin(); i != bindings.end(); ++i) { + if (match(i->first, *args)) msg.deliverTo(i->second); + } +} + +HeadersExchange::~HeadersExchange() {} + +const std::string HeadersExchange::typeName("headers"); + +namespace +{ + + bool match_values(const Value& bind, const Value& msg) { + return dynamic_cast<const EmptyValue*>(&bind) || bind == msg; + } + +} + + +bool HeadersExchange::match(const FieldTable& bind, const FieldTable& msg) { + typedef FieldTable::ValueMap Map; + std::string what = bind.getString(x_match); + if (what == all) { + for (Map::const_iterator i = bind.getMap().begin(); + i != bind.getMap().end(); + ++i) + { + if (i->first != x_match) + { + Map::const_iterator j = msg.getMap().find(i->first); + if (j == msg.getMap().end()) return false; + if (!match_values(*(i->second), *(j->second))) return false; + } + } + return true; + } else if (what == any) { + for (Map::const_iterator i = bind.getMap().begin(); + i != bind.getMap().end(); + ++i) + { + if (i->first != x_match) + { + Map::const_iterator j = msg.getMap().find(i->first); + if (j != msg.getMap().end()) { + if (match_values(*(i->second), *(j->second))) return true; + } + } + } + return false; + } else { + return false; + } +} + + + diff --git a/qpid/cpp-0-9/lib/broker/HeadersExchange.h b/qpid/cpp-0-9/lib/broker/HeadersExchange.h new file mode 100644 index 0000000000..5e8da5ad85 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/HeadersExchange.h @@ -0,0 +1,65 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _HeadersExchange_ +#define _HeadersExchange_ + +#include <vector> +#include <BrokerExchange.h> +#include <FieldTable.h> +#include <BrokerMessage.h> +#include <sys/Monitor.h> +#include <BrokerQueue.h> + +namespace qpid { +namespace broker { + + +class HeadersExchange : public virtual Exchange { + typedef std::pair<qpid::framing::FieldTable, Queue::shared_ptr> Binding; + typedef std::vector<Binding> Bindings; + + Bindings bindings; + qpid::sys::Mutex lock; + + public: + static const std::string typeName; + + HeadersExchange(const string& name); + + virtual std::string getType(){ return typeName; } + + virtual void bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args); + + virtual void unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args); + + virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args); + + virtual ~HeadersExchange(); + + static bool match(const qpid::framing::FieldTable& bindArgs, const qpid::framing::FieldTable& msgArgs); +}; + + + +} +} + +#endif diff --git a/qpid/cpp-0-9/lib/broker/InMemoryContent.cpp b/qpid/cpp-0-9/lib/broker/InMemoryContent.cpp new file mode 100644 index 0000000000..3e4ac29486 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/InMemoryContent.cpp @@ -0,0 +1,73 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <InMemoryContent.h> +#include "AMQFrame.h" +#include "framing/ChannelAdapter.h" + +using namespace qpid::broker; +using namespace qpid::framing; +using boost::static_pointer_cast; + +void InMemoryContent::add(AMQContentBody::shared_ptr data) +{ + content.push_back(data); +} + +uint32_t InMemoryContent::size() +{ + int sum(0); + for (content_iterator i = content.begin(); i != content.end(); i++) { + sum += (*i)->size(); + } + return sum; +} + +// FIXME aconway 2007-02-01: Remove version parameter. +void InMemoryContent::send(ChannelAdapter& channel, uint32_t framesize) +{ + for (content_iterator i = content.begin(); i != content.end(); i++) { + if ((*i)->size() > framesize) { + uint32_t offset = 0; + for (int chunk = (*i)->size() / framesize; chunk > 0; chunk--) { + string data = (*i)->getData().substr(offset, framesize); + channel.send(new AMQContentBody(data)); + offset += framesize; + } + uint32_t remainder = (*i)->size() % framesize; + if (remainder) { + string data = (*i)->getData().substr(offset, remainder); + channel.send(new AMQContentBody(data)); + } + } else { + AMQBody::shared_ptr contentBody = + static_pointer_cast<AMQBody, AMQContentBody>(*i); + channel.send(contentBody); + } + } +} + +void InMemoryContent::encode(Buffer& buffer) +{ + for (content_iterator i = content.begin(); i != content.end(); i++) { + (*i)->encode(buffer); + } +} + diff --git a/qpid/cpp-0-9/lib/broker/InMemoryContent.h b/qpid/cpp-0-9/lib/broker/InMemoryContent.h new file mode 100644 index 0000000000..7a58ace3a7 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/InMemoryContent.h @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _InMemoryContent_ +#define _InMemoryContent_ + +#include <Content.h> +#include <vector> + + +namespace qpid { + namespace broker { + class InMemoryContent : public Content{ + typedef std::vector<qpid::framing::AMQContentBody::shared_ptr> content_list; + typedef content_list::iterator content_iterator; + + content_list content; + public: + void add(qpid::framing::AMQContentBody::shared_ptr data); + uint32_t size(); + void send(framing::ChannelAdapter&, uint32_t framesize); + void encode(qpid::framing::Buffer& buffer); + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/LazyLoadedContent.cpp b/qpid/cpp-0-9/lib/broker/LazyLoadedContent.cpp new file mode 100644 index 0000000000..131943b448 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/LazyLoadedContent.cpp @@ -0,0 +1,68 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <LazyLoadedContent.h> +#include "AMQFrame.h" +#include "framing/ChannelAdapter.h" + +using namespace qpid::broker; +using namespace qpid::framing; + +LazyLoadedContent::~LazyLoadedContent() +{ + store->destroy(msg); +} + +LazyLoadedContent::LazyLoadedContent(MessageStore* const _store, Message* const _msg, uint64_t _expectedSize) : + store(_store), msg(_msg), expectedSize(_expectedSize) {} + +void LazyLoadedContent::add(AMQContentBody::shared_ptr data) +{ + store->appendContent(msg, data->getData()); +} + +uint32_t LazyLoadedContent::size() +{ + return 0;//all content is written as soon as it is added +} + +void LazyLoadedContent::send(ChannelAdapter& channel, uint32_t framesize) +{ + if (expectedSize > framesize) { + for (uint64_t offset = 0; offset < expectedSize; offset += framesize) + { + uint64_t remaining = expectedSize - offset; + string data; + store->loadContent(msg, data, offset, + remaining > framesize ? framesize : remaining); + channel.send(new AMQContentBody(data)); + } + } else { + string data; + store->loadContent(msg, data, 0, expectedSize); + channel.send(new AMQContentBody(data)); + } +} + +void LazyLoadedContent::encode(Buffer&) +{ + //do nothing as all content is written as soon as it is added +} + diff --git a/qpid/cpp-0-9/lib/broker/LazyLoadedContent.h b/qpid/cpp-0-9/lib/broker/LazyLoadedContent.h new file mode 100644 index 0000000000..e000a4ef69 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/LazyLoadedContent.h @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _LazyLoadedContent_ +#define _LazyLoadedContent_ + +#include <Content.h> +#include <MessageStore.h> + +namespace qpid { + namespace broker { + class LazyLoadedContent : public Content{ + MessageStore* const store; + Message* const msg; + const uint64_t expectedSize; + public: + LazyLoadedContent( + MessageStore* const store, Message* const msg, + uint64_t expectedSize); + ~LazyLoadedContent(); + void add(qpid::framing::AMQContentBody::shared_ptr data); + uint32_t size(); + void send( + framing::ChannelAdapter&, + uint32_t framesize); + void encode(qpid::framing::Buffer& buffer); + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/Makefile.am b/qpid/cpp-0-9/lib/broker/Makefile.am new file mode 100644 index 0000000000..68649c2b28 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Makefile.am @@ -0,0 +1,96 @@ +AM_CXXFLAGS = $(WARNING_CFLAGS) +INCLUDES = \ + -I$(top_srcdir)/gen \ + -I$(top_srcdir)/lib/common \ + -I$(top_srcdir)/lib/common/sys \ + -I$(top_srcdir)/lib/common/framing \ + $(APR_CXXFLAGS) + +lib_LTLIBRARIES = libqpidbroker.la +libqpidbroker_la_LIBADD = ../common/libqpidcommon.la +libqpidbroker_la_LDFLAGS = -version-info $(LIBTOOL_VERSION_INFO_ARG) +libqpidbroker_la_SOURCES = \ + AccumulatedAck.cpp \ + AccumulatedAck.h \ + AutoDelete.cpp \ + AutoDelete.h \ + Binding.h \ + Broker.cpp \ + Broker.h \ + BrokerSingleton.cpp \ + BrokerSingleton.h \ + BrokerChannel.cpp \ + BrokerChannel.h \ + BrokerExchange.h \ + BrokerMessage.cpp \ + BrokerMessage.h \ + BrokerMessageMessage.cpp \ + BrokerMessageMessage.h \ + BrokerQueue.cpp \ + BrokerQueue.h \ + Configuration.cpp \ + Configuration.h \ + ConnectionToken.h \ + Consumer.h \ + Content.h \ + DeletingTxOp.cpp \ + DeletingTxOp.h \ + Deliverable.h \ + DeliverableMessage.cpp \ + DeliverableMessage.h \ + DeliveryRecord.cpp \ + DeliveryRecord.h \ + DirectExchange.cpp \ + DirectExchange.h \ + ExchangeBinding.cpp \ + ExchangeBinding.h \ + ExchangeRegistry.cpp \ + ExchangeRegistry.h \ + FanOutExchange.cpp \ + FanOutExchange.h \ + HeadersExchange.cpp \ + HeadersExchange.h \ + InMemoryContent.cpp \ + InMemoryContent.h \ + LazyLoadedContent.cpp \ + LazyLoadedContent.h \ + MessageBuilder.cpp \ + MessageBuilder.h \ + MessageStore.h \ + MessageStoreModule.cpp \ + MessageStoreModule.h \ + NameGenerator.cpp \ + NameGenerator.h \ + NullMessageStore.cpp \ + NullMessageStore.h \ + Prefetch.h \ + QueuePolicy.cpp \ + QueuePolicy.h \ + QueueRegistry.cpp \ + QueueRegistry.h \ + RecoveryManager.cpp \ + RecoveryManager.h \ + Reference.cpp \ + Reference.h \ + ConnectionFactory.cpp \ + ConnectionFactory.h \ + Connection.cpp \ + Connection.h \ + BrokerAdapter.cpp \ + BrokerAdapter.h \ + MessageHandlerImpl.cpp \ + MessageHandlerImpl.h \ + TopicExchange.cpp \ + TopicExchange.h \ + TransactionalStore.h \ + TxAck.cpp \ + TxAck.h \ + TxBuffer.cpp \ + TxBuffer.h \ + TxOp.h \ + TxPublish.cpp \ + TxPublish.h + + +# Force build during dist phase so help2man will work. +dist-hook: $(lib_LTLIBRARIES) diff --git a/qpid/cpp-0-9/lib/broker/MessageBuilder.cpp b/qpid/cpp-0-9/lib/broker/MessageBuilder.cpp new file mode 100644 index 0000000000..8bffaef50f --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/MessageBuilder.cpp @@ -0,0 +1,74 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <MessageBuilder.h> + +#include <InMemoryContent.h> +#include <LazyLoadedContent.h> + +using namespace qpid::broker; +using namespace qpid::framing; +using std::auto_ptr; + +MessageBuilder::MessageBuilder(CompletionHandler* _handler, + MessageStore* const _store, + uint64_t _stagingThreshold +) : + handler(_handler), + store(_store), + stagingThreshold(_stagingThreshold) +{} + +void MessageBuilder::route(){ + if (message->isComplete()) { + if (handler) handler->complete(message); + message.reset(); + } +} + +void MessageBuilder::initialise(Message::shared_ptr& msg){ + if(message.get()){ + THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Invalid message sequence: got publish before previous content was completed."); + } + message = msg; +} + +void MessageBuilder::setHeader(AMQHeaderBody::shared_ptr& header){ + if(!message.get()){ + THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Invalid message sequence: got header before publish."); + } + message->setHeader(header); + if (stagingThreshold && header->getContentSize() >= stagingThreshold) { + store->stage(message.get()); + message->releaseContent(store); + } else { + auto_ptr<Content> content(new InMemoryContent()); + message->setContent(content); + } + route(); +} + +void MessageBuilder::addContent(AMQContentBody::shared_ptr& content){ + if(!message.get()){ + THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Invalid message sequence: got content before publish."); + } + message->addContent(content); + route(); +} diff --git a/qpid/cpp-0-9/lib/broker/MessageBuilder.h b/qpid/cpp-0-9/lib/broker/MessageBuilder.h new file mode 100644 index 0000000000..30834e1075 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/MessageBuilder.h @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _MessageBuilder_ +#define _MessageBuilder_ + +#include <memory> +#include <QpidError.h> +#include <BrokerExchange.h> +#include <BrokerMessage.h> +#include <MessageStore.h> +#include <AMQContentBody.h> +#include <AMQHeaderBody.h> +#include <BasicPublishBody.h> +#include "CompletionHandler.h" + +namespace qpid { + namespace broker { + class MessageBuilder{ + public: + MessageBuilder(CompletionHandler* _handler, + MessageStore* const store = 0, + uint64_t stagingThreshold = 0); + void initialise(Message::shared_ptr& msg); + void setHeader(framing::AMQHeaderBody::shared_ptr& header); + void addContent(framing::AMQContentBody::shared_ptr& content); + Message::shared_ptr getMessage() { return message; } + private: + Message::shared_ptr message; + CompletionHandler* handler; + MessageStore* const store; + const uint64_t stagingThreshold; + + void route(); + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/MessageHandlerImpl.cpp b/qpid/cpp-0-9/lib/broker/MessageHandlerImpl.cpp new file mode 100644 index 0000000000..fa7c10f26c --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/MessageHandlerImpl.cpp @@ -0,0 +1,243 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "QpidError.h" +#include "MessageHandlerImpl.h" +#include "BrokerChannel.h" +#include "FramingContent.h" +#include "Connection.h" +#include "Broker.h" +#include "BrokerMessageMessage.h" +#include "MessageAppendBody.h" +#include "MessageTransferBody.h" +#include "BrokerAdapter.h" + +namespace qpid { +namespace broker { + +using namespace framing; + +MessageHandlerImpl::MessageHandlerImpl(CoreRefs& parent) + : HandlerImplType(parent) {} + +// +// Message class method handlers +// + +void +MessageHandlerImpl::cancel(const MethodContext& context, + const string& destination ) +{ + channel.cancel(destination); + client.ok(context.getRequestId()); +} + +void +MessageHandlerImpl::open(const MethodContext& context, + const string& reference) +{ + references.open(reference); + client.ok(context.getRequestId()); +} + +void +MessageHandlerImpl::append(const MethodContext& context, + const string& reference, + const string& /*bytes*/ ) +{ + references.get(reference)->append( + boost::shared_polymorphic_downcast<MessageAppendBody>( + context.methodBody)); + client.ok(context.getRequestId()); +} + +void +MessageHandlerImpl::close(const MethodContext& context, + const string& reference) +{ + Reference::shared_ptr ref = references.get(reference); + client.ok(context.getRequestId()); + + // Send any transfer messages to their correct exchanges and okay them + const Reference::Messages& msgs = ref->getMessages(); + for (Reference::Messages::const_iterator m = msgs.begin(); m != msgs.end(); ++m) { + channel.handleInlineTransfer(*m); + client.ok((*m)->getRequestId()); + } + ref->close(); +} + +void +MessageHandlerImpl::checkpoint(const MethodContext& context, + const string& /*reference*/, + const string& /*identifier*/ ) +{ + // Initial implementation (which is conforming) is to do nothing here + // and return offset zero for the resume + client.ok(context.getRequestId()); +} + +void +MessageHandlerImpl::resume(const MethodContext& context, + const string& reference, + const string& /*identifier*/ ) +{ + // Initial (null) implementation + // open reference and return 0 offset + references.open(reference); + client.offset(0, context.getRequestId()); +} + +void +MessageHandlerImpl::offset(const MethodContext&, + uint64_t /*value*/ ) +{ + // Shouldn't ever receive this as it is reponse to resume + // which is never sent + // TODO astitcher 2007-02-16 What is the correct exception to throw here? + THROW_QPID_ERROR(INTERNAL_ERROR, "impossible"); +} + +void +MessageHandlerImpl::consume(const MethodContext& context, + uint16_t /*ticket*/, + const string& queueName, + const string& destination, + bool noLocal, + bool noAck, + bool exclusive, + const framing::FieldTable& filter ) +{ + Queue::shared_ptr queue = connection.getQueue(queueName, channel.getId()); + if(!destination.empty() && channel.exists(destination)) + throw ConnectionException(530, "Consumer tags must be unique"); + string tag = destination; + channel.consume( + tag, queue, !noAck, exclusive, + noLocal ? &connection : 0, &filter); + client.ok(context.getRequestId()); + // Dispatch messages as there is now a consumer. + queue->dispatch(); +} + +void +MessageHandlerImpl::get( const MethodContext& context, + uint16_t /*ticket*/, + const string& queueName, + const string& destination, + bool noAck ) +{ + Queue::shared_ptr queue = + connection.getQueue(queueName, context.channel->getId()); + + if(channel.get(queue, destination, !noAck)) + client.ok(context.getRequestId()); + else + client.empty(context.getRequestId()); +} + +void +MessageHandlerImpl::empty( const MethodContext& ) +{ + // Shouldn't ever receive this as it is a response to get + // which is never sent + // TODO astitcher 2007-02-09 What is the correct exception to throw here? + THROW_QPID_ERROR(INTERNAL_ERROR, "Impossible"); +} + +void +MessageHandlerImpl::ok(const MethodContext& /*context*/) +{ + channel.ack(); +} + +void +MessageHandlerImpl::qos(const MethodContext& context, + uint32_t prefetchSize, + uint16_t prefetchCount, + bool /*global*/ ) +{ + //TODO: handle global + channel.setPrefetchSize(prefetchSize); + channel.setPrefetchCount(prefetchCount); + client.ok(context.getRequestId()); +} + +void +MessageHandlerImpl::recover(const MethodContext& context, + bool requeue) +{ + channel.recover(requeue); + client.ok(context.getRequestId()); +} + +void +MessageHandlerImpl::reject(const MethodContext& /*context*/, + uint16_t /*code*/, + const string& /*text*/ ) +{ + channel.ack(); + // channel.requeue(); +} + +void +MessageHandlerImpl::transfer(const MethodContext& context, + uint16_t /*ticket*/, + const string& /* destination */, + bool /*redelivered*/, + bool /*immediate*/, + uint64_t /*ttl*/, + uint8_t /*priority*/, + uint64_t /*timestamp*/, + uint8_t /*deliveryMode*/, + uint64_t /*expiration*/, + const string& /*exchangeName*/, + const string& /*routingKey*/, + const string& /*messageId*/, + const string& /*correlationId*/, + const string& /*replyTo*/, + const string& /*contentType*/, + const string& /*contentEncoding*/, + const string& /*userId*/, + const string& /*appId*/, + const string& /*transactionId*/, + const string& /*securityToken*/, + const framing::FieldTable& /*applicationHeaders*/, + const framing::Content& body, + bool /*mandatory*/) +{ + MessageTransferBody::shared_ptr transfer( + boost::shared_polymorphic_downcast<MessageTransferBody>( + context.methodBody)); + RequestId requestId = context.getRequestId(); + + if (body.isInline()) { + MessageMessage::shared_ptr message( + new MessageMessage(&connection, requestId, transfer)); + channel.handleInlineTransfer(message); + client.ok(requestId); + } else { + Reference::shared_ptr ref(references.get(body.getValue())); + MessageMessage::shared_ptr message( + new MessageMessage(&connection, requestId, transfer, ref)); + ref->addMessage(message); + } +} + + +}} // namespace qpid::broker diff --git a/qpid/cpp-0-9/lib/broker/MessageHandlerImpl.h b/qpid/cpp-0-9/lib/broker/MessageHandlerImpl.h new file mode 100644 index 0000000000..872d429d5c --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/MessageHandlerImpl.h @@ -0,0 +1,130 @@ +#ifndef _broker_MessageHandlerImpl_h +#define _broker_MessageHandlerImpl_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <memory> + +#include "AMQP_ServerOperations.h" +#include "AMQP_ClientProxy.h" +#include "Reference.h" +#include "HandlerImpl.h" + +namespace qpid { +namespace broker { + +class Connection; +class Broker; +class MessageMessage; + +class MessageHandlerImpl : + public framing::AMQP_ServerOperations::MessageHandler, + public HandlerImpl<framing::AMQP_ClientProxy::Message> +{ + public: + MessageHandlerImpl(CoreRefs& parent); + + void append(const framing::MethodContext&, + const std::string& reference, + const std::string& bytes ); + + void cancel(const framing::MethodContext&, + const std::string& destination ); + + void checkpoint(const framing::MethodContext&, + const std::string& reference, + const std::string& identifier ); + + void close(const framing::MethodContext&, + const std::string& reference ); + + void consume(const framing::MethodContext&, + uint16_t ticket, + const std::string& queue, + const std::string& destination, + bool noLocal, + bool noAck, + bool exclusive, + const framing::FieldTable& filter ); + + void empty( const framing::MethodContext& ); + + void get(const framing::MethodContext&, + uint16_t ticket, + const std::string& queue, + const std::string& destination, + bool noAck ); + + void offset(const framing::MethodContext&, + uint64_t value ); + + void ok( const framing::MethodContext& ); + + void open(const framing::MethodContext&, + const std::string& reference ); + + void qos(const framing::MethodContext&, + uint32_t prefetchSize, + uint16_t prefetchCount, + bool global ); + + void recover(const framing::MethodContext&, + bool requeue ); + + void reject(const framing::MethodContext&, + uint16_t code, + const std::string& text ); + + void resume(const framing::MethodContext&, + const std::string& reference, + const std::string& identifier ); + + void transfer(const framing::MethodContext&, + uint16_t ticket, + const std::string& destination, + bool redelivered, + bool immediate, + uint64_t ttl, + uint8_t priority, + uint64_t timestamp, + uint8_t deliveryMode, + uint64_t expiration, + const std::string& exchange, + const std::string& routingKey, + const std::string& messageId, + const std::string& correlationId, + const std::string& replyTo, + const std::string& contentType, + const std::string& contentEncoding, + const std::string& userId, + const std::string& appId, + const std::string& transactionId, + const std::string& securityToken, + const framing::FieldTable& applicationHeaders, + const framing::Content& body, + bool mandatory ); + private: + ReferenceRegistry references; +}; + +}} // namespace qpid::broker + + + +#endif /*!_broker_MessageHandlerImpl_h*/ diff --git a/qpid/cpp-0-9/lib/broker/MessageStore.h b/qpid/cpp-0-9/lib/broker/MessageStore.h new file mode 100644 index 0000000000..9e38408886 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/MessageStore.h @@ -0,0 +1,140 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _MessageStore_ +#define _MessageStore_ + +#include <BrokerMessage.h> +#include <FieldTable.h> +#include <RecoveryManager.h> +#include <TransactionalStore.h> + +namespace qpid { + namespace broker { + struct MessageStoreSettings + { + /** + * Messages whose content length is larger than this value + * will be staged (i.e. will have thier data written to + * disk as it arrives) and will load their data lazily. On + * recovery therefore, only the headers should be loaded. + */ + uint64_t stagingThreshold; + }; + /** + * An abstraction of the persistent storage for messages. (In + * all methods, any pointers/references to queues or messages + * are valid only for the duration of the call). + */ + class MessageStore : public TransactionalStore{ + public: + /** + * Record the existance of a durable queue + */ + virtual void create(const Queue& queue, const qpid::framing::FieldTable& settings) = 0; + /** + * Destroy a durable queue + */ + virtual void destroy(const Queue& queue) = 0; + + /** + * Request recovery of queue and message state from store + */ + virtual void recover(RecoveryManager& queues, const MessageStoreSettings* const settings = 0) = 0; + + /** + * Stores a messages before it has been enqueued + * (enqueueing automatically stores the message so this is + * only required if storage is required prior to that + * point). If the message has not yet been stored it will + * store the headers as well as any content passed in. A + * persistence id will be set on the message which can be + * used to load the content or to append to it. + */ + virtual void stage(Message* const msg) = 0; + + /** + * Destroys a previously staged message. This only needs + * to be called if the message is never enqueued. (Once + * enqueued, deletion will be automatic when the message + * is dequeued from all queues it was enqueued onto). + */ + virtual void destroy(Message* const msg) = 0; + + /** + * Appends content to a previously staged message + */ + virtual void appendContent(Message* const msg, const std::string& data) = 0; + + /** + * Loads (a section) of content data for the specified + * message (previously stored through a call to stage or + * enqueue) into data. The offset refers to the content + * only (i.e. an offset of 0 implies that the start of the + * content should be loaded, not the headers or related + * meta-data). + */ + virtual void loadContent(Message* const msg, std::string& data, uint64_t offset, uint32_t length) = 0; + + /** + * Enqueues a message, storing the message if it has not + * been previously stored and recording that the given + * message is on the given queue. + * + * @param msg the message to enqueue + * @param queue the name of the queue onto which it is to be enqueued + * @param xid (a pointer to) an identifier of the + * distributed transaction in which the operation takes + * place or null for 'local' transactions + */ + virtual void enqueue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const std::string * const xid) = 0; + /** + * Dequeues a message, recording that the given message is + * no longer on the given queue and deleting the message + * if it is no longer on any other queue. + * + * @param msg the message to dequeue + * @param queue the name of th queue from which it is to be dequeued + * @param xid (a pointer to) an identifier of the + * distributed transaction in which the operation takes + * place or null for 'local' transactions + */ + virtual void dequeue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const std::string * const xid) = 0; + + /** + * Treat all enqueue/dequeues where this xid was specified as being prepared. + */ + virtual void prepared(const std::string * const xid) = 0; + /** + * Treat all enqueue/dequeues where this xid was specified as being committed. + */ + virtual void committed(const std::string * const xid) = 0; + /** + * Treat all enqueue/dequeues where this xid was specified as being aborted. + */ + virtual void aborted(const std::string * const xid) = 0; + + virtual ~MessageStore(){} + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/MessageStoreModule.cpp b/qpid/cpp-0-9/lib/broker/MessageStoreModule.cpp new file mode 100644 index 0000000000..676e86f84a --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/MessageStoreModule.cpp @@ -0,0 +1,104 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <MessageStoreModule.h> +#include <iostream> + +using namespace qpid::broker; + +MessageStoreModule::MessageStoreModule(const std::string& name) : store(name) +{ +} + +void MessageStoreModule::create(const Queue& queue, const qpid::framing::FieldTable& settings) +{ + store->create(queue, settings); +} + +void MessageStoreModule::destroy(const Queue& queue) +{ + store->destroy(queue); +} + +void MessageStoreModule::recover(RecoveryManager& registry, const MessageStoreSettings* const settings) +{ + store->recover(registry, settings); +} + +void MessageStoreModule::stage(Message* const msg) +{ + store->stage(msg); +} + +void MessageStoreModule::destroy(Message* const msg) +{ + store->destroy(msg); +} + +void MessageStoreModule::appendContent(Message* const msg, const std::string& data) +{ + store->appendContent(msg, data); +} + +void MessageStoreModule::loadContent(Message* const msg, string& data, uint64_t offset, uint32_t length) +{ + store->loadContent(msg, data, offset, length); +} + +void MessageStoreModule::enqueue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const string * const xid) +{ + store->enqueue(ctxt, msg, queue, xid); +} + +void MessageStoreModule::dequeue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const string * const xid) +{ + store->dequeue(ctxt, msg, queue, xid); +} + +void MessageStoreModule::prepared(const string * const xid) +{ + store->prepared(xid); +} + +void MessageStoreModule::committed(const string * const xid) +{ + store->committed(xid); +} + +void MessageStoreModule::aborted(const string * const xid) +{ + store->aborted(xid); +} + +std::auto_ptr<TransactionContext> MessageStoreModule::begin() +{ + return store->begin(); +} + +void MessageStoreModule::commit(TransactionContext* ctxt) +{ + store->commit(ctxt); +} + +void MessageStoreModule::abort(TransactionContext* ctxt) +{ + store->abort(ctxt); +} diff --git a/qpid/cpp-0-9/lib/broker/MessageStoreModule.h b/qpid/cpp-0-9/lib/broker/MessageStoreModule.h new file mode 100644 index 0000000000..27fedbf635 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/MessageStoreModule.h @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _MessageStoreModule_ +#define _MessageStoreModule_ + +#include <BrokerMessage.h> +#include <MessageStore.h> +#include <BrokerQueue.h> +#include <RecoveryManager.h> +#include <sys/Module.h> + +namespace qpid { + namespace broker { + /** + * A null implementation of the MessageStore interface + */ + class MessageStoreModule : public MessageStore{ + qpid::sys::Module<MessageStore> store; + public: + MessageStoreModule(const std::string& name); + void create(const Queue& queue, const qpid::framing::FieldTable& settings); + void destroy(const Queue& queue); + void recover(RecoveryManager& queues, const MessageStoreSettings* const settings = 0); + void stage(Message* const msg); + void destroy(Message* const msg); + void appendContent(Message* const msg, const std::string& data); + void loadContent(Message* const msg, std::string& data, uint64_t offset, uint32_t length); + void enqueue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const string * const xid); + void dequeue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const string * const xid); + void prepared(const std::string * const xid); + void committed(const std::string * const xid); + void aborted(const std::string * const xid); + std::auto_ptr<TransactionContext> begin(); + void commit(TransactionContext* ctxt); + void abort(TransactionContext* ctxt); + ~MessageStoreModule(){} + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/NameGenerator.cpp b/qpid/cpp-0-9/lib/broker/NameGenerator.cpp new file mode 100644 index 0000000000..3f281859fa --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/NameGenerator.cpp @@ -0,0 +1,32 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <NameGenerator.h> +#include <sstream> + +using namespace qpid::broker; + +NameGenerator::NameGenerator(const std::string& _base) : base(_base), counter(1) {} + +std::string NameGenerator::generate(){ + std::stringstream ss; + ss << base << counter++; + return ss.str(); +} diff --git a/qpid/cpp-0-9/lib/broker/NameGenerator.h b/qpid/cpp-0-9/lib/broker/NameGenerator.h new file mode 100644 index 0000000000..b2dbbdfb69 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/NameGenerator.h @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _NameGenerator_ +#define _NameGenerator_ + +#include <BrokerMessage.h> + +namespace qpid { + namespace broker { + class NameGenerator{ + const std::string base; + unsigned int counter; + public: + NameGenerator(const std::string& base); + std::string generate(); + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/NullMessageStore.cpp b/qpid/cpp-0-9/lib/broker/NullMessageStore.cpp new file mode 100644 index 0000000000..bcb15c2ae0 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/NullMessageStore.cpp @@ -0,0 +1,104 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <NullMessageStore.h> + +#include <BrokerQueue.h> +#include <RecoveryManager.h> + +#include <iostream> + +using namespace qpid::broker; + +NullMessageStore::NullMessageStore(bool _warn) : warn(_warn){} + +void NullMessageStore::create(const Queue& queue, const qpid::framing::FieldTable&) +{ + if (warn) std::cout << "WARNING: Can't create durable queue '" << queue.getName() << "'. Persistence not enabled." << std::endl; +} + +void NullMessageStore::destroy(const Queue& queue) +{ + if (warn) std::cout << "WARNING: Can't destroy durable queue '" << queue.getName() << "'. Persistence not enabled." << std::endl; +} + +void NullMessageStore::recover(RecoveryManager&, const MessageStoreSettings* const) +{ + if (warn) std::cout << "WARNING: Persistence not enabled, no recovery of queues or messages." << std::endl; +} + +void NullMessageStore::stage(Message* const) +{ + if (warn) std::cout << "WARNING: Can't stage message. Persistence not enabled." << std::endl; +} + +void NullMessageStore::destroy(Message* const) +{ + if (warn) std::cout << "WARNING: No need to destroy staged message. Persistence not enabled." << std::endl; +} + +void NullMessageStore::appendContent(Message* const, const string&) +{ + if (warn) std::cout << "WARNING: Can't append content. Persistence not enabled." << std::endl; +} + +void NullMessageStore::loadContent(Message* const, string&, uint64_t, uint32_t) +{ + if (warn) std::cout << "WARNING: Can't load content. Persistence not enabled." << std::endl; +} + +void NullMessageStore::enqueue(TransactionContext*, Message* const, const Queue& queue, const string * const) +{ + if (warn) std::cout << "WARNING: Can't enqueue message onto '" << queue.getName() << "'. Persistence not enabled." << std::endl; +} + +void NullMessageStore::dequeue(TransactionContext*, Message* const, const Queue& queue, const string * const) +{ + if (warn) std::cout << "WARNING: Can't dequeue message from '" << queue.getName() << "'. Persistence not enabled." << std::endl; +} + +void NullMessageStore::prepared(const string * const) +{ + if (warn) std::cout << "WARNING: Persistence not enabled." << std::endl; +} + +void NullMessageStore::committed(const string * const) +{ + if (warn) std::cout << "WARNING: Persistence not enabled." << std::endl; +} + +void NullMessageStore::aborted(const string * const) +{ + if (warn) std::cout << "WARNING: Persistence not enabled." << std::endl; +} + +std::auto_ptr<TransactionContext> NullMessageStore::begin() +{ + return std::auto_ptr<TransactionContext>(); +} + +void NullMessageStore::commit(TransactionContext*) +{ +} + +void NullMessageStore::abort(TransactionContext*) +{ +} diff --git a/qpid/cpp-0-9/lib/broker/NullMessageStore.h b/qpid/cpp-0-9/lib/broker/NullMessageStore.h new file mode 100644 index 0000000000..705f18ab43 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/NullMessageStore.h @@ -0,0 +1,59 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _NullMessageStore_ +#define _NullMessageStore_ + +#include <BrokerMessage.h> +#include <MessageStore.h> +#include <BrokerQueue.h> + +namespace qpid { + namespace broker { + + /** + * A null implementation of the MessageStore interface + */ + class NullMessageStore : public MessageStore{ + const bool warn; + public: + NullMessageStore(bool warn = false); + virtual void create(const Queue& queue, const qpid::framing::FieldTable& settings); + virtual void destroy(const Queue& queue); + virtual void recover(RecoveryManager& queues, const MessageStoreSettings* const settings = 0); + virtual void stage(Message* const msg); + virtual void destroy(Message* const msg); + virtual void appendContent(Message* const msg, const std::string& data); + virtual void loadContent(Message* const msg, std::string& data, uint64_t offset, uint32_t length); + virtual void enqueue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const string * const xid); + virtual void dequeue(TransactionContext* ctxt, Message* const msg, const Queue& queue, const string * const xid); + virtual void prepared(const std::string * const xid); + virtual void committed(const std::string * const xid); + virtual void aborted(const std::string * const xid); + virtual std::auto_ptr<TransactionContext> begin(); + virtual void commit(TransactionContext* ctxt); + virtual void abort(TransactionContext* ctxt); + ~NullMessageStore(){} + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/Prefetch.h b/qpid/cpp-0-9/lib/broker/Prefetch.h new file mode 100644 index 0000000000..b6d4026c3f --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Prefetch.h @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _Prefetch_ +#define _Prefetch_ + +#include <amqp_types.h> + +namespace qpid { + namespace broker { + /** + * Count and total size of asynchronously delivered + * (i.e. pushed) messages that have acks outstanding. + */ + struct Prefetch{ + uint32_t size; + uint16_t count; + + void reset() { size = 0; count = 0; } + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/QueuePolicy.cpp b/qpid/cpp-0-9/lib/broker/QueuePolicy.cpp new file mode 100644 index 0000000000..94b86f2bbb --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/QueuePolicy.cpp @@ -0,0 +1,69 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <QueuePolicy.h> + +using namespace qpid::broker; +using namespace qpid::framing; + +QueuePolicy::QueuePolicy(uint32_t _maxCount, uint64_t _maxSize) : + maxCount(_maxCount), maxSize(_maxSize), count(0), size(0) {} + +QueuePolicy::QueuePolicy(const FieldTable& settings) : + maxCount(getInt(settings, maxCountKey, 0)), + maxSize(getInt(settings, maxSizeKey, 0)), count(0), size(0) {} + +void QueuePolicy::enqueued(uint64_t _size) +{ + if (maxCount) count++; + if (maxSize) size += _size; +} + +void QueuePolicy::dequeued(uint64_t _size) +{ + if (maxCount) count--; + if (maxSize) size -= _size; +} + +bool QueuePolicy::limitExceeded() +{ + return (maxSize && size > maxSize) || (maxCount && count > maxCount); +} + +void QueuePolicy::update(FieldTable& settings) +{ + if (maxCount) settings.setInt(maxCountKey, maxCount); + if (maxSize) settings.setInt(maxSizeKey, maxSize); +} + + +int QueuePolicy::getInt(const FieldTable& settings, const std::string& key, int defaultValue) +{ + //Note: currently field table only contain signed 32 bit ints, which + // restricts the values that can be set on the queue policy. + try { + return settings.getInt(key); + } catch (FieldNotFoundException& ignore) { + return defaultValue; + } +} + +const std::string QueuePolicy::maxCountKey("qpid.max_count"); +const std::string QueuePolicy::maxSizeKey("qpid.max_size"); diff --git a/qpid/cpp-0-9/lib/broker/QueuePolicy.h b/qpid/cpp-0-9/lib/broker/QueuePolicy.h new file mode 100644 index 0000000000..e7688f3e67 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/QueuePolicy.h @@ -0,0 +1,54 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _QueuePolicy_ +#define _QueuePolicy_ + +#include <FieldTable.h> + +namespace qpid { + namespace broker { + class QueuePolicy + { + static const std::string maxCountKey; + static const std::string maxSizeKey; + + const uint32_t maxCount; + const uint64_t maxSize; + uint32_t count; + uint64_t size; + + static int getInt(const qpid::framing::FieldTable& settings, const std::string& key, int defaultValue); + + public: + QueuePolicy(uint32_t maxCount, uint64_t maxSize); + QueuePolicy(const qpid::framing::FieldTable& settings); + void enqueued(uint64_t size); + void dequeued(uint64_t size); + void update(qpid::framing::FieldTable& settings); + bool limitExceeded(); + uint32_t getMaxCount() const { return maxCount; } + uint64_t getMaxSize() const { return maxSize; } + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/QueueRegistry.cpp b/qpid/cpp-0-9/lib/broker/QueueRegistry.cpp new file mode 100644 index 0000000000..d33cd09840 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/QueueRegistry.cpp @@ -0,0 +1,78 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <QueueRegistry.h> +#include <sstream> +#include <assert.h> + +using namespace qpid::broker; +using namespace qpid::sys; + +QueueRegistry::QueueRegistry(MessageStore* const _store) : counter(1), store(_store){} + +QueueRegistry::~QueueRegistry(){} + +std::pair<Queue::shared_ptr, bool> +QueueRegistry::declare(const string& declareName, bool durable, + uint32_t autoDelete, const ConnectionToken* owner) +{ + Mutex::ScopedLock locker(lock); + string name = declareName.empty() ? generateName() : declareName; + assert(!name.empty()); + QueueMap::iterator i = queues.find(name); + if (i == queues.end()) { + Queue::shared_ptr queue(new Queue(name, autoDelete, durable ? store : 0, owner)); + queues[name] = queue; + return std::pair<Queue::shared_ptr, bool>(queue, true); + } else { + return std::pair<Queue::shared_ptr, bool>(i->second, false); + } +} + +void QueueRegistry::destroy(const string& name){ + Mutex::ScopedLock locker(lock); + queues.erase(name); +} + +Queue::shared_ptr QueueRegistry::find(const string& name){ + Mutex::ScopedLock locker(lock); + QueueMap::iterator i = queues.find(name); + if (i == queues.end()) { + return Queue::shared_ptr(); + } else { + return i->second; + } +} + +string QueueRegistry::generateName(){ + string name; + do { + std::stringstream ss; + ss << "tmp_" << counter++; + name = ss.str(); + // Thread safety: Private function, only called with lock held + // so this is OK. + } while(queues.find(name) != queues.end()); + return name; +} + +MessageStore* const QueueRegistry::getStore() const { + return store; +} diff --git a/qpid/cpp-0-9/lib/broker/QueueRegistry.h b/qpid/cpp-0-9/lib/broker/QueueRegistry.h new file mode 100644 index 0000000000..079034359e --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/QueueRegistry.h @@ -0,0 +1,96 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _QueueRegistry_ +#define _QueueRegistry_ + +#include <map> +#include <sys/Monitor.h> +#include <BrokerQueue.h> + +namespace qpid { +namespace broker { + +/** + * A registry of queues indexed by queue name. + * + * Queues are reference counted using shared_ptr to ensure that they + * are deleted when and only when they are no longer in use. + * + */ +class QueueRegistry{ + + public: + QueueRegistry(MessageStore* const store = 0); + ~QueueRegistry(); + + /** + * Declare a queue. + * + * @return The queue and a boolean flag which is true if the queue + * was created by this declare call false if it already existed. + */ + std::pair<Queue::shared_ptr, bool> declare(const string& name, bool durable = false, uint32_t autodelete = 0, + const ConnectionToken* const owner = 0); + + /** + * Destroy the named queue. + * + * Note: if the queue is in use it is not actually destroyed until + * all shared_ptrs to it are destroyed. During that time it is + * possible that a new queue with the same name may be + * created. This should not create any problems as the new and + * old queues exist independently. The registry has + * forgotten the old queue so there can be no confusion for + * subsequent calls to find or declare with the same name. + * + */ + void destroy(const string& name); + + /** + * Find the named queue. Return 0 if not found. + */ + Queue::shared_ptr find(const string& name); + + /** + * Generate unique queue name. + */ + string generateName(); + + /** + * Return the message store used. + */ + MessageStore* const getStore() const; + + + private: + typedef std::map<string, Queue::shared_ptr> QueueMap; + QueueMap queues; + qpid::sys::Mutex lock; + int counter; + MessageStore* const store; +}; + + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/RecoveryManager.cpp b/qpid/cpp-0-9/lib/broker/RecoveryManager.cpp new file mode 100644 index 0000000000..6548e6a24f --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/RecoveryManager.cpp @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <RecoveryManager.h> + +using namespace qpid::broker; + +RecoveryManager::RecoveryManager(QueueRegistry& _queues, ExchangeRegistry& _exchanges) : queues(_queues), exchanges(_exchanges) {} + +RecoveryManager::~RecoveryManager() {} + +Queue::shared_ptr RecoveryManager::recoverQueue(const string& name) +{ + std::pair<Queue::shared_ptr, bool> result = queues.declare(name, true); + try { + Exchange::shared_ptr exchange = exchanges.getDefault(); + if (exchange) { + exchange->bind(result.first, result.first->getName(), 0); + } + } catch (ChannelException& e) { + //assume no default exchange has been declared + } + return result.first; +} + +Exchange::shared_ptr RecoveryManager::recoverExchange(const string& name, const string& type) +{ + return exchanges.declare(name, type).first; +} diff --git a/qpid/cpp-0-9/lib/broker/RecoveryManager.h b/qpid/cpp-0-9/lib/broker/RecoveryManager.h new file mode 100644 index 0000000000..d4e4cff3fd --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/RecoveryManager.h @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _RecoveryManager_ +#define _RecoveryManager_ + +#include <ExchangeRegistry.h> +#include <QueueRegistry.h> + +namespace qpid { +namespace broker { + + class RecoveryManager{ + QueueRegistry& queues; + ExchangeRegistry& exchanges; + public: + RecoveryManager(QueueRegistry& queues, ExchangeRegistry& exchanges); + ~RecoveryManager(); + Queue::shared_ptr recoverQueue(const std::string& name); + Exchange::shared_ptr recoverExchange(const std::string& name, const std::string& type); + }; + + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/Reference.cpp b/qpid/cpp-0-9/lib/broker/Reference.cpp new file mode 100644 index 0000000000..c4c33e6363 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Reference.cpp @@ -0,0 +1,54 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <boost/bind.hpp> +#include "Reference.h" +#include "BrokerMessageMessage.h" +#include "QpidError.h" +#include "MessageAppendBody.h" +#include "CompletionHandler.h" + +namespace qpid { +namespace broker { + +Reference::shared_ptr ReferenceRegistry::open(const Reference::Id& id) { + ReferenceMap::iterator i = references.find(id); + // TODO aconway 2007-02-05: should we throw Channel or Connection + // exceptions here? + if (i != references.end()) + throw ConnectionException(503, "Attempt to re-open reference " +id); + return references[id] = Reference::shared_ptr(new Reference(id, this)); +} + +Reference::shared_ptr ReferenceRegistry::get(const Reference::Id& id) { + ReferenceMap::iterator i = references.find(id); + if (i == references.end()) + throw ConnectionException(503, "Attempt to use non-existent reference "+id); + return i->second; +} + +void Reference::append(AppendPtr ptr) { + appends.push_back(ptr); + size += ptr->getBytes().length(); +} + +void Reference::close() { + registry->references.erase(getId()); +} + +}} // namespace qpid::broker diff --git a/qpid/cpp-0-9/lib/broker/Reference.h b/qpid/cpp-0-9/lib/broker/Reference.h new file mode 100644 index 0000000000..e453645a54 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/Reference.h @@ -0,0 +1,111 @@ +#ifndef _broker_Reference_h +#define _broker_Reference_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <string> +#include <vector> +#include <map> +#include <boost/shared_ptr.hpp> +#include <boost/range.hpp> + +namespace qpid { + +namespace framing { +class MessageAppendBody; +} + +namespace broker { + +class MessageMessage; +class ReferenceRegistry; + +/** + * A reference is an accumulation point for data in a multi-frame + * message. A reference can be used by multiple transfer commands to + * create multiple messages, so the reference tracks which commands + * are using it. When the reference is closed, all the associated + * transfers are completed. + * + * THREAD UNSAFE: per-channel resource, access to channels is + * serialized. + */ +class Reference +{ + public: + typedef std::string Id; + typedef boost::shared_ptr<Reference> shared_ptr; + typedef boost::shared_ptr<MessageMessage> MessagePtr; + typedef std::vector<MessagePtr> Messages; + typedef boost::shared_ptr<framing::MessageAppendBody> AppendPtr; + typedef std::vector<AppendPtr> Appends; + + Reference(const Id& id_=Id(), ReferenceRegistry* reg=0) + : id(id_), size(0), registry(reg) {} + + const std::string& getId() const { return id; } + uint64_t getSize() const { return size; } + + /** Add a message to be completed with this reference */ + void addMessage(MessagePtr message) { messages.push_back(message); } + + /** Append more data to the reference */ + void append(AppendPtr ptr); + + /** Close the reference, complete each associated message */ + void close(); + + const Appends& getAppends() const { return appends; } + const Messages& getMessages() const { return messages; } + + private: + Id id; + uint64_t size; + ReferenceRegistry* registry; + Messages messages; + Appends appends; +}; + + +/** + * A registry/factory for references. + * + * THREAD UNSAFE: per-channel resource, access to channels is + * serialized. + */ +class ReferenceRegistry { + public: + ReferenceRegistry() {}; + Reference::shared_ptr open(const Reference::Id& id); + Reference::shared_ptr get(const Reference::Id& id); + + private: + typedef std::map<Reference::Id, Reference::shared_ptr> ReferenceMap; + ReferenceMap references; + + // Reference calls references.erase(). + friend class Reference; +}; + + +}} // namespace qpid::broker + + + +#endif /*!_broker_Reference_h*/ diff --git a/qpid/cpp-0-9/lib/broker/TopicExchange.cpp b/qpid/cpp-0-9/lib/broker/TopicExchange.cpp new file mode 100644 index 0000000000..3ebb3c8c56 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/TopicExchange.cpp @@ -0,0 +1,156 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <TopicExchange.h> +#include <ExchangeBinding.h> +#include <algorithm> + +using namespace qpid::broker; +using namespace qpid::framing; +using namespace qpid::sys; + +// TODO aconway 2006-09-20: More efficient matching algorithm. +// Areas for improvement: +// - excessive string copying: should be 0 copy, match from original buffer. +// - match/lookup: use descision tree or other more efficient structure. + +Tokens& Tokens::operator=(const std::string& s) { + clear(); + if (s.empty()) return *this; + std::string::const_iterator i = s.begin(); + while (true) { + // Invariant: i is at the beginning of the next untokenized word. + std::string::const_iterator j = find(i, s.end(), '.'); + push_back(std::string(i, j)); + if (j == s.end()) return *this; + i = j + 1; + } + return *this; +} + +TopicPattern& TopicPattern::operator=(const Tokens& tokens) { + Tokens::operator=(tokens); + normalize(); + return *this; +} + +namespace { +const std::string hashmark("#"); +const std::string star("*"); +} + +void TopicPattern::normalize() { + std::string word; + Tokens::iterator i = begin(); + while (i != end()) { + if (*i == hashmark) { + ++i; + while (i != end()) { + // Invariant: *(i-1)==#, [begin()..i-1] is normalized. + if (*i == star) { // Move * before #. + std::swap(*i, *(i-1)); + ++i; + } else if (*i == hashmark) { + erase(i); // Remove extra # + } else { + break; + } + } + } else { + i ++; + } + } +} + + +namespace { +// TODO aconway 2006-09-20: Ineficient to convert every routingKey to a string. +// Need StringRef class that operates on a string in place witout copy. +// Should be applied everywhere strings are extracted from frames. +// +bool do_match(Tokens::const_iterator pattern_begin, Tokens::const_iterator pattern_end, Tokens::const_iterator target_begin, Tokens::const_iterator target_end) +{ + // Invariant: [pattern_begin..p) matches [target_begin..t) + Tokens::const_iterator p = pattern_begin; + Tokens::const_iterator t = target_begin; + while (p != pattern_end && t != target_end) + { + if (*p == star || *p == *t) { + ++p, ++t; + } else if (*p == hashmark) { + ++p; + if (do_match(p, pattern_end, t, target_end)) return true; + while (t != target_end) { + ++t; + if (do_match(p, pattern_end, t, target_end)) return true; + } + return false; + } else { + return false; + } + } + while (p != pattern_end && *p == hashmark) ++p; // Ignore trailing # + return t == target_end && p == pattern_end; +} +} + +bool TopicPattern::match(const Tokens& target) const +{ + return do_match(begin(), end(), target.begin(), target.end()); +} + +TopicExchange::TopicExchange(const string& _name) : Exchange(_name) { } + +void TopicExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args){ + Monitor::ScopedLock l(lock); + TopicPattern routingPattern(routingKey); + bindings[routingPattern].push_back(queue); + queue->bound(new ExchangeBinding(this, queue, routingKey, args)); +} + +void TopicExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/){ + Monitor::ScopedLock l(lock); + BindingMap::iterator bi = bindings.find(TopicPattern(routingKey)); + Queue::vector& qv(bi->second); + if (bi == bindings.end()) return; + Queue::vector::iterator q = find(qv.begin(), qv.end(), queue); + if(q == qv.end()) return; + qv.erase(q); + if(qv.empty()) bindings.erase(bi); +} + + +void TopicExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/){ + Monitor::ScopedLock l(lock); + for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) { + if (i->first.match(routingKey)) { + Queue::vector& qv(i->second); + for(Queue::vector::iterator j = qv.begin(); j != qv.end(); j++){ + msg.deliverTo(*j); + } + } + } +} + +TopicExchange::~TopicExchange() {} + +const std::string TopicExchange::typeName("topic"); + + diff --git a/qpid/cpp-0-9/lib/broker/TopicExchange.h b/qpid/cpp-0-9/lib/broker/TopicExchange.h new file mode 100644 index 0000000000..fa0c86863a --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/TopicExchange.h @@ -0,0 +1,100 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _TopicExchange_ +#define _TopicExchange_ + +#include <map> +#include <vector> +#include <BrokerExchange.h> +#include <FieldTable.h> +#include <BrokerMessage.h> +#include <sys/Monitor.h> +#include <BrokerQueue.h> + +namespace qpid { +namespace broker { + +/** A vector of string tokens */ +class Tokens : public std::vector<std::string> { + public: + Tokens() {}; + // Default copy, assign, dtor are sufficient. + + /** Tokenize s, provides automatic conversion of string to Tokens */ + Tokens(const std::string& s) { operator=(s); } + /** Tokenizing assignment operator s */ + Tokens & operator=(const std::string& s); + + private: + size_t hash; +}; + + +/** + * Tokens that have been normalized as a pattern and can be matched + * with topic Tokens. Normalized meands all sequences of mixed * and + * # are reduced to a series of * followed by at most one #. + */ +class TopicPattern : public Tokens +{ + public: + TopicPattern() {} + // Default copy, assign, dtor are sufficient. + TopicPattern(const Tokens& tokens) { operator=(tokens); } + TopicPattern(const std::string& str) { operator=(str); } + TopicPattern& operator=(const Tokens&); + TopicPattern& operator=(const std::string& str) { return operator=(Tokens(str)); } + + /** Match a topic */ + bool match(const std::string& topic) { return match(Tokens(topic)); } + bool match(const Tokens& topic) const; + + private: + void normalize(); +}; + +class TopicExchange : public virtual Exchange{ + typedef std::map<TopicPattern, Queue::vector> BindingMap; + BindingMap bindings; + qpid::sys::Mutex lock; + + public: + static const std::string typeName; + + TopicExchange(const string& name); + + virtual std::string getType(){ return typeName; } + + virtual void bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args); + + virtual void unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args); + + virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args); + + virtual ~TopicExchange(); +}; + + + +} +} + +#endif diff --git a/qpid/cpp-0-9/lib/broker/TransactionalStore.h b/qpid/cpp-0-9/lib/broker/TransactionalStore.h new file mode 100644 index 0000000000..17bca3878a --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/TransactionalStore.h @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _TransactionalStore_ +#define _TransactionalStore_ + +#include <memory> + +namespace qpid { + namespace broker { + struct InvalidTransactionContextException : public std::exception {}; + + class TransactionContext{ + public: + virtual ~TransactionContext(){} + }; + + class TransactionalStore{ + public: + virtual std::auto_ptr<TransactionContext> begin() = 0; + virtual void commit(TransactionContext*) = 0; + virtual void abort(TransactionContext*) = 0; + + virtual ~TransactionalStore(){} + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/TxAck.cpp b/qpid/cpp-0-9/lib/broker/TxAck.cpp new file mode 100644 index 0000000000..b5211158f3 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/TxAck.cpp @@ -0,0 +1,54 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <TxAck.h> + +using std::bind1st; +using std::bind2nd; +using std::mem_fun_ref; +using namespace qpid::broker; + +TxAck::TxAck(AccumulatedAck& _acked, std::list<DeliveryRecord>& _unacked, const std::string* const _xid) : + acked(_acked), unacked(_unacked), xid(_xid){ + +} + +bool TxAck::prepare(TransactionContext* ctxt) throw(){ + try{ + //dequeue all acked messages from their queues + for (ack_iterator i = unacked.begin(); i != unacked.end(); i++) { + if (i->coveredBy(&acked)) { + i->discard(ctxt, xid); + } + } + return true; + }catch(...){ + std::cout << "TxAck::prepare() - Failed to prepare" << std::endl; + return false; + } +} + +void TxAck::commit() throw(){ + //remove all acked records from the list + unacked.remove_if(bind2nd(mem_fun_ref(&DeliveryRecord::coveredBy), &acked)); +} + +void TxAck::rollback() throw(){ +} diff --git a/qpid/cpp-0-9/lib/broker/TxAck.h b/qpid/cpp-0-9/lib/broker/TxAck.h new file mode 100644 index 0000000000..88c321c445 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/TxAck.h @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _TxAck_ +#define _TxAck_ + +#include <algorithm> +#include <functional> +#include <list> +#include <AccumulatedAck.h> +#include <DeliveryRecord.h> +#include <TxOp.h> + +namespace qpid { + namespace broker { + /** + * Defines the transactional behaviour for acks received by a + * transactional channel. + */ + class TxAck : public TxOp{ + AccumulatedAck& acked; + std::list<DeliveryRecord>& unacked; + const std::string* const xid; + + public: + /** + * @param acked a representation of the accumulation of + * acks received + * @param unacked the record of delivered messages + */ + TxAck(AccumulatedAck& acked, std::list<DeliveryRecord>& unacked, const std::string* const xid = 0); + virtual bool prepare(TransactionContext* ctxt) throw(); + virtual void commit() throw(); + virtual void rollback() throw(); + virtual ~TxAck(){} + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/TxBuffer.cpp b/qpid/cpp-0-9/lib/broker/TxBuffer.cpp new file mode 100644 index 0000000000..acd3283bb7 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/TxBuffer.cpp @@ -0,0 +1,55 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <TxBuffer.h> + +using std::mem_fun; +using namespace qpid::broker; + +bool TxBuffer::prepare(TransactionalStore* const store) +{ + std::auto_ptr<TransactionContext> ctxt; + if(store) ctxt = store->begin(); + for(op_iterator i = ops.begin(); i < ops.end(); i++){ + if(!(*i)->prepare(ctxt.get())){ + if(store) store->abort(ctxt.get()); + return false; + } + } + if(store) store->commit(ctxt.get()); + return true; +} + +void TxBuffer::commit() +{ + for_each(ops.begin(), ops.end(), mem_fun(&TxOp::commit)); + ops.clear(); +} + +void TxBuffer::rollback() +{ + for_each(ops.begin(), ops.end(), mem_fun(&TxOp::rollback)); + ops.clear(); +} + +void TxBuffer::enlist(TxOp* const op) +{ + ops.push_back(op); +} diff --git a/qpid/cpp-0-9/lib/broker/TxBuffer.h b/qpid/cpp-0-9/lib/broker/TxBuffer.h new file mode 100644 index 0000000000..2d9a2a3679 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/TxBuffer.h @@ -0,0 +1,107 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _TxBuffer_ +#define _TxBuffer_ + +#include <algorithm> +#include <functional> +#include <vector> +#include <TransactionalStore.h> +#include <TxOp.h> + +/** + * Represents a single transaction. As such, an instance of this class + * will hold a list of operations representing the workload of the + * transaction. This work can be committed or rolled back. Committing + * is a two-stage process: first all the operations should be + * prepared, then if that succeeds they can be committed. + * + * In the 2pc case, a successful prepare may be followed by either a + * commit or a rollback. + * + * Atomicity of prepare is ensured by using a lower level + * transactional facility. This saves explicitly rolling back all the + * successfully prepared ops when one of them fails. i.e. we do not + * use 2pc internally, we instead ensure that prepare is atomic at a + * lower level. This makes individual prepare operations easier to + * code. + * + * Transactions on a messaging broker effect three types of 'action': + * (1) updates to persistent storage (2) updates to transient storage + * or cached data (3) network writes. + * + * Of these, (1) should always occur atomically during prepare to + * ensure that if the broker crashes while a transaction is being + * completed the persistent state (which is all that then remains) is + * consistent. (3) can only be done on commit, after a successful + * prepare. There is a little more flexibility with (2) but any + * changes made during prepare should be subject to the control of the + * TransactionalStore in use. + */ +namespace qpid { + namespace broker { + class TxBuffer{ + typedef std::vector<TxOp*>::iterator op_iterator; + std::vector<TxOp*> ops; + public: + /** + * Requests that all ops are prepared. This should + * primarily involve making sure that a persistent record + * of the operations is stored where necessary. + * + * All ops will be prepared under a transaction on the + * specified store. If any operation fails on prepare, + * this transaction will be rolled back. + * + * Once prepared, a transaction can be committed (or in + * the 2pc case, rolled back). + * + * @returns true if all the operations prepared + * successfully, false if not. + */ + bool prepare(TransactionalStore* const store); + /** + * Signals that the ops all prepared all completed + * successfully and can now commit, i.e. the operation can + * now be fully carried out. + * + * Should only be called after a call to prepare() returns + * true. + */ + void commit(); + /** + * Rolls back all the operations. + * + * Should only be called either after a call to prepare() + * returns true (2pc) or instead of a prepare call + * ('server-local') + */ + void rollback(); + /** + * Adds an operation to the transaction. + */ + void enlist(TxOp* const op); + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/TxOp.h b/qpid/cpp-0-9/lib/broker/TxOp.h new file mode 100644 index 0000000000..abba84a8e8 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/TxOp.h @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _TxOp_ +#define _TxOp_ + +#include <TransactionalStore.h> + +namespace qpid { + namespace broker { + class TxOp{ + public: + virtual bool prepare(TransactionContext*) throw() = 0; + virtual void commit() throw() = 0; + virtual void rollback() throw() = 0; + virtual ~TxOp(){} + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/broker/TxPublish.cpp b/qpid/cpp-0-9/lib/broker/TxPublish.cpp new file mode 100644 index 0000000000..49dd8abd89 --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/TxPublish.cpp @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <TxPublish.h> + +using namespace qpid::broker; + +TxPublish::TxPublish(Message::shared_ptr _msg, const std::string* const _xid) : msg(_msg), xid(_xid) {} + +bool TxPublish::prepare(TransactionContext* ctxt) throw(){ + try{ + for_each(queues.begin(), queues.end(), Prepare(ctxt, msg, xid)); + return true; + }catch(...){ + std::cout << "TxPublish::prepare() - Failed to prepare" << std::endl; + return false; + } +} + +void TxPublish::commit() throw(){ + for_each(queues.begin(), queues.end(), Commit(msg)); +} + +void TxPublish::rollback() throw(){ +} + +void TxPublish::deliverTo(Queue::shared_ptr& queue){ + queues.push_back(queue); +} + +TxPublish::Prepare::Prepare(TransactionContext* _ctxt, Message::shared_ptr& _msg, const string* const _xid) + : ctxt(_ctxt), msg(_msg), xid(_xid){} + +void TxPublish::Prepare::operator()(Queue::shared_ptr& queue){ + queue->enqueue(ctxt, msg, xid); +} + +TxPublish::Commit::Commit(Message::shared_ptr& _msg) : msg(_msg){} + +void TxPublish::Commit::operator()(Queue::shared_ptr& queue){ + queue->process(msg); +} + diff --git a/qpid/cpp-0-9/lib/broker/TxPublish.h b/qpid/cpp-0-9/lib/broker/TxPublish.h new file mode 100644 index 0000000000..75f201257e --- /dev/null +++ b/qpid/cpp-0-9/lib/broker/TxPublish.h @@ -0,0 +1,80 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _TxPublish_ +#define _TxPublish_ + +#include <algorithm> +#include <functional> +#include <list> +#include <Deliverable.h> +#include <BrokerMessage.h> +#include <MessageStore.h> +#include <BrokerQueue.h> +#include <TxOp.h> + +namespace qpid { + namespace broker { + /** + * Defines the behaviour for publish operations on a + * transactional channel. Messages are routed through + * exchanges when received but are not at that stage delivered + * to the matching queues, rather the queues are held in an + * instance of this class. On prepare() the message is marked + * enqueued to the relevant queues in the MessagesStore. On + * commit() the messages will be passed to the queue for + * dispatch or to be added to the in-memory queue. + */ + class TxPublish : public TxOp, public Deliverable{ + class Prepare{ + TransactionContext* ctxt; + Message::shared_ptr& msg; + const std::string* const xid; + public: + Prepare(TransactionContext* ctxt, Message::shared_ptr& msg, const std::string* const xid); + void operator()(Queue::shared_ptr& queue); + }; + + class Commit{ + Message::shared_ptr& msg; + public: + Commit(Message::shared_ptr& msg); + void operator()(Queue::shared_ptr& queue); + }; + + Message::shared_ptr msg; + const std::string* const xid; + std::list<Queue::shared_ptr> queues; + + public: + TxPublish(Message::shared_ptr msg, const std::string* const xid = 0); + virtual bool prepare(TransactionContext* ctxt) throw(); + virtual void commit() throw(); + virtual void rollback() throw(); + + virtual void deliverTo(Queue::shared_ptr& queue); + + virtual ~TxPublish(){} + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/client/Basic.cpp b/qpid/cpp-0-9/lib/client/Basic.cpp new file mode 100644 index 0000000000..4a1cf249a8 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/Basic.cpp @@ -0,0 +1,255 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include <iostream> +#include "Basic.h" +#include "AMQMethodBody.h" +#include "ClientChannel.h" +#include "ReturnedMessageHandler.h" +#include "MessageListener.h" +#include "framing/FieldTable.h" +#include "Connection.h" + +using namespace std; + +namespace qpid { +namespace client { + +using namespace sys; +using namespace framing; + +Basic::Basic(Channel& ch) : channel(ch), returnsHandler(0) {} + +void Basic::consume( + Queue& queue, std::string& tag, MessageListener* listener, + AckMode ackMode, bool noLocal, bool synch, const FieldTable* fields) +{ + channel.sendAndReceiveSync<BasicConsumeOkBody>( + synch, + new BasicConsumeBody( + channel.version, 0, queue.getName(), tag, noLocal, + ackMode == NO_ACK, false, !synch, + fields ? *fields : FieldTable())); + if (synch) { + BasicConsumeOkBody::shared_ptr response = + boost::shared_polymorphic_downcast<BasicConsumeOkBody>( + channel.responses.getResponse()); + tag = response->getConsumerTag(); + } + // FIXME aconway 2007-02-20: Race condition! + // We could receive the first message for the consumer + // before we create the consumer below. + // Move consumer creation to handler for BasicConsumeOkBody + { + Mutex::ScopedLock l(lock); + ConsumerMap::iterator i = consumers.find(tag); + if (i != consumers.end()) + THROW_QPID_ERROR(CLIENT_ERROR, + "Consumer already exists with tag="+tag); + Consumer& c = consumers[tag]; + c.listener = listener; + c.ackMode = ackMode; + c.lastDeliveryTag = 0; + } +} + + +void Basic::cancel(const std::string& tag, bool synch) { + Consumer c; + { + Mutex::ScopedLock l(lock); + ConsumerMap::iterator i = consumers.find(tag); + if (i == consumers.end()) + return; + c = i->second; + consumers.erase(i); + } + if(c.ackMode == LAZY_ACK && c.lastDeliveryTag > 0) + channel.send(new BasicAckBody(channel.version, c.lastDeliveryTag, true)); + channel.sendAndReceiveSync<BasicCancelOkBody>( + synch, new BasicCancelBody(channel.version, tag, !synch)); +} + +void Basic::cancelAll(){ + ConsumerMap consumersCopy; + { + Mutex::ScopedLock l(lock); + consumersCopy = consumers; + consumers.clear(); + } + for (ConsumerMap::iterator i=consumersCopy.begin(); + i != consumersCopy.end(); ++i) + { + Consumer& c = i->second; + if ((c.ackMode == LAZY_ACK || c.ackMode == AUTO_ACK) + && c.lastDeliveryTag > 0) + { + channel.send(new BasicAckBody(channel.version, c.lastDeliveryTag, true)); + } + } +} + + + +bool Basic::get(Message& msg, const Queue& queue, AckMode ackMode) { + // Expect a message starting with a BasicGetOk + incoming.startGet(); + channel.send(new BasicGetBody(channel.version, 0, queue.getName(), ackMode)); + return incoming.waitGet(msg); +} + + +void Basic::publish( + const Message& msg, const Exchange& exchange, + const std::string& routingKey, bool mandatory, bool immediate) +{ + const string e = exchange.getName(); + string key = routingKey; + channel.send(new BasicPublishBody(channel.version, 0, e, key, mandatory, immediate)); + //break msg up into header frame and content frame(s) and send these + channel.send(msg.getHeader()); + string data = msg.getData(); + uint64_t data_length = data.length(); + if(data_length > 0){ + //frame itself uses 8 bytes + uint32_t frag_size = channel.connection->getMaxFrameSize() - 8; + if(data_length < frag_size){ + channel.send(new AMQContentBody(data)); + }else{ + uint32_t offset = 0; + uint32_t remaining = data_length - offset; + while (remaining > 0) { + uint32_t length = remaining > frag_size ? frag_size : remaining; + string frag(data.substr(offset, length)); + channel.send(new AMQContentBody(frag)); + + offset += length; + remaining = data_length - offset; + } + } + } +} + +void Basic::handle(boost::shared_ptr<AMQMethodBody> method) { + assert(method->amqpClassId() ==BasicGetBody::CLASS_ID); + switch(method->amqpMethodId()) { + case BasicDeliverBody::METHOD_ID: + case BasicReturnBody::METHOD_ID: + case BasicGetOkBody::METHOD_ID: + case BasicGetEmptyBody::METHOD_ID: + incoming.add(method); + return; + } + throw Channel::UnknownMethod(); +} + +void Basic::deliver(Consumer& consumer, Message& msg){ + //record delivery tag: + consumer.lastDeliveryTag = msg.getDeliveryTag(); + + //allow registered listener to handle the message + consumer.listener->received(msg); + + if(channel.isOpen()){ + bool multiple(false); + switch(consumer.ackMode){ + case LAZY_ACK: + multiple = true; + if(++(consumer.count) < channel.getPrefetch()) + break; + //else drop-through + case AUTO_ACK: + consumer.lastDeliveryTag = 0; + channel.send( + new BasicAckBody( + channel.version, msg.getDeliveryTag(), multiple)); + case NO_ACK: // Nothing to do + case CLIENT_ACK: // User code must ack. + break; + // TODO aconway 2007-02-22: Provide a way for user + // to ack! + } + } + + //as it stands, transactionality is entirely orthogonal to ack + //mode, though the acks will not be processed by the broker under + //a transaction until it commits. +} + + +void Basic::run() { + while(channel.isOpen()) { + try { + Message msg = incoming.waitDispatch(); + if(msg.getMethod()->isA<BasicReturnBody>()) { + ReturnedMessageHandler* handler=0; + { + Mutex::ScopedLock l(lock); + handler=returnsHandler; + } + if(handler == 0) { + // TODO aconway 2007-02-20: proper logging. + cout << "Message returned: " << msg.getData() << endl; + } + else + handler->returned(msg); + } + else { + BasicDeliverBody::shared_ptr deliverBody = + boost::shared_polymorphic_downcast<BasicDeliverBody>( + msg.getMethod()); + std::string tag = deliverBody->getConsumerTag(); + Consumer consumer; + { + Mutex::ScopedLock l(lock); + ConsumerMap::iterator i = consumers.find(tag); + if(i == consumers.end()) + THROW_QPID_ERROR(PROTOCOL_ERROR+504, + "Unknown consumer tag=" + tag); + consumer = i->second; + } + deliver(consumer, msg); + } + } + catch (const ShutdownException&) { + /* Orderly shutdown */ + } + catch (const Exception& e) { + // FIXME aconway 2007-02-20: Report exception to user. + cout << "client::Basic::run() terminated by: " << e.toString() + << "(" << typeid(e).name() << ")" << endl; + } + } +} + +void Basic::setReturnedMessageHandler(ReturnedMessageHandler* handler){ + Mutex::ScopedLock l(lock); + returnsHandler = handler; +} + +void Basic::setQos(){ + channel.sendAndReceive<BasicQosOkBody>( + new BasicQosBody(channel.version, 0, channel.getPrefetch(), false)); + if(channel.isTransactional()) + channel.sendAndReceive<TxSelectOkBody>(new TxSelectBody(channel.version)); +} + + +// TODO aconway 2007-02-22: NOTES: +// Move incoming to BasicChannel - check for uses. + +}} // namespace qpid::client diff --git a/qpid/cpp-0-9/lib/client/Basic.h b/qpid/cpp-0-9/lib/client/Basic.h new file mode 100644 index 0000000000..f6ae633ab8 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/Basic.h @@ -0,0 +1,195 @@ +#ifndef _client_Basic_h +#define _client_Basic_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "IncomingMessage.h" +#include "sys/Runnable.h" + +namespace qpid { + +namespace framing { +class AMQMethodBody; +class FieldTable; +} + +namespace client { + +class Channel; +class Message; +class Queue; +class Exchange; +class MessageListener; +class ReturnedMessageHandler; + +/** + * The available acknowledgements modes. + * + * \ingroup clientapi + */ +enum AckMode { + /** No acknowledgement will be sent, broker can + discard messages as soon as they are delivered + to a consumer using this mode. **/ + NO_ACK = 0, + /** Each message will be automatically + acknowledged as soon as it is delivered to the + application **/ + AUTO_ACK = 1, + /** Acknowledgements will be sent automatically, + but not for each message. **/ + LAZY_ACK = 2, + /** The application is responsible for explicitly + acknowledging messages. **/ + CLIENT_ACK = 3 +}; + + +/** + * Represents the AMQP Basic class for sending and receiving messages. + */ +class Basic : public sys::Runnable +{ + public: + Basic(Channel& parent); + + /** + * Creates a 'consumer' for a queue. Messages in (or arriving + * at) that queue will be delivered to consumers + * asynchronously. + * + * @param queue a Queue instance representing the queue to + * consume from + * + * @param tag an identifier to associate with the consumer + * that can be used to cancel its subscription (if empty, this + * will be assigned by the broker) + * + * @param listener a pointer to an instance of an + * implementation of the MessageListener interface. Messages + * received from this queue for this consumer will result in + * invocation of the received() method on the listener, with + * the message itself passed in. + * + * @param ackMode the mode of acknowledgement that the broker + * should assume for this consumer. @see AckMode + * + * @param noLocal if true, this consumer will not be sent any + * message published by this connection + * + * @param synch if true this call will block until a response + * is received from the broker + */ + void consume( + Queue& queue, std::string& tag, MessageListener* listener, + AckMode ackMode = NO_ACK, bool noLocal = false, bool synch = true, + const framing::FieldTable* fields = 0); + + /** + * Cancels a subscription previously set up through a call to consume(). + * + * @param tag the identifier used (or assigned) in the consume + * request that set up the subscription to be cancelled. + * + * @param synch if true this call will block until a response + * is received from the broker + */ + void cancel(const std::string& tag, bool synch = true); + /** + * Synchronous pull of a message from a queue. + * + * @param msg a message object that will contain the message + * headers and content if the call completes. + * + * @param queue the queue to consume from + * + * @param ackMode the acknowledgement mode to use (@see + * AckMode) + * + * @return true if a message was succcessfully dequeued from + * the queue, false if the queue was empty. + */ + bool get(Message& msg, const Queue& queue, AckMode ackMode = NO_ACK); + + /** + * Publishes (i.e. sends a message to the broker). + * + * @param msg the message to publish + * + * @param exchange the exchange to publish the message to + * + * @param routingKey the routing key to publish with + * + * @param mandatory if true and the exchange to which this + * publish is directed has no matching bindings, the message + * will be returned (see setReturnedMessageHandler()). + * + * @param immediate if true and there is no consumer to + * receive this message on publication, the message will be + * returned (see setReturnedMessageHandler()). + */ + void publish(const Message& msg, const Exchange& exchange, + const std::string& routingKey, + bool mandatory = false, bool immediate = false); + + /** + * Set a handler for this channel that will process any + * returned messages + * + * @see publish() + */ + void setReturnedMessageHandler(ReturnedMessageHandler* handler); + + /** + * Deliver messages from the broker to the appropriate MessageListener. + */ + void run(); + + + private: + + struct Consumer{ + MessageListener* listener; + AckMode ackMode; + int count; + uint64_t lastDeliveryTag; + }; + + typedef std::map<std::string, Consumer> ConsumerMap; + + void handle(boost::shared_ptr<framing::AMQMethodBody>); + void setQos(); + void cancelAll(); + void deliver(Consumer& consumer, Message& msg); + + sys::Mutex lock; + Channel& channel; + IncomingMessage incoming; + ConsumerMap consumers; + ReturnedMessageHandler* returnsHandler; + + // FIXME aconway 2007-02-22: Remove friendship. + friend class Channel; +}; + +}} // namespace qpid::client + + + +#endif /*!_client_Basic_h*/ diff --git a/qpid/cpp-0-9/lib/client/ClientAdapter.cpp b/qpid/cpp-0-9/lib/client/ClientAdapter.cpp new file mode 100644 index 0000000000..c77f049c96 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ClientAdapter.cpp @@ -0,0 +1,70 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include "AMQP_ClientOperations.h" +#include "ClientAdapter.h" +#include "Connection.h" +#include "Exception.h" +#include "AMQMethodBody.h" + +namespace qpid { +namespace client { + +using namespace qpid; +using namespace qpid::framing; + +typedef std::vector<Queue::shared_ptr>::iterator queue_iterator; + +void ClientAdapter::handleMethodInContext( + boost::shared_ptr<qpid::framing::AMQMethodBody> method, + const MethodContext& context +) +{ + try{ + method->invoke(*clientOps, context); + }catch(ChannelException& e){ + connection.client->getChannel().close( + context, e.code, e.toString(), + method->amqpClassId(), method->amqpMethodId()); + connection.closeChannel(getId()); + }catch(ConnectionException& e){ + connection.client->getConnection().close( + context, e.code, e.toString(), + method->amqpClassId(), method->amqpMethodId()); + }catch(std::exception& e){ + connection.client->getConnection().close( + context, 541/*internal error*/, e.what(), + method->amqpClassId(), method->amqpMethodId()); + } +} + +void ClientAdapter::handleHeader(AMQHeaderBody::shared_ptr body) { + channel->handleHeader(body); +} + +void ClientAdapter::handleContent(AMQContentBody::shared_ptr body) { + channel->handleContent(body); +} + +void ClientAdapter::handleHeartbeat(AMQHeartbeatBody::shared_ptr) { + // TODO aconway 2007-01-17: Implement heartbeats. +} + + + +}} // namespace qpid::client + diff --git a/qpid/cpp-0-9/lib/client/ClientAdapter.h b/qpid/cpp-0-9/lib/client/ClientAdapter.h new file mode 100644 index 0000000000..d5e16fc6ad --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ClientAdapter.h @@ -0,0 +1,66 @@ +#ifndef _client_ClientAdapter_h +#define _client_ClientAdapter_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "ChannelAdapter.h" +#include "ClientChannel.h" + +namespace qpid { +namespace client { + +class AMQMethodBody; +class Connection; + +/** + * Per-channel protocol adapter. + * + * Translates protocol bodies into calls on the core Channel, + * Connection and Client objects. + * + * Owns a channel, has references to Connection and Client. + */ +class ClientAdapter : public framing::ChannelAdapter +{ + public: + ClientAdapter(std::auto_ptr<Channel> ch, Connection&, Client&); + Channel& getChannel() { return *channel; } + + void handleHeader(boost::shared_ptr<qpid::framing::AMQHeaderBody>); + void handleContent(boost::shared_ptr<qpid::framing::AMQContentBody>); + void handleHeartbeat(boost::shared_ptr<qpid::framing::AMQHeartbeatBody>); + + private: + void handleMethodInContext( + boost::shared_ptr<qpid::framing::AMQMethodBody> method, + const framing::MethodContext& context); + + class ClientOps; + + std::auto_ptr<Channel> channel; + Connection& connection; + Client& client; + boost::shared_ptr<ClientOps> clientOps; +}; + +}} // namespace qpid::client + + + +#endif /*!_client_ClientAdapter_h*/ diff --git a/qpid/cpp-0-9/lib/client/ClientChannel.cpp b/qpid/cpp-0-9/lib/client/ClientChannel.cpp new file mode 100644 index 0000000000..84aa73e6bc --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ClientChannel.cpp @@ -0,0 +1,302 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <ClientChannel.h> +#include <sys/Monitor.h> +#include <ClientMessage.h> +#include <QpidError.h> +#include <MethodBodyInstances.h> +#include "Connection.h" + +// FIXME aconway 2007-01-26: Evaluate all throws, ensure consistent +// handling of errors that should close the connection or the channel. +// Make sure the user thread receives a connection in each case. +// +using namespace std; +using namespace boost; +using namespace qpid::client; +using namespace qpid::framing; +using namespace qpid::sys; + +Channel::Channel(bool _transactional, uint16_t _prefetch) : + basic(*this), + connection(0), + prefetch(_prefetch), + transactional(_transactional) +{ } + +Channel::~Channel(){ + close(); +} + +void Channel::open(ChannelId id, Connection& con) +{ + if (isOpen()) + THROW_QPID_ERROR(INTERNAL_ERROR, "Attempt to re-open channel "+id); + connection = &con; + init(id, con, con.getVersion()); // ChannelAdapter initialization. + string oob; + if (id != 0) + sendAndReceive<ChannelOpenOkBody>(new ChannelOpenBody(version, oob)); +} + +void Channel::protocolInit( + const std::string& uid, const std::string& pwd, const std::string& vhost) { + assert(connection); + responses.expect(); + connection->connector->init(); // Send ProtocolInit block. + responses.receive<ConnectionStartBody>(); + + FieldTable props; + string mechanism("PLAIN"); + string response = ((char)0) + uid + ((char)0) + pwd; + string locale("en_US"); + ConnectionTuneBody::shared_ptr proposal = + sendAndReceive<ConnectionTuneBody>( + new ConnectionStartOkBody( + version, responses.getRequestId(), props, mechanism, + response, locale)); + + /** + * Assume for now that further challenges will not be required + //receive connection.secure + responses.receive(connection_secure)); + //send connection.secure-ok + connection->send(new AMQFrame(0, new ConnectionSecureOkBody(response))); + **/ + + send(new ConnectionTuneOkBody( + version, responses.getRequestId(), proposal->getChannelMax(), connection->getMaxFrameSize(), + proposal->getHeartbeat())); + + uint16_t heartbeat = proposal->getHeartbeat(); + connection->connector->setReadTimeout(heartbeat * 2); + connection->connector->setWriteTimeout(heartbeat); + + // Send connection open. + std::string capabilities; + responses.expect(); + send(new ConnectionOpenBody(version, vhost, capabilities, true)); + //receive connection.open-ok (or redirect, but ignore that for now + //esp. as using force=true). + responses.waitForResponse(); + if(responses.validate<ConnectionOpenOkBody>()) { + //ok + }else if(responses.validate<ConnectionRedirectBody>()){ + //ignore for now + ConnectionRedirectBody::shared_ptr redirect( + shared_polymorphic_downcast<ConnectionRedirectBody>( + responses.getResponse())); + cout << "Received redirection to " << redirect->getHost() + << endl; + } else { + THROW_QPID_ERROR(PROTOCOL_ERROR, "Bad response"); + } +} + +bool Channel::isOpen() const { return connection; } + +void Channel::setQos() { + basic.setQos(); + // FIXME aconway 2007-02-22: message +} + +void Channel::setPrefetch(uint16_t _prefetch){ + prefetch = _prefetch; + setQos(); +} + +void Channel::declareExchange(Exchange& exchange, bool synch){ + string name = exchange.getName(); + string type = exchange.getType(); + FieldTable args; + sendAndReceiveSync<ExchangeDeclareOkBody>( + synch, + new ExchangeDeclareBody( + version, 0, name, type, false, false, false, false, !synch, args)); +} + +void Channel::deleteExchange(Exchange& exchange, bool synch){ + string name = exchange.getName(); + sendAndReceiveSync<ExchangeDeleteOkBody>( + synch, + new ExchangeDeleteBody(version, 0, name, false, !synch)); +} + +void Channel::declareQueue(Queue& queue, bool synch){ + string name = queue.getName(); + FieldTable args; + sendAndReceiveSync<QueueDeclareOkBody>( + synch, + new QueueDeclareBody( + version, 0, name, false/*passive*/, queue.isDurable(), + queue.isExclusive(), queue.isAutoDelete(), !synch, args)); + if(synch){ + if(queue.getName().length() == 0){ + QueueDeclareOkBody::shared_ptr response = + shared_polymorphic_downcast<QueueDeclareOkBody>( + responses.getResponse()); + queue.setName(response->getQueue()); + } + } +} + +void Channel::deleteQueue(Queue& queue, bool ifunused, bool ifempty, bool synch){ + //ticket, queue, ifunused, ifempty, nowait + string name = queue.getName(); + sendAndReceiveSync<QueueDeleteOkBody>( + synch, + new QueueDeleteBody(version, 0, name, ifunused, ifempty, !synch)); +} + +void Channel::bind(const Exchange& exchange, const Queue& queue, const std::string& key, const FieldTable& args, bool synch){ + string e = exchange.getName(); + string q = queue.getName(); + sendAndReceiveSync<QueueBindOkBody>( + synch, + new QueueBindBody(version, 0, q, e, key,!synch, args)); +} + +void Channel::commit(){ + sendAndReceive<TxCommitOkBody>(new TxCommitBody(version)); +} + +void Channel::rollback(){ + sendAndReceive<TxRollbackOkBody>(new TxRollbackBody(version)); +} + +void Channel::handleMethodInContext( + AMQMethodBody::shared_ptr method, const MethodContext&) +{ + if(responses.isWaiting()) { + responses.signalResponse(method); + return; + } + try { + switch (method->amqpClassId()) { + case BasicDeliverBody::CLASS_ID: basic.handle(method); break; + case ChannelCloseBody::CLASS_ID: handleChannel(method); break; + case ConnectionCloseBody::CLASS_ID: handleConnection(method); break; + default: throw UnknownMethod(); + } + } + catch (const UnknownMethod&) { + connection->close( + 504, "Unknown method", + method->amqpClassId(), method->amqpMethodId()); + } +} + +void Channel::handleChannel(AMQMethodBody::shared_ptr method) { + switch (method->amqpMethodId()) { + case ChannelCloseBody::METHOD_ID: + peerClose(shared_polymorphic_downcast<ChannelCloseBody>(method)); + return; + case ChannelFlowBody::METHOD_ID: + // FIXME aconway 2007-02-22: Not yet implemented. + return; + } + throw UnknownMethod(); +} + +void Channel::handleConnection(AMQMethodBody::shared_ptr method) { + if (method->amqpMethodId() == ConnectionCloseBody::METHOD_ID) { + connection->close(); + return; + } + throw UnknownMethod(); +} + +void Channel::handleHeader(AMQHeaderBody::shared_ptr body){ + basic.incoming.add(body); +} + +void Channel::handleContent(AMQContentBody::shared_ptr body){ + basic.incoming.add(body); +} + +void Channel::handleHeartbeat(AMQHeartbeatBody::shared_ptr /*body*/){ + THROW_QPID_ERROR(PROTOCOL_ERROR + 504, "Channel received heartbeat"); +} + +void Channel::start(){ + basicDispatcher = Thread(basic); +} + +// Close called by local application. +void Channel::close( + uint16_t code, const std::string& text, + ClassId classId, MethodId methodId) +{ + if (isOpen()) { + try { + if (getId() != 0) { + sendAndReceive<ChannelCloseOkBody>( + new ChannelCloseBody( + version, code, text, classId, methodId)); + } + static_cast<ConnectionForChannel*>(connection)->erase(getId()); + closeInternal(); + } catch (...) { + static_cast<ConnectionForChannel*>(connection)->erase(getId()); + closeInternal(); + throw; + } + } +} + +// Channel closed by peer. +void Channel::peerClose(ChannelCloseBody::shared_ptr) { + assert(isOpen()); + closeInternal(); + // FIXME aconway 2007-01-26: How to throw the proper exception + // to the application thread? +} + +void Channel::closeInternal() { + if (isOpen()); + { + basic.cancelAll(); + basic.incoming.shutdown(); + connection = 0; + // A 0 response means we are closed. + responses.signalResponse(AMQMethodBody::shared_ptr()); + } + basicDispatcher.join(); +} + +void Channel::sendAndReceive(AMQMethodBody* toSend, ClassId c, MethodId m) +{ + responses.expect(); + send(toSend); + responses.receive(c, m); +} + +void Channel::sendAndReceiveSync( + bool sync, AMQMethodBody* body, ClassId c, MethodId m) +{ + if(sync) + sendAndReceive(body, c, m); + else + send(body); +} + + diff --git a/qpid/cpp-0-9/lib/client/ClientChannel.h b/qpid/cpp-0-9/lib/client/ClientChannel.h new file mode 100644 index 0000000000..3ecab05d0b --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ClientChannel.h @@ -0,0 +1,250 @@ +#ifndef _client_ClientChannel_h +#define _client_ClientChannel_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "sys/types.h" +#include <framing/amqp_framing.h> +#include <ClientExchange.h> +#include <ClientMessage.h> +#include <ClientQueue.h> +#include <ResponseHandler.h> +#include "ChannelAdapter.h" +#include "Thread.h" +#include "Basic.h" + +namespace qpid { + +namespace framing { +class ChannelCloseBody; +class AMQMethodBody; +} + +namespace client { + +class Connection; + + +/** + * Represents an AMQP channel, i.e. loosely a session of work. It + * is through a channel that most of the AMQP 'methods' are + * exposed. + * + * \ingroup clientapi + */ +class Channel : public framing::ChannelAdapter +{ + private: + // TODO aconway 2007-02-22: Remove friendship. + friend class Basic; + // FIXME aconway 2007-02-22: friend class Message; + + struct UnknownMethod {}; + + sys::Mutex lock; + Basic basic; + Connection* connection; + sys::Thread basicDispatcher; + ResponseHandler responses; + + uint16_t prefetch; + const bool transactional; + framing::ProtocolVersion version; + + void handleHeader(framing::AMQHeaderBody::shared_ptr body); + void handleContent(framing::AMQContentBody::shared_ptr body); + void handleHeartbeat(framing::AMQHeartbeatBody::shared_ptr body); + void handleMethodInContext( + framing::AMQMethodBody::shared_ptr, const framing::MethodContext&); + void handleChannel(framing::AMQMethodBody::shared_ptr method); + void handleConnection(framing::AMQMethodBody::shared_ptr method); + + void setQos(); + + void protocolInit( + const std::string& uid, const std::string& pwd, + const std::string& vhost); + + void sendAndReceive( + framing::AMQMethodBody*, framing::ClassId, framing::MethodId); + + void sendAndReceiveSync( + bool sync, + framing::AMQMethodBody*, framing::ClassId, framing::MethodId); + + template <class BodyType> + boost::shared_ptr<BodyType> sendAndReceive(framing::AMQMethodBody* body) { + sendAndReceive(body, BodyType::CLASS_ID, BodyType::METHOD_ID); + return boost::shared_polymorphic_downcast<BodyType>( + responses.getResponse()); + } + + template <class BodyType> void sendAndReceiveSync( + bool sync, framing::AMQMethodBody* body) { + sendAndReceiveSync( + sync, body, BodyType::CLASS_ID, BodyType::METHOD_ID); + } + + void open(framing::ChannelId, Connection&); + void closeInternal(); + void peerClose(boost::shared_ptr<framing::ChannelCloseBody>); + + friend class Connection; + + public: + + /** + * Creates a channel object. + * + * @param transactional if true, the publishing and acknowledgement + * of messages will be transactional and can be committed or + * aborted in atomic units (@see commit(), @see rollback()) + * + * @param prefetch specifies the number of unacknowledged + * messages the channel is willing to have sent to it + * asynchronously + */ + Channel(bool transactional = false, uint16_t prefetch = 500); + ~Channel(); + + /** + * Declares an exchange. + * + * In AMQP Exchanges are the destinations to which messages + * are published. They have Queues bound to them and route + * messages they receive to those queues. The routing rules + * depend on the type of the exchange. + * + * @param exchange an Exchange object representing the + * exchange to declare + * + * @param synch if true this call will block until a response + * is received from the broker + */ + void declareExchange(Exchange& exchange, bool synch = true); + /** + * Deletes an exchange + * + * @param exchange an Exchange object representing the exchange to delete + * + * @param synch if true this call will block until a response + * is received from the broker + */ + void deleteExchange(Exchange& exchange, bool synch = true); + /** + * Declares a Queue + * + * @param queue a Queue object representing the queue to declare + * + * @param synch if true this call will block until a response + * is received from the broker + */ + void declareQueue(Queue& queue, bool synch = true); + /** + * Deletes a Queue + * + * @param queue a Queue object representing the queue to delete + * + * @param synch if true this call will block until a response + * is received from the broker + */ + void deleteQueue(Queue& queue, bool ifunused = false, bool ifempty = false, bool synch = true); + /** + * Binds a queue to an exchange. The exact semantics of this + * (in particular how 'routing keys' and 'binding arguments' + * are used) depends on the type of the exchange. + * + * @param exchange an Exchange object representing the + * exchange to bind to + * + * @param queue a Queue object representing the queue to be + * bound + * + * @param key the 'routing key' for the binding + * + * @param args the 'binding arguments' for the binding + * + * @param synch if true this call will block until a response + * is received from the broker + */ + void bind(const Exchange& exchange, const Queue& queue, + const std::string& key, const framing::FieldTable& args, + bool synch = true); + + /** + * Get a Basic object which provides functions to send and + * receive messages using the AMQP 0-8 Basic class methods. + *@see Basic + */ + Basic& getBasic() { return basic; } + + /** + * For a transactional channel this will commit all + * publications and acknowledgements since the last commit (or + * the channel was opened if there has been no previous + * commit). This will cause published messages to become + * available to consumers and acknowledged messages to be + * consumed and removed from the queues they were dispatched + * from. + * + * Transactionailty of a channel is specified when the channel + * object is created (@see Channel()). + */ + void commit(); + + /** + * For a transactional channel, this will rollback any + * publications or acknowledgements. It will be as if the + * ppblished messages were never sent and the acknowledged + * messages were never consumed. + */ + void rollback(); + + /** + * Change the prefetch in use. + */ + void setPrefetch(uint16_t prefetch); + + uint16_t getPrefetch() { return prefetch; } + + /** + * Start message dispatching on a new thread + */ + void start(); + + /** + * Close the channel with optional error information. + * Closing a channel that is not open has no effect. + */ + void close( + framing::ReplyCode = 200, const std::string& ="OK", + framing::ClassId = 0, framing::MethodId = 0); + + /** True if the channel is transactional */ + bool isTransactional() { return transactional; } + + /** True if the channel is open */ + bool isOpen() const; +}; + +}} + +#endif /*!_client_ClientChannel_h*/ diff --git a/qpid/cpp-0-9/lib/client/ClientExchange.cpp b/qpid/cpp-0-9/lib/client/ClientExchange.cpp new file mode 100644 index 0000000000..5e5f3f14c6 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ClientExchange.cpp @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <ClientExchange.h> + +qpid::client::Exchange::Exchange(std::string _name, std::string _type) : name(_name), type(_type){} +const std::string& qpid::client::Exchange::getName() const { return name; } +const std::string& qpid::client::Exchange::getType() const { return type; } + +const std::string qpid::client::Exchange::DIRECT_EXCHANGE = "direct"; +const std::string qpid::client::Exchange::TOPIC_EXCHANGE = "topic"; +const std::string qpid::client::Exchange::HEADERS_EXCHANGE = "headers"; + +const qpid::client::Exchange qpid::client::Exchange::DEFAULT_EXCHANGE("", DIRECT_EXCHANGE); +const qpid::client::Exchange qpid::client::Exchange::STANDARD_DIRECT_EXCHANGE("amq.direct", DIRECT_EXCHANGE); +const qpid::client::Exchange qpid::client::Exchange::STANDARD_TOPIC_EXCHANGE("amq.topic", TOPIC_EXCHANGE); +const qpid::client::Exchange qpid::client::Exchange::STANDARD_HEADERS_EXCHANGE("amq.headers", HEADERS_EXCHANGE); diff --git a/qpid/cpp-0-9/lib/client/ClientExchange.h b/qpid/cpp-0-9/lib/client/ClientExchange.h new file mode 100644 index 0000000000..a8ac21fa9b --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ClientExchange.h @@ -0,0 +1,106 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <string> + +#ifndef _Exchange_ +#define _Exchange_ + +namespace qpid { +namespace client { + + /** + * A 'handle' used to represent an AMQP exchange in the Channel + * methods. Exchanges are the destinations to which messages are + * published. + * + * There are different types of exchange (the standard types are + * available as static constants, see DIRECT_EXCHANGE, + * TOPIC_EXCHANGE and HEADERS_EXCHANGE). A Queue can be bound to + * an exchange using Channel::bind() and messages published to + * that exchange are then routed to the queue based on the details + * of the binding and the type of exchange. + * + * There are some standard exchange instances that are predeclared + * on all AMQP brokers. These are defined as static members + * STANDARD_DIRECT_EXCHANGE, STANDARD_TOPIC_EXCHANGE and + * STANDARD_HEADERS_EXCHANGE. There is also the 'default' exchange + * (member DEFAULT_EXCHANGE) which is nameless and of type + * 'direct' and has every declared queue bound to it by queue + * name. + * + * \ingroup clientapi + */ + class Exchange{ + const std::string name; + const std::string type; + + public: + /** + * A direct exchange routes messages published with routing + * key X to any queue bound with key X (i.e. an exact match is + * used). + */ + static const std::string DIRECT_EXCHANGE; + /** + * A topic exchange treat the key with which a queue is bound + * as a pattern and routes all messages whose routing keys + * match that pattern to the bound queue. The routing key for + * a message must consist of zero or more alpha-numeric words + * delimited by dots. The pattern is of a similar form but * + * can be used to match excatly one word and # can be used to + * match zero or more words. + */ + static const std::string TOPIC_EXCHANGE; + /** + * The headers exchange routes messages based on whether their + * headers match the binding arguments specified when + * binding. (see the AMQP spec for more details). + */ + static const std::string HEADERS_EXCHANGE; + + /** + * The 'default' exchange, nameless and of type 'direct'. Has + * every declared queue bound to it by name. + */ + static const Exchange DEFAULT_EXCHANGE; + /** + * The standard direct exchange, named amq.direct. + */ + static const Exchange STANDARD_DIRECT_EXCHANGE; + /** + * The standard topic exchange, named amq.topic. + */ + static const Exchange STANDARD_TOPIC_EXCHANGE; + /** + * The standard headers exchange, named amq.header. + */ + static const Exchange STANDARD_HEADERS_EXCHANGE; + + Exchange(std::string name, std::string type = DIRECT_EXCHANGE); + const std::string& getName() const; + const std::string& getType() const; + }; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/client/ClientMessage.cpp b/qpid/cpp-0-9/lib/client/ClientMessage.cpp new file mode 100644 index 0000000000..f55c4abfe6 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ClientMessage.cpp @@ -0,0 +1,162 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <ClientMessage.h> +using namespace qpid::client; +using namespace qpid::framing; + +Message::Message(const std::string& d) + : header(new AMQHeaderBody(BASIC)) +{ + setData(d); +} + +void Message::setData(const std::string& d) { + data = d; + header->setContentSize(d.size()); +} + +Message::Message(AMQHeaderBody::shared_ptr& _header) : header(_header){ +} + +Message::~Message(){ +} + +BasicHeaderProperties* Message::getHeaderProperties() const { + return dynamic_cast<BasicHeaderProperties*>(header->getProperties()); +} + +const std::string& Message::getContentType() const { + return getHeaderProperties()->getContentType(); +} + +const std::string& Message::getContentEncoding() const { + return getHeaderProperties()->getContentEncoding(); +} + +FieldTable& Message::getHeaders() const { + return getHeaderProperties()->getHeaders(); +} + +uint8_t Message::getDeliveryMode() const { + return getHeaderProperties()->getDeliveryMode(); +} + +uint8_t Message::getPriority() const { + return getHeaderProperties()->getPriority(); +} + +const std::string& Message::getCorrelationId() const { + return getHeaderProperties()->getCorrelationId(); +} + +const std::string& Message::getReplyTo() const { + return getHeaderProperties()->getReplyTo(); +} + +const std::string& Message::getExpiration() const { + return getHeaderProperties()->getExpiration(); +} + +const std::string& Message::getMessageId() const { + return getHeaderProperties()->getMessageId(); +} + +uint64_t Message::getTimestamp() const { + return getHeaderProperties()->getTimestamp(); +} + +const std::string& Message::getType() const { + return getHeaderProperties()->getType(); +} + +const std::string& Message::getUserId() const { + return getHeaderProperties()->getUserId(); +} + +const std::string& Message::getAppId() const { + return getHeaderProperties()->getAppId(); +} + +const std::string& Message::getClusterId() const { + return getHeaderProperties()->getClusterId(); +} + +void Message::setContentType(const std::string& type){ + getHeaderProperties()->setContentType(type); +} + +void Message::setContentEncoding(const std::string& encoding){ + getHeaderProperties()->setContentEncoding(encoding); +} + +void Message::setHeaders(const FieldTable& headers){ + getHeaderProperties()->setHeaders(headers); +} + +void Message::setDeliveryMode(uint8_t mode){ + getHeaderProperties()->setDeliveryMode(mode); +} + +void Message::setPriority(uint8_t priority){ + getHeaderProperties()->setPriority(priority); +} + +void Message::setCorrelationId(const std::string& correlationId){ + getHeaderProperties()->setCorrelationId(correlationId); +} + +void Message::setReplyTo(const std::string& replyTo){ + getHeaderProperties()->setReplyTo(replyTo); +} + +void Message::setExpiration(const std::string& expiration){ + getHeaderProperties()->setExpiration(expiration); +} + +void Message::setMessageId(const std::string& messageId){ + getHeaderProperties()->setMessageId(messageId); +} + +void Message::setTimestamp(uint64_t timestamp){ + getHeaderProperties()->setTimestamp(timestamp); +} + +void Message::setType(const std::string& type){ + getHeaderProperties()->setType(type); +} + +void Message::setUserId(const std::string& userId){ + getHeaderProperties()->setUserId(userId); +} + +void Message::setAppId(const std::string& appId){ + getHeaderProperties()->setAppId(appId); +} + +void Message::setClusterId(const std::string& clusterId){ + getHeaderProperties()->setClusterId(clusterId); +} + + +uint64_t Message::getDeliveryTag() const { + BasicDeliverBody* deliver=dynamic_cast<BasicDeliverBody*>(method.get()); + return deliver ? deliver->getDeliveryTag() : 0; +} diff --git a/qpid/cpp-0-9/lib/client/ClientMessage.h b/qpid/cpp-0-9/lib/client/ClientMessage.h new file mode 100644 index 0000000000..cb239ed4d6 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ClientMessage.h @@ -0,0 +1,125 @@ +#ifndef _client_ClientMessage_h +#define _client_ClientMessage_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <string> +#include <framing/amqp_framing.h> + +namespace qpid { + +namespace client { +class IncomingMessage; + +/** + * A representation of messages for sent or recived through the + * client api. + * + * \ingroup clientapi + */ +class Message { + framing::AMQMethodBody::shared_ptr method; + framing::AMQHeaderBody::shared_ptr header; + std::string data; + bool redelivered; + + // FIXME aconway 2007-02-20: const incorrect, needs const return type. + framing::BasicHeaderProperties* getHeaderProperties() const; + Message(qpid::framing::AMQHeaderBody::shared_ptr& header); + + public: + Message(const std::string& data=std::string()); + ~Message(); + + /** + * Allows the application to access the content of messages + * received. + * + * @return a string representing the data of the message + */ + std::string getData() const { return data; } + + /** + * Allows the application to set the content of messages to be + * sent. + * + * @param data a string representing the data of the message + */ + void setData(const std::string& _data); + + /** + * @return true if this message was delivered previously (to + * any consumer) but was not acknowledged. + */ + bool isRedelivered(){ return redelivered; } + void setRedelivered(bool _redelivered){ redelivered = _redelivered; } + + uint64_t getDeliveryTag() const; + + const std::string& getContentType() const; + const std::string& getContentEncoding() const; + qpid::framing::FieldTable& getHeaders() const; + uint8_t getDeliveryMode() const; + uint8_t getPriority() const; + const std::string& getCorrelationId() const; + const std::string& getReplyTo() const; + const std::string& getExpiration() const; + const std::string& getMessageId() const; + uint64_t getTimestamp() const; + const std::string& getType() const; + const std::string& getUserId() const; + const std::string& getAppId() const; + const std::string& getClusterId() const; + + void setContentType(const std::string& type); + void setContentEncoding(const std::string& encoding); + void setHeaders(const qpid::framing::FieldTable& headers); + /** + * Sets the delivery mode. 1 = non-durable, 2 = durable. + */ + void setDeliveryMode(uint8_t mode); + void setPriority(uint8_t priority); + void setCorrelationId(const std::string& correlationId); + void setReplyTo(const std::string& replyTo); + void setExpiration(const std::string& expiration); + void setMessageId(const std::string& messageId); + void setTimestamp(uint64_t timestamp); + void setType(const std::string& type); + void setUserId(const std::string& userId); + void setAppId(const std::string& appId); + void setClusterId(const std::string& clusterId); + + /** Get the method used to deliver this message */ + boost::shared_ptr<framing::AMQMethodBody> getMethod() const + { return method; } + + void setMethod(framing::AMQMethodBody::shared_ptr m) { method=m; } + boost::shared_ptr<framing::AMQHeaderBody> getHeader() const + { return header; } + + // TODO aconway 2007-02-15: remove friendships. + friend class IncomingMessage; + friend class Channel; +}; + +}} + +#endif /*!_client_ClientMessage_h*/ diff --git a/qpid/cpp-0-9/lib/client/ClientQueue.cpp b/qpid/cpp-0-9/lib/client/ClientQueue.cpp new file mode 100644 index 0000000000..773be504d8 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ClientQueue.cpp @@ -0,0 +1,58 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <ClientQueue.h> + +qpid::client::Queue::Queue() : name(""), autodelete(true), exclusive(true), durable(false){} + +qpid::client::Queue::Queue(std::string _name) : name(_name), autodelete(false), exclusive(false), durable(false){} + +qpid::client::Queue::Queue(std::string _name, bool temp) : name(_name), autodelete(temp), exclusive(temp), durable(false){} + +qpid::client::Queue::Queue(std::string _name, bool _autodelete, bool _exclusive, bool _durable) + : name(_name), autodelete(_autodelete), exclusive(_exclusive), durable(_durable){} + +const std::string& qpid::client::Queue::getName() const{ + return name; +} + +void qpid::client::Queue::setName(const std::string& _name){ + name = _name; +} + +bool qpid::client::Queue::isAutoDelete() const{ + return autodelete; +} + +bool qpid::client::Queue::isExclusive() const{ + return exclusive; +} + +bool qpid::client::Queue::isDurable() const{ + return durable; +} + +void qpid::client::Queue::setDurable(bool _durable){ + durable = _durable; +} + + + + diff --git a/qpid/cpp-0-9/lib/client/ClientQueue.h b/qpid/cpp-0-9/lib/client/ClientQueue.h new file mode 100644 index 0000000000..b37a44b004 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ClientQueue.h @@ -0,0 +1,103 @@ +#ifndef _client_ClientQueue_h +#define _client_ClientQueue_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <string> + +namespace qpid { +namespace client { + + /** + * A 'handle' used to represent an AMQP queue in the Channel + * methods. Creating an instance of this class does not cause the + * queue to be created on the broker. Rather, an instance of this + * class should be passed to Channel::declareQueue() to ensure + * that the queue exists or is created. + * + * Queues hold messages and allow clients to consume + * (see Channel::consume()) or get (see Channel::get()) those messags. A + * queue receives messages by being bound to one or more Exchange; + * messages published to that exchange may then be routed to the + * queue based on the details of the binding and the type of the + * exchange (see Channel::bind()). + * + * Queues are identified by a name. They can be exclusive (in which + * case they can only be used in the context of the connection + * over which they were declared, and are deleted when then + * connection closes), or they can be shared. Shared queues can be + * auto deleted when they have no consumers. + * + * We use the term 'temporary queue' to refer to an exclusive + * queue. + * + * \ingroup clientapi + */ + class Queue{ + std::string name; + const bool autodelete; + const bool exclusive; + bool durable; + + public: + + /** + * Creates an unnamed, non-durable, temporary queue. A name + * will be assigned to this queue instance by a call to + * Channel::declareQueue(). + */ + Queue(); + /** + * Creates a shared, non-durable, queue with a given name, + * that will not be autodeleted. + * + * @param name the name of the queue + */ + Queue(std::string name); + /** + * Creates a non-durable queue with a given name. + * + * @param name the name of the queue + * + * @param temp if true the queue will be a temporary queue, if + * false it will be shared and not autodeleted. + */ + Queue(std::string name, bool temp); + /** + * This constructor allows the autodelete, exclusive and + * durable propeties to be explictly set. Note however that if + * exclusive is true, autodelete has no meaning as exclusive + * queues are always destroyed when the connection that + * created them is closed. + */ + Queue(std::string name, bool autodelete, bool exclusive, bool durable); + const std::string& getName() const; + void setName(const std::string&); + bool isAutoDelete() const; + bool isExclusive() const; + bool isDurable() const; + void setDurable(bool durable); + }; + +} +} + +#endif /*!_client_ClientQueue_h*/ diff --git a/qpid/cpp-0-9/lib/client/Connection.cpp b/qpid/cpp-0-9/lib/client/Connection.cpp new file mode 100644 index 0000000000..618f3cbc92 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/Connection.cpp @@ -0,0 +1,156 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <algorithm> +#include <boost/format.hpp> +#include <boost/bind.hpp> + +#include <Connection.h> +#include <ClientChannel.h> +#include <ClientMessage.h> +#include <QpidError.h> +#include <iostream> +#include <sstream> +#include <MethodBodyInstances.h> +#include <functional> + +using namespace qpid::framing; +using namespace qpid::sys; + + +namespace qpid { +namespace client { + +const std::string Connection::OK("OK"); + +Connection::Connection( + bool _debug, uint32_t _max_frame_size, + framing::ProtocolVersion _version +) : channelIdCounter(0), version(_version), max_frame_size(_max_frame_size), + defaultConnector(version, _debug, _max_frame_size), + isOpen(false), debug(_debug) +{ + setConnector(defaultConnector); +} + +Connection::~Connection(){} + +void Connection::setConnector(Connector& con) +{ + connector = &con; + connector->setInputHandler(this); + connector->setTimeoutHandler(this); + connector->setShutdownHandler(this); + out = connector->getOutputHandler(); +} + +void Connection::open( + const std::string& host, int port, + const std::string& uid, const std::string& pwd, const std::string& vhost) +{ + if (isOpen) + THROW_QPID_ERROR(INTERNAL_ERROR, "Channel object is already open"); + connector->connect(host, port); + channels[0] = &channel0; + channel0.open(0, *this); + channel0.protocolInit(uid, pwd, vhost); + isOpen = true; +} + +void Connection::shutdown() { + close(); +} + +void Connection::close( + ReplyCode code, const string& msg, ClassId classId, MethodId methodId +) +{ + if(isOpen) { + // TODO aconway 2007-01-29: Exception handling - could end up + // partly closed with threads left unjoined. + isOpen = false; + channel0.sendAndReceive<ConnectionCloseOkBody>( + new ConnectionCloseBody( + getVersion(), code, msg, classId, methodId)); + + using boost::bind; + for_each(channels.begin(), channels.end(), + bind(&Channel::closeInternal, + bind(&ChannelMap::value_type::second, _1))); + channels.clear(); + connector->close(); + } +} + +void Connection::openChannel(Channel& channel) { + ChannelId id = ++channelIdCounter; + assert (channels.find(id) == channels.end()); + assert(out); + channels[id] = &channel; + channel.open(id, *this); +} + +void Connection::erase(ChannelId id) { + channels.erase(id); +} + +void Connection::received(AMQFrame* frame){ + // FIXME aconway 2007-01-25: Mutex + ChannelId id = frame->getChannel(); + Channel* channel = channels[id]; + // FIXME aconway 2007-01-26: Exception thrown here is hanging the + // client. Need to review use of exceptions. + if (channel == 0) + THROW_QPID_ERROR( + PROTOCOL_ERROR+504, + (boost::format("Invalid channel number %g") % id).str()); + try{ + channel->handleBody(frame->getBody()); + }catch(const qpid::QpidError& e){ + channelException( + *channel, dynamic_cast<AMQMethodBody*>(frame->getBody().get()), e); + } +} + +void Connection::send(AMQFrame* frame) { + out->send(frame); +} + +void Connection::channelException( + Channel& channel, AMQMethodBody* method, const QpidError& e) +{ + int code = (e.code >= PROTOCOL_ERROR) ? e.code - PROTOCOL_ERROR : 500; + string msg = e.msg; + if(method == 0) + channel.close(code, msg); + else + channel.close( + code, msg, method->amqpClassId(), method->amqpMethodId()); +} + +void Connection::idleIn(){ + connector->close(); +} + +void Connection::idleOut(){ + out->send(new AMQFrame(version, 0, new AMQHeartbeatBody())); +} + +}} // namespace qpid::client diff --git a/qpid/cpp-0-9/lib/client/Connection.h b/qpid/cpp-0-9/lib/client/Connection.h new file mode 100644 index 0000000000..b4bd311511 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/Connection.h @@ -0,0 +1,194 @@ +#ifndef _client_Connection_ +#define _client_Connection_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <map> +#include <string> +#include <boost/shared_ptr.hpp> + +#include "amqp_types.h" +#include <QpidError.h> +#include <Connector.h> +#include <sys/ShutdownHandler.h> +#include <sys/TimeoutHandler.h> + + +#include "framing/amqp_types.h" +#include <framing/amqp_framing.h> +#include <ClientExchange.h> +#include <IncomingMessage.h> +#include <ClientMessage.h> +#include <MessageListener.h> +#include <ClientQueue.h> +#include <ResponseHandler.h> +#include <AMQP_HighestVersion.h> +#include "ClientChannel.h" + +namespace qpid { + +/** + * The client namespace contains all classes that make up a client + * implementation of the AMQP protocol. The key classes that form + * the basis of the client API to be used by applications are + * Connection and Channel. + */ +namespace client { + +class Channel; + +/** + * \internal provide access to selected private channel functions + * for the Connection without making it a friend of the entire channel. + */ +class ConnectionForChannel : + public framing::InputHandler, + public framing::OutputHandler, + public sys::TimeoutHandler, + public sys::ShutdownHandler + +{ + private: + friend class Channel; + virtual void erase(framing::ChannelId) = 0; +}; + + +/** + * \defgroup clientapi Application API for an AMQP client + */ + +/** + * Represents a connection to an AMQP broker. All communication is + * initiated by establishing a connection, then opening one or + * more Channels over that connection. + * + * \ingroup clientapi + */ +class Connection : public ConnectionForChannel +{ + typedef std::map<framing::ChannelId, Channel*> ChannelMap; + + framing::ChannelId channelIdCounter; + static const std::string OK; + + framing::ProtocolVersion version; + const uint32_t max_frame_size; + ChannelMap channels; + Connector defaultConnector; + Connector* connector; + framing::OutputHandler* out; + volatile bool isOpen; + Channel channel0; + bool debug; + + void erase(framing::ChannelId); + void channelException( + Channel&, framing::AMQMethodBody*, const QpidError&); + + // TODO aconway 2007-01-26: too many friendships, untagle these classes. + friend class Channel; + + public: + /** + * Creates a connection object, but does not open the + * connection. + * + * @param _version the version of the protocol to connect with + * + * @param debug turns on tracing for the connection + * (i.e. prints details of the frames sent and received to std + * out). Optional and defaults to false. + * + * @param max_frame_size the maximum frame size that the + * client will accept. Optional and defaults to 65536. + */ + Connection(bool debug = false, uint32_t max_frame_size = 65536, + framing::ProtocolVersion=framing::highestProtocolVersion); + ~Connection(); + + /** + * Opens a connection to a broker. + * + * @param host the host on which the broker is running + * + * @param port the port on the which the broker is listening + * + * @param uid the userid to connect with + * + * @param pwd the password to connect with (currently SASL + * PLAIN is the only authentication method supported so this + * is sent in clear text) + * + * @param virtualhost the AMQP virtual host to use (virtual + * hosts, where implemented(!), provide namespace partitioning + * within a single broker). + */ + void open(const std::string& host, int port = 5672, + const std::string& uid = "guest", + const std::string& pwd = "guest", + const std::string& virtualhost = "/"); + + /** + * Close the connection with optional error information for the peer. + * + * Any further use of this connection (without reopening it) will + * not succeed. + */ + void close(framing::ReplyCode=200, const std::string& msg=OK, + framing::ClassId = 0, framing::MethodId = 0); + + /** + * Associate a Channel with this connection and open it for use. + * + * In AMQP channels are like multi-plexed 'sessions' of work over + * a connection. Almost all the interaction with AMQP is done over + * a channel. + * + * @param connection the connection object to be associated with + * the channel. Call Channel::close() to close the channel. + */ + void openChannel(Channel&); + + + // TODO aconway 2007-01-26: can these be private? + void send(framing::AMQFrame*); + void received(framing::AMQFrame*); + void idleOut(); + void idleIn(); + void shutdown(); + + /**\internal used for testing */ + void setConnector(Connector& connector); + + /** + * @return the maximum frame size in use on this connection + */ + inline uint32_t getMaxFrameSize(){ return max_frame_size; } + + /** @return protocol version in use on this connection. */ + framing::ProtocolVersion getVersion() const { return version; } +}; + +}} // namespace qpid::client + + +#endif diff --git a/qpid/cpp-0-9/lib/client/Connector.cpp b/qpid/cpp-0-9/lib/client/Connector.cpp new file mode 100644 index 0000000000..7b73cc016a --- /dev/null +++ b/qpid/cpp-0-9/lib/client/Connector.cpp @@ -0,0 +1,188 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <QpidError.h> +#include <sys/Time.h> +#include "Connector.h" + +namespace qpid { +namespace client { + +using namespace qpid::sys; +using namespace qpid::framing; +using qpid::QpidError; + +Connector::Connector( + ProtocolVersion ver, bool _debug, uint32_t buffer_size +) : debug(_debug), + receive_buffer_size(buffer_size), + send_buffer_size(buffer_size), + version(ver), + closed(true), + lastIn(0), lastOut(0), + timeout(0), + idleIn(0), idleOut(0), + timeoutHandler(0), + shutdownHandler(0), + inbuf(receive_buffer_size), + outbuf(send_buffer_size) +{ } + +Connector::~Connector(){ } + +void Connector::connect(const std::string& host, int port){ + socket = Socket::createTcp(); + socket.connect(host, port); + closed = false; + receiver = Thread(this); +} + +void Connector::init(){ + ProtocolInitiation init(version); + writeBlock(&init); +} + +void Connector::close(){ + closed = true; + socket.close(); + receiver.join(); +} + +void Connector::setInputHandler(InputHandler* handler){ + input = handler; +} + +void Connector::setShutdownHandler(ShutdownHandler* handler){ + shutdownHandler = handler; +} + +OutputHandler* Connector::getOutputHandler(){ + return this; +} + +void Connector::send(AMQFrame* f){ + std::auto_ptr<AMQFrame> frame(f); + AMQBody::shared_ptr body = frame->getBody(); + writeBlock(frame.get()); + if(debug) std::cout << "SENT: " << *frame << std::endl; +} + +void Connector::writeBlock(AMQDataBlock* data){ + Mutex::ScopedLock l(writeLock); + data->encode(outbuf); + //transfer data to wire + outbuf.flip(); + writeToSocket(outbuf.start(), outbuf.available()); + outbuf.clear(); +} + +void Connector::writeToSocket(char* data, size_t available){ + size_t written = 0; + while(written < available && !closed){ + ssize_t sent = socket.send(data + written, available-written); + if(sent > 0) { + lastOut = now() * TIME_MSEC; + written += sent; + } + } +} + +void Connector::handleClosed(){ + closed = true; + socket.close(); + if(shutdownHandler) shutdownHandler->shutdown(); +} + +void Connector::checkIdle(ssize_t status){ + if(timeoutHandler){ + Time t = now() * TIME_MSEC; + if(status == Socket::SOCKET_TIMEOUT) { + if(idleIn && (t - lastIn > idleIn)){ + timeoutHandler->idleIn(); + } + } + else if(status == 0 || status == Socket::SOCKET_EOF) { + handleClosed(); + } + else { + lastIn = t; + } + if(idleOut && (t - lastOut > idleOut)){ + timeoutHandler->idleOut(); + } + } +} + +void Connector::setReadTimeout(uint16_t t){ + idleIn = t * 1000;//t is in secs + if(idleIn && (!timeout || idleIn < timeout)){ + timeout = idleIn; + setSocketTimeout(); + } + +} + +void Connector::setWriteTimeout(uint16_t t){ + idleOut = t * 1000;//t is in secs + if(idleOut && (!timeout || idleOut < timeout)){ + timeout = idleOut; + setSocketTimeout(); + } +} + +void Connector::setSocketTimeout(){ + socket.setTimeout(timeout*TIME_MSEC); +} + +void Connector::setTimeoutHandler(TimeoutHandler* handler){ + timeoutHandler = handler; +} + +void Connector::run(){ + try{ + while(!closed){ + ssize_t available = inbuf.available(); + if(available < 1){ + THROW_QPID_ERROR(INTERNAL_ERROR, "Frame exceeds buffer size."); + } + ssize_t received = socket.recv(inbuf.start(), available); + checkIdle(received); + + if(!closed && received > 0){ + inbuf.move(received); + inbuf.flip();//position = 0, limit = total data read + + AMQFrame frame(version); + while(frame.decode(inbuf)){ + if(debug) std::cout << "RECV: " << frame << std::endl; + input->received(&frame); + } + //need to compact buffer to preserve any 'extra' data + inbuf.compact(); + } + } + } catch (const std::exception& e) { + std::cout << e.what() << std::endl; + handleClosed(); + } +} + +}} // namespace qpid::client diff --git a/qpid/cpp-0-9/lib/client/Connector.h b/qpid/cpp-0-9/lib/client/Connector.h new file mode 100644 index 0000000000..91234d2321 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/Connector.h @@ -0,0 +1,98 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _Connector_ +#define _Connector_ + + +#include <framing/InputHandler.h> +#include <framing/OutputHandler.h> +#include <framing/InitiationHandler.h> +#include <framing/ProtocolInitiation.h> +#include <ProtocolVersion.h> +#include <sys/ShutdownHandler.h> +#include <sys/TimeoutHandler.h> +#include <sys/Thread.h> +#include <sys/Monitor.h> +#include <sys/Socket.h> + +namespace qpid { + +namespace client { + +class Connector : public framing::OutputHandler, + private sys::Runnable +{ + const bool debug; + const int receive_buffer_size; + const int send_buffer_size; + framing::ProtocolVersion version; + + bool closed; + + int64_t lastIn; + int64_t lastOut; + int64_t timeout; + uint32_t idleIn; + uint32_t idleOut; + + sys::TimeoutHandler* timeoutHandler; + sys::ShutdownHandler* shutdownHandler; + framing::InputHandler* input; + framing::InitiationHandler* initialiser; + framing::OutputHandler* output; + + framing::Buffer inbuf; + framing::Buffer outbuf; + + sys::Mutex writeLock; + sys::Thread receiver; + + sys::Socket socket; + + void checkIdle(ssize_t status); + void writeBlock(framing::AMQDataBlock* data); + void writeToSocket(char* data, size_t available); + void setSocketTimeout(); + + void run(); + void handleClosed(); + + friend class Channel; + public: + Connector(framing::ProtocolVersion pVersion, + bool debug = false, uint32_t buffer_size = 1024); + virtual ~Connector(); + virtual void connect(const std::string& host, int port); + virtual void init(); + virtual void close(); + virtual void setInputHandler(framing::InputHandler* handler); + virtual void setTimeoutHandler(sys::TimeoutHandler* handler); + virtual void setShutdownHandler(sys::ShutdownHandler* handler); + virtual framing::OutputHandler* getOutputHandler(); + virtual void send(framing::AMQFrame* frame); + virtual void setReadTimeout(uint16_t timeout); + virtual void setWriteTimeout(uint16_t timeout); +}; + +}} + + +#endif diff --git a/qpid/cpp-0-9/lib/client/IncomingMessage.cpp b/qpid/cpp-0-9/lib/client/IncomingMessage.cpp new file mode 100644 index 0000000000..07f94ceb64 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/IncomingMessage.cpp @@ -0,0 +1,172 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <IncomingMessage.h> +#include "framing/AMQHeaderBody.h" +#include "framing/AMQContentBody.h" +#include "BasicGetOkBody.h" +#include "BasicReturnBody.h" +#include "BasicDeliverBody.h" +#include <QpidError.h> +#include <iostream> + +namespace qpid { +namespace client { + +using namespace sys; +using namespace framing; + +struct IncomingMessage::Guard: public Mutex::ScopedLock { + Guard(IncomingMessage* im) : Mutex::ScopedLock(im->lock) { + im->shutdownError.throwIf(); + } +}; + +IncomingMessage::IncomingMessage() { reset(); } + +void IncomingMessage::reset() { + state = &IncomingMessage::expectRequest; + endFn= &IncomingMessage::endRequest; + buildMessage = Message(); +} + +void IncomingMessage::startGet() { + Guard g(this); + if (state != &IncomingMessage::expectRequest) { + endGet(new QPID_ERROR(CLIENT_ERROR, "Message already in progress.")); + } + else { + state = &IncomingMessage::expectGetOk; + endFn = &IncomingMessage::endGet; + getError.reset(); + getState = GETTING; + } +} + +bool IncomingMessage::waitGet(Message& msg) { + Guard g(this); + while (getState == GETTING && !shutdownError && !getError) + getReady.wait(lock); + shutdownError.throwIf(); + getError.throwIf(); + msg = getMessage; + return getState==GOT; +} + +Message IncomingMessage::waitDispatch() { + Guard g(this); + while(dispatchQueue.empty() && !shutdownError) + dispatchReady.wait(lock); + shutdownError.throwIf(); + + Message msg(dispatchQueue.front()); + dispatchQueue.pop(); + return msg; +} + +void IncomingMessage::add(BodyPtr body) { + Guard g(this); + shutdownError.throwIf(); + // Call the current state function. + (this->*state)(body); +} + +void IncomingMessage::shutdown() { + Mutex::ScopedLock l(lock); + shutdownError.reset(new ShutdownException()); + getReady.notify(); + dispatchReady.notify(); +} + +bool IncomingMessage::isShutdown() const { + Mutex::ScopedLock l(lock); + return shutdownError; +} + +// Common check for all the expect functions. Called in network thread. +template<class T> +boost::shared_ptr<T> IncomingMessage::expectCheck(BodyPtr body) { + boost::shared_ptr<T> ptr = boost::dynamic_pointer_cast<T>(body); + if (!ptr) + throw QPID_ERROR(PROTOCOL_ERROR+504, "Unexpected frame type"); + return ptr; +} + +void IncomingMessage::expectGetOk(BodyPtr body) { + if (dynamic_cast<BasicGetOkBody*>(body.get())) + state = &IncomingMessage::expectHeader; + else if (dynamic_cast<BasicGetEmptyBody*>(body.get())) { + getState = EMPTY; + endGet(); + } + else + throw QPID_ERROR(PROTOCOL_ERROR+504, "Unexpected frame type"); +} + +void IncomingMessage::expectHeader(BodyPtr body) { + AMQHeaderBody::shared_ptr header = expectCheck<AMQHeaderBody>(body); + buildMessage.header = header; + state = &IncomingMessage::expectContent; + checkComplete(); +} + +void IncomingMessage::expectContent(BodyPtr body) { + AMQContentBody::shared_ptr content = expectCheck<AMQContentBody>(body); + buildMessage.setData(buildMessage.getData() + content->getData()); + checkComplete(); +} + +void IncomingMessage::checkComplete() { + size_t declaredSize = buildMessage.header->getContentSize(); + size_t currentSize = buildMessage.getData().size(); + if (declaredSize == currentSize) + (this->*endFn)(0); + else if (declaredSize < currentSize) + (this->*endFn)(new QPID_ERROR( + PROTOCOL_ERROR, "Message content exceeds declared size.")); +} + +void IncomingMessage::expectRequest(BodyPtr body) { + AMQMethodBody::shared_ptr method = expectCheck<AMQMethodBody>(body); + buildMessage.setMethod(method); + state = &IncomingMessage::expectHeader; +} + +void IncomingMessage::endGet(Exception* ex) { + getError.reset(ex); + if (getState == GETTING) { + getMessage = buildMessage; + getState = GOT; + } + reset(); + getReady.notify(); +} + +void IncomingMessage::endRequest(Exception* ex) { + ExceptionHolder eh(ex); + if (!eh) { + dispatchQueue.push(buildMessage); + reset(); + dispatchReady.notify(); + } + eh.throwIf(); +} + +}} // namespace qpid::client diff --git a/qpid/cpp-0-9/lib/client/IncomingMessage.h b/qpid/cpp-0-9/lib/client/IncomingMessage.h new file mode 100644 index 0000000000..2d7c8723c5 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/IncomingMessage.h @@ -0,0 +1,118 @@ +#ifndef _IncomingMessage_ +#define _IncomingMessage_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <string> +#include <queue> +#include <framing/amqp_framing.h> +#include "ExceptionHolder.h" +#include "ClientMessage.h" +#include "sys/Mutex.h" +#include "sys/Condition.h" + +namespace qpid { + +namespace framing { +class AMQBody; +} + +namespace client { +/** + * Accumulates incoming message frames into messages. + * Client-initiated messages (basic.get) are initiated and made + * available to the user thread one at a time. + * + * Broker initiated messages (basic.return, basic.deliver) are + * queued for handling by the user dispatch thread. + */ +class IncomingMessage { + public: + typedef boost::shared_ptr<framing::AMQBody> BodyPtr; + IncomingMessage(); + + /** Expect a new message starting with getOk. Called in user thread.*/ + void startGet(); + + /** Wait for the message to complete, return the message. + * Called in user thread. + *@raises QpidError if there was an error. + */ + bool waitGet(Message&); + + /** Wait for the next broker-initiated message. */ + Message waitDispatch(); + + /** Add a frame body to the message. Called in network thread. */ + void add(BodyPtr); + + /** Shut down: all further calls to any function throw ex. */ + void shutdown(); + + /** Check if shutdown */ + bool isShutdown() const; + + private: + + typedef void (IncomingMessage::* ExpectFn)(BodyPtr); + typedef void (IncomingMessage::* EndFn)(Exception*); + typedef std::queue<Message> MessageQueue; + struct Guard; + friend struct Guard; + + void reset(); + template <class T> boost::shared_ptr<T> expectCheck(BodyPtr); + + // State functions - a state machine where each state is + // a member function that processes a frame body. + void expectGetOk(BodyPtr); + void expectHeader(BodyPtr); + void expectContent(BodyPtr); + void expectRequest(BodyPtr); + + // End functions. + void endGet(Exception* ex = 0); + void endRequest(Exception* ex); + + // Check for complete message. + void checkComplete(); + + mutable sys::Mutex lock; + ExpectFn state; + EndFn endFn; + Message buildMessage; + ExceptionHolder shutdownError; + + // For basic.get messages. + sys::Condition getReady; + ExceptionHolder getError; + Message getMessage; + enum { GETTING, GOT, EMPTY } getState; + + // For broker-initiated messages + sys::Condition dispatchReady; + MessageQueue dispatchQueue; +}; + +}} + + +#endif diff --git a/qpid/cpp-0-9/lib/client/Makefile.am b/qpid/cpp-0-9/lib/client/Makefile.am new file mode 100644 index 0000000000..1e10a2a244 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/Makefile.am @@ -0,0 +1,36 @@ +AM_CXXFLAGS = $(WARNING_CFLAGS) +INCLUDES = \ + -I$(top_srcdir)/gen \ + -I$(top_srcdir)/lib/common \ + -I$(top_srcdir)/lib/common/sys \ + -I$(top_srcdir)/lib/common/framing \ + $(APR_CXXFLAGS) + +lib_LTLIBRARIES = libqpidclient.la +libqpidclient_la_LIBADD = ../common/libqpidcommon.la +libqpidclient_la_LDFLAGS = -version-info $(LIBTOOL_VERSION_INFO_ARG) +libqpidclient_la_SOURCES = \ + ClientChannel.cpp \ + ClientExchange.cpp \ + ClientMessage.cpp \ + ClientQueue.cpp \ + Basic.cpp \ + Connection.cpp \ + Connector.cpp \ + IncomingMessage.cpp \ + MessageListener.cpp \ + ResponseHandler.cpp \ + ReturnedMessageHandler.cpp +pkginclude_HEADERS = \ + ClientChannel.h \ + ClientExchange.h \ + ClientMessage.h \ + ClientQueue.h \ + Basic.h \ + Connection.h \ + Connector.h \ + IncomingMessage.h \ + MessageListener.h \ + MethodBodyInstances.h \ + ResponseHandler.h \ + ReturnedMessageHandler.h diff --git a/qpid/cpp-0-9/lib/client/MessageListener.cpp b/qpid/cpp-0-9/lib/client/MessageListener.cpp new file mode 100644 index 0000000000..70d44e7040 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/MessageListener.cpp @@ -0,0 +1,24 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <MessageListener.h> + +qpid::client::MessageListener::~MessageListener() {} diff --git a/qpid/cpp-0-9/lib/client/MessageListener.h b/qpid/cpp-0-9/lib/client/MessageListener.h new file mode 100644 index 0000000000..cfb917b4f8 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/MessageListener.h @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <string> + +#ifndef _MessageListener_ +#define _MessageListener_ + +#include <ClientMessage.h> + +namespace qpid { +namespace client { + + /** + * An interface through which asynchronously delivered messages + * can be received by an application. + * + * @see Channel::consume() + * + * \ingroup clientapi + */ + class MessageListener{ + public: + virtual ~MessageListener(); + virtual void received(Message& msg) = 0; + }; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/client/MethodBodyInstances.h b/qpid/cpp-0-9/lib/client/MethodBodyInstances.h new file mode 100644 index 0000000000..acbeeb1158 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/MethodBodyInstances.h @@ -0,0 +1,100 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <framing/amqp_framing.h> + +#ifndef _MethodBodyInstances_h_ +#define _MethodBodyInstances_h_ + +namespace qpid { +namespace client { + +/** + * A list of method body instances that can be used to compare against + * incoming bodies. + */ +class MethodBodyInstances +{ +private: + qpid::framing::ProtocolVersion version; +public: + const qpid::framing::BasicCancelOkBody basic_cancel_ok; + const qpid::framing::BasicConsumeOkBody basic_consume_ok; + const qpid::framing::BasicDeliverBody basic_deliver; + const qpid::framing::BasicGetEmptyBody basic_get_empty; + const qpid::framing::BasicGetOkBody basic_get_ok; + const qpid::framing::BasicQosOkBody basic_qos_ok; + const qpid::framing::BasicReturnBody basic_return; + const qpid::framing::ChannelCloseBody channel_close; + const qpid::framing::ChannelCloseOkBody channel_close_ok; + const qpid::framing::ChannelFlowBody channel_flow; + const qpid::framing::ChannelOpenOkBody channel_open_ok; + const qpid::framing::ConnectionCloseBody connection_close; + const qpid::framing::ConnectionCloseOkBody connection_close_ok; + const qpid::framing::ConnectionOpenOkBody connection_open_ok; + const qpid::framing::ConnectionRedirectBody connection_redirect; + const qpid::framing::ConnectionStartBody connection_start; + const qpid::framing::ConnectionTuneBody connection_tune; + const qpid::framing::ExchangeDeclareOkBody exchange_declare_ok; + const qpid::framing::ExchangeDeleteOkBody exchange_delete_ok; + const qpid::framing::QueueDeclareOkBody queue_declare_ok; + const qpid::framing::QueueDeleteOkBody queue_delete_ok; + const qpid::framing::QueueBindOkBody queue_bind_ok; + const qpid::framing::TxCommitOkBody tx_commit_ok; + const qpid::framing::TxRollbackOkBody tx_rollback_ok; + const qpid::framing::TxSelectOkBody tx_select_ok; + + MethodBodyInstances(uint8_t major, uint8_t minor) : + version(major, minor), + basic_cancel_ok(version), + basic_consume_ok(version), + basic_deliver(version), + basic_get_empty(version), + basic_get_ok(version), + basic_qos_ok(version), + basic_return(version), + channel_close(version), + channel_close_ok(version), + channel_flow(version), + channel_open_ok(version), + connection_close(version), + connection_close_ok(version), + connection_open_ok(version), + connection_redirect(version), + connection_start(version), + connection_tune(version), + exchange_declare_ok(version), + exchange_delete_ok(version), + queue_declare_ok(version), + queue_delete_ok(version), + queue_bind_ok(version), + tx_commit_ok(version), + tx_rollback_ok(version), + tx_select_ok(version) + {} + +}; + +static MethodBodyInstances method_bodies(8, 0); + +} // namespace client +} // namespace qpid + +#endif diff --git a/qpid/cpp-0-9/lib/client/ResponseHandler.cpp b/qpid/cpp-0-9/lib/client/ResponseHandler.cpp new file mode 100644 index 0000000000..4498de41ae --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ResponseHandler.cpp @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <boost/format.hpp> + +#include <ResponseHandler.h> +#include <sys/Monitor.h> +#include <QpidError.h> +#include "amqp_types.h" + +using namespace qpid::sys; +using namespace qpid::framing; + +namespace qpid { +namespace client { + +ResponseHandler::ResponseHandler() : waiting(false){} + +ResponseHandler::~ResponseHandler(){} + +bool ResponseHandler::validate(ClassId c, MethodId m) { + return response != 0 && + response->amqpClassId() ==c && response->amqpMethodId() == m; +} + +void ResponseHandler::waitForResponse(){ + Monitor::ScopedLock l(monitor); + while (waiting) + monitor.wait(); +} + +void ResponseHandler::signalResponse( + qpid::framing::AMQMethodBody::shared_ptr _response) +{ + Monitor::ScopedLock l(monitor); + response = _response; + waiting = false; + monitor.notify(); +} + +void ResponseHandler::receive(ClassId c, MethodId m) { + Monitor::ScopedLock l(monitor); + while (waiting) + monitor.wait(); + getResponse(); // Check for closed. + if(!validate(response->amqpClassId(), response->amqpMethodId())) { + THROW_QPID_ERROR( + PROTOCOL_ERROR, + boost::format("Expected class:method %d:%d, got %d:%d") + % c % m % response->amqpClassId() % response->amqpMethodId()); + } +} + +framing::AMQMethodBody::shared_ptr ResponseHandler::getResponse() { + if (!response) + THROW_QPID_ERROR( + PROTOCOL_ERROR, "Channel closed unexpectedly."); + return response; +} + +RequestId ResponseHandler::getRequestId() { + assert(response->getRequestId()); + return response->getRequestId(); +} +void ResponseHandler::expect(){ + waiting = true; +} + +}} // namespace qpid::client diff --git a/qpid/cpp-0-9/lib/client/ResponseHandler.h b/qpid/cpp-0-9/lib/client/ResponseHandler.h new file mode 100644 index 0000000000..d28048c3d3 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ResponseHandler.h @@ -0,0 +1,68 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <string> + +#include <framing/amqp_framing.h> // FIXME aconway 2007-02-01: #include cleanup. +#include <sys/Monitor.h> + +#ifndef _ResponseHandler_ +#define _ResponseHandler_ + +namespace qpid { +namespace client { + +/** + * Holds a response from the broker peer for the client. + */ +class ResponseHandler{ + bool waiting; + qpid::framing::AMQMethodBody::shared_ptr response; + qpid::sys::Monitor monitor; + + public: + ResponseHandler(); + ~ResponseHandler(); + + bool isWaiting(){ return waiting; } + framing::AMQMethodBody::shared_ptr getResponse(); + void waitForResponse(); + + void signalResponse(framing::AMQMethodBody::shared_ptr response); + + void expect();//must be called before calling receive + bool validate(framing::ClassId, framing::MethodId); + void receive(framing::ClassId, framing::MethodId); + + framing::RequestId getRequestId(); + + template <class BodyType> bool validate() { + return validate(BodyType::CLASS_ID, BodyType::METHOD_ID); + } + template <class BodyType> void receive() { + receive(BodyType::CLASS_ID, BodyType::METHOD_ID); + } +}; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/client/ReturnedMessageHandler.cpp b/qpid/cpp-0-9/lib/client/ReturnedMessageHandler.cpp new file mode 100644 index 0000000000..ee9f7462ef --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ReturnedMessageHandler.cpp @@ -0,0 +1,24 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <ReturnedMessageHandler.h> + +qpid::client::ReturnedMessageHandler::~ReturnedMessageHandler() {} diff --git a/qpid/cpp-0-9/lib/client/ReturnedMessageHandler.h b/qpid/cpp-0-9/lib/client/ReturnedMessageHandler.h new file mode 100644 index 0000000000..137f0b2e17 --- /dev/null +++ b/qpid/cpp-0-9/lib/client/ReturnedMessageHandler.h @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <string> + +#ifndef _ReturnedMessageHandler_ +#define _ReturnedMessageHandler_ + +#include <ClientMessage.h> + +namespace qpid { +namespace client { + + /** + * An interface through which returned messages can be received by + * an application. + * + * @see Channel::setReturnedMessageHandler() + * + * \ingroup clientapi + */ + class ReturnedMessageHandler{ + public: + virtual ~ReturnedMessageHandler(); + virtual void returned(Message& msg) = 0; + }; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/Exception.cpp b/qpid/cpp-0-9/lib/common/Exception.cpp new file mode 100644 index 0000000000..f7d91498e0 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/Exception.cpp @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <Exception.h> + +namespace qpid { + +Exception::Exception() throw() {} + +Exception::Exception(const std::string& str) throw() : whatStr(str) {} + +Exception::Exception(const char* str) throw() : whatStr(str) {} + +Exception::~Exception() throw() {} + +const char* Exception::what() const throw() { return whatStr.c_str(); } + +std::string Exception::toString() const throw() { return whatStr; } + +Exception* Exception::clone() const throw() { return new Exception(*this); } + +void Exception::throwSelf() const { throw *this; } + +ShutdownException::ShutdownException() : Exception("Shut down.") {} + +EmptyException::EmptyException() : Exception("Empty.") {} + +} // namespace qpid diff --git a/qpid/cpp-0-9/lib/common/Exception.h b/qpid/cpp-0-9/lib/common/Exception.h new file mode 100644 index 0000000000..b8cd68cf8c --- /dev/null +++ b/qpid/cpp-0-9/lib/common/Exception.h @@ -0,0 +1,97 @@ +#ifndef _Exception_ +#define _Exception_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <exception> +#include <string> +#include <memory> +#include <boost/shared_ptr.hpp> +#include <boost/lexical_cast.hpp> + +#include "amqp_types.h" + +namespace qpid +{ +/** + * Exception base class for all Qpid exceptions. + */ +class Exception : public std::exception +{ + protected: + std::string whatStr; + + public: + Exception() throw(); + Exception(const std::string& str) throw(); + Exception(const char* str) throw(); + Exception(const std::exception&) throw(); + + /** Allow any type that has ostream operator<< to act as message */ + template <class T> + Exception(const T& message) + : whatStr(boost::lexical_cast<std::string>(message)) {} + + virtual ~Exception() throw(); + + virtual const char* what() const throw(); + virtual std::string toString() const throw(); + + virtual Exception* clone() const throw(); + virtual void throwSelf() const; + + typedef boost::shared_ptr<Exception> shared_ptr; +}; + +struct ChannelException : public Exception { + framing::ReplyCode code; + template <class T> + ChannelException(framing::ReplyCode code_, const T& message) + : Exception(message), code(code_) {} + void throwSelf() const { throw *this; } +}; + +struct ConnectionException : public Exception { + framing::ReplyCode code; + template <class T> + ConnectionException(framing::ReplyCode code_, const T& message) + : Exception(message), code(code_) {} + void throwSelf() const { throw *this; } +}; + +/** + * Exception used to indicate that a thread should shut down. + * Does not indicate an error that should be signalled to the user. + */ +struct ShutdownException : public Exception { + ShutdownException(); + void throwSelf() const { throw *this; } +}; + +/** Exception to indicate empty queue or other empty state */ +struct EmptyException : public Exception { + EmptyException(); + void throwSelf() const { throw *this; } +}; + +} + +#endif /*!_Exception_*/ diff --git a/qpid/cpp-0-9/lib/common/ExceptionHolder.cpp b/qpid/cpp-0-9/lib/common/ExceptionHolder.cpp new file mode 100644 index 0000000000..de8d7b2487 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/ExceptionHolder.cpp @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "ExceptionHolder.h" + +namespace qpid { + +ExceptionHolder::ExceptionHolder(const std::exception& e) { + const Exception* ex = dynamic_cast<const Exception*>(&e); + if (ex) { + reset(ex->clone()); + } else { + reset(new Exception(e.what())); + } +} + +} diff --git a/qpid/cpp-0-9/lib/common/ExceptionHolder.h b/qpid/cpp-0-9/lib/common/ExceptionHolder.h new file mode 100644 index 0000000000..2769455aba --- /dev/null +++ b/qpid/cpp-0-9/lib/common/ExceptionHolder.h @@ -0,0 +1,67 @@ +#ifndef _qpid_ExceptionHolder_h +#define _qpid_ExceptionHolder_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <assert.h> +#include <Exception.h> +#include <boost/shared_ptr.hpp> + +namespace qpid { + +// FIXME aconway 2007-02-20: Not necessary, a simple +// Exception::shared_ptr will do the job. Remove +// +/** + * Holder for a heap-allocated exc eption that can be stack allocated + * and thrown safely. + * + * Basically this is a shared_ptr with the Exception functions added + * so the catcher need not be aware that it is a pointer rather than a + * reference. + * + * shared_ptr is chosen over auto_ptr because it has normal + * copy semantics. + */ +class ExceptionHolder : public Exception, public boost::shared_ptr<Exception> +{ + public: + typedef boost::shared_ptr<Exception> shared_ptr; + + ExceptionHolder() throw() {} + ExceptionHolder(Exception* p) throw() : shared_ptr(p) {} + ExceptionHolder(shared_ptr p) throw() : shared_ptr(p) {} + + ExceptionHolder(const Exception& e) throw() : shared_ptr(e.clone()) {} + ExceptionHolder(const std::exception& e); + + ~ExceptionHolder() throw() {} + + const char* what() const throw() { return get()->what(); } + std::string toString() const throw() { return get()->toString(); } + Exception* clone() const throw() { return get()->clone(); } + void throwIf() const { if (get()) get()->throwSelf(); } + void throwSelf() const { assert(get()); get()->throwSelf(); } +}; + +} // namespace qpid + + + +#endif /*!_qpid_ExceptionHolder_h*/ diff --git a/qpid/cpp-0-9/lib/common/Makefile.am b/qpid/cpp-0-9/lib/common/Makefile.am new file mode 100644 index 0000000000..d70adf1186 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/Makefile.am @@ -0,0 +1,142 @@ +AM_CXXFLAGS = $(WARNING_CFLAGS) + +INCLUDES = \ + -I$(top_srcdir)/gen \ + -I$(top_srcdir)/lib/common/sys \ + -I$(top_srcdir)/lib/common/framing \ + $(APR_CXXFLAGS) + +apr = sys/apr +apr_src = \ + $(apr)/APRAcceptor.cpp \ + $(apr)/APRBase.cpp \ + $(apr)/APRPool.cpp \ + $(apr)/APRSocket.cpp \ + $(apr)/LFProcessor.cpp \ + $(apr)/LFSessionContext.cpp \ + $(apr)/Socket.cpp \ + $(apr)/Thread.cpp +apr_hdr = \ + $(apr)/APRBase.h \ + $(apr)/APRPool.h \ + $(apr)/APRSocket.h \ + $(apr)/LFProcessor.h \ + $(apr)/LFSessionContext.h + +posix = sys/posix +posix_src = \ + $(posix)/PosixAcceptor.cpp \ + $(posix)/Socket.cpp \ + $(posix)/Thread.cpp \ + $(posix)/check.cpp \ + $(posix)/EventChannel.cpp \ + $(posix)/EventChannelThreads.cpp +posix_hdr = \ + $(posix)/check.h \ + $(posix)/EventChannel.h \ + $(posix)/EventChannelThreads.h + +EXTRA_DIST=$(posix_src) $(posix_hdr) +platform_src = $(apr_src) +platform_hdr = $(apr_hdr) + +framing = framing +gen = $(srcdir)/../../gen + +lib_LTLIBRARIES = libqpidcommon.la +libqpidcommon_la_LIBADD = \ + $(APR_LIBS) \ + $(LIB_DLOPEN) \ + $(LIB_CLOCK_GETTIME) + +libqpidcommon_la_LDFLAGS = \ + -version-info \ + $(LIBTOOL_VERSION_INFO_ARG) + +libqpidcommon_la_SOURCES = \ + $(platform_src) \ + $(framing)/AMQBody.cpp \ + $(framing)/AMQRequestBody.cpp \ + $(framing)/AMQResponseBody.cpp \ + $(framing)/AMQContentBody.cpp \ + $(framing)/AMQFrame.cpp \ + $(framing)/AMQHeaderBody.cpp \ + $(framing)/AMQHeartbeatBody.cpp \ + $(framing)/AMQMethodBody.cpp \ + $(framing)/MethodContext.cpp \ + $(framing)/BasicHeaderProperties.cpp \ + $(framing)/BodyHandler.cpp \ + $(framing)/ChannelAdapter.cpp \ + $(framing)/Buffer.cpp \ + $(framing)/FieldTable.cpp \ + $(framing)/FramingContent.cpp \ + $(framing)/InitiationHandler.cpp \ + $(framing)/ProtocolInitiation.cpp \ + $(framing)/ProtocolVersion.cpp \ + $(framing)/ProtocolVersionException.cpp \ + $(framing)/Requester.cpp \ + $(framing)/Responder.cpp \ + $(framing)/Value.cpp \ + $(framing)/Proxy.cpp \ + $(gen)/AMQP_ClientProxy.cpp \ + $(gen)/AMQP_HighestVersion.h \ + $(gen)/AMQP_MethodVersionMap.cpp \ + $(gen)/AMQP_ServerProxy.cpp \ + Exception.cpp \ + ExceptionHolder.cpp \ + QpidError.cpp \ + sys/Runnable.cpp \ + sys/Time.cpp \ + sys/ProducerConsumer.cpp + +nobase_pkginclude_HEADERS = \ + $(gen)/AMQP_HighestVersion.h \ + $(platform_hdr) \ + $(framing)/AMQBody.h \ + $(framing)/AMQContentBody.h \ + $(framing)/AMQDataBlock.h \ + $(framing)/AMQFrame.h \ + $(framing)/AMQHeaderBody.h \ + $(framing)/AMQHeartbeatBody.h \ + $(framing)/AMQMethodBody.h \ + $(framing)/MethodContext.h \ + $(framing)/BasicHeaderProperties.h \ + $(framing)/BodyHandler.h \ + $(framing)/ChannelAdapter.h \ + $(framing)/Buffer.h \ + $(framing)/FieldTable.h \ + $(framing)/FramingContent.h \ + $(framing)/HeaderProperties.h \ + $(framing)/InitiationHandler.h \ + $(framing)/InputHandler.h \ + $(framing)/OutputHandler.h \ + $(framing)/ProtocolInitiation.h \ + $(framing)/ProtocolVersion.h \ + $(framing)/ProtocolVersionException.h \ + $(framing)/Value.h \ + $(framing)/amqp_framing.h \ + $(framing)/amqp_types.h \ + $(framing)/Proxy.h \ + Exception.h \ + ExceptionHolder.h \ + QpidError.h \ + SharedObject.h \ + sys/Acceptor.h \ + sys/AtomicCount.h \ + sys/Module.h \ + sys/Monitor.h \ + sys/Mutex.h \ + sys/Runnable.h \ + sys/ConnectionOutputHandler.h \ + sys/ConnectionInputHandler.h \ + sys/ConnectionInputHandlerFactory.h \ + sys/ShutdownHandler.h \ + sys/Socket.h \ + sys/Thread.h \ + sys/Time.h \ + sys/TimeoutHandler.h \ + sys/ProducerConsumer.h + + +# Force build during dist phase so help2man will work. +dist-hook: $(lib_LTLIBRARIES) diff --git a/qpid/cpp-0-9/lib/common/QpidError.cpp b/qpid/cpp-0-9/lib/common/QpidError.cpp new file mode 100644 index 0000000000..9cd3051d1e --- /dev/null +++ b/qpid/cpp-0-9/lib/common/QpidError.cpp @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <boost/format.hpp> + +#include <QpidError.h> +#include <sstream> + +using namespace qpid; + +QpidError::QpidError() : code(0) {} + +QpidError::~QpidError() throw() {} + +Exception* QpidError::clone() const throw() { return new QpidError(*this); } + +void QpidError::throwSelf() const { throw *this; } + +void QpidError::init() { + whatStr = boost::str(boost::format("Error [%d] %s (%s:%d)") + % code % msg % loc.file % loc.line); +} + + diff --git a/qpid/cpp-0-9/lib/common/QpidError.h b/qpid/cpp-0-9/lib/common/QpidError.h new file mode 100644 index 0000000000..2a0395ab79 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/QpidError.h @@ -0,0 +1,78 @@ +#ifndef __QpidError__ +#define __QpidError__ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <string> +#include <memory> +#include <ostream> + +#include <Exception.h> + +namespace qpid { + +struct SrcLine { + public: + SrcLine(const std::string& file_="", int line_=0) : + file(file_), line(line_) {} + + std::string file; + int line; +}; + +class QpidError : public Exception +{ + public: + const int code; + SrcLine loc; + std::string msg; + + QpidError(); + + template <class T> + QpidError(int code_, const T& msg_, const SrcLine& loc_) throw() + : code(code_), loc(loc_), msg(boost::lexical_cast<std::string>(msg_)) + { init(); } + + ~QpidError() throw(); + Exception* clone() const throw(); + void throwSelf() const; + + private: + + void init(); +}; + + +} // namespace qpid + +#define SRCLINE ::qpid::SrcLine(__FILE__, __LINE__) + +#define QPID_ERROR(CODE, MESSAGE) ::qpid::QpidError((CODE), (MESSAGE), SRCLINE) + +#define THROW_QPID_ERROR(CODE, MESSAGE) throw QPID_ERROR(CODE,MESSAGE) + +const int PROTOCOL_ERROR = 10000; +const int APR_ERROR = 20000; +const int FRAMING_ERROR = 30000; +const int CLIENT_ERROR = 40000; +const int INTERNAL_ERROR = 50000; + +#endif diff --git a/qpid/cpp-0-9/lib/common/SharedObject.h b/qpid/cpp-0-9/lib/common/SharedObject.h new file mode 100644 index 0000000000..852a036ab9 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/SharedObject.h @@ -0,0 +1,55 @@ +#ifndef _SharedObject_ +#define _SharedObject_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <boost/shared_ptr.hpp> +#include <boost/noncopyable.hpp> + +namespace qpid { + /** + * Template to enforce shared object conventions. + * Shared object classes should inherit : public qpid::SharedObject + * That ensures Foo: + * - has typedef boost::shared_ptr<T> shared_ptr + * - has virtual destructor + * - is boost::noncopyable (no default copy or assign) + * - has a protected default constructor. + * + * Shared objects should not have public constructors. + * Make constructors protected and provide public statc create() + * functions that return a shared_ptr. + */ + template <class T> + class SharedObject : private boost::noncopyable + { + public: + typedef boost::shared_ptr<T> shared_ptr; + + virtual ~SharedObject() {}; + + protected: + SharedObject() {} + }; +} + +#endif /*!_SharedObject_*/ diff --git a/qpid/cpp-0-9/lib/common/doxygen_mainpage.h b/qpid/cpp-0-9/lib/common/doxygen_mainpage.h new file mode 100644 index 0000000000..b354238cd0 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/doxygen_mainpage.h @@ -0,0 +1,45 @@ +// This header file is just for doxygen documentation purposes. + +/*!\mainpage Qpid C++ Developer Kit. + * + *\section intro_sec Introduction + * + * The <a href=http://incubator.apache.org/qpid/index.html>Qpid project</a> provides implementations of the <a href="http://amqp.org/">AMQP messaging specification</a> in several programming language. + * + * Qpidc provides APIs and libraries to implement AMQP + * clients in C++. Qpidc clients can interact with any compliant AMQP + * message broker. The Qpid project also provides an AMQP broker + * daemon called qpidd that you can use with your qpidc clients. + * + *\section install_sec Installation + * + * If you are installing from the source distribution + <pre> + > ./configure && make + > make install </pre> + * This will build and install the client development kit and the broker + * in standard places. Use + * <code>./configure --help</code> for more options. + * + * You can also install from RPMs with the <code>rpm -i</code> command. + * You will need + * - <code>qpidc</code> for core libraries. + * - <code>qpidc-devel</code> for header files and developer documentation. + * - <code>qpidd</code> for the broker daemon. + * + *\section getstart_sec Getting Started + * + * If you have installed in the standard places you should use + * these compile flags: + * + *<code> -I/usr/include/qpidc -I/usr/include/qpidc/framing -I/usr/include/qpidc/sys</code> + * + * and these link flags: + * + *<code> -lqpidcommon -lqpidclient</code> + * + * If you have installed somewhere else you should modify the flags + * appropriately. + * + * See the \ref clientapi "client API module" for more on the client API. + */ diff --git a/qpid/cpp-0-9/lib/common/framing/AMQBody.cpp b/qpid/cpp-0-9/lib/common/framing/AMQBody.cpp new file mode 100644 index 0000000000..c7c253beda --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQBody.cpp @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <AMQBody.h> +#include <iostream> + +std::ostream& qpid::framing::operator<<(std::ostream& out, const qpid::framing::AMQBody& body) +{ + body.print(out); + return out; +} + +qpid::framing::AMQBody::~AMQBody() {} + + diff --git a/qpid/cpp-0-9/lib/common/framing/AMQBody.h b/qpid/cpp-0-9/lib/common/framing/AMQBody.h new file mode 100644 index 0000000000..26076956ca --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQBody.h @@ -0,0 +1,59 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <boost/shared_ptr.hpp> +#include <amqp_types.h> +#include <Buffer.h> + +#ifndef _AMQBody_ +#define _AMQBody_ + +namespace qpid { + namespace framing { + + class AMQBody + { + public: + typedef boost::shared_ptr<AMQBody> shared_ptr; + + virtual ~AMQBody(); + virtual uint32_t size() const = 0; + virtual uint8_t type() const = 0; + virtual void encode(Buffer& buffer) const = 0; + virtual void decode(Buffer& buffer, uint32_t size) = 0; + + virtual void print(std::ostream& out) const = 0; + }; + + std::ostream& operator<<(std::ostream& out, const AMQBody& body) ; + + enum BodyTypes { + METHOD_BODY = 1, + HEADER_BODY = 2, + CONTENT_BODY = 3, + HEARTBEAT_BODY = 8, + REQUEST_BODY = 9, + RESPONSE_BODY = 10 + }; + } +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/AMQContentBody.cpp b/qpid/cpp-0-9/lib/common/framing/AMQContentBody.cpp new file mode 100644 index 0000000000..573c17dade --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQContentBody.cpp @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <AMQContentBody.h> +#include <iostream> + +qpid::framing::AMQContentBody::AMQContentBody(){ +} + +qpid::framing::AMQContentBody::AMQContentBody(const string& _data) : data(_data){ +} + +uint32_t qpid::framing::AMQContentBody::size() const{ + return data.size(); +} +void qpid::framing::AMQContentBody::encode(Buffer& buffer) const{ + buffer.putRawData(data); +} +void qpid::framing::AMQContentBody::decode(Buffer& buffer, uint32_t _size){ + buffer.getRawData(data, _size); +} + +void qpid::framing::AMQContentBody::print(std::ostream& out) const +{ + out << "content (" << size() << " bytes)"; +} diff --git a/qpid/cpp-0-9/lib/common/framing/AMQContentBody.h b/qpid/cpp-0-9/lib/common/framing/AMQContentBody.h new file mode 100644 index 0000000000..c9fa7cde5c --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQContentBody.h @@ -0,0 +1,53 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <amqp_types.h> +#include <AMQBody.h> +#include <Buffer.h> + +#ifndef _AMQContentBody_ +#define _AMQContentBody_ + +namespace qpid { +namespace framing { + +class AMQContentBody : public AMQBody +{ + string data; + +public: + typedef boost::shared_ptr<AMQContentBody> shared_ptr; + + AMQContentBody(); + AMQContentBody(const string& data); + inline virtual ~AMQContentBody(){} + inline uint8_t type() const { return CONTENT_BODY; }; + inline string& getData(){ return data; } + uint32_t size() const; + void encode(Buffer& buffer) const; + void decode(Buffer& buffer, uint32_t size); + void print(std::ostream& out) const; +}; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/AMQDataBlock.h b/qpid/cpp-0-9/lib/common/framing/AMQDataBlock.h new file mode 100644 index 0000000000..2a6f843f1e --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQDataBlock.h @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <Buffer.h> + +#ifndef _AMQDataBlock_ +#define _AMQDataBlock_ + +namespace qpid { +namespace framing { + +class AMQDataBlock +{ +public: + virtual ~AMQDataBlock() {} + virtual void encode(Buffer& buffer) = 0; + virtual bool decode(Buffer& buffer) = 0; + virtual uint32_t size() const = 0; +}; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/AMQFrame.cpp b/qpid/cpp-0-9/lib/common/framing/AMQFrame.cpp new file mode 100644 index 0000000000..bc9061b169 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQFrame.cpp @@ -0,0 +1,139 @@ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <boost/format.hpp> + +#include <AMQFrame.h> +#include <QpidError.h> +#include "AMQRequestBody.h" +#include "AMQResponseBody.h" + + +namespace qpid { +namespace framing { + + +AMQP_MethodVersionMap AMQFrame::versionMap; + +AMQFrame::AMQFrame(ProtocolVersion _version): +version(_version) + { + assert(version != ProtocolVersion(0,0)); + } + +AMQFrame::AMQFrame(ProtocolVersion _version, uint16_t _channel, AMQBody* _body) : +version(_version), channel(_channel), body(_body) +{} + +AMQFrame::AMQFrame(ProtocolVersion _version, uint16_t _channel, const AMQBody::shared_ptr& _body) : +version(_version), channel(_channel), body(_body) +{} + +AMQFrame::~AMQFrame() {} + +uint16_t AMQFrame::getChannel(){ + return channel; +} + +AMQBody::shared_ptr AMQFrame::getBody(){ + return body; +} + +void AMQFrame::encode(Buffer& buffer) +{ + buffer.putOctet(body->type()); + buffer.putShort(channel); + buffer.putLong(body->size()); + body->encode(buffer); + buffer.putOctet(0xCE); +} + +uint32_t AMQFrame::size() const{ + assert(body.get()); + return 1/*type*/ + 2/*channel*/ + 4/*body size*/ + body->size() + + 1/*0xCE*/; +} + +bool AMQFrame::decode(Buffer& buffer) +{ + if(buffer.available() < 7) + return false; + buffer.record(); + uint32_t frameSize = decodeHead(buffer); + if(buffer.available() < frameSize + 1){ + buffer.restore(); + return false; + } + decodeBody(buffer, frameSize); + uint8_t end = buffer.getOctet(); + if(end != 0xCE) THROW_QPID_ERROR(FRAMING_ERROR, "Frame end not found"); + return true; +} + +uint32_t AMQFrame::decodeHead(Buffer& buffer){ + type = buffer.getOctet(); + channel = buffer.getShort(); + return buffer.getLong(); +} + +void AMQFrame::decodeBody(Buffer& buffer, uint32_t size) +{ + switch(type) + { + case METHOD_BODY: + body = AMQMethodBody::create(versionMap, version, buffer); + break; + case REQUEST_BODY: + body = AMQRequestBody::create(versionMap, version, buffer); + break; + case RESPONSE_BODY: + body = AMQResponseBody::create(versionMap, version, buffer); + break; + case HEADER_BODY: + body = AMQBody::shared_ptr(new AMQHeaderBody()); + break; + case CONTENT_BODY: + body = AMQBody::shared_ptr(new AMQContentBody()); + break; + case HEARTBEAT_BODY: + body = AMQBody::shared_ptr(new AMQHeartbeatBody()); + break; + default: + THROW_QPID_ERROR( + FRAMING_ERROR, + boost::format("Unknown frame type %d") % type); + } + body->decode(buffer, size); +} + +std::ostream& operator<<(std::ostream& out, const AMQFrame& t) +{ + out << "Frame[channel=" << t.channel << "; "; + if (t.body.get() == 0) + out << "empty"; + else + out << *t.body; + out << "]"; + return out; +} + + +}} // namespace qpid::framing diff --git a/qpid/cpp-0-9/lib/common/framing/AMQFrame.h b/qpid/cpp-0-9/lib/common/framing/AMQFrame.h new file mode 100644 index 0000000000..0c18e0c2a5 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQFrame.h @@ -0,0 +1,78 @@ +#ifndef _AMQFrame_ +#define _AMQFrame_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <boost/cast.hpp> + +#include <amqp_types.h> +#include <AMQBody.h> +#include <AMQDataBlock.h> +#include <AMQMethodBody.h> +#include <AMQHeaderBody.h> +#include <AMQContentBody.h> +#include <AMQHeartbeatBody.h> +#include <AMQP_MethodVersionMap.h> +#include <AMQP_HighestVersion.h> +#include <Buffer.h> + +namespace qpid { +namespace framing { + + +class AMQFrame : public AMQDataBlock +{ + public: + AMQFrame(ProtocolVersion _version = highestProtocolVersion); + AMQFrame(ProtocolVersion _version, uint16_t channel, AMQBody* body); + AMQFrame(ProtocolVersion _version, uint16_t channel, const AMQBody::shared_ptr& body); + virtual ~AMQFrame(); + virtual void encode(Buffer& buffer); + virtual bool decode(Buffer& buffer); + virtual uint32_t size() const; + uint16_t getChannel(); + AMQBody::shared_ptr getBody(); + + /** Convenience template to cast the body to an expected type */ + template <class T> boost::shared_ptr<T> castBody() { + assert(dynamic_cast<T*>(getBody().get())); + boost::static_pointer_cast<T>(getBody()); + } + + uint32_t decodeHead(Buffer& buffer); + void decodeBody(Buffer& buffer, uint32_t size); + + private: + static AMQP_MethodVersionMap versionMap; + ProtocolVersion version; + + uint16_t channel; + uint8_t type; + AMQBody::shared_ptr body; + + + friend std::ostream& operator<<(std::ostream& out, const AMQFrame& body); +}; + +}} // namespace qpid::framing + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/AMQHeaderBody.cpp b/qpid/cpp-0-9/lib/common/framing/AMQHeaderBody.cpp new file mode 100644 index 0000000000..3ddae4eebf --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQHeaderBody.cpp @@ -0,0 +1,75 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <AMQHeaderBody.h> +#include <QpidError.h> +#include <BasicHeaderProperties.h> + +qpid::framing::AMQHeaderBody::AMQHeaderBody(int classId) : weight(0), contentSize(0){ + createProperties(classId); +} + +qpid::framing::AMQHeaderBody::AMQHeaderBody() : properties(0), weight(0), contentSize(0){ +} + +qpid::framing::AMQHeaderBody::~AMQHeaderBody(){ + delete properties; +} + +uint32_t qpid::framing::AMQHeaderBody::size() const{ + return 12 + properties->size(); +} + +void qpid::framing::AMQHeaderBody::encode(Buffer& buffer) const { + buffer.putShort(properties->classId()); + buffer.putShort(weight); + buffer.putLongLong(contentSize); + properties->encode(buffer); +} + +void qpid::framing::AMQHeaderBody::decode(Buffer& buffer, uint32_t bufSize){ + uint16_t classId = buffer.getShort(); + weight = buffer.getShort(); + contentSize = buffer.getLongLong(); + createProperties(classId); + properties->decode(buffer, bufSize - 12); +} + +void qpid::framing::AMQHeaderBody::createProperties(int classId){ + switch(classId){ + case BASIC: + properties = new qpid::framing::BasicHeaderProperties(); + break; + default: + THROW_QPID_ERROR(FRAMING_ERROR, "Unknown header class"); + } +} + +void qpid::framing::AMQHeaderBody::print(std::ostream& out) const +{ + out << "header (" << size() << " bytes)" << " content_size=" << getContentSize(); + const BasicHeaderProperties* props = + dynamic_cast<const BasicHeaderProperties*>(getProperties()); + if (props) { + out << ", message_id=" << props->getMessageId(); + out << ", delivery_mode=" << (int) props->getDeliveryMode(); + out << ", headers=" << const_cast<BasicHeaderProperties*>(props)->getHeaders(); + } +} diff --git a/qpid/cpp-0-9/lib/common/framing/AMQHeaderBody.h b/qpid/cpp-0-9/lib/common/framing/AMQHeaderBody.h new file mode 100644 index 0000000000..d57f93aacd --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQHeaderBody.h @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <amqp_types.h> +#include <AMQBody.h> +#include <Buffer.h> +#include <HeaderProperties.h> + +#ifndef _AMQHeaderBody_ +#define _AMQHeaderBody_ + +namespace qpid { +namespace framing { + +class AMQHeaderBody : public AMQBody +{ + HeaderProperties* properties; + uint16_t weight; + uint64_t contentSize; + + void createProperties(int classId); +public: + typedef boost::shared_ptr<AMQHeaderBody> shared_ptr; + + AMQHeaderBody(int classId); + AMQHeaderBody(); + inline uint8_t type() const { return HEADER_BODY; } + HeaderProperties* getProperties(){ return properties; } + const HeaderProperties* getProperties() const { return properties; } + inline uint64_t getContentSize() const { return contentSize; } + inline void setContentSize(uint64_t _size) { contentSize = _size; } + virtual ~AMQHeaderBody(); + virtual uint32_t size() const; + virtual void encode(Buffer& buffer) const; + virtual void decode(Buffer& buffer, uint32_t size); + virtual void print(std::ostream& out) const; +}; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/AMQHeartbeatBody.cpp b/qpid/cpp-0-9/lib/common/framing/AMQHeartbeatBody.cpp new file mode 100644 index 0000000000..63f83a3d29 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQHeartbeatBody.cpp @@ -0,0 +1,29 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <AMQHeartbeatBody.h> +#include <iostream> + +qpid::framing::AMQHeartbeatBody::~AMQHeartbeatBody() {} + +void qpid::framing::AMQHeartbeatBody::print(std::ostream& out) const { + out << "heartbeat"; +} diff --git a/qpid/cpp-0-9/lib/common/framing/AMQHeartbeatBody.h b/qpid/cpp-0-9/lib/common/framing/AMQHeartbeatBody.h new file mode 100644 index 0000000000..a3e9d823f1 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQHeartbeatBody.h @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <amqp_types.h> +#include <AMQBody.h> +#include <Buffer.h> + +#ifndef _AMQHeartbeatBody_ +#define _AMQHeartbeatBody_ + +namespace qpid { +namespace framing { + +class AMQHeartbeatBody : public AMQBody +{ +public: + typedef boost::shared_ptr<AMQHeartbeatBody> shared_ptr; + + virtual ~AMQHeartbeatBody(); + inline uint32_t size() const { return 0; } + inline uint8_t type() const { return HEARTBEAT_BODY; } + inline void encode(Buffer& ) const {} + inline void decode(Buffer& , uint32_t /*size*/) {} + virtual void print(std::ostream& out) const; +}; + +} +} + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/AMQMethodBody.cpp b/qpid/cpp-0-9/lib/common/framing/AMQMethodBody.cpp new file mode 100644 index 0000000000..23502068f5 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQMethodBody.cpp @@ -0,0 +1,59 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <AMQFrame.h> +#include <AMQMethodBody.h> +#include <QpidError.h> +#include "AMQP_MethodVersionMap.h" + +namespace qpid { +namespace framing { + +void AMQMethodBody::encodeId(Buffer& buffer) const{ + buffer.putShort(amqpClassId()); + buffer.putShort(amqpMethodId()); +} + +void AMQMethodBody::invoke(AMQP_ServerOperations&, const MethodContext&){ + assert(0); + THROW_QPID_ERROR(PROTOCOL_ERROR, "Method not supported by AMQP Server."); +} + +AMQMethodBody::shared_ptr AMQMethodBody::create( + AMQP_MethodVersionMap& versionMap, ProtocolVersion version, + Buffer& buffer) +{ + ClassMethodId id; + id.decode(buffer); + return AMQMethodBody::shared_ptr( + versionMap.createMethodBody( + id.classId, id.methodId, version.getMajor(), version.getMinor())); +} + +void AMQMethodBody::ClassMethodId::decode(Buffer& buffer) { + classId = buffer.getShort(); + methodId = buffer.getShort(); +} + +void AMQMethodBody::decode(Buffer& buffer, uint32_t /*size*/) { + decodeContent(buffer); +} + +}} // namespace qpid::framing diff --git a/qpid/cpp-0-9/lib/common/framing/AMQMethodBody.h b/qpid/cpp-0-9/lib/common/framing/AMQMethodBody.h new file mode 100644 index 0000000000..c2b00c2169 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQMethodBody.h @@ -0,0 +1,84 @@ +#ifndef _AMQMethodBody_ +#define _AMQMethodBody_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <amqp_types.h> +#include <AMQBody.h> +#include <Buffer.h> +#include <AMQP_ServerOperations.h> +#include <MethodContext.h> + +namespace qpid { +namespace framing { + +class AMQP_MethodVersionMap; + +class AMQMethodBody : public AMQBody +{ + public: + typedef boost::shared_ptr<AMQMethodBody> shared_ptr; + + static shared_ptr create( + AMQP_MethodVersionMap& map, ProtocolVersion version, Buffer& buf); + + ProtocolVersion version; + uint8_t type() const { return METHOD_BODY; } + AMQMethodBody(uint8_t major, uint8_t minor) : version(major, minor) {} + AMQMethodBody(ProtocolVersion ver) : version(ver) {} + virtual ~AMQMethodBody() {} + void decode(Buffer&, uint32_t); + + virtual MethodId amqpMethodId() const = 0; + virtual ClassId amqpClassId() const = 0; + + virtual void invoke(AMQP_ServerOperations&, const MethodContext&); + + template <class T> bool isA() { + return amqpClassId()==T::CLASS_ID && amqpMethodId()==T::METHOD_ID; + } + + /** Return request ID or response correlationID */ + virtual RequestId getRequestId() const { return 0; } + + virtual bool isRequest() const { return false; } + virtual bool isResponse() const { return false; } + + protected: + static uint32_t baseSize() { return 4; } + + struct ClassMethodId { + uint16_t classId; + uint16_t methodId; + void decode(Buffer& b); + }; + + void encodeId(Buffer& buffer) const; + virtual void encodeContent(Buffer& buffer) const = 0; + virtual void decodeContent(Buffer& buffer) = 0; +}; + + +}} // namespace qpid::framing + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/AMQRequestBody.cpp b/qpid/cpp-0-9/lib/common/framing/AMQRequestBody.cpp new file mode 100644 index 0000000000..54e1c11863 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQRequestBody.cpp @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "AMQRequestBody.h" +#include "AMQP_MethodVersionMap.h" + +namespace qpid { +namespace framing { + +void AMQRequestBody::Data::encode(Buffer& buffer) const { + buffer.putLongLong(requestId); + buffer.putLongLong(responseMark); + buffer.putLong(0); // Reserved long in spec. +} + +void AMQRequestBody::Data::decode(Buffer& buffer) { + requestId = buffer.getLongLong(); + responseMark = buffer.getLongLong(); + buffer.getLong(); // Ignore reserved long. +} + +void AMQRequestBody::encode(Buffer& buffer) const { + data.encode(buffer); + encodeId(buffer); + encodeContent(buffer); +} + +AMQRequestBody::shared_ptr +AMQRequestBody::create( + AMQP_MethodVersionMap& versionMap, ProtocolVersion version, + Buffer& buffer) +{ + ClassMethodId id; + Data data; + data.decode(buffer); + id.decode(buffer); + AMQRequestBody* body = dynamic_cast<AMQRequestBody*>( + versionMap.createMethodBody( + id.classId, id.methodId, version.getMajor(), version.getMinor())); + assert(body); + body->data = data; + return AMQRequestBody::shared_ptr(body); +} + +void AMQRequestBody::printPrefix(std::ostream& out) const { + out << "request(id=" << data.requestId << ",mark=" + << data.responseMark << "): "; +} + +}} // namespace qpid::framing + diff --git a/qpid/cpp-0-9/lib/common/framing/AMQRequestBody.h b/qpid/cpp-0-9/lib/common/framing/AMQRequestBody.h new file mode 100644 index 0000000000..e184fff1d6 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQRequestBody.h @@ -0,0 +1,78 @@ +#ifndef _framing_AMQRequestBody_h +#define _framing_AMQRequestBody_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "AMQMethodBody.h" + +namespace qpid { +namespace framing { + +/** + * Body of a request method frame. + */ +class AMQRequestBody : public AMQMethodBody +{ + public: + typedef boost::shared_ptr<AMQRequestBody> shared_ptr; + + struct Data { + Data(RequestId id=0, ResponseId mark=0) + : requestId(id), responseMark(mark) {} + void encode(Buffer&) const; + void decode(Buffer&); + + RequestId requestId; + ResponseId responseMark; + }; + + static Data& getData(const AMQBody::shared_ptr& body) { + return boost::dynamic_pointer_cast<AMQRequestBody>(body)->getData(); + } + + static shared_ptr create( + AMQP_MethodVersionMap& versionMap, ProtocolVersion version, + Buffer& buffer); + + AMQRequestBody(ProtocolVersion v, RequestId id=0, ResponseId mark=0) + : AMQMethodBody(v), data(id, mark) {} + + uint8_t type() const { return REQUEST_BODY; } + void encode(Buffer& buffer) const; + + Data& getData() { return data; } + RequestId getRequestId() const { return data.requestId; } + ResponseId getResponseMark() const { return data.responseMark; } + void setRequestId(RequestId id) { data.requestId=id; } + void setResponseMark(ResponseId mark) { data.responseMark=mark; } + + bool isRequest()const { return true; } + protected: + static const uint32_t baseSize() { return AMQMethodBody::baseSize()+20; } + void printPrefix(std::ostream& out) const; + + private: + Data data; +}; + +}} // namespace qpid::framing + + + +#endif /*!_framing_AMQRequestBody_h*/ diff --git a/qpid/cpp-0-9/lib/common/framing/AMQResponseBody.cpp b/qpid/cpp-0-9/lib/common/framing/AMQResponseBody.cpp new file mode 100644 index 0000000000..7da71a5d25 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQResponseBody.cpp @@ -0,0 +1,65 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "AMQFrame.h" +#include "AMQResponseBody.h" +#include "AMQP_MethodVersionMap.h" + +namespace qpid { +namespace framing { + +void AMQResponseBody::Data::encode(Buffer& buffer) const { + buffer.putLongLong(responseId); + buffer.putLongLong(requestId); + buffer.putLong(batchOffset); +} + +void AMQResponseBody::Data::decode(Buffer& buffer) { + responseId = buffer.getLongLong(); + requestId = buffer.getLongLong(); + batchOffset = buffer.getLong(); +} + +void AMQResponseBody::encode(Buffer& buffer) const { + data.encode(buffer); + encodeId(buffer); + encodeContent(buffer); +} + +AMQResponseBody::shared_ptr AMQResponseBody::create( + AMQP_MethodVersionMap& versionMap, ProtocolVersion version, + Buffer& buffer) +{ + ClassMethodId id; + Data data; + data.decode(buffer); + id.decode(buffer); + AMQResponseBody* body = dynamic_cast<AMQResponseBody*>( + versionMap.createMethodBody( + id.classId, id.methodId, version.getMajor(), version.getMinor())); + assert(body); + body->data = data; + return AMQResponseBody::shared_ptr(body); +} + +void AMQResponseBody::printPrefix(std::ostream& out) const { + out << "response(id=" << data.responseId << ",request=" << data.requestId + << ",batch=" << data.batchOffset << "): "; +} + +}} // namespace qpid::framing diff --git a/qpid/cpp-0-9/lib/common/framing/AMQResponseBody.h b/qpid/cpp-0-9/lib/common/framing/AMQResponseBody.h new file mode 100644 index 0000000000..fa381baddd --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/AMQResponseBody.h @@ -0,0 +1,85 @@ +#ifndef _framing_AMQResponseBody_h +#define _framing_AMQResponseBody_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "AMQMethodBody.h" + +namespace qpid { +namespace framing { + +class AMQP_MethodVersionMap; + +/** + * Body of a response method frame. + */ +class AMQResponseBody : public AMQMethodBody +{ + + public: + typedef boost::shared_ptr<AMQResponseBody> shared_ptr; + + struct Data { + Data(ResponseId id=0, RequestId req=0, BatchOffset off=0) + : responseId(id), requestId(req), batchOffset(off) {} + void encode(Buffer&) const; + void decode(Buffer&); + + uint64_t responseId; + uint64_t requestId; + uint32_t batchOffset; + }; + + static Data& getData(const AMQBody::shared_ptr& body) { + return boost::dynamic_pointer_cast<AMQResponseBody>(body)->getData(); + } + + static shared_ptr create( + AMQP_MethodVersionMap& versionMap, ProtocolVersion version, + Buffer& buffer); + + AMQResponseBody( + ProtocolVersion v, ResponseId id=0, RequestId req=0, BatchOffset off=0) + : AMQMethodBody(v), data(id, req, off) {} + + uint8_t type() const { return RESPONSE_BODY; } + void encode(Buffer& buffer) const; + + Data& getData() { return data; } + ResponseId getResponseId() const { return data.responseId; } + RequestId getRequestId() const { return data.requestId; } + BatchOffset getBatchOffset() const { return data.batchOffset; } + void setResponseId(ResponseId id) { data.responseId = id; } + void setRequestId(RequestId id) { data.requestId = id; } + void setBatchOffset(BatchOffset id) { data.batchOffset = id; } + + bool isResponse() const { return true; } + protected: + static const uint32_t baseSize() { return AMQMethodBody::baseSize()+20; } + void printPrefix(std::ostream& out) const; + + private: + Data data; +}; + +}} // namespace qpid::framing + + + +#endif /*!_framing_AMQResponseBody_h*/ diff --git a/qpid/cpp-0-9/lib/common/framing/BasicHeaderProperties.cpp b/qpid/cpp-0-9/lib/common/framing/BasicHeaderProperties.cpp new file mode 100644 index 0000000000..930ec9f4dd --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/BasicHeaderProperties.cpp @@ -0,0 +1,103 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <BasicHeaderProperties.h> + +//TODO: This could be easily generated from the spec + +qpid::framing::BasicHeaderProperties::BasicHeaderProperties() : deliveryMode(0), priority(0), timestamp(0){} +qpid::framing::BasicHeaderProperties::~BasicHeaderProperties(){} + +uint32_t qpid::framing::BasicHeaderProperties::size() const{ + uint32_t bytes = 2;//flags + if(contentType.length() > 0) bytes += contentType.length() + 1; + if(contentEncoding.length() > 0) bytes += contentEncoding.length() + 1; + if(headers.count() > 0) bytes += headers.size(); + if(deliveryMode != 0) bytes += 1; + if(priority != 0) bytes += 1; + if(correlationId.length() > 0) bytes += correlationId.length() + 1; + if(replyTo.length() > 0) bytes += replyTo.length() + 1; + if(expiration.length() > 0) bytes += expiration.length() + 1; + if(messageId.length() > 0) bytes += messageId.length() + 1; + if(timestamp != 0) bytes += 8; + if(type.length() > 0) bytes += type.length() + 1; + if(userId.length() > 0) bytes += userId.length() + 1; + if(appId.length() > 0) bytes += appId.length() + 1; + if(clusterId.length() > 0) bytes += clusterId.length() + 1; + + return bytes; +} + +void qpid::framing::BasicHeaderProperties::encode(qpid::framing::Buffer& buffer) const{ + uint16_t flags = getFlags(); + buffer.putShort(flags); + + if(contentType.length() > 0) buffer.putShortString(contentType); + if(contentEncoding.length() > 0) buffer.putShortString(contentEncoding); + if(headers.count() > 0) buffer.putFieldTable(headers); + if(deliveryMode != 0) buffer.putOctet(deliveryMode); + if(priority != 0) buffer.putOctet(priority); + if(correlationId.length() > 0) buffer.putShortString(correlationId); + if(replyTo.length() > 0) buffer.putShortString(replyTo); + if(expiration.length() > 0) buffer.putShortString(expiration); + if(messageId.length() > 0) buffer.putShortString(messageId); + if(timestamp != 0) buffer.putLongLong(timestamp);; + if(type.length() > 0) buffer.putShortString(type); + if(userId.length() > 0) buffer.putShortString(userId); + if(appId.length() > 0) buffer.putShortString(appId); + if(clusterId.length() > 0) buffer.putShortString(clusterId); +} + +void qpid::framing::BasicHeaderProperties::decode(qpid::framing::Buffer& buffer, uint32_t /*size*/){ + uint16_t flags = buffer.getShort(); + if(flags & (1 << 15)) buffer.getShortString(contentType); + if(flags & (1 << 14)) buffer.getShortString(contentEncoding); + if(flags & (1 << 13)) buffer.getFieldTable(headers); + if(flags & (1 << 12)) deliveryMode = buffer.getOctet(); + if(flags & (1 << 11)) priority = buffer.getOctet(); + if(flags & (1 << 10)) buffer.getShortString(correlationId); + if(flags & (1 << 9)) buffer.getShortString(replyTo); + if(flags & (1 << 8)) buffer.getShortString(expiration); + if(flags & (1 << 7)) buffer.getShortString(messageId); + if(flags & (1 << 6)) timestamp = buffer.getLongLong(); + if(flags & (1 << 5)) buffer.getShortString(type); + if(flags & (1 << 4)) buffer.getShortString(userId); + if(flags & (1 << 3)) buffer.getShortString(appId); + if(flags & (1 << 2)) buffer.getShortString(clusterId); +} + +uint16_t qpid::framing::BasicHeaderProperties::getFlags() const{ + uint16_t flags(0); + if(contentType.length() > 0) flags |= (1 << 15); + if(contentEncoding.length() > 0) flags |= (1 << 14); + if(headers.count() > 0) flags |= (1 << 13); + if(deliveryMode != 0) flags |= (1 << 12); + if(priority != 0) flags |= (1 << 11); + if(correlationId.length() > 0) flags |= (1 << 10); + if(replyTo.length() > 0) flags |= (1 << 9); + if(expiration.length() > 0) flags |= (1 << 8); + if(messageId.length() > 0) flags |= (1 << 7); + if(timestamp != 0) flags |= (1 << 6); + if(type.length() > 0) flags |= (1 << 5); + if(userId.length() > 0) flags |= (1 << 4); + if(appId.length() > 0) flags |= (1 << 3); + if(clusterId.length() > 0) flags |= (1 << 2); + return flags; +} diff --git a/qpid/cpp-0-9/lib/common/framing/BasicHeaderProperties.h b/qpid/cpp-0-9/lib/common/framing/BasicHeaderProperties.h new file mode 100644 index 0000000000..1f3fd31250 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/BasicHeaderProperties.h @@ -0,0 +1,97 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <amqp_types.h> +#include <Buffer.h> +#include <FieldTable.h> +#include <HeaderProperties.h> + +#ifndef _BasicHeaderProperties_ +#define _BasicHeaderProperties_ + +namespace qpid { +namespace framing { + enum delivery_mode {TRANSIENT = 1, PERSISTENT = 2}; + + //TODO: This could be easily generated from the spec + class BasicHeaderProperties : public HeaderProperties + { + string contentType; + string contentEncoding; + FieldTable headers; + uint8_t deliveryMode; + uint8_t priority; + string correlationId; + string replyTo; + string expiration; + string messageId; + uint64_t timestamp; + string type; + string userId; + string appId; + string clusterId; + + uint16_t getFlags() const; + + public: + BasicHeaderProperties(); + virtual ~BasicHeaderProperties(); + virtual uint32_t size() const; + virtual void encode(Buffer& buffer) const; + virtual void decode(Buffer& buffer, uint32_t size); + + inline virtual uint8_t classId() { return BASIC; } + + inline const string& getContentType() const { return contentType; } + inline const string& getContentEncoding() const { return contentEncoding; } + inline FieldTable& getHeaders() { return headers; } + inline uint8_t getDeliveryMode() const { return deliveryMode; } + inline uint8_t getPriority() const { return priority; } + inline const string& getCorrelationId() const {return correlationId; } + inline const string& getReplyTo() const { return replyTo; } + inline const string& getExpiration() const { return expiration; } + inline const string& getMessageId() const {return messageId; } + inline uint64_t getTimestamp() const { return timestamp; } + inline const string& getType() const { return type; } + inline const string& getUserId() const { return userId; } + inline const string& getAppId() const { return appId; } + inline const string& getClusterId() const { return clusterId; } + + void inline setContentType(const string& _type){ contentType = _type; } + void inline setContentEncoding(const string& encoding){ contentEncoding = encoding; } + void inline setHeaders(const FieldTable& _headers){ headers = _headers; } + void inline setDeliveryMode(uint8_t mode){ deliveryMode = mode; } + void inline setPriority(uint8_t _priority){ priority = _priority; } + void inline setCorrelationId(const string& _correlationId){ correlationId = _correlationId; } + void inline setReplyTo(const string& _replyTo){ replyTo = _replyTo;} + void inline setExpiration(const string& _expiration){ expiration = _expiration; } + void inline setMessageId(const string& _messageId){ messageId = _messageId; } + void inline setTimestamp(uint64_t _timestamp){ timestamp = _timestamp; } + void inline setType(const string& _type){ type = _type; } + void inline setUserId(const string& _userId){ userId = _userId; } + void inline setAppId(const string& _appId){appId = _appId; } + void inline setClusterId(const string& _clusterId){ clusterId = _clusterId; } + }; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/BodyHandler.cpp b/qpid/cpp-0-9/lib/common/framing/BodyHandler.cpp new file mode 100644 index 0000000000..5dd0c0c23d --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/BodyHandler.cpp @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "QpidError.h" +#include "BodyHandler.h" +#include <AMQRequestBody.h> +#include <AMQResponseBody.h> +#include <AMQMethodBody.h> +#include <AMQHeaderBody.h> +#include <AMQContentBody.h> +#include <AMQHeartbeatBody.h> + +using namespace qpid::framing; +using namespace boost; + +BodyHandler::~BodyHandler() {} + +void BodyHandler::handleBody(shared_ptr<AMQBody> body) { + switch(body->type()) + { + case REQUEST_BODY: + handleRequest(shared_polymorphic_cast<AMQRequestBody>(body)); + break; + case RESPONSE_BODY: + handleResponse(shared_polymorphic_cast<AMQResponseBody>(body)); + break; + case METHOD_BODY: + handleMethod(shared_polymorphic_cast<AMQMethodBody>(body)); + break; + case HEADER_BODY: + handleHeader(shared_polymorphic_cast<AMQHeaderBody>(body)); + break; + case CONTENT_BODY: + handleContent(shared_polymorphic_cast<AMQContentBody>(body)); + break; + case HEARTBEAT_BODY: + handleHeartbeat(shared_polymorphic_cast<AMQHeartbeatBody>(body)); + break; + default: + QPID_ERROR(PROTOCOL_ERROR, "Unknown frame type "+body->type()); + } +} + diff --git a/qpid/cpp-0-9/lib/common/framing/BodyHandler.h b/qpid/cpp-0-9/lib/common/framing/BodyHandler.h new file mode 100644 index 0000000000..cb3f0997b0 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/BodyHandler.h @@ -0,0 +1,61 @@ +#ifndef _BodyHandler_ +#define _BodyHandler_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <boost/shared_ptr.hpp> + +#include "Requester.h" +#include "Responder.h" + +namespace qpid { +namespace framing { + +class AMQRequestBody; +class AMQResponseBody; +class AMQMethodBody; +class AMQHeaderBody; +class AMQContentBody; +class AMQHeartbeatBody; + +/** + * Interface to handle incoming frame bodies. + * Derived classes provide logic for each frame type. + */ +class BodyHandler { + public: + virtual ~BodyHandler(); + virtual void handleBody(boost::shared_ptr<AMQBody> body); + + protected: + virtual void handleRequest(boost::shared_ptr<AMQRequestBody>) = 0; + virtual void handleResponse(boost::shared_ptr<AMQResponseBody>) = 0; + virtual void handleMethod(boost::shared_ptr<AMQMethodBody>) = 0; + virtual void handleHeader(boost::shared_ptr<AMQHeaderBody>) = 0; + virtual void handleContent(boost::shared_ptr<AMQContentBody>) = 0; + virtual void handleHeartbeat(boost::shared_ptr<AMQHeartbeatBody>) = 0; +}; + +}} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/Buffer.cpp b/qpid/cpp-0-9/lib/common/framing/Buffer.cpp new file mode 100644 index 0000000000..52c9a42d55 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/Buffer.cpp @@ -0,0 +1,183 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <Buffer.h> +#include <FramingContent.h> +#include <FieldTable.h> + +qpid::framing::Buffer::Buffer(uint32_t _size) : size(_size), owner(true), position(0), limit(_size){ + data = new char[size]; +} + +qpid::framing::Buffer::Buffer(char* _data, uint32_t _size) : size(_size), owner(false), data(_data), position(0), limit(_size){ +} + +qpid::framing::Buffer::~Buffer(){ + if(owner) delete[] data; +} + +void qpid::framing::Buffer::flip(){ + limit = position; + position = 0; +} + +void qpid::framing::Buffer::clear(){ + limit = size; + position = 0; +} + +void qpid::framing::Buffer::compact(){ + uint32_t p = limit - position; + //copy p chars from position to 0 + memmove(data, data + position, p); + limit = size; + position = p; +} + +void qpid::framing::Buffer::record(){ + r_position = position; + r_limit = limit; +} + +void qpid::framing::Buffer::restore(){ + position = r_position; + limit = r_limit; +} + +uint32_t qpid::framing::Buffer::available(){ + return limit - position; +} + +char* qpid::framing::Buffer::start(){ + return data + position; +} + +void qpid::framing::Buffer::move(uint32_t bytes){ + position += bytes; +} + +void qpid::framing::Buffer::putOctet(uint8_t i){ + data[position++] = i; +} + +void qpid::framing::Buffer::putShort(uint16_t i){ + uint16_t b = i; + data[position++] = (uint8_t) (0xFF & (b >> 8)); + data[position++] = (uint8_t) (0xFF & b); +} + +void qpid::framing::Buffer::putLong(uint32_t i){ + uint32_t b = i; + data[position++] = (uint8_t) (0xFF & (b >> 24)); + data[position++] = (uint8_t) (0xFF & (b >> 16)); + data[position++] = (uint8_t) (0xFF & (b >> 8)); + data[position++] = (uint8_t) (0xFF & b); +} + +void qpid::framing::Buffer::putLongLong(uint64_t i){ + uint32_t hi = i >> 32; + uint32_t lo = i; + putLong(hi); + putLong(lo); +} + +uint8_t qpid::framing::Buffer::getOctet(){ + return (uint8_t) data[position++]; +} + +uint16_t qpid::framing::Buffer::getShort(){ + uint16_t hi = (unsigned char) data[position++]; + hi = hi << 8; + hi |= (unsigned char) data[position++]; + return hi; +} + +uint32_t qpid::framing::Buffer::getLong(){ + uint32_t a = (unsigned char) data[position++]; + uint32_t b = (unsigned char) data[position++]; + uint32_t c = (unsigned char) data[position++]; + uint32_t d = (unsigned char) data[position++]; + a = a << 24; + a |= b << 16; + a |= c << 8; + a |= d; + return a; +} + +uint64_t qpid::framing::Buffer::getLongLong(){ + uint64_t hi = getLong(); + uint64_t lo = getLong(); + hi = hi << 32; + return hi | lo; +} + + +void qpid::framing::Buffer::putShortString(const string& s){ + uint8_t len = s.length(); + putOctet(len); + s.copy(data + position, len); + position += len; +} + +void qpid::framing::Buffer::putLongString(const string& s){ + uint32_t len = s.length(); + putLong(len); + s.copy(data + position, len); + position += len; +} + +void qpid::framing::Buffer::getShortString(string& s){ + uint8_t len = getOctet(); + s.assign(data + position, len); + position += len; +} + +void qpid::framing::Buffer::getLongString(string& s){ + uint32_t len = getLong(); + s.assign(data + position, len); + position += len; +} + +void qpid::framing::Buffer::putFieldTable(const FieldTable& t){ + t.encode(*this); +} + +void qpid::framing::Buffer::getFieldTable(FieldTable& t){ + t.decode(*this); +} + +void qpid::framing::Buffer::putContent(const Content& c){ + c.encode(*this); +} + +void qpid::framing::Buffer::getContent(Content& c){ + c.decode(*this); +} + +void qpid::framing::Buffer::putRawData(const string& s){ + uint32_t len = s.length(); + s.copy(data + position, len); + position += len; +} + +void qpid::framing::Buffer::getRawData(string& s, uint32_t len){ + s.assign(data + position, len); + position += len; +} diff --git a/qpid/cpp-0-9/lib/common/framing/Buffer.h b/qpid/cpp-0-9/lib/common/framing/Buffer.h new file mode 100644 index 0000000000..63a15c7c3d --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/Buffer.h @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <amqp_types.h> + +#ifndef _Buffer_ +#define _Buffer_ + +namespace qpid { +namespace framing { + +class Content; +class FieldTable; + +class Buffer +{ + const uint32_t size; + const bool owner;//indicates whether the data is owned by this instance + char* data; + uint32_t position; + uint32_t limit; + uint32_t r_position; + uint32_t r_limit; + +public: + + Buffer(uint32_t size); + Buffer(char* data, uint32_t size); + ~Buffer(); + + void flip(); + void clear(); + void compact(); + void record(); + void restore(); + uint32_t available(); + char* start(); + void move(uint32_t bytes); + + void putOctet(uint8_t i); + void putShort(uint16_t i); + void putLong(uint32_t i); + void putLongLong(uint64_t i); + + uint8_t getOctet(); + uint16_t getShort(); + uint32_t getLong(); + uint64_t getLongLong(); + + void putShortString(const string& s); + void putLongString(const string& s); + void getShortString(string& s); + void getLongString(string& s); + + void putFieldTable(const FieldTable& t); + void getFieldTable(FieldTable& t); + + void putContent(const Content& c); + void getContent(Content& c); + + void putRawData(const string& s); + void getRawData(string& s, uint32_t size); + +}; + +}} // namespace qpid::framing + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/ChannelAdapter.cpp b/qpid/cpp-0-9/lib/common/framing/ChannelAdapter.cpp new file mode 100644 index 0000000000..8a1ff39ee5 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/ChannelAdapter.cpp @@ -0,0 +1,99 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include <boost/format.hpp> + +#include "ChannelAdapter.h" +#include "AMQFrame.h" +#include "Exception.h" + +using boost::format; + +namespace qpid { +namespace framing { + +void ChannelAdapter::init( + ChannelId i, OutputHandler& o, ProtocolVersion v) +{ + assertChannelNotOpen(); + id = i; + out = &o; + version = v; +} + +RequestId ChannelAdapter::send(AMQBody::shared_ptr body) { + RequestId result = 0; + assertChannelOpen(); + switch (body->type()) { + case REQUEST_BODY: { + AMQRequestBody::shared_ptr request = + boost::shared_polymorphic_downcast<AMQRequestBody>(body); + requester.sending(request->getData()); + result = request->getData().requestId; + break; + } + case RESPONSE_BODY: { + AMQResponseBody::shared_ptr response = + boost::shared_polymorphic_downcast<AMQResponseBody>(body); + responder.sending(response->getData()); + break; + } + } + out->send(new AMQFrame(getVersion(), getId(), body)); + return result; +} + +void ChannelAdapter::handleRequest(AMQRequestBody::shared_ptr request) { + assertMethodOk(*request); + AMQRequestBody::Data& requestData = request->getData(); + responder.received(requestData); + handleMethodInContext(request, MethodContext(this, request)); +} + +void ChannelAdapter::handleResponse(AMQResponseBody::shared_ptr response) { + assertMethodOk(*response); + // TODO aconway 2007-01-30: Consider a response handled on receipt. + // Review - any cases where this is not the case? + AMQResponseBody::Data& responseData = response->getData(); + requester.processed(responseData); + handleMethod(response); +} + +void ChannelAdapter::handleMethod(AMQMethodBody::shared_ptr method) { + assertMethodOk(*method); + handleMethodInContext(method, MethodContext(this, method)); +} + +void ChannelAdapter::assertMethodOk(AMQMethodBody& method) const { + if (getId() != 0 && method.amqpClassId() == ConnectionOpenBody::CLASS_ID) + throw ConnectionException( + 504, format("Connection method on non-0 channel %d.")%getId()); +} + +void ChannelAdapter::assertChannelOpen() const { + if (getId() != 0 && !isOpen()) + throw ConnectionException( + 504, format("Channel %d is not open.")%getId()); +} + +void ChannelAdapter::assertChannelNotOpen() const { + if (getId() != 0 && isOpen()) + throw ConnectionException( + 504, format("Channel %d is already open.") % getId()); +} + +}} // namespace qpid::framing diff --git a/qpid/cpp-0-9/lib/common/framing/ChannelAdapter.h b/qpid/cpp-0-9/lib/common/framing/ChannelAdapter.h new file mode 100644 index 0000000000..f6e3986eed --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/ChannelAdapter.h @@ -0,0 +1,105 @@ +#ifndef _ChannelAdapter_ +#define _ChannelAdapter_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <boost/shared_ptr.hpp> + +#include "BodyHandler.h" +#include "Requester.h" +#include "Responder.h" +#include "framing/amqp_types.h" + +namespace qpid { +namespace framing { + +class MethodContext; + +// FIXME aconway 2007-02-20: Rename as ChannelBase or just Channel. + +/** + * Base class for client and broker channels. + * + * - receives frame bodies from the network. + * - Updates request/response data. + * - Dispatches requests with a MethodContext for responses. + * + * send() + * - Updates request/resposne ID data. + * - Forwards frame to the peer. + * + * Thread safety: OBJECT UNSAFE. Instances must not be called + * concurrently. AMQP defines channels to be serialized. + */ +class ChannelAdapter : public BodyHandler { + public: + /** + *@param output Processed frames are forwarded to this handler. + */ + ChannelAdapter(ChannelId id_=0, OutputHandler* out_=0, + ProtocolVersion ver=ProtocolVersion()) + : id(id_), out(out_), version(ver) {} + + /** Initialize the channel adapter. */ + void init(ChannelId, OutputHandler&, ProtocolVersion); + + ChannelId getId() const { return id; } + ProtocolVersion getVersion() const { return version; } + + /** + * Wrap body in a frame and send the frame. + * Takes ownership of body. + */ + RequestId send(AMQBody::shared_ptr body); + RequestId send(AMQBody* body) { return send(AMQBody::shared_ptr(body)); } + + void handleMethod(boost::shared_ptr<qpid::framing::AMQMethodBody>); + void handleRequest(boost::shared_ptr<qpid::framing::AMQRequestBody>); + void handleResponse(boost::shared_ptr<qpid::framing::AMQResponseBody>); + + virtual bool isOpen() const = 0; + + protected: + void assertMethodOk(AMQMethodBody& method) const; + void assertChannelOpen() const; + void assertChannelNotOpen() const; + + virtual void handleMethodInContext( + boost::shared_ptr<qpid::framing::AMQMethodBody> method, + const MethodContext& context) = 0; + + RequestId getFirstAckRequest() { return requester.getFirstAckRequest(); } + RequestId getLastAckRequest() { return requester.getLastAckRequest(); } + RequestId getNextSendRequestId() { return requester.getNextId(); } + + private: + ChannelId id; + OutputHandler* out; + ProtocolVersion version; + Requester requester; + Responder responder; +}; + +}} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/FieldTable.cpp b/qpid/cpp-0-9/lib/common/framing/FieldTable.cpp new file mode 100644 index 0000000000..5bbc4651d3 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/FieldTable.cpp @@ -0,0 +1,150 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <FieldTable.h> +#include <QpidError.h> +#include <Buffer.h> +#include <Value.h> +#include <assert.h> + +namespace qpid { +namespace framing { + +FieldTable::~FieldTable() {} + +uint32_t FieldTable::size() const { + uint32_t len(4); + for(ValueMap::const_iterator i = values.begin(); i != values.end(); ++i) { + // 2 = shortstr_len_byyte + type_char_byte + len += 2 + (i->first).size() + (i->second)->size(); + } + return len; +} + +int FieldTable::count() const { + return values.size(); +} + +namespace +{ +std::ostream& operator<<(std::ostream& out, const FieldTable::ValueMap::value_type& i) { + return out << i.first << ":" << *i.second; +} +} + +std::ostream& operator<<(std::ostream& out, const FieldTable& t) { + out << "{"; + FieldTable::ValueMap::const_iterator i = t.getMap().begin(); + if (i != t.getMap().end()) out << *i++; + while (i != t.getMap().end()) + { + out << "," << *i++; + } + return out << "}"; +} + +void FieldTable::setString(const std::string& name, const std::string& value){ + values[name] = ValuePtr(new StringValue(value)); +} + +void FieldTable::setInt(const std::string& name, int value){ + values[name] = ValuePtr(new IntegerValue(value)); +} + +void FieldTable::setTimestamp(const std::string& name, uint64_t value){ + values[name] = ValuePtr(new TimeValue(value)); +} + +void FieldTable::setTable(const std::string& name, const FieldTable& value){ + values[name] = ValuePtr(new FieldTableValue(value)); +} + +namespace { +template <class T> T default_value() { return T(); } +template <> int default_value<int>() { return 0; } +template <> uint64_t default_value<uint64_t>() { return 0; } +} + +template <class T> +T FieldTable::getValue(const std::string& name) const +{ + ValueMap::const_iterator i = values.find(name); + if (i == values.end()) return default_value<T>(); + const ValueOps<T> *vt = dynamic_cast<const ValueOps<T>*>(i->second.get()); + return vt->getValue(); +} + +std::string FieldTable::getString(const std::string& name) const { + return getValue<std::string>(name); +} + +int FieldTable::getInt(const std::string& name) const { + return getValue<int>(name); +} + +uint64_t FieldTable::getTimestamp(const std::string& name) const { + return getValue<uint64_t>(name); +} + +void FieldTable::getTable(const std::string& name, FieldTable& value) const { + value = getValue<FieldTable>(name); +} + +void FieldTable::encode(Buffer& buffer) const{ + buffer.putLong(size() - 4); + for (ValueMap::const_iterator i = values.begin(); i!=values.end(); ++i) { + buffer.putShortString(i->first); + buffer.putOctet(i->second->getType()); + i->second->encode(buffer); + } +} + +void FieldTable::decode(Buffer& buffer){ + uint32_t len = buffer.getLong(); + uint32_t available = buffer.available(); + if (available < len) + THROW_QPID_ERROR(FRAMING_ERROR, "Not enough data for field table."); + uint32_t leftover = available - len; + while(buffer.available() > leftover){ + std::string name; + buffer.getShortString(name); + std::auto_ptr<Value> value(Value::decode_value(buffer)); + values[name] = ValuePtr(value.release()); + } +} + + +bool FieldTable::operator==(const FieldTable& x) const { + if (values.size() != x.values.size()) return false; + for (ValueMap::const_iterator i = values.begin(); i != values.end(); ++i) { + ValueMap::const_iterator j = x.values.find(i->first); + if (j == x.values.end()) return false; + if (*(i->second) != *(j->second)) return false; + } + return true; +} + +void FieldTable::erase(const std::string& name) +{ + values.erase(values.find(name)); +} + +} +} diff --git a/qpid/cpp-0-9/lib/common/framing/FieldTable.h b/qpid/cpp-0-9/lib/common/framing/FieldTable.h new file mode 100644 index 0000000000..e25a7d3f8c --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/FieldTable.h @@ -0,0 +1,90 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <vector> +#include <boost/shared_ptr.hpp> +#include <map> +#include <amqp_types.h> + +#ifndef _FieldTable_ +#define _FieldTable_ + +namespace qpid { + /** + * The framing namespace contains classes that are used to create, + * send and receive the basic packets from which AMQP is built. + */ +namespace framing { + +class Value; +class Buffer; + +/** + * A set of name-value pairs. (See the AMQP spec for more details on + * AMQP field tables). + * + * \ingroup clientapi + */ +class FieldTable +{ + public: + typedef boost::shared_ptr<Value> ValuePtr; + typedef std::map<std::string, ValuePtr> ValueMap; + + ~FieldTable(); + uint32_t size() const; + int count() const; + void setString(const std::string& name, const std::string& value); + void setInt(const std::string& name, int value); + void setTimestamp(const std::string& name, uint64_t value); + void setTable(const std::string& name, const FieldTable& value); + //void setDecimal(string& name, xxx& value); + std::string getString(const std::string& name) const; + int getInt(const std::string& name) const; + uint64_t getTimestamp(const std::string& name) const; + void getTable(const std::string& name, FieldTable& value) const; + //void getDecimal(string& name, xxx& value); + void erase(const std::string& name); + + void encode(Buffer& buffer) const; + void decode(Buffer& buffer); + + bool operator==(const FieldTable& other) const; + + // TODO aconway 2006-09-26: Yeuch! Rework FieldTable to have + // a map-like interface. + const ValueMap& getMap() const { return values; } + ValueMap& getMap() { return values; } + + private: + friend std::ostream& operator<<(std::ostream& out, const FieldTable& body); + ValueMap values; + template<class T> T getValue(const std::string& name) const; +}; + +class FieldNotFoundException{}; +class UnknownFieldName : public FieldNotFoundException{}; +class IncorrectFieldType : public FieldNotFoundException{}; +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/FramingContent.cpp b/qpid/cpp-0-9/lib/common/framing/FramingContent.cpp new file mode 100644 index 0000000000..24efa38dcb --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/FramingContent.cpp @@ -0,0 +1,75 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <assert.h> + +#include "Buffer.h" +#include "FramingContent.h" +#include <QpidError.h> +#include <sstream> + +namespace qpid { +namespace framing { + +Content::Content() : discriminator(0) {} + +Content::Content(uint8_t _discriminator, const string& _value): discriminator(_discriminator), value(_value) { + validate(); +} + +void Content::validate() { + if (discriminator == REFERENCE) { + if(value.empty()) { + THROW_QPID_ERROR(FRAMING_ERROR, "Reference cannot be empty"); + } + }else if (discriminator != INLINE) { + std::stringstream out; + out << "Invalid discriminator: " << (int) discriminator; + THROW_QPID_ERROR(FRAMING_ERROR, out.str()); + } +} + +Content::~Content() {} + +void Content::encode(Buffer& buffer) const { + buffer.putOctet(discriminator); + buffer.putLongString(value); +} + +void Content::decode(Buffer& buffer) { + discriminator = buffer.getOctet(); + buffer.getLongString(value); + validate(); +} + +size_t Content::size() const { + return 1/*discriminator*/ + 4/*for recording size of long string*/ + value.size(); +} + +std::ostream& operator<<(std::ostream& out, const Content& content) { + if (content.discriminator == REFERENCE) { + out << "{REF:" << content.value << "}"; + } else if (content.discriminator == INLINE) { + out << "{INLINE:" << content.value.size() << " bytes}"; + } + return out; +} + +}} // namespace framing::qpid diff --git a/qpid/cpp-0-9/lib/common/framing/FramingContent.h b/qpid/cpp-0-9/lib/common/framing/FramingContent.h new file mode 100644 index 0000000000..696bcc7c1a --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/FramingContent.h @@ -0,0 +1,40 @@ +#ifndef _framing_FramingContent_h +#define _framing_FramingContent_h + +#include <ostream> + +namespace qpid { +namespace framing { + +enum discriminator_types { INLINE = 0, REFERENCE = 1 }; + +/** + * A representation of the AMQP 'content' data type (used for message + * bodies) which can hold inline data or a reference. + */ +class Content +{ + uint8_t discriminator; + string value; + + void validate(); + + public: + Content(); + Content(uint8_t _discriminator, const string& _value); + ~Content(); + + void encode(Buffer& buffer) const; + void decode(Buffer& buffer); + size_t size() const; + bool isInline() const { return discriminator == INLINE; } + bool isReference() const { return discriminator == REFERENCE; } + const string& getValue() const { return value; } + + friend std::ostream& operator<<(std::ostream&, const Content&); +}; + +}} // namespace qpid::framing + + +#endif /*!_framing_FramingContent_h*/ diff --git a/qpid/cpp-0-9/lib/common/framing/HeaderProperties.h b/qpid/cpp-0-9/lib/common/framing/HeaderProperties.h new file mode 100644 index 0000000000..1ec4840309 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/HeaderProperties.h @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <amqp_types.h> +#include <Buffer.h> + +#ifndef _HeaderProperties_ +#define _HeaderProperties_ + +namespace qpid { +namespace framing { + + enum header_classes{BASIC = 60}; + + class HeaderProperties + { + + public: + inline virtual ~HeaderProperties(){} + virtual uint8_t classId() = 0; + virtual uint32_t size() const = 0; + virtual void encode(Buffer& buffer) const = 0; + virtual void decode(Buffer& buffer, uint32_t size) = 0; + }; +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/InitiationHandler.cpp b/qpid/cpp-0-9/lib/common/framing/InitiationHandler.cpp new file mode 100644 index 0000000000..dd92c9859b --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/InitiationHandler.cpp @@ -0,0 +1,24 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <InitiationHandler.h> + +qpid::framing::InitiationHandler::~InitiationHandler() {} diff --git a/qpid/cpp-0-9/lib/common/framing/InitiationHandler.h b/qpid/cpp-0-9/lib/common/framing/InitiationHandler.h new file mode 100644 index 0000000000..d94fc58d2c --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/InitiationHandler.h @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <string> + +#ifndef _InitiationHandler_ +#define _InitiationHandler_ + +#include <ProtocolInitiation.h> + +namespace qpid { +namespace framing { + + class InitiationHandler{ + public: + virtual ~InitiationHandler(); + virtual void initiated(ProtocolInitiation* header) = 0; + }; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/InputHandler.h b/qpid/cpp-0-9/lib/common/framing/InputHandler.h new file mode 100644 index 0000000000..4e2d4bcc9b --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/InputHandler.h @@ -0,0 +1,39 @@ +#ifndef _InputHandler_ +#define _InputHandler_ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <AMQFrame.h> +#include <boost/noncopyable.hpp> + +namespace qpid { +namespace framing { + +class InputHandler : private boost::noncopyable { + public: + virtual ~InputHandler() {} + virtual void received(AMQFrame* frame) = 0; +}; + +}} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/MethodContext.cpp b/qpid/cpp-0-9/lib/common/framing/MethodContext.cpp new file mode 100644 index 0000000000..73af73f8e5 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/MethodContext.cpp @@ -0,0 +1,31 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "MethodContext.h" +#include "amqp_types.h" +#include "AMQRequestBody.h" + +namespace qpid { +namespace framing { + +RequestId MethodContext::getRequestId() const { + return boost::shared_polymorphic_downcast<AMQRequestBody>(methodBody) + ->getRequestId(); +} + +}} // namespace qpid::framing diff --git a/qpid/cpp-0-9/lib/common/framing/MethodContext.h b/qpid/cpp-0-9/lib/common/framing/MethodContext.h new file mode 100644 index 0000000000..3493924bf6 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/MethodContext.h @@ -0,0 +1,80 @@ +#ifndef _framing_MethodContext_h +#define _framing_MethodContext_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <boost/shared_ptr.hpp> + +#include "OutputHandler.h" +#include "ProtocolVersion.h" + +namespace qpid { +namespace framing { + +class BodyHandler; +class AMQMethodBody; +class ChannelAdapter; + +/** + * Invocation context for an AMQP method. + * + * It provides the method being processed and the channel on which + * it arrived. + * + * All Handler functions take a MethodContext as the last parameter. + */ +struct MethodContext +{ + typedef boost::shared_ptr<AMQMethodBody> BodyPtr; + + MethodContext(ChannelAdapter* ch=0, BodyPtr method=BodyPtr()) + : channel(ch), methodBody(method) {} + + /** + * Channel on which the method being processed arrived. + * 0 if the method was constructed by the caller + * rather than received from a channel. + */ + ChannelAdapter* channel; + + /** + * Body of the method being processed. + * It's useful for passing around instead of unpacking all its parameters. + * It's also provides the request ID when constructing a response. + */ + BodyPtr methodBody; + + /** + * Return methodBody's request ID. + * It is an error to call this if methodBody is not a request. + */ + RequestId getRequestId() const; +}; + +// FIXME aconway 2007-02-01: Method context only required on Handler +// functions, not on Proxy functions. If we add set/getChannel(ChannelAdapter*) +// on AMQBody and set it during decodeing then we could get rid of the context. + + + +}} // namespace qpid::framing + + + +#endif /*!_framing_MethodContext_h*/ diff --git a/qpid/cpp-0-9/lib/common/framing/OutputHandler.h b/qpid/cpp-0-9/lib/common/framing/OutputHandler.h new file mode 100644 index 0000000000..9ffd4227d8 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/OutputHandler.h @@ -0,0 +1,39 @@ +#ifndef _OutputHandler_ +#define _OutputHandler_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <boost/noncopyable.hpp> + +namespace qpid { +namespace framing { +class AMQFrame; + +class OutputHandler : private boost::noncopyable { + public: + virtual ~OutputHandler() {} + virtual void send(AMQFrame* frame) = 0; +}; + +}} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/ProtocolInitiation.cpp b/qpid/cpp-0-9/lib/common/framing/ProtocolInitiation.cpp new file mode 100644 index 0000000000..de53488f7b --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/ProtocolInitiation.cpp @@ -0,0 +1,63 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <ProtocolInitiation.h> + +namespace qpid { +namespace framing { + +ProtocolInitiation::ProtocolInitiation(){} + +ProtocolInitiation::ProtocolInitiation(uint8_t _major, uint8_t _minor) : version(_major, _minor) {} + +ProtocolInitiation::ProtocolInitiation(ProtocolVersion p) : version(p) {} + +ProtocolInitiation::~ProtocolInitiation(){} + +void ProtocolInitiation::encode(Buffer& buffer){ + buffer.putOctet('A'); + buffer.putOctet('M'); + buffer.putOctet('Q'); + buffer.putOctet('P'); + buffer.putOctet(1);//class + buffer.putOctet(1);//instance + buffer.putOctet(version.getMajor()); + buffer.putOctet(version.getMinor()); +} + +bool ProtocolInitiation::decode(Buffer& buffer){ + if(buffer.available() >= 8){ + buffer.getOctet();//A + buffer.getOctet();//M + buffer.getOctet();//Q + buffer.getOctet();//P + buffer.getOctet();//class + buffer.getOctet();//instance + version.setMajor(buffer.getOctet()); + version.setMinor(buffer.getOctet()); + return true; + }else{ + return false; + } +} + +//TODO: this should prbably be generated from the spec at some point to keep the version numbers up to date + +}} // namespace qpid::framing diff --git a/qpid/cpp-0-9/lib/common/framing/ProtocolInitiation.h b/qpid/cpp-0-9/lib/common/framing/ProtocolInitiation.h new file mode 100644 index 0000000000..ed7b59e94e --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/ProtocolInitiation.h @@ -0,0 +1,54 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <amqp_types.h> +#include <Buffer.h> +#include <AMQDataBlock.h> +#include <ProtocolVersion.h> + +#ifndef _ProtocolInitiation_ +#define _ProtocolInitiation_ + +namespace qpid { +namespace framing { + +class ProtocolInitiation : public AMQDataBlock +{ +private: + ProtocolVersion version; + +public: + ProtocolInitiation(); + ProtocolInitiation(uint8_t major, uint8_t minor); + ProtocolInitiation(ProtocolVersion p); + virtual ~ProtocolInitiation(); + virtual void encode(Buffer& buffer); + virtual bool decode(Buffer& buffer); + inline virtual uint32_t size() const { return 8; } + inline uint8_t getMajor() const { return version.getMajor(); } + inline uint8_t getMinor() const { return version.getMinor(); } + inline ProtocolVersion getVersion() const { return version; } +}; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/ProtocolVersion.cpp b/qpid/cpp-0-9/lib/common/framing/ProtocolVersion.cpp new file mode 100644 index 0000000000..fd4b1a645f --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/ProtocolVersion.cpp @@ -0,0 +1,44 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <ProtocolVersion.h> +#include <sstream> + +using namespace qpid::framing; + +const std::string ProtocolVersion::toString() const +{ + std::stringstream ss; + ss << major_ << "-" << minor_; + return ss.str(); +} + +ProtocolVersion& ProtocolVersion::operator=(ProtocolVersion p) +{ + major_ = p.major_; + minor_ = p.minor_; + return *this; +} + +bool ProtocolVersion::operator==(ProtocolVersion p) const +{ + return major_ == p.major_ && minor_ == p.minor_; +} + diff --git a/qpid/cpp-0-9/lib/common/framing/ProtocolVersion.h b/qpid/cpp-0-9/lib/common/framing/ProtocolVersion.h new file mode 100644 index 0000000000..5e1429c1ea --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/ProtocolVersion.h @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _ProtocolVersion_ +#define _ProtocolVersion_ + +#include <amqp_types.h> + +namespace qpid +{ +namespace framing +{ + +class ProtocolVersion +{ +private: + uint8_t major_; + uint8_t minor_; + +public: + ProtocolVersion(uint8_t _major=0, uint8_t _minor=0) + : major_(_major), minor_(_minor) {} + + uint8_t getMajor() const { return major_; } + void setMajor(uint8_t major) { major_ = major; } + uint8_t getMinor() const { return minor_; } + void setMinor(uint8_t minor) { minor_ = minor; } + const std::string toString() const; + + ProtocolVersion& operator=(ProtocolVersion p); + + bool operator==(ProtocolVersion p) const; + bool operator!=(ProtocolVersion p) const { return ! (*this == p); } +}; + +} // namespace framing +} // namespace qpid + + +#endif // ifndef _ProtocolVersion_ diff --git a/qpid/cpp-0-9/lib/common/framing/ProtocolVersionException.cpp b/qpid/cpp-0-9/lib/common/framing/ProtocolVersionException.cpp new file mode 100644 index 0000000000..9088422f6f --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/ProtocolVersionException.cpp @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <boost/format.hpp> +#include <ProtocolVersionException.h> + + +using namespace qpid::framing; + +void ProtocolVersionException::init(const std::string& msg) +{ + whatStr = boost::str( + boost::format("ProtocolVersionException: %s found: %s") + % versionFound.toString() % msg); +} + diff --git a/qpid/cpp-0-9/lib/common/framing/ProtocolVersionException.h b/qpid/cpp-0-9/lib/common/framing/ProtocolVersionException.h new file mode 100644 index 0000000000..8e2de8b843 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/ProtocolVersionException.h @@ -0,0 +1,56 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#ifndef _ProtocolVersionException_ +#define _ProtocolVersionException_ + +#include <Exception.h> +#include <ProtocolVersion.h> +#include <string> +#include <vector> + +namespace qpid { +namespace framing { + +class ProtocolVersionException : public qpid::Exception +{ +protected: + ProtocolVersion versionFound; + +public: + ~ProtocolVersionException() throw() {} + + template <class T> + ProtocolVersionException( + ProtocolVersion ver, const T& msg) throw () : versionFound(ver) + { init(boost::lexical_cast<std::string>(msg)); } + + template <class T> + ProtocolVersionException(const T& msg) throw () + { init(boost::lexical_cast<std::string>(msg)); } + + private: + void init(const std::string& msg); +}; + +}} // namespace qpid::framing + +#endif //ifndef _ProtocolVersionException_ diff --git a/qpid/cpp-0-9/lib/common/framing/Proxy.cpp b/qpid/cpp-0-9/lib/common/framing/Proxy.cpp new file mode 100644 index 0000000000..0b2a882a49 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/Proxy.cpp @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "Proxy.h" +#include "ChannelAdapter.h" +#include "ProtocolVersion.h" + +namespace qpid { +namespace framing { + +Proxy::~Proxy() {} + +ProtocolVersion Proxy::getProtocolVersion() const { + return channel.getVersion(); +} + +}} // namespace qpid::framing diff --git a/qpid/cpp-0-9/lib/common/framing/Proxy.h b/qpid/cpp-0-9/lib/common/framing/Proxy.h new file mode 100644 index 0000000000..8ed46ed748 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/Proxy.h @@ -0,0 +1,51 @@ +#ifndef _framing_Proxy_h +#define _framing_Proxy_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "ProtocolVersion.h" + +namespace qpid { +namespace framing { + +class ChannelAdapter; +class FieldTable; +class Content; + +/** + * Base class for proxies. + */ +class Proxy +{ + + public: + Proxy(ChannelAdapter& ch) : channel(ch) {} + virtual ~Proxy(); + + ProtocolVersion getProtocolVersion() const; + + protected: + ChannelAdapter& channel; +}; + +}} // namespace qpid::framing + + + +#endif /*!_framing_Proxy_h*/ diff --git a/qpid/cpp-0-9/lib/common/framing/Requester.cpp b/qpid/cpp-0-9/lib/common/framing/Requester.cpp new file mode 100644 index 0000000000..9ee809e2ee --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/Requester.cpp @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <boost/format.hpp> + +#include "Requester.h" +#include "QpidError.h" + +namespace qpid { +namespace framing { + +Requester::Requester() : lastId(0), responseMark(0) {} + +void Requester::sending(AMQRequestBody::Data& request) { + request.requestId = ++lastId; + request.responseMark = responseMark; +} + +void Requester::processed(const AMQResponseBody::Data& response) { + responseMark = response.responseId; + firstAckRequest = response.requestId; + lastAckRequest = firstAckRequest + response.batchOffset; +} + +}} // namespace qpid::framing diff --git a/qpid/cpp-0-9/lib/common/framing/Requester.h b/qpid/cpp-0-9/lib/common/framing/Requester.h new file mode 100644 index 0000000000..dcc4460041 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/Requester.h @@ -0,0 +1,67 @@ +#ifndef _framing_Requester_h +#define _framing_Requester_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <set> +#include "AMQRequestBody.h" +#include "AMQResponseBody.h" + +namespace qpid { +namespace framing { + +class AMQRequestBody; +class AMQResponseBody; + +/** + * Manage request IDs and the response mark for locally initiated requests. + * + * THREAD UNSAFE: This class is called as frames are sent or received + * sequentially on a connection, so it does not need to be thread safe. + */ +class Requester +{ + public: + Requester(); + + /** Called before sending a request to set request data. */ + void sending(AMQRequestBody::Data&); + + /** Called after processing a response. */ + void processed(const AMQResponseBody::Data&); + + /** Get the next request id to be used. */ + RequestId getNextId() { return lastId + 1; } + /** Get the first request acked by this response */ + RequestId getFirstAckRequest() { return firstAckRequest; } + /** Get the last request acked by this response */ + RequestId getLastAckRequest() { return lastAckRequest; } + + private: + RequestId lastId; + ResponseId responseMark; + ResponseId firstAckRequest; + ResponseId lastAckRequest; +}; + +}} // namespace qpid::framing + + + +#endif /*!_framing_Requester_h*/ diff --git a/qpid/cpp-0-9/lib/common/framing/Responder.cpp b/qpid/cpp-0-9/lib/common/framing/Responder.cpp new file mode 100644 index 0000000000..c8c5ce8dcc --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/Responder.cpp @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include <boost/format.hpp> + +#include "Responder.h" +#include "QpidError.h" + +namespace qpid { +namespace framing { + +Responder::Responder() : lastId(0), responseMark(0) {} + +void Responder::received(const AMQRequestBody::Data& request) { + if (request.responseMark < responseMark || request.responseMark > lastId) + THROW_QPID_ERROR( + PROTOCOL_ERROR, boost::format("Invalid response mark %d.") + %request.responseMark); + responseMark = request.responseMark; +} + +void Responder::sending(AMQResponseBody::Data& response) { + response.responseId = ++lastId; + assert(response.requestId); // Should be already set. + response.batchOffset = 0; +} + +}} // namespace qpid::framing + diff --git a/qpid/cpp-0-9/lib/common/framing/Responder.h b/qpid/cpp-0-9/lib/common/framing/Responder.h new file mode 100644 index 0000000000..0e1785256b --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/Responder.h @@ -0,0 +1,61 @@ +#ifndef _framing_Responder_h +#define _framing_Responder_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "AMQRequestBody.h" +#include "AMQResponseBody.h" + +namespace qpid { +namespace framing { + +/** + * Manage response ids and response mark remotely initianted requests. + * + * THREAD UNSAFE: This class is called as frames are sent or received + * sequentially on a connection, so it does not need to be thread safe. + */ +class Responder +{ + public: + Responder(); + + /** Called after receiving a request. */ + void received(const AMQRequestBody::Data& request); + + /** Called before sending a response to set respose data. */ + void sending(AMQResponseBody::Data& response); + + /** Get the ID of the highest response acknowledged by the peer. */ + ResponseId getResponseMark() { return responseMark; } + + // TODO aconway 2007-01-14: Batching support - store unsent + // Response for equality comparison with subsequent responses. + // + + private: + ResponseId lastId; + ResponseId responseMark; +}; + +}} // namespace qpid::framing + + + +#endif /*!_framing_Responder_h*/ diff --git a/qpid/cpp-0-9/lib/common/framing/Value.cpp b/qpid/cpp-0-9/lib/common/framing/Value.cpp new file mode 100644 index 0000000000..03e005e384 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/Value.cpp @@ -0,0 +1,122 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <Value.h> +#include <Buffer.h> +#include <FieldTable.h> +#include <QpidError.h> +#include <sstream> + +namespace qpid { +namespace framing { + +Value::~Value() {} + +void StringValue::encode(Buffer& buffer){ + buffer.putLongString(value); +} +void StringValue::decode(Buffer& buffer){ + buffer.getLongString(value); +} + +void IntegerValue::encode(Buffer& buffer){ + buffer.putLong((uint32_t) value); +} +void IntegerValue::decode(Buffer& buffer){ + value = buffer.getLong(); +} + +void TimeValue::encode(Buffer& buffer){ + buffer.putLongLong(value); +} +void TimeValue::decode(Buffer& buffer){ + value = buffer.getLongLong(); +} + +void DecimalValue::encode(Buffer& buffer){ + buffer.putOctet(value.decimals); + buffer.putLong(value.value); +} +void DecimalValue::decode(Buffer& buffer){ + value = Decimal(buffer.getLong(), buffer.getOctet()); +} + +void FieldTableValue::encode(Buffer& buffer){ + buffer.putFieldTable(value); +} +void FieldTableValue::decode(Buffer& buffer){ + buffer.getFieldTable(value); +} + +std::auto_ptr<Value> Value::decode_value(Buffer& buffer) +{ + std::auto_ptr<Value> value; + uint8_t type = buffer.getOctet(); + switch(type){ + case 'S': + value.reset(new StringValue()); + break; + case 'I': + value.reset(new IntegerValue()); + break; + case 'D': + value.reset(new DecimalValue()); + break; + case 'T': + value.reset(new TimeValue()); + break; + case 'F': + value.reset(new FieldTableValue()); + break; + + //non-standard types, introduced in java client for JMS compliance + case 'x': + value.reset(new BinaryValue()); + break; + default: + std::stringstream out; + out << "Unknown field table value type: " << type; + THROW_QPID_ERROR(FRAMING_ERROR, out.str()); + } + value->decode(buffer); + return value; +} + +EmptyValue::~EmptyValue() {} + +void EmptyValue::print(std::ostream& out) const +{ + out << "<empty field value>"; +} + +std::ostream& operator<<(std::ostream& out, const Value& v) { + v.print(out); + return out; +} + +std::ostream& operator<<(std::ostream& out, const Decimal& d) +{ + return out << "Decimal(" << d.value << "," << d.decimals << ")"; +} + +}} + + + diff --git a/qpid/cpp-0-9/lib/common/framing/Value.h b/qpid/cpp-0-9/lib/common/framing/Value.h new file mode 100644 index 0000000000..8752b02f40 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/Value.h @@ -0,0 +1,171 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <vector> +#include <amqp_types.h> +#include <FieldTable.h> + +#ifndef _Value_ +#define _Value_ + +namespace qpid { +namespace framing { + +class Buffer; + +/** + * Represents a decimal value. + * No arithmetic functionality for now, we only care about encoding/decoding. + */ +struct Decimal { + uint32_t value; + uint8_t decimals; + + Decimal(uint32_t value_=0, uint8_t decimals_=0) : value(value_), decimals(decimals_) {} + bool operator==(const Decimal& d) const { + return decimals == d.decimals && value == d.value; + } + bool operator!=(const Decimal& d) const { return !(*this == d); } +}; + +std::ostream& operator<<(std::ostream& out, const Decimal& d); + +/** + * Polymorpic base class for values. + */ +class Value { + public: + virtual ~Value(); + virtual uint32_t size() const = 0; + virtual char getType() const = 0; + virtual void encode(Buffer& buffer) = 0; + virtual void decode(Buffer& buffer) = 0; + virtual bool operator==(const Value&) const = 0; + bool operator!=(const Value& v) const { return !(*this == v); } + virtual void print(std::ostream& out) const = 0; + + /** Create a new value by decoding from the buffer */ + static std::auto_ptr<Value> decode_value(Buffer& buffer); +}; + +std::ostream& operator<<(std::ostream& out, const Value& d); + + +/** + * Template for common operations on Value sub-classes. + */ +template <class T> +class ValueOps : public Value +{ + protected: + T value; + public: + ValueOps() {} + ValueOps(const T& v) : value(v) {} + const T& getValue() const { return value; } + T& getValue() { return value; } + + virtual bool operator==(const Value& v) const { + const ValueOps<T>* vo = dynamic_cast<const ValueOps<T>*>(&v); + if (vo == 0) return false; + else return value == vo->value; + } + + void print(std::ostream& out) const { out << value; } +}; + + +class StringValue : public ValueOps<std::string> { + public: + StringValue(const std::string& v) : ValueOps<std::string>(v) {} + StringValue() {} + virtual uint32_t size() const { return 4 + value.length(); } + virtual char getType() const { return 'S'; } + virtual void encode(Buffer& buffer); + virtual void decode(Buffer& buffer); +}; + +class IntegerValue : public ValueOps<int> { + public: + IntegerValue(int v) : ValueOps<int>(v) {} + IntegerValue(){} + virtual uint32_t size() const { return 4; } + virtual char getType() const { return 'I'; } + virtual void encode(Buffer& buffer); + virtual void decode(Buffer& buffer); +}; + +class TimeValue : public ValueOps<uint64_t> { + public: + TimeValue(uint64_t v) : ValueOps<uint64_t>(v){} + TimeValue(){} + virtual uint32_t size() const { return 8; } + virtual char getType() const { return 'T'; } + virtual void encode(Buffer& buffer); + virtual void decode(Buffer& buffer); +}; + +class DecimalValue : public ValueOps<Decimal> { + public: + DecimalValue(const Decimal& d) : ValueOps<Decimal>(d) {} + DecimalValue(uint32_t value_=0, uint8_t decimals_=0) : + ValueOps<Decimal>(Decimal(value_, decimals_)){} + virtual uint32_t size() const { return 5; } + virtual char getType() const { return 'D'; } + virtual void encode(Buffer& buffer); + virtual void decode(Buffer& buffer); +}; + + +class FieldTableValue : public ValueOps<FieldTable> { + public: + FieldTableValue(const FieldTable& v) : ValueOps<FieldTable>(v){} + FieldTableValue(){} + virtual uint32_t size() const { return 4 + value.size(); } + virtual char getType() const { return 'F'; } + virtual void encode(Buffer& buffer); + virtual void decode(Buffer& buffer); +}; + +class EmptyValue : public Value { + public: + ~EmptyValue(); + virtual uint32_t size() const { return 0; } + virtual char getType() const { return 0; } + virtual void encode(Buffer& ) {} + virtual void decode(Buffer& ) {} + virtual bool operator==(const Value& v) const { + return dynamic_cast<const EmptyValue*>(&v); + } + virtual void print(std::ostream& out) const; +}; + +//non-standard types, introduced in java client for JMS compliance +class BinaryValue : public StringValue { + public: + BinaryValue(const std::string& v) : StringValue(v) {} + BinaryValue() {} + virtual char getType() const { return 'x'; } +}; + +}} // qpid::framing + +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/amqp_framing.h b/qpid/cpp-0-9/lib/common/framing/amqp_framing.h new file mode 100644 index 0000000000..62f87352f8 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/amqp_framing.h @@ -0,0 +1,36 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <amqp_types.h> +#include <AMQFrame.h> +#include <AMQBody.h> +#include <BodyHandler.h> +#include <AMQMethodBody.h> +#include <AMQHeaderBody.h> +#include <AMQContentBody.h> +#include <AMQHeartbeatBody.h> +#include <AMQP_MethodVersionMap.h> +#include <InputHandler.h> +#include <OutputHandler.h> +#include <InitiationHandler.h> +#include <ProtocolInitiation.h> +#include <BasicHeaderProperties.h> +#include <ProtocolVersion.h> +#include <ProtocolVersionException.h> diff --git a/qpid/cpp-0-9/lib/common/framing/amqp_types.h b/qpid/cpp-0-9/lib/common/framing/amqp_types.h new file mode 100644 index 0000000000..49963bd570 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/amqp_types.h @@ -0,0 +1,57 @@ +#ifndef AMQP_TYPES_H +#define AMQP_TYPES_H +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** \file + * Type definitions and forward declarations of all types used to + * in AMQP messages. + */ + +#include <string> +#ifdef _WINDOWS +#include "windows.h" +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +#endif +#ifndef _WINDOWS +#include "stdint.h" +#endif + +namespace qpid { +namespace framing { + +using std::string; +typedef uint16_t ChannelId; +typedef uint64_t RequestId; +typedef uint64_t ResponseId; +typedef uint32_t BatchOffset; +typedef uint16_t ClassId; +typedef uint16_t MethodId; +typedef uint16_t ReplyCode; + +// Types represented by classes. +class Content; +class FieldTable; +}} // namespace qpid::framing +#endif diff --git a/qpid/cpp-0-9/lib/common/framing/amqp_types_full.h b/qpid/cpp-0-9/lib/common/framing/amqp_types_full.h new file mode 100644 index 0000000000..6a24a99d38 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/framing/amqp_types_full.h @@ -0,0 +1,36 @@ +#ifndef _framing_amqp_types_decl_h +#define _framing_amqp_types_decl_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** \file + * Type definitions and full declarations of all types used to + * in AMQP messages. + * + * Its better to include amqp_types.h in another header instead of this file + * unless the header actually needs the full declarations. Including + * full declarations when forward declarations would do increases compile + * times. + */ + +#include "amqp_types.h" +#include "FramingContent.h" +#include "FieldTable.h" + +#endif /*!_framing_amqp_types_decl_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/Acceptor.h b/qpid/cpp-0-9/lib/common/sys/Acceptor.h new file mode 100644 index 0000000000..f571dcbddd --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/Acceptor.h @@ -0,0 +1,47 @@ +#ifndef _sys_Acceptor_h +#define _sys_Acceptor_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <stdint.h> +#include <SharedObject.h> + +namespace qpid { +namespace sys { + +class ConnectionInputHandlerFactory; + +class Acceptor : public qpid::SharedObject<Acceptor> +{ + public: + static Acceptor::shared_ptr create(int16_t port, int backlog, int threads, bool trace = false); + virtual ~Acceptor() = 0; + virtual int16_t getPort() const = 0; + virtual void run(qpid::sys::ConnectionInputHandlerFactory* factory) = 0; + virtual void shutdown() = 0; +}; + +}} + + + +#endif /*!_sys_Acceptor_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/AtomicCount.h b/qpid/cpp-0-9/lib/common/sys/AtomicCount.h new file mode 100644 index 0000000000..63670cbf00 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/AtomicCount.h @@ -0,0 +1,53 @@ +#ifndef _posix_AtomicCount_h +#define _posix_AtomicCount_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <boost/detail/atomic_count.hpp> +#include "ScopedIncrement.h" + +namespace qpid { +namespace sys { + +/** + * Atomic counter. + */ +class AtomicCount : boost::noncopyable { + public: + typedef ScopedDecrement<AtomicCount> ScopedDecrement; + typedef ScopedIncrement<AtomicCount> ScopedIncrement; + + AtomicCount(long value = 0) : count(value) {} + + void operator++() { ++count ; } + + long operator--() { return --count; } + + operator long() const { return count; } + + + private: + boost::detail::atomic_count count; +}; + + +}} + + +#endif // _posix_AtomicCount_h diff --git a/qpid/cpp-0-9/lib/common/sys/Condition.h b/qpid/cpp-0-9/lib/common/sys/Condition.h new file mode 100644 index 0000000000..9d70af5b84 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/Condition.h @@ -0,0 +1,128 @@ +#ifndef _sys_Condition_h +#define _sys_Condition_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <sys/errno.h> +#include <boost/noncopyable.hpp> +#include <sys/Mutex.h> +#include <sys/Time.h> + +#ifdef USE_APR +# include <apr_thread_cond.h> +#endif + +namespace qpid { +namespace sys { + +/** + * A condition variable for thread synchronization. + */ +class Condition +{ + public: + inline Condition(); + inline ~Condition(); + inline void wait(Mutex&); + inline bool wait(Mutex&, const Time& absoluteTime); + inline void notify(); + inline void notifyAll(); + + private: +#ifdef USE_APR + apr_thread_cond_t* condition; +#else + pthread_cond_t condition; +#endif +}; + + +// APR ================================================================ +#ifdef USE_APR + +Condition::Condition() { + CHECK_APR_SUCCESS(apr_thread_cond_create(&condition, APRPool::get())); +} + +Condition::~Condition() { + CHECK_APR_SUCCESS(apr_thread_cond_destroy(condition)); +} + +void Condition::wait(Mutex& mutex) { + CHECK_APR_SUCCESS(apr_thread_cond_wait(condition, mutex.mutex)); +} + +bool Condition::wait(Mutex& mutex, const Time& absoluteTime){ + // APR uses microseconds. + apr_status_t status = + apr_thread_cond_timedwait( + condition, mutex.mutex, absoluteTime/TIME_USEC); + if(status != APR_TIMEUP) CHECK_APR_SUCCESS(status); + return status == 0; +} + +void Condition::notify(){ + CHECK_APR_SUCCESS(apr_thread_cond_signal(condition)); +} + +void Condition::notifyAll(){ + CHECK_APR_SUCCESS(apr_thread_cond_broadcast(condition)); +} + +#else +// POSIX ================================================================ + +Condition::Condition() { + QPID_POSIX_THROW_IF(pthread_cond_init(&condition, 0)); +} + +Condition::~Condition() { + QPID_POSIX_THROW_IF(pthread_cond_destroy(&condition)); +} + +void Condition::wait(Mutex& mutex) { + QPID_POSIX_THROW_IF(pthread_cond_wait(&condition, &mutex.mutex)); +} + +bool Condition::wait(Mutex& mutex, const Time& absoluteTime){ + struct timespec ts; + toTimespec(ts, absoluteTime); + int status = pthread_cond_timedwait(&condition, &mutex.mutex, &ts); + if (status != 0) { + if (status == ETIMEDOUT) return false; + throw QPID_POSIX_ERROR(status); + } + return true; +} + +void Condition::notify(){ + QPID_POSIX_THROW_IF(pthread_cond_signal(&condition)); +} + +void Condition::notifyAll(){ + QPID_POSIX_THROW_IF(pthread_cond_broadcast(&condition)); +} +#endif /*USE_APR*/ + + +}} +#endif /*!_sys_Condition_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/ConnectionInputHandler.h b/qpid/cpp-0-9/lib/common/sys/ConnectionInputHandler.h new file mode 100644 index 0000000000..fa70dfaf48 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/ConnectionInputHandler.h @@ -0,0 +1,45 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _ConnectionInputHandler_ +#define _ConnectionInputHandler_ + +#include <InputHandler.h> +#include <InitiationHandler.h> +#include <ProtocolInitiation.h> +#include <sys/TimeoutHandler.h> + +namespace qpid { +namespace sys { + + class ConnectionInputHandler : + public qpid::framing::InitiationHandler, + public qpid::framing::InputHandler, + public TimeoutHandler + { + public: + virtual void closed() = 0; + }; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/sys/ConnectionInputHandlerFactory.h b/qpid/cpp-0-9/lib/common/sys/ConnectionInputHandlerFactory.h new file mode 100644 index 0000000000..af7d411928 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/ConnectionInputHandlerFactory.h @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _ConnectionInputHandlerFactory_ +#define _ConnectionInputHandlerFactory_ + +#include <boost/noncopyable.hpp> + +namespace qpid { +namespace sys { + +class ConnectionOutputHandler; +class ConnectionInputHandler; + +/** + * Callback interface used by the Acceptor to + * create a ConnectionInputHandler for each new connection. + */ +class ConnectionInputHandlerFactory : private boost::noncopyable +{ + public: + virtual ConnectionInputHandler* create(ConnectionOutputHandler* ctxt) = 0; + virtual ~ConnectionInputHandlerFactory(){} +}; + +}} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/sys/ConnectionOutputHandler.h b/qpid/cpp-0-9/lib/common/sys/ConnectionOutputHandler.h new file mode 100644 index 0000000000..91849e1dfb --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/ConnectionOutputHandler.h @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _ConnectionOutputHandler_ +#define _ConnectionOutputHandler_ + +#include <OutputHandler.h> + +namespace qpid { +namespace sys { + +/** + * Provides the output handler associated with a connection. + */ +class ConnectionOutputHandler : public virtual qpid::framing::OutputHandler +{ + public: + virtual void close() = 0; +}; + +}} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/sys/Module.h b/qpid/cpp-0-9/lib/common/sys/Module.h new file mode 100644 index 0000000000..9bf5d6e1fc --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/Module.h @@ -0,0 +1,161 @@ +#ifndef _sys_Module_h +#define _sys_Module_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <boost/noncopyable.hpp> +#include <iostream> +#include <QpidError.h> + +namespace qpid { +namespace sys { +#if USE_APR +#include <apr_dso.h> + typedef apr_dso_handle_t* dso_handle_t; +#else + typedef void* dso_handle_t; +#endif + + template <class T> class Module : private boost::noncopyable + { + typedef T* create_t(); + typedef void destroy_t(T*); + + dso_handle_t handle; + destroy_t* destroy; + T* ptr; + + void load(const std::string& name); + void unload(); + void* getSymbol(const std::string& name); + + public: + Module(const std::string& name); + T* operator->(); + T* get(); + ~Module() throw(); + }; + +} +} + +using namespace qpid::sys; + +template <class T> Module<T>::Module(const std::string& module) : destroy(0), ptr(0) +{ + load(module); + //TODO: need a better strategy for symbol names to allow multiple + //modules to be loaded without clashes... + + //Note: need the double cast to avoid errors in casting from void* to function pointer with -pedantic + create_t* create = reinterpret_cast<create_t*>(reinterpret_cast<intptr_t>(getSymbol("create"))); + destroy = reinterpret_cast<destroy_t*>(reinterpret_cast<intptr_t>(getSymbol("destroy"))); + ptr = create(); +} + +template <class T> T* Module<T>::operator->() +{ + return ptr; +} + +template <class T> T* Module<T>::get() +{ + return ptr; +} + +template <class T> Module<T>::~Module() throw() +{ + try { + if (handle && ptr) { + destroy(ptr); + } + if (handle) unload(); + } catch (std::exception& e) { + std::cout << "Error while destroying module: " << e.what() << std::endl; + } + destroy = 0; + handle = 0; + ptr = 0; +} + +// APR ================================================================ +#if USE_APR + +#include <apr/APRBase.h> +#include <apr/APRPool.h> + +template <class T> void Module<T>::load(const std::string& name) +{ + CHECK_APR_SUCCESS(apr_dso_load(&handle, name.c_str(), APRPool::get())); +} + +template <class T> void Module<T>::unload() +{ + CHECK_APR_SUCCESS(apr_dso_unload(handle)); +} + +template <class T> void* Module<T>::getSymbol(const std::string& name) +{ + apr_dso_handle_sym_t symbol; + CHECK_APR_SUCCESS(apr_dso_sym(&symbol, handle, name.c_str())); + return (void*) symbol; +} + +// POSIX================================================================ +#else + +#include <dlfcn.h> + +template <class T> void Module<T>::load(const std::string& name) +{ + dlerror(); + handle = dlopen(name.c_str(), RTLD_NOW); + const char* error = dlerror(); + if (error) { + THROW_QPID_ERROR(INTERNAL_ERROR, error); + } +} + +template <class T> void Module<T>::unload() +{ + dlerror(); + dlclose(handle); + const char* error = dlerror(); + if (error) { + THROW_QPID_ERROR(INTERNAL_ERROR, error); + } +} + +template <class T> void* Module<T>::getSymbol(const std::string& name) +{ + dlerror(); + void* sym = dlsym(handle, name.c_str()); + const char* error = dlerror(); + if (error) { + THROW_QPID_ERROR(INTERNAL_ERROR, error); + } + return sym; +} + +#endif //if USE_APR + +#endif //ifndef _sys_Module_h + diff --git a/qpid/cpp-0-9/lib/common/sys/Monitor.h b/qpid/cpp-0-9/lib/common/sys/Monitor.h new file mode 100644 index 0000000000..a3bbd3c5aa --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/Monitor.h @@ -0,0 +1,55 @@ +#ifndef _sys_Monitor_h +#define _sys_Monitor_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <sys/errno.h> +#include <sys/Condition.h> + +#ifdef USE_APR +# include <apr_thread_cond.h> +#endif + +namespace qpid { +namespace sys { + +/** + * A monitor is a condition variable and a mutex + */ +class Monitor : public Mutex, public Condition { + public: + using Condition::wait; + inline void wait(); + inline bool wait(const Time& absoluteTime); +}; + + +void Monitor::wait() { + Condition::wait(*this); +} + +bool Monitor::wait(const Time& absoluteTime) { + return Condition::wait(*this, absoluteTime); +} + +}} +#endif /*!_sys_Monitor_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/Mutex.h b/qpid/cpp-0-9/lib/common/sys/Mutex.h new file mode 100644 index 0000000000..9db9be0981 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/Mutex.h @@ -0,0 +1,165 @@ +#ifndef _sys_Mutex_h +#define _sys_Mutex_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifdef USE_APR +# include <apr_thread_mutex.h> +# include <apr/APRBase.h> +# include <apr/APRPool.h> +#else +# include <pthread.h> +# include <posix/check.h> +#endif +#include <boost/noncopyable.hpp> + +namespace qpid { +namespace sys { + +class Condition; + +/** + * Scoped lock template: calls lock() in ctor, unlock() in dtor. + * L can be any class with lock() and unlock() functions. + */ +template <class L> +class ScopedLock +{ + public: + ScopedLock(L& l) : mutex(l) { l.lock(); } + ~ScopedLock() { mutex.unlock(); } + private: + L& mutex; +}; + +template <class L> +class ScopedUnlock +{ + public: + ScopedUnlock(L& l) : mutex(l) { l.unlock(); } + ~ScopedUnlock() { mutex.lock(); } + private: + L& mutex; +}; + +/** + * Mutex lock. + */ +class Mutex : private boost::noncopyable { + public: + typedef ScopedLock<Mutex> ScopedLock; + typedef ScopedUnlock<Mutex> ScopedUnlock; + + inline Mutex(); + inline ~Mutex(); + inline void lock(); + inline void unlock(); + inline void trylock(); + + protected: +#ifdef USE_APR + apr_thread_mutex_t* mutex; +#else + pthread_mutex_t mutex; +#endif + friend class Condition; +}; + +#ifdef USE_APR +// APR ================================================================ + +Mutex::Mutex() { + CHECK_APR_SUCCESS(apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, APRPool::get())); +} + +Mutex::~Mutex(){ + CHECK_APR_SUCCESS(apr_thread_mutex_destroy(mutex)); +} + +void Mutex::lock() { + CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex)); +} +void Mutex::unlock() { + CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex)); +} + +void Mutex::trylock() { + CHECK_APR_SUCCESS(apr_thread_mutex_trylock(mutex)); +} + +#else +// POSIX ================================================================ + +/** + * PODMutex is a POD, can be static-initialized with + * PODMutex m = QPID_PODMUTEX_INITIALIZER + */ +struct PODMutex +{ + typedef ScopedLock<PODMutex> ScopedLock; + + inline void lock(); + inline void unlock(); + inline void trylock(); + + // Must be public to be a POD: + pthread_mutex_t mutex; +}; + +#define QPID_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER } + + +void PODMutex::lock() { + QPID_POSIX_THROW_IF(pthread_mutex_lock(&mutex)); +} +void PODMutex::unlock() { + QPID_POSIX_THROW_IF(pthread_mutex_unlock(&mutex)); +} + +void PODMutex::trylock() { + QPID_POSIX_THROW_IF(pthread_mutex_trylock(&mutex)); +} + + +Mutex::Mutex() { + QPID_POSIX_THROW_IF(pthread_mutex_init(&mutex, 0)); +} + +Mutex::~Mutex(){ + QPID_POSIX_THROW_IF(pthread_mutex_destroy(&mutex)); +} + +void Mutex::lock() { + QPID_POSIX_THROW_IF(pthread_mutex_lock(&mutex)); +} +void Mutex::unlock() { + QPID_POSIX_THROW_IF(pthread_mutex_unlock(&mutex)); +} + +void Mutex::trylock() { + QPID_POSIX_THROW_IF(pthread_mutex_trylock(&mutex)); +} + +#endif // USE_APR + +}} + + + +#endif /*!_sys_Mutex_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/ProducerConsumer.cpp b/qpid/cpp-0-9/lib/common/sys/ProducerConsumer.cpp new file mode 100644 index 0000000000..3f6156f230 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/ProducerConsumer.cpp @@ -0,0 +1,141 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include "QpidError.h" +#include "ScopedIncrement.h" +#include "ProducerConsumer.h" + +namespace qpid { +namespace sys { + +// // ================ ProducerConsumer + +ProducerConsumer::ProducerConsumer(size_t init_items) + : items(init_items), waiters(0), stopped(false) +{} + +void ProducerConsumer::stop() { + Mutex::ScopedLock l(monitor); + stopped = true; + monitor.notifyAll(); + // Wait for waiting consumers to wake up. + while (waiters > 0) + monitor.wait(); +} + +size_t ProducerConsumer::available() const { + Mutex::ScopedLock l(monitor); + return items; +} + +size_t ProducerConsumer::consumers() const { + Mutex::ScopedLock l(monitor); + return waiters; +} + +// ================ Lock + +ProducerConsumer::Lock::Lock(ProducerConsumer& p) + : pc(p), lock(p.monitor), status(INCOMPLETE) {} + +bool ProducerConsumer::Lock::isOk() const { + return !pc.isStopped() && status==INCOMPLETE; +} + +void ProducerConsumer::Lock::checkOk() const { + assert(!pc.isStopped()); + assert(status == INCOMPLETE); +} + +ProducerConsumer::Lock::~Lock() { + assert(status != INCOMPLETE || pc.isStopped()); +} + +void ProducerConsumer::Lock::confirm() { + checkOk(); + status = CONFIRMED; +} + +void ProducerConsumer::Lock::cancel() { + checkOk(); + status = CANCELLED; +} + +// ================ ProducerLock + +ProducerConsumer::ProducerLock::ProducerLock(ProducerConsumer& p) : Lock(p) +{} + + +ProducerConsumer::ProducerLock::~ProducerLock() { + if (status == CONFIRMED) { + pc.items++; + pc.monitor.notify(); // Notify a consumer. + } +} + +// ================ ConsumerLock + +ProducerConsumer::ConsumerLock::ConsumerLock(ProducerConsumer& p) : Lock(p) +{ + if (isOk()) { + ScopedIncrement<size_t> inc(pc.waiters); + while (pc.items == 0 && !pc.stopped) { + pc.monitor.wait(); + } + } +} + +ProducerConsumer::ConsumerLock::ConsumerLock( + ProducerConsumer& p, const Time& timeout) : Lock(p) +{ + if (isOk()) { + // Don't wait if timeout==0 + if (timeout == 0) { + if (pc.items == 0) + status = TIMEOUT; + return; + } + else { + Time deadline = now() + timeout; + ScopedIncrement<size_t> inc(pc.waiters); + while (pc.items == 0 && !pc.stopped) { + if (!pc.monitor.wait(deadline)) { + status = TIMEOUT; + return; + } + } + } + } +} + +ProducerConsumer::ConsumerLock::~ConsumerLock() { + if (pc.isStopped()) { + if (pc.waiters == 0) + pc.monitor.notifyAll(); // All waiters woken, notify stop thread(s) + } + else if (status==CONFIRMED) { + pc.items--; + if (pc.items > 0) + pc.monitor.notify(); // Notify another consumer. + } +} + + +}} // namespace qpid::sys diff --git a/qpid/cpp-0-9/lib/common/sys/ProducerConsumer.h b/qpid/cpp-0-9/lib/common/sys/ProducerConsumer.h new file mode 100644 index 0000000000..742639323b --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/ProducerConsumer.h @@ -0,0 +1,165 @@ +#ifndef _sys_ProducerConsumer_h +#define _sys_ProducerConsumer_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include <boost/noncopyable.hpp> +#include "Exception.h" +#include "sys/Monitor.h" + +namespace qpid { +namespace sys { + +/** + * Producer-consumer synchronisation. + * + * Producers increase the number of available items, consumers reduce it. + * Consumers wait till an item is available. Waiting threads can be + * woken for shutdown using stop(). + * + * Note: Currently implements unbounded producer-consumer, i.e. no limit + * to available items, producers never block. Can be extended to support + * bounded PC if required. + * + // TODO aconway 2007-02-13: example, from tests. +*/ +class ProducerConsumer +{ + public: + ProducerConsumer(size_t init_items=0); + + ~ProducerConsumer() { stop(); } + + /** + * Wake any threads waiting for ProducerLock or ConsumerLock. + *@post No threads are waiting in Producer or Consumer locks. + */ + void stop(); + + /** True if queue is stopped */ + bool isStopped() { return stopped; } + + /** Number of items available for consumers */ + size_t available() const; + + /** Number of consumers waiting for items */ + size_t consumers() const; + + /** True if available == 0 */ + bool empty() const { return available() == 0; } + + /** + * Base class for producer and consumer locks. + */ + class Lock : private boost::noncopyable { + public: + + /** + * You must call isOk() after creating a lock to verify its state. + * + *@return true means the lock succeeded. You MUST call either + *confirm() or cancel() before the lock goes out of scope. + * + * false means the lock failed - timed out or the + * ProducerConsumer is stopped. You should not do anything in + * the scope of the lock. + */ + bool isOk() const; + + /** + * Confirm that an item was produced/consumed. + *@pre isOk() + */ + void confirm(); + + /** + * Cancel the lock to indicate nothing was produced/consumed. + * Note that locks are not actually released until destroyed. + * + *@pre isOk() + */ + void cancel(); + + /** True if this lock experienced a timeout */ + bool isTimedOut() const { return status == TIMEOUT; } + + /** True if we have been stopped */ + bool isStopped() const { return pc.isStopped(); } + + ProducerConsumer& pc; + + protected: + /** Lock status */ + enum Status { INCOMPLETE, CONFIRMED, CANCELLED, TIMEOUT }; + + Lock(ProducerConsumer& p); + ~Lock(); + void checkOk() const; + Mutex::ScopedLock lock; + Status status; + }; + + /** Lock for code that produces items. */ + struct ProducerLock : public Lock { + /** + * Acquire locks to produce an item. + *@post If isOk() the calling thread has exclusive access + * to produce an item. + */ + ProducerLock(ProducerConsumer& p); + + /** Release locks, signal waiting consumers if confirm() was called. */ + ~ProducerLock(); + }; + + /** Lock for code that consumes items */ + struct ConsumerLock : public Lock { + /** + * Wait for an item to consume and acquire locks. + * + *@post If isOk() there is at least one item available and the + *calling thread has exclusive access to consume it. + */ + ConsumerLock(ProducerConsumer& p); + + /** + * Wait up to timeout to acquire lock. + *@post If isOk() caller has a producer lock. + * If isTimedOut() there was a timeout. + * If neither then we were stopped. + */ + ConsumerLock(ProducerConsumer& p, const Time& timeout); + + /** Release locks */ + ~ConsumerLock(); + }; + + private: + mutable Monitor monitor; + size_t items; + size_t waiters; + bool stopped; + + friend class Lock; + friend class ProducerLock; + friend class ConsumerLock; +}; + +}} // namespace qpid::sys + +#endif /*!_sys_ProducerConsumer_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/Runnable.cpp b/qpid/cpp-0-9/lib/common/sys/Runnable.cpp new file mode 100644 index 0000000000..30122c682f --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/Runnable.cpp @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "Runnable.h" +#include <boost/bind.hpp> + +namespace qpid { +namespace sys { + +Runnable::~Runnable() {} + +Runnable::Functor Runnable::functor() +{ + return boost::bind(&Runnable::run, this); +} + +}} diff --git a/qpid/cpp-0-9/lib/common/sys/Runnable.h b/qpid/cpp-0-9/lib/common/sys/Runnable.h new file mode 100644 index 0000000000..fb3927c612 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/Runnable.h @@ -0,0 +1,50 @@ +#ifndef _Runnable_ +#define _Runnable_ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <boost/function.hpp> + +namespace qpid { +namespace sys { + +/** + * Interface for objects that can be run, e.g. in a thread. + */ +class Runnable +{ + public: + /** Type to represent a runnable as a Functor */ + typedef boost::function0<void> Functor; + + virtual ~Runnable(); + + /** Derived classes override run(). */ + virtual void run() = 0; + + /** Create a functor object that will call this->run(). */ + Functor functor(); +}; + +}} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/sys/ScopedIncrement.h b/qpid/cpp-0-9/lib/common/sys/ScopedIncrement.h new file mode 100644 index 0000000000..f14461ddaf --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/ScopedIncrement.h @@ -0,0 +1,59 @@ +#ifndef _posix_ScopedIncrement_h +#define _posix_ScopedIncrement_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <boost/noncopyable.hpp> + +namespace qpid { +namespace sys { + +/** Increment counter in constructor and decrement in destructor. */ +template <class T> +class ScopedIncrement : boost::noncopyable +{ + public: + ScopedIncrement(T& c) : count(c) { ++count; } + ~ScopedIncrement() { --count; } + private: + T& count; +}; + + +/** Decrement counter in constructor and increment in destructor. */ +template <class T> +class ScopedDecrement : boost::noncopyable +{ + public: + ScopedDecrement(T& c) : count(c) { value = --count; } + ~ScopedDecrement() { ++count; } + + /** Return the value after the decrement. */ + operator long() { return value; } + + private: + T& count; + long value; +}; + + +}} + + +#endif // _posix_ScopedIncrement_h diff --git a/qpid/cpp-0-9/lib/common/sys/ShutdownHandler.h b/qpid/cpp-0-9/lib/common/sys/ShutdownHandler.h new file mode 100644 index 0000000000..88baecb5b6 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/ShutdownHandler.h @@ -0,0 +1,37 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _ShutdownHandler_ +#define _ShutdownHandler_ + +namespace qpid { +namespace sys { + + class ShutdownHandler + { + public: + virtual void shutdown() = 0; + virtual ~ShutdownHandler(){} + }; + +} +} + +#endif diff --git a/qpid/cpp-0-9/lib/common/sys/Socket.h b/qpid/cpp-0-9/lib/common/sys/Socket.h new file mode 100644 index 0000000000..d793a240c6 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/Socket.h @@ -0,0 +1,88 @@ +#ifndef _sys_Socket_h +#define _sys_Socket_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <string> +#include <sys/Time.h> + +#ifdef USE_APR +# include <apr_network_io.h> +#endif + +namespace qpid { +namespace sys { + +class Socket +{ + public: + /** Create an initialized TCP socket */ + static Socket createTcp(); + + /** Create a socket wrapper for descriptor. */ +#ifdef USE_APR + Socket(apr_socket_t* descriptor = 0); +#else + Socket(int descriptor = 0); +#endif + + /** Set timeout for read and write */ + void setTimeout(Time interval); + + void connect(const std::string& host, int port); + + void close(); + + enum { SOCKET_TIMEOUT=-2, SOCKET_EOF=-3 } ErrorCode; + + /** Returns bytes sent or an ErrorCode value < 0. */ + ssize_t send(const void* data, size_t size); + + /** + * Returns bytes received, an ErrorCode value < 0 or 0 + * if the connection closed in an orderly manner. + */ + ssize_t recv(void* data, size_t size); + + /** Bind to a port and start listening. + *@param port 0 means choose an available port. + *@param backlog maximum number of pending connections. + *@return The bound port. + */ + int listen(int port = 0, int backlog = 10); + + /** Get file descriptor */ + int fd(); + + private: +#ifdef USE_APR + apr_socket_t* socket; +#else + void init() const; + mutable int socket; // Initialized on demand. +#endif +}; + +}} + + +#endif /*!_sys_Socket_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/Thread.h b/qpid/cpp-0-9/lib/common/sys/Thread.h new file mode 100644 index 0000000000..47b95b6234 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/Thread.h @@ -0,0 +1,142 @@ +#ifndef _sys_Thread_h +#define _sys_Thread_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <sys/Runnable.h> + +#ifdef USE_APR +# include <apr_thread_proc.h> +# include <apr_portable.h> +# include <apr/APRPool.h> +# include <apr/APRBase.h> +#else +# include <posix/check.h> +# include <pthread.h> +#endif + +namespace qpid { +namespace sys { + +class Thread +{ + public: + inline static Thread current(); + inline static void yield(); + + inline Thread(); + inline explicit Thread(qpid::sys::Runnable*); + inline explicit Thread(qpid::sys::Runnable&); + + inline void join(); + + inline long id(); + + private: +#ifdef USE_APR + static void* APR_THREAD_FUNC runRunnable(apr_thread_t* thread, void *data); + inline Thread(apr_thread_t* t); + apr_thread_t* thread; +#else + static void* runRunnable(void* runnable); + inline Thread(pthread_t); + pthread_t thread; +#endif +}; + + +Thread::Thread() : thread(0) {} + +// APR ================================================================ +#ifdef USE_APR + +Thread::Thread(Runnable* runnable) { + CHECK_APR_SUCCESS( + apr_thread_create(&thread, 0, runRunnable, runnable, APRPool::get())); +} + +Thread::Thread(Runnable& runnable) { + CHECK_APR_SUCCESS( + apr_thread_create(&thread, 0, runRunnable, &runnable, APRPool::get())); +} + +void Thread::join(){ + apr_status_t status; + if (thread != 0) + CHECK_APR_SUCCESS(apr_thread_join(&status, thread)); +} + +long Thread::id() { + return long(thread); +} + +Thread::Thread(apr_thread_t* t) : thread(t) {} + +Thread Thread::current(){ + apr_thread_t* thr; + apr_os_thread_t osthr = apr_os_thread_current(); + CHECK_APR_SUCCESS(apr_os_thread_put(&thr, &osthr, APRPool::get())); + return Thread(thr); +} + +void Thread::yield() +{ + apr_thread_yield(); +} + + +// POSIX ================================================================ +#else + +Thread::Thread(Runnable* runnable) { + QPID_POSIX_THROW_IF(pthread_create(&thread, NULL, runRunnable, runnable)); +} + +Thread::Thread(Runnable& runnable) { + QPID_POSIX_THROW_IF(pthread_create(&thread, NULL, runRunnable, &runnable)); +} + +void Thread::join(){ + QPID_POSIX_THROW_IF(pthread_join(thread, 0)); +} + +long Thread::id() { + return long(thread); +} + +Thread::Thread(pthread_t thr) : thread(thr) {} + +Thread Thread::current() { + return Thread(pthread_self()); +} + +void Thread::yield() +{ + QPID_POSIX_THROW_IF(pthread_yield()); +} + + +#endif + +}} + +#endif /*!_sys_Thread_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/ThreadSafeQueue.h b/qpid/cpp-0-9/lib/common/sys/ThreadSafeQueue.h new file mode 100644 index 0000000000..ff949a3e16 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/ThreadSafeQueue.h @@ -0,0 +1,98 @@ +#ifndef _sys_ThreadSafeQueue_h +#define _sys_ThreadSafeQueue_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <deque> +#include "ProducerConsumer.h" +#include "Exception.h" + +namespace qpid { +namespace sys { + +/** + * A thread safe queue template. + */ +template <class T, class ContainerType=std::deque<T> > +class ThreadSafeQueue +{ + public: + + ThreadSafeQueue() {} + + /** Push a value onto the back of the queue */ + void push(const T& value) { + ProducerConsumer::ProducerLock producer(pc); + if (producer.isOk()) { + producer.confirm(); + container.push_back(value); + } + } + + /** Pop a value from the front of the queue. Waits till value is available. + *@throw ShutdownException if queue is stopped while waiting. + */ + T pop() { + ProducerConsumer::ConsumerLock consumer(pc); + if (consumer.isOk()) { + consumer.confirm(); + T value(container.front()); + container.pop_front(); + return value; + } + throw ShutdownException(); + } + + /** + * If a value becomes available within the timeout, set outValue + * and return true. Otherwise return false; + */ + bool pop(T& outValue, const Time& timeout) { + ProducerConsumer::ConsumerLock consumer(pc, timeout); + if (consumer.isOk()) { + consumer.confirm(); + outValue = container.front(); + container.pop_front(); + return true; + } + return false; + } + + /** Interrupt threads waiting in pop() */ + void stop() { pc.stop(); } + + /** True if queue is stopped */ + bool isStopped() { return pc.isStopped(); } + + /** Size of the queue */ + size_t size() { ProducerConsumer::Lock l(pc); return container.size(); } + + /** True if queue is empty */ + bool empty() { ProducerConsumer::Lock l(pc); return container.empty(); } + + private: + ProducerConsumer pc; + ContainerType container; +}; + +}} // namespace qpid::sys + + + +#endif /*!_sys_ThreadSafeQueue_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/Time.cpp b/qpid/cpp-0-9/lib/common/sys/Time.cpp new file mode 100644 index 0000000000..ad6185b966 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/Time.cpp @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "Time.h" + +namespace qpid { +namespace sys { + +// APR ================================================================ +#if USE_APR + +Time now() { return apr_time_now() * TIME_USEC; } + +// POSIX================================================================ +#else + +Time now() { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return toTime(ts); +} + +struct timespec toTimespec(const Time& t) { + struct timespec ts; + toTimespec(ts, t); + return ts; +} + +struct timespec& toTimespec(struct timespec& ts, const Time& t) { + ts.tv_sec = t / TIME_SEC; + ts.tv_nsec = t % TIME_SEC; + return ts; +} + +Time toTime(const struct timespec& ts) { + return ts.tv_sec*TIME_SEC + ts.tv_nsec; +} + + +#endif +}} + diff --git a/qpid/cpp-0-9/lib/common/sys/Time.h b/qpid/cpp-0-9/lib/common/sys/Time.h new file mode 100644 index 0000000000..3dd46741d8 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/Time.h @@ -0,0 +1,58 @@ +#ifndef _sys_Time_h +#define _sys_Time_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <stdint.h> + +#ifdef USE_APR +# include <apr_time.h> +#else +# include <time.h> +#endif + +namespace qpid { +namespace sys { + +/** Time in nanoseconds */ +typedef int64_t Time; + +Time now(); + +/** Nanoseconds per second. */ +const Time TIME_SEC = 1000*1000*1000; +/** Nanoseconds per millisecond */ +const Time TIME_MSEC = 1000*1000; +/** Nanoseconds per microseconds. */ +const Time TIME_USEC = 1000; +/** Nanoseconds per nanosecond. */ +const Time TIME_NSEC = 1; + +#ifndef USE_APR +struct timespec toTimespec(const Time& t); +struct timespec& toTimespec(struct timespec& ts, const Time& t); +Time toTime(const struct timespec& ts); +#endif + +}} + +#endif /*!_sys_Time_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/TimeoutHandler.h b/qpid/cpp-0-9/lib/common/sys/TimeoutHandler.h new file mode 100644 index 0000000000..0c10709bbf --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/TimeoutHandler.h @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _TimeoutHandler_ +#define _TimeoutHandler_ + +namespace qpid { +namespace sys { + + class TimeoutHandler + { + public: + virtual void idleOut() = 0; + virtual void idleIn() = 0; + virtual ~TimeoutHandler(){} + }; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/sys/apr/APRAcceptor.cpp b/qpid/cpp-0-9/lib/common/sys/apr/APRAcceptor.cpp new file mode 100644 index 0000000000..52384857ed --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/APRAcceptor.cpp @@ -0,0 +1,122 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <sys/Acceptor.h> +#include <sys/ConnectionInputHandlerFactory.h> +#include "LFProcessor.h" +#include "LFSessionContext.h" +#include "APRBase.h" +#include "APRPool.h" + +namespace qpid { +namespace sys { + +class APRAcceptor : public Acceptor +{ + public: + APRAcceptor(int16_t port, int backlog, int threads, bool trace); + virtual int16_t getPort() const; + virtual void run(qpid::sys::ConnectionInputHandlerFactory* factory); + virtual void shutdown(); + + private: + void shutdownImpl(); + + private: + int16_t port; + bool trace; + LFProcessor processor; + apr_socket_t* socket; + volatile bool running; + Mutex shutdownLock; +}; + +// Define generic Acceptor::create() to return APRAcceptor. +Acceptor::shared_ptr Acceptor::create(int16_t port, int backlog, int threads, bool trace) +{ + return Acceptor::shared_ptr(new APRAcceptor(port, backlog, threads, trace)); +} +// Must define Acceptor virtual dtor. +Acceptor::~Acceptor() {} + +APRAcceptor::APRAcceptor(int16_t port_, int backlog, int threads, bool trace_) : + port(port_), + trace(trace_), + processor(APRPool::get(), threads, 1000, 5000000), + running(false) +{ + apr_sockaddr_t* address; + CHECK_APR_SUCCESS(apr_sockaddr_info_get(&address, APR_ANYADDR, APR_UNSPEC, port, APR_IPV4_ADDR_OK, APRPool::get())); + CHECK_APR_SUCCESS(apr_socket_create(&socket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, APRPool::get())); + CHECK_APR_SUCCESS(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1)); + CHECK_APR_SUCCESS(apr_socket_bind(socket, address)); + CHECK_APR_SUCCESS(apr_socket_listen(socket, backlog)); +} + +int16_t APRAcceptor::getPort() const { + apr_sockaddr_t* address; + CHECK_APR_SUCCESS(apr_socket_addr_get(&address, APR_LOCAL, socket)); + return address->port; +} + +void APRAcceptor::run(ConnectionInputHandlerFactory* factory) { + running = true; + processor.start(); + std::cout << "Listening on port " << getPort() << "..." << std::endl; + while(running){ + apr_socket_t* client; + apr_status_t status = apr_socket_accept(&client, socket, APRPool::get()); + if(status == APR_SUCCESS){ + //make this socket non-blocking: + CHECK_APR_SUCCESS(apr_socket_timeout_set(client, 0)); + CHECK_APR_SUCCESS(apr_socket_opt_set(client, APR_SO_NONBLOCK, 1)); + CHECK_APR_SUCCESS(apr_socket_opt_set(client, APR_TCP_NODELAY, 1)); + CHECK_APR_SUCCESS(apr_socket_opt_set(client, APR_SO_SNDBUF, 32768)); + CHECK_APR_SUCCESS(apr_socket_opt_set(client, APR_SO_RCVBUF, 32768)); + LFSessionContext* session = new LFSessionContext(APRPool::get(), client, &processor, trace); + session->init(factory->create(session)); + }else{ + Mutex::ScopedLock locker(shutdownLock); + if(running) { + if(status != APR_EINTR){ + std::cout << "ERROR: " << get_desc(status) << std::endl; + } + shutdownImpl(); + } + } + } +} + +void APRAcceptor::shutdown() { + Mutex::ScopedLock locker(shutdownLock); + if (running) { + shutdownImpl(); + } +} + +void APRAcceptor::shutdownImpl() { + Mutex::ScopedLock locker(shutdownLock); + running = false; + processor.stop(); + CHECK_APR_SUCCESS(apr_socket_close(socket)); +} + + +}} diff --git a/qpid/cpp-0-9/lib/common/sys/apr/APRBase.cpp b/qpid/cpp-0-9/lib/common/sys/apr/APRBase.cpp new file mode 100644 index 0000000000..861071499f --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/APRBase.cpp @@ -0,0 +1,90 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <QpidError.h> +#include "APRBase.h" + +using namespace qpid::sys; + +APRBase* APRBase::instance = 0; + +APRBase* APRBase::getInstance(){ + if(instance == 0){ + instance = new APRBase(); + } + return instance; +} + + +APRBase::APRBase() : count(0){ + apr_initialize(); + CHECK_APR_SUCCESS(apr_pool_create(&pool, 0)); + CHECK_APR_SUCCESS(apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, pool)); +} + +APRBase::~APRBase(){ + CHECK_APR_SUCCESS(apr_thread_mutex_destroy(mutex)); + apr_pool_destroy(pool); + apr_terminate(); +} + +bool APRBase::_increment(){ + bool deleted(false); + CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex)); + if(this == instance){ + count++; + }else{ + deleted = true; + } + CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex)); + return !deleted; +} + +void APRBase::_decrement(){ + APRBase* copy = 0; + CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex)); + if(--count == 0){ + copy = instance; + instance = 0; + } + CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex)); + if(copy != 0){ + delete copy; + } +} + +void APRBase::increment(){ + int count = 0; + while(count++ < 2 && !getInstance()->_increment()){ + std::cout << "WARNING: APR initialization triggered concurrently with termination." << std::endl; + } +} + +void APRBase::decrement(){ + getInstance()->_decrement(); +} + +std::string qpid::sys::get_desc(apr_status_t status){ + const int size = 50; + char tmp[size]; + return std::string(apr_strerror(status, tmp, size)); +} + diff --git a/qpid/cpp-0-9/lib/common/sys/apr/APRBase.h b/qpid/cpp-0-9/lib/common/sys/apr/APRBase.h new file mode 100644 index 0000000000..6a866a554a --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/APRBase.h @@ -0,0 +1,78 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _APRBase_ +#define _APRBase_ + +#include <string> +#include <apr_thread_mutex.h> +#include <apr_errno.h> +#include <QpidError.h> + +namespace qpid { +namespace sys { + + /** + * Use of APR libraries necessitates explicit init and terminate + * calls. Any class using APR libs should obtain the reference to + * this singleton and increment on construction, decrement on + * destruction. This class can then correctly initialise apr + * before the first use and terminate after the last use. + */ + class APRBase{ + static APRBase* instance; + apr_pool_t* pool; + apr_thread_mutex_t* mutex; + int count; + + APRBase(); + ~APRBase(); + static APRBase* getInstance(); + bool _increment(); + void _decrement(); + public: + static void increment(); + static void decrement(); + }; + + //this is also a convenient place for a helper function for error checking: + void check(apr_status_t status, const char* file, const int line); + std::string get_desc(apr_status_t status); + +#define CHECK_APR_SUCCESS(A) qpid::sys::check(A, __FILE__, __LINE__); + +} +} + +// Inlined as it is called *a lot* +void inline qpid::sys::check(apr_status_t status, const char* file, const int line){ + if (status != APR_SUCCESS){ + const int size = 50; + char tmp[size]; + std::string msg(apr_strerror(status, tmp, size)); + throw qpid::QpidError(APR_ERROR + ((int) status), msg, + qpid::SrcLine(file, line)); + } +} + + + + +#endif diff --git a/qpid/cpp-0-9/lib/common/sys/apr/APRPool.cpp b/qpid/cpp-0-9/lib/common/sys/apr/APRPool.cpp new file mode 100644 index 0000000000..e8b71f6e8a --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/APRPool.cpp @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "APRPool.h" +#include "APRBase.h" +#include <boost/pool/detail/singleton.hpp> + +using namespace qpid::sys; + +APRPool::APRPool(){ + APRBase::increment(); + CHECK_APR_SUCCESS(apr_pool_create(&pool, NULL)); +} + +APRPool::~APRPool(){ + apr_pool_destroy(pool); + APRBase::decrement(); +} + +apr_pool_t* APRPool::get() { + return boost::details::pool::singleton_default<APRPool>::instance().pool; +} + diff --git a/qpid/cpp-0-9/lib/common/sys/apr/APRPool.h b/qpid/cpp-0-9/lib/common/sys/apr/APRPool.h new file mode 100644 index 0000000000..da7661fcfa --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/APRPool.h @@ -0,0 +1,50 @@ +#ifndef _APRPool_ +#define _APRPool_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <boost/noncopyable.hpp> +#include <apr_pools.h> + +namespace qpid { +namespace sys { +/** + * Singleton APR memory pool. + */ +class APRPool : private boost::noncopyable { + public: + APRPool(); + ~APRPool(); + + /** Get singleton instance */ + static apr_pool_t* get(); + + private: + apr_pool_t* pool; +}; + +}} + + + + + +#endif /*!_APRPool_*/ diff --git a/qpid/cpp-0-9/lib/common/sys/apr/APRSocket.cpp b/qpid/cpp-0-9/lib/common/sys/apr/APRSocket.cpp new file mode 100644 index 0000000000..96dbd132a1 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/APRSocket.cpp @@ -0,0 +1,78 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "APRBase.h" +#include "APRSocket.h" +#include <assert.h> +#include <iostream> + +using namespace qpid::sys; +using namespace qpid::framing; + +APRSocket::APRSocket(apr_socket_t* _socket) : socket(_socket), closed(false){ + +} + +void APRSocket::read(qpid::framing::Buffer& buffer){ + apr_size_t bytes; + bytes = buffer.available(); + apr_status_t s = apr_socket_recv(socket, buffer.start(), &bytes); + buffer.move(bytes); + if(APR_STATUS_IS_TIMEUP(s)){ + //timed out + }else if(APR_STATUS_IS_EOF(s)){ + close(); + } +} + +void APRSocket::write(qpid::framing::Buffer& buffer){ + apr_size_t bytes; + do{ + bytes = buffer.available(); + apr_socket_send(socket, buffer.start(), &bytes); + buffer.move(bytes); + }while(bytes > 0); +} + +void APRSocket::close(){ + if(!closed){ + std::cout << "Closing socket " << socket << "@" << this << std::endl; + CHECK_APR_SUCCESS(apr_socket_close(socket)); + closed = true; + } +} + +bool APRSocket::isOpen() const { + return !closed; +} + +uint8_t APRSocket::read(){ + char data[1]; + apr_size_t bytes = 1; + apr_status_t s = apr_socket_recv(socket, data, &bytes); + if(APR_STATUS_IS_EOF(s) || bytes == 0){ + return 0; + }else{ + return *data; + } +} + +APRSocket::~APRSocket(){ +} diff --git a/qpid/cpp-0-9/lib/common/sys/apr/APRSocket.h b/qpid/cpp-0-9/lib/common/sys/apr/APRSocket.h new file mode 100644 index 0000000000..a55dfc06b0 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/APRSocket.h @@ -0,0 +1,48 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _APRSocket_ +#define _APRSocket_ + +#include <apr_network_io.h> +#include <Buffer.h> + +namespace qpid { +namespace sys { + + class APRSocket + { + apr_socket_t* const socket; + volatile bool closed; + public: + APRSocket(apr_socket_t* socket); + void read(qpid::framing::Buffer& b); + void write(qpid::framing::Buffer& b); + void close(); + bool isOpen() const; + uint8_t read(); + ~APRSocket(); + }; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/sys/apr/LFProcessor.cpp b/qpid/cpp-0-9/lib/common/sys/apr/LFProcessor.cpp new file mode 100644 index 0000000000..2b6fc92623 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/LFProcessor.cpp @@ -0,0 +1,179 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <sstream> +#include <QpidError.h> +#include "LFProcessor.h" +#include "APRBase.h" +#include "LFSessionContext.h" + +using namespace qpid::sys; +using qpid::QpidError; + +// TODO aconway 2006-10-12: stopped is read outside locks. +// + +LFProcessor::LFProcessor(apr_pool_t* pool, int _workers, int _size, int _timeout) : + size(_size), + timeout(_timeout), + signalledCount(0), + current(0), + count(0), + workerCount(_workers), + hasLeader(false), + workers(new Thread[_workers]), + stopped(false) +{ + + CHECK_APR_SUCCESS(apr_pollset_create(&pollset, size, pool, APR_POLLSET_THREADSAFE)); +} + + +LFProcessor::~LFProcessor(){ + if (!stopped) stop(); + delete[] workers; + CHECK_APR_SUCCESS(apr_pollset_destroy(pollset)); +} + +void LFProcessor::start(){ + for(int i = 0; i < workerCount; i++){ + workers[i] = Thread(this); + } +} + +void LFProcessor::add(const apr_pollfd_t* const fd){ + CHECK_APR_SUCCESS(apr_pollset_add(pollset, fd)); + Monitor::ScopedLock l(countLock); + sessions.push_back(reinterpret_cast<LFSessionContext*>(fd->client_data)); + count++; +} + +void LFProcessor::remove(const apr_pollfd_t* const fd){ + CHECK_APR_SUCCESS(apr_pollset_remove(pollset, fd)); + Monitor::ScopedLock l(countLock); + sessions.erase(find(sessions.begin(), sessions.end(), reinterpret_cast<LFSessionContext*>(fd->client_data))); + count--; +} + +void LFProcessor::reactivate(const apr_pollfd_t* const fd){ + CHECK_APR_SUCCESS(apr_pollset_add(pollset, fd)); +} + +void LFProcessor::deactivate(const apr_pollfd_t* const fd){ + CHECK_APR_SUCCESS(apr_pollset_remove(pollset, fd)); +} + +void LFProcessor::update(const apr_pollfd_t* const fd){ + CHECK_APR_SUCCESS(apr_pollset_remove(pollset, fd)); + CHECK_APR_SUCCESS(apr_pollset_add(pollset, fd)); +} + +bool LFProcessor::full(){ + Mutex::ScopedLock locker(countLock); + return count == size; +} + +bool LFProcessor::empty(){ + Mutex::ScopedLock locker(countLock); + return count == 0; +} + +void LFProcessor::poll() { + apr_status_t status = APR_EGENERAL; + do{ + current = 0; + if(!stopped){ + status = apr_pollset_poll(pollset, timeout, &signalledCount, &signalledFDs); + } + }while(status != APR_SUCCESS && !stopped); +} + +void LFProcessor::run(){ + try{ + while(!stopped){ + const apr_pollfd_t* event = 0; + LFSessionContext* session = 0; + { + Monitor::ScopedLock l(leadLock); + waitToLead(); + event = getNextEvent(); + if(!event) return; + session = reinterpret_cast<LFSessionContext*>( + event->client_data); + session->startProcessing(); + relinquishLead(); + } + + //process event: + if(event->rtnevents & APR_POLLIN) session->read(); + if(event->rtnevents & APR_POLLOUT) session->write(); + + if(session->isClosed()){ + session->handleClose(); + Monitor::ScopedLock l(countLock); + sessions.erase(find(sessions.begin(),sessions.end(), session)); + count--; + }else{ + session->stopProcessing(); + } + } + }catch(std::exception e){ + std::cout << e.what() << std::endl; + } +} + +void LFProcessor::waitToLead(){ + while(hasLeader && !stopped) leadLock.wait(); + hasLeader = !stopped; +} + +void LFProcessor::relinquishLead(){ + hasLeader = false; + leadLock.notify(); +} + +const apr_pollfd_t* LFProcessor::getNextEvent(){ + while(true){ + if(stopped){ + return 0; + }else if(current < signalledCount){ + //use result of previous poll if one is available + return signalledFDs + (current++); + }else{ + //else poll to get new events + poll(); + } + } +} + +void LFProcessor::stop(){ + stopped = true; + { + Monitor::ScopedLock l(leadLock); + leadLock.notifyAll(); + } + for(int i = 0; i < workerCount; i++){ + workers[i].join(); + } + for(iterator i = sessions.begin(); i < sessions.end(); i++){ + (*i)->shutdown(); + } +} + diff --git a/qpid/cpp-0-9/lib/common/sys/apr/LFProcessor.h b/qpid/cpp-0-9/lib/common/sys/apr/LFProcessor.h new file mode 100644 index 0000000000..de90199472 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/LFProcessor.h @@ -0,0 +1,121 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _LFProcessor_ +#define _LFProcessor_ + +#include <apr_poll.h> +#include <iostream> +#include <vector> +#include <sys/Monitor.h> +#include <sys/Runnable.h> +#include <sys/Thread.h> + +namespace qpid { +namespace sys { + + class LFSessionContext; + + /** + * This class processes a poll set using the leaders-followers + * pattern for thread synchronization: the leader will poll and on + * the poll returning, it will remove a session, promote a + * follower to leadership, then process the session. + */ + class LFProcessor : private virtual qpid::sys::Runnable + { + typedef std::vector<LFSessionContext*>::iterator iterator; + + const int size; + const apr_interval_time_t timeout; + apr_pollset_t* pollset; + int signalledCount; + int current; + const apr_pollfd_t* signalledFDs; + int count; + const int workerCount; + bool hasLeader; + qpid::sys::Thread* workers; + qpid::sys::Monitor leadLock; + qpid::sys::Mutex countLock; + std::vector<LFSessionContext*> sessions; + volatile bool stopped; + + const apr_pollfd_t* getNextEvent(); + void waitToLead(); + void relinquishLead(); + void poll(); + virtual void run(); + + public: + LFProcessor(apr_pool_t* pool, int workers, int size, int timeout); + /** + * Add the fd to the poll set. Relies on the client_data being + * an instance of LFSessionContext. + */ + void add(const apr_pollfd_t* const fd); + /** + * Remove the fd from the poll set. + */ + void remove(const apr_pollfd_t* const fd); + /** + * Signal that the fd passed in, already part of the pollset, + * has had its flags altered. + */ + void update(const apr_pollfd_t* const fd); + /** + * Add an fd back to the poll set after deactivation. + */ + void reactivate(const apr_pollfd_t* const fd); + /** + * Temporarily remove the fd from the poll set. Called when processing + * is about to begin. + */ + void deactivate(const apr_pollfd_t* const fd); + /** + * Indicates whether the capacity of this processor has been + * reached (or whether it can still handle further fd's). + */ + bool full(); + /** + * Indicates whether there are any fd's registered. + */ + bool empty(); + /** + * Stop processing. + */ + void stop(); + /** + * Start processing. + */ + void start(); + /** + * Is processing stopped? + */ + bool isStopped(); + + ~LFProcessor(); + }; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/sys/apr/LFSessionContext.cpp b/qpid/cpp-0-9/lib/common/sys/apr/LFSessionContext.cpp new file mode 100644 index 0000000000..503dfddbb7 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/LFSessionContext.cpp @@ -0,0 +1,179 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "LFSessionContext.h" +#include "APRBase.h" +#include <QpidError.h> +#include <assert.h> + +using namespace qpid::sys; +using namespace qpid::sys; +using namespace qpid::framing; + +LFSessionContext::LFSessionContext(apr_pool_t* _pool, apr_socket_t* _socket, + LFProcessor* const _processor, + bool _debug) : + debug(_debug), + socket(_socket), + initiated(false), + in(65536), + out(65536), + processor(_processor), + processing(false), + closing(false) +{ + + fd.p = _pool; + fd.desc_type = APR_POLL_SOCKET; + fd.reqevents = APR_POLLIN; + fd.client_data = this; + fd.desc.s = _socket; + + out.flip(); +} + +LFSessionContext::~LFSessionContext(){ + +} + +void LFSessionContext::read(){ + socket.read(in); + in.flip(); + if(initiated){ + AMQFrame frame; + try{ + while(frame.decode(in)){ + if(debug) log("RECV", &frame); + handler->received(&frame); + } + }catch(QpidError error){ + std::cout << "Error [" << error.code << "] " << error.msg + << " (" << error.loc.file << ":" << error.loc.line + << ")" << std::endl; + } + }else{ + ProtocolInitiation protocolInit; + if(protocolInit.decode(in)){ + handler->initiated(&protocolInit); + initiated = true; + if(debug) std::cout << "INIT [" << &socket << "]" << std::endl; + } + } + in.compact(); +} + +void LFSessionContext::write(){ + bool done = isClosed(); + while(!done){ + if(out.available() > 0){ + socket.write(out); + if(out.available() > 0){ + + //incomplete write, leave flags to receive notification of readiness to write + done = true;//finished processing for now, but write is still in progress + } + }else{ + //do we have any frames to write? + Mutex::ScopedLock l(writeLock); + if(!framesToWrite.empty()){ + out.clear(); + bool encoded(false); + AMQFrame* frame = framesToWrite.front(); + while(frame && out.available() >= frame->size()){ + encoded = true; + frame->encode(out); + if(debug) log("SENT", frame); + delete frame; + framesToWrite.pop(); + frame = framesToWrite.empty() ? 0 : framesToWrite.front(); + } + if(!encoded) THROW_QPID_ERROR(FRAMING_ERROR, "Could not write frame, too large for buffer."); + out.flip(); + }else{ + //reset flags, don't care about writability anymore + fd.reqevents = APR_POLLIN; + done = true; + + if(closing){ + socket.close(); + } + } + } + } +} + +void LFSessionContext::send(AMQFrame* frame){ + Mutex::ScopedLock l(writeLock); + if(!closing){ + framesToWrite.push(frame); + if(!(fd.reqevents & APR_POLLOUT)){ + fd.reqevents |= APR_POLLOUT; + if(!processing){ + processor->update(&fd); + } + } + } +} + +void LFSessionContext::startProcessing(){ + Mutex::ScopedLock l(writeLock); + processing = true; + processor->deactivate(&fd); +} + +void LFSessionContext::stopProcessing(){ + Mutex::ScopedLock l(writeLock); + processor->reactivate(&fd); + processing = false; +} + +void LFSessionContext::close(){ + Mutex::ScopedLock l(writeLock); + closing = true; + if(!processing){ + //allow pending frames to be written to socket + fd.reqevents = APR_POLLOUT; + processor->update(&fd); + } +} + +void LFSessionContext::handleClose(){ + handler->closed(); + std::cout << "Session closed [" << &socket << "]" << std::endl; + delete handler; + delete this; +} + +void LFSessionContext::shutdown(){ + socket.close(); + handleClose(); +} + +void LFSessionContext::init(ConnectionInputHandler* _handler){ + handler = _handler; + processor->add(&fd); +} + +void LFSessionContext::log(const std::string& desc, AMQFrame* const frame){ + Mutex::ScopedLock l(logLock); + std::cout << desc << " [" << &socket << "]: " << *frame << std::endl; +} + +Mutex LFSessionContext::logLock; diff --git a/qpid/cpp-0-9/lib/common/sys/apr/LFSessionContext.h b/qpid/cpp-0-9/lib/common/sys/apr/LFSessionContext.h new file mode 100644 index 0000000000..81cfc0efda --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/LFSessionContext.h @@ -0,0 +1,90 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _LFSessionContext_ +#define _LFSessionContext_ + +#include <queue> + +#include <apr_network_io.h> +#include <apr_poll.h> +#include <apr_time.h> + +#include <AMQFrame.h> +#include <Buffer.h> +#include <sys/Monitor.h> +#include <sys/ConnectionOutputHandler.h> +#include <sys/ConnectionInputHandler.h> + +#include "APRSocket.h" +#include "LFProcessor.h" + +namespace qpid { +namespace sys { + + +class LFSessionContext : public virtual qpid::sys::ConnectionOutputHandler +{ + const bool debug; + APRSocket socket; + bool initiated; + + qpid::framing::Buffer in; + qpid::framing::Buffer out; + + qpid::sys::ConnectionInputHandler* handler; + LFProcessor* const processor; + + apr_pollfd_t fd; + + std::queue<qpid::framing::AMQFrame*> framesToWrite; + qpid::sys::Mutex writeLock; + + bool processing; + bool closing; + + static qpid::sys::Mutex logLock; + void log(const std::string& desc, + qpid::framing::AMQFrame* const frame); + + + public: + LFSessionContext(apr_pool_t* pool, apr_socket_t* socket, + LFProcessor* const processor, + bool debug = false); + virtual ~LFSessionContext(); + virtual void send(qpid::framing::AMQFrame* frame); + virtual void close(); + void read(); + void write(); + void init(qpid::sys::ConnectionInputHandler* handler); + void startProcessing(); + void stopProcessing(); + void handleClose(); + void shutdown(); + inline apr_pollfd_t* const getFd(){ return &fd; } + inline bool isClosed(){ return !socket.isOpen(); } +}; + +} +} + + +#endif diff --git a/qpid/cpp-0-9/lib/common/sys/apr/Socket.cpp b/qpid/cpp-0-9/lib/common/sys/apr/Socket.cpp new file mode 100644 index 0000000000..bca4da6c96 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/Socket.cpp @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + + +#include <sys/Socket.h> +#include <apr/APRBase.h> +#include <apr/APRPool.h> + + +using namespace qpid::sys; + +Socket Socket::createTcp() { + Socket s; + CHECK_APR_SUCCESS( + apr_socket_create( + &s.socket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, + APRPool::get())); + return s; +} + +Socket::Socket(apr_socket_t* s) { + socket = s; +} + +void Socket::setTimeout(Time interval) { + apr_socket_timeout_set(socket, interval/TIME_USEC); +} + +void Socket::connect(const std::string& host, int port) { + apr_sockaddr_t* address; + CHECK_APR_SUCCESS( + apr_sockaddr_info_get( + &address, host.c_str(), APR_UNSPEC, port, APR_IPV4_ADDR_OK, + APRPool::get())); + CHECK_APR_SUCCESS(apr_socket_connect(socket, address)); +} + +void Socket::close() { + if (socket == 0) return; + CHECK_APR_SUCCESS(apr_socket_close(socket)); + socket = 0; +} + +ssize_t Socket::send(const void* data, size_t size) +{ + apr_size_t sent = size; + apr_status_t status = + apr_socket_send(socket, reinterpret_cast<const char*>(data), &sent); + if (APR_STATUS_IS_TIMEUP(status)) return SOCKET_TIMEOUT; + if (APR_STATUS_IS_EOF(status)) return SOCKET_EOF; + CHECK_APR_SUCCESS(status); + return sent; +} + +ssize_t Socket::recv(void* data, size_t size) +{ + apr_size_t received = size; + apr_status_t status = + apr_socket_recv(socket, reinterpret_cast<char*>(data), &received); + if (APR_STATUS_IS_TIMEUP(status)) + return SOCKET_TIMEOUT; + if (APR_STATUS_IS_EOF(status)) + return SOCKET_EOF; + CHECK_APR_SUCCESS(status); + return received; +} + + diff --git a/qpid/cpp-0-9/lib/common/sys/apr/Thread.cpp b/qpid/cpp-0-9/lib/common/sys/apr/Thread.cpp new file mode 100644 index 0000000000..5c4799aa96 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/apr/Thread.cpp @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <sys/Thread.h> + +using namespace qpid::sys; +using qpid::sys::Runnable; + +void* APR_THREAD_FUNC Thread::runRunnable(apr_thread_t* thread, void *data) { + reinterpret_cast<Runnable*>(data)->run(); + CHECK_APR_SUCCESS(apr_thread_exit(thread, APR_SUCCESS)); + return NULL; +} + + diff --git a/qpid/cpp-0-9/lib/common/sys/posix/EventChannel.cpp b/qpid/cpp-0-9/lib/common/sys/posix/EventChannel.cpp new file mode 100644 index 0000000000..16c7ec9c3f --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/posix/EventChannel.cpp @@ -0,0 +1,325 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <mqueue.h> +#include <string.h> +#include <iostream> + +#include <sys/errno.h> +#include <sys/socket.h> +#include <sys/epoll.h> + +#include <typeinfo> +#include <iostream> +#include <queue> + +#include <boost/ptr_container/ptr_map.hpp> +#include <boost/current_function.hpp> + +#include <QpidError.h> +#include <sys/Monitor.h> + +#include "check.h" +#include "EventChannel.h" + +using namespace std; + + +// Convenience template to zero out a struct. +template <class S> struct ZeroStruct : public S { + ZeroStruct() { memset(this, 0, sizeof(*this)); } +}; + +namespace qpid { +namespace sys { + + +/** + * EventHandler wraps an epoll file descriptor. Acts as private + * interface between EventChannel and subclasses. + * + * Also implements Event interface for events that are not associated + * with a file descriptor and are passed via the message queue. + */ +class EventHandler : public Event, private Monitor +{ + public: + EventHandler(int epollSize = 256); + ~EventHandler(); + + int getEpollFd() { return epollFd; } + void epollAdd(int fd, uint32_t epollEvents, Event* event); + void epollMod(int fd, uint32_t epollEvents, Event* event); + void epollDel(int fd); + + void mqPut(Event* event); + Event* mqGet(); + + protected: + // Should never be called, only complete. + void prepare(EventHandler&) { assert(0); } + Event* complete(EventHandler& eh); + + private: + int epollFd; + std::string mqName; + int mqFd; + std::queue<Event*> mqEvents; +}; + +EventHandler::EventHandler(int epollSize) +{ + epollFd = epoll_create(epollSize); + if (epollFd < 0) throw QPID_POSIX_ERROR(errno); + + // Create a POSIX message queue for non-fd events. + // We write one byte and never read it is always ready for read + // when we add it to epoll. + // + ZeroStruct<struct mq_attr> attr; + attr.mq_maxmsg = 1; + attr.mq_msgsize = 1; + do { + char tmpnam[L_tmpnam]; + tmpnam_r(tmpnam); + mqName = tmpnam + 4; // Skip "tmp/" + mqFd = mq_open( + mqName.c_str(), O_CREAT|O_EXCL|O_RDWR|O_NONBLOCK, S_IRWXU, &attr); + if (mqFd < 0) throw QPID_POSIX_ERROR(errno); + } while (mqFd == EEXIST); // Name already taken, try again. + + static char zero = '\0'; + mq_send(mqFd, &zero, 1, 0); + epollAdd(mqFd, 0, this); +} + +EventHandler::~EventHandler() { + mq_close(mqFd); + mq_unlink(mqName.c_str()); +} + +void EventHandler::mqPut(Event* event) { + ScopedLock l(*this); + assert(event != 0); + mqEvents.push(event); + epollMod(mqFd, EPOLLIN|EPOLLONESHOT, this); +} + +Event* EventHandler::mqGet() { + ScopedLock l(*this); + if (mqEvents.empty()) + return 0; + Event* event = mqEvents.front(); + mqEvents.pop(); + if(!mqEvents.empty()) + epollMod(mqFd, EPOLLIN|EPOLLONESHOT, this); + return event; +} + +void EventHandler::epollAdd(int fd, uint32_t epollEvents, Event* event) +{ + ZeroStruct<struct epoll_event> ee; + ee.data.ptr = event; + ee.events = epollEvents; + if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &ee) < 0) + throw QPID_POSIX_ERROR(errno); +} + +void EventHandler::epollMod(int fd, uint32_t epollEvents, Event* event) +{ + ZeroStruct<struct epoll_event> ee; + ee.data.ptr = event; + ee.events = epollEvents; + if (epoll_ctl(epollFd, EPOLL_CTL_MOD, fd, &ee) < 0) + throw QPID_POSIX_ERROR(errno); +} + +void EventHandler::epollDel(int fd) { + if (epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, 0) < 0) + throw QPID_POSIX_ERROR(errno); +} + +Event* EventHandler::complete(EventHandler& eh) +{ + assert(&eh == this); + Event* event = mqGet(); + return event==0 ? 0 : event->complete(eh); +} + +// ================================================================ +// EventChannel + +EventChannel::shared_ptr EventChannel::create() { + return shared_ptr(new EventChannel()); +} + +EventChannel::EventChannel() : handler(new EventHandler()) {} + +EventChannel::~EventChannel() {} + +void EventChannel::postEvent(Event& e) +{ + e.prepare(*handler); +} + +Event* EventChannel::getEvent() +{ + static const int infiniteTimeout = -1; + ZeroStruct<struct epoll_event> epollEvent; + + // Loop until we can complete the event. Some events may re-post + // themselves and return 0 from complete, e.g. partial reads. // + Event* event = 0; + while (event == 0) { + int eventCount = epoll_wait(handler->getEpollFd(), + &epollEvent, 1, infiniteTimeout); + if (eventCount < 0) { + if (errno != EINTR) { + // TODO aconway 2006-11-28: Proper handling/logging of errors. + cerr << BOOST_CURRENT_FUNCTION << " ignoring error " + << PosixError::getMessage(errno) << endl; + assert(0); + } + } + else if (eventCount == 1) { + event = reinterpret_cast<Event*>(epollEvent.data.ptr); + assert(event != 0); + try { + event = event->complete(*handler); + } + catch (const Exception& e) { + if (event) + event->setError(e); + } + catch (const std::exception& e) { + if (event) + event->setError(e); + } + } + } + return event; +} + +Event::~Event() {} + +void Event::prepare(EventHandler& handler) +{ + handler.mqPut(this); +} + +bool Event::hasError() const { + return error; +} + +void Event::throwIfError() throw (Exception) { + if (hasError()) + error.throwSelf(); +} + +Event* Event::complete(EventHandler&) +{ + return this; +} + +void Event::dispatch() +{ + try { + if (!callback.empty()) + callback(); + } catch (const std::exception&) { + throw; + } catch (...) { + throw QPID_ERROR(INTERNAL_ERROR, "Unknown exception."); + } +} + +void Event::setError(const ExceptionHolder& e) { + error = e; +} + +void ReadEvent::prepare(EventHandler& handler) +{ + handler.epollAdd(descriptor, EPOLLIN | EPOLLONESHOT, this); +} + +ssize_t ReadEvent::doRead() { + ssize_t n = ::read(descriptor, static_cast<char*>(buffer) + received, + size - received); + if (n > 0) received += n; + return n; +} + +Event* ReadEvent::complete(EventHandler& handler) +{ + // Read as much as possible without blocking. + ssize_t n = doRead(); + while (n > 0 && received < size) doRead(); + + if (received == size) { + handler.epollDel(descriptor); + received = 0; // Reset for re-use. + return this; + } + else if (n <0 && (errno == EAGAIN)) { + // Keep polling for more. + handler.epollMod(descriptor, EPOLLIN | EPOLLONESHOT, this); + return 0; + } + else { + // Unexpected EOF or error. Throw ENODATA for EOF. + handler.epollDel(descriptor); + received = 0; // Reset for re-use. + throw QPID_POSIX_ERROR((n < 0) ? errno : ENODATA); + } +} + +void WriteEvent::prepare(EventHandler& handler) +{ + handler.epollAdd(descriptor, EPOLLOUT | EPOLLONESHOT, this); +} + +Event* WriteEvent::complete(EventHandler& handler) +{ + ssize_t n = write(descriptor, static_cast<const char*>(buffer) + written, + size - written); + if (n < 0) throw QPID_POSIX_ERROR(errno); + written += n; + if(written < size) { + // Keep polling. + handler.epollMod(descriptor, EPOLLOUT | EPOLLONESHOT, this); + return 0; + } + written = 0; // Reset for re-use. + handler.epollDel(descriptor); + return this; +} + +void AcceptEvent::prepare(EventHandler& handler) +{ + handler.epollAdd(descriptor, EPOLLIN | EPOLLONESHOT, this); +} + +Event* AcceptEvent::complete(EventHandler& handler) +{ + handler.epollDel(descriptor); + accepted = ::accept(descriptor, 0, 0); + if (accepted < 0) throw QPID_POSIX_ERROR(errno); + return this; +} + +}} diff --git a/qpid/cpp-0-9/lib/common/sys/posix/EventChannel.h b/qpid/cpp-0-9/lib/common/sys/posix/EventChannel.h new file mode 100644 index 0000000000..49c7fce740 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/posix/EventChannel.h @@ -0,0 +1,176 @@ +#ifndef _sys_EventChannel_h +#define _sys_EventChannel_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <SharedObject.h> +#include <ExceptionHolder.h> +#include <boost/function.hpp> +#include <memory> + +namespace qpid { +namespace sys { + +class Event; +class EventHandler; +class EventChannel; + +/** + * Base class for all Events. + */ +class Event +{ + public: + /** Type for callback when event is dispatched */ + typedef boost::function0<void> Callback; + + /** + * Create an event with optional callback. + * Instances of Event are sent directly through the channel. + * Derived classes define additional waiting behaviour. + *@param cb A callback functor that is invoked when dispatch() is called. + */ + Event(Callback cb = 0) : callback(cb) {} + + virtual ~Event(); + + /** Call the callback provided to the constructor, if any. */ + void dispatch(); + + /** True if there was an error processing this event */ + bool hasError() const; + + /** If hasError() throw the corresponding exception. */ + void throwIfError() throw(Exception); + + protected: + virtual void prepare(EventHandler&); + virtual Event* complete(EventHandler&); + void setError(const ExceptionHolder& e); + + Callback callback; + ExceptionHolder error; + + friend class EventChannel; + friend class EventHandler; +}; + +template <class BufT> +class IOEvent : public Event { + public: + void getDescriptor() const { return descriptor; } + size_t getSize() const { return size; } + BufT getBuffer() const { return buffer; } + + protected: + IOEvent(int fd, Callback cb, size_t sz, BufT buf) : + Event(cb), descriptor(fd), buffer(buf), size(sz) {} + + int descriptor; + BufT buffer; + size_t size; +}; + +/** Asynchronous read event */ +class ReadEvent : public IOEvent<void*> +{ + public: + explicit ReadEvent(int fd=-1, void* buf=0, size_t sz=0, Callback cb=0) : + IOEvent<void*>(fd, cb, sz, buf), received(0) {} + + private: + void prepare(EventHandler&); + Event* complete(EventHandler&); + ssize_t doRead(); + + size_t received; +}; + +/** Asynchronous write event */ +class WriteEvent : public IOEvent<const void*> +{ + public: + explicit WriteEvent(int fd=-1, const void* buf=0, size_t sz=0, + Callback cb=0) : + IOEvent<const void*>(fd, cb, sz, buf), written(0) {} + + protected: + void prepare(EventHandler&); + Event* complete(EventHandler&); + + private: + ssize_t doWrite(); + size_t written; +}; + +/** Asynchronous socket accept event */ +class AcceptEvent : public Event +{ + public: + /** Accept a connection on fd. */ + explicit AcceptEvent(int fd=-1, Callback cb=0) : + Event(cb), descriptor(fd), accepted(0) {} + + /** Get descriptor for server socket */ + int getAcceptedDesscriptor() const { return accepted; } + + private: + void prepare(EventHandler&); + Event* complete(EventHandler&); + + int descriptor; + int accepted; +}; + + +class QueueSet; + +/** + * Channel to post and wait for events. + */ +class EventChannel : public qpid::SharedObject<EventChannel> +{ + public: + static shared_ptr create(); + + ~EventChannel(); + + /** Post an event to the channel. */ + void postEvent(Event& event); + + /** Post an event to the channel. Must not be 0. */ + void postEvent(Event* event) { postEvent(*event); } + + /** + * Wait for the next complete event. + *@return Pointer to event. Will never return 0. + */ + Event* getEvent(); + + private: + EventChannel(); + boost::shared_ptr<EventHandler> handler; +}; + + +}} + + + +#endif /*!_sys_EventChannel_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/posix/EventChannelAcceptor.cpp b/qpid/cpp-0-9/lib/common/sys/posix/EventChannelAcceptor.cpp new file mode 100644 index 0000000000..548fbd1881 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/posix/EventChannelAcceptor.cpp @@ -0,0 +1,149 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> + +#include <boost/assert.hpp> +#include <boost/ptr_container/ptr_vector.hpp> +#include <boost/ptr_container/ptr_deque.hpp> +#include <boost/bind.hpp> +#include <boost/scoped_ptr.hpp> + +#include <sys/ConnectionOutputHandler.h> +#include <sys/ConnectionInputHandler.h> +#include <sys/ConnectionInputHandlerFactory.h> +#include <sys/Acceptor.h> +#include <sys/Socket.h> +#include <framing/Buffer.h> +#include <framing/AMQFrame.h> +#include <Exception.h> + +#include "EventChannelConnection.h" + +namespace qpid { +namespace sys { + +using namespace qpid::framing; +using namespace std; + +class EventChannelAcceptor : public Acceptor { + public: + + + EventChannelAcceptor( + int16_t port_, int backlog, int nThreads, bool trace_ + ); + + int getPort() const; + + void run(ConnectionInputHandlerFactory& factory); + + void shutdown(); + + private: + + void accept(); + + Mutex lock; + Socket listener; + const int port; + const bool isTrace; + bool isRunning; + boost::ptr_vector<EventChannelConnection> connections; + AcceptEvent acceptEvent; + ConnectionInputHandlerFactory* factory; + bool isShutdown; + EventChannelThreads::shared_ptr threads; +}; + +Acceptor::shared_ptr Acceptor::create( + int16_t port, int backlog, int threads, bool trace) +{ + return Acceptor::shared_ptr( + new EventChannelAcceptor(port, backlog, threads, trace)); +} + +// Must define Acceptor virtual dtor. +Acceptor::~Acceptor() {} + +EventChannelAcceptor::EventChannelAcceptor( + int16_t port_, int backlog, int nThreads, bool trace_ +) : listener(Socket::createTcp()), + port(listener.listen(int(port_), backlog)), + isTrace(trace_), + isRunning(false), + acceptEvent(listener.fd(), + boost::bind(&EventChannelAcceptor::accept, this)), + factory(0), + isShutdown(false), + threads(EventChannelThreads::create(EventChannel::create(), nThreads)) +{ } + +int EventChannelAcceptor::getPort() const { + return port; // Immutable no need for lock. +} + +void EventChannelAcceptor::run(ConnectionInputHandlerFactory& f) { + { + Mutex::ScopedLock l(lock); + if (!isRunning && !isShutdown) { + isRunning = true; + factory = &f; + threads->post(acceptEvent); + } + } + threads->join(); // Wait for shutdown. +} + +void EventChannelAcceptor::shutdown() { + bool doShutdown = false; + { + Mutex::ScopedLock l(lock); + doShutdown = !isShutdown; // I'm the shutdown thread. + isShutdown = true; + } + if (doShutdown) { + ::close(acceptEvent.getDescriptor()); + threads->shutdown(); + for_each(connections.begin(), connections.end(), + boost::bind(&EventChannelConnection::close, _1)); + } + threads->join(); +} + +void EventChannelAcceptor::accept() +{ + // No lock, we only post one accept event at a time. + if (isShutdown) + return; + if (acceptEvent.getException()) { + Exception::log(*acceptEvent.getException(), + "EventChannelAcceptor::accept"); + shutdown(); + return; + } + // TODO aconway 2006-11-29: Need to reap closed connections also. + int fd = acceptEvent.getAcceptedDesscriptor(); + connections.push_back( + new EventChannelConnection(threads, *factory, fd, fd, isTrace)); + threads->post(acceptEvent); // Keep accepting. +} + +}} // namespace qpid::sys diff --git a/qpid/cpp-0-9/lib/common/sys/posix/EventChannelConnection.cpp b/qpid/cpp-0-9/lib/common/sys/posix/EventChannelConnection.cpp new file mode 100644 index 0000000000..4449dc3035 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/posix/EventChannelConnection.cpp @@ -0,0 +1,229 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <iostream> + +#include <boost/bind.hpp> +#include <boost/assert.hpp> + +#include "EventChannelConnection.h" +#include "sys/ConnectionInputHandlerFactory.h" +#include "QpidError.h" + +using namespace std; +using namespace qpid; +using namespace qpid::framing; + +namespace qpid { +namespace sys { + +const size_t EventChannelConnection::bufferSize = 65536; + +EventChannelConnection::EventChannelConnection( + EventChannelThreads::shared_ptr threads_, + ConnectionInputHandlerFactory& factory_, + int rfd, + int wfd, + bool isTrace_ +) : + readFd(rfd), + writeFd(wfd ? wfd : rfd), + readCallback(boost::bind(&EventChannelConnection::closeOnException, + this, &EventChannelConnection::endInitRead)), + + isWriting(false), + isClosed(false), + threads(threads_), + handler(factory_.create(this)), + in(bufferSize), + out(bufferSize), + isTrace(isTrace_) +{ + BOOST_ASSERT(readFd > 0); + BOOST_ASSERT(writeFd > 0); + closeOnException(&EventChannelConnection::startRead); +} + + +void EventChannelConnection::send(std::auto_ptr<AMQFrame> frame) { + { + Monitor::ScopedLock lock(monitor); + assert(frame.get()); + writeFrames.push_back(frame.release()); + } + closeOnException(&EventChannelConnection::startWrite); +} + +void EventChannelConnection::close() { + { + Monitor::ScopedLock lock(monitor); + if (isClosed) + return; + isClosed = true; + } + ::close(readFd); + ::close(writeFd); + { + Monitor::ScopedLock lock(monitor); + while (busyThreads > 0) + monitor.wait(); + } + handler->closed(); +} + +void EventChannelConnection::closeNoThrow() { + Exception::tryCatchLog<void>( + boost::bind(&EventChannelConnection::close, this), + false, + "Exception closing channel" + ); +} + +/** + * Call f in a try/catch block and close the connection if + * an exception is thrown. + */ +void EventChannelConnection::closeOnException(MemberFnPtr f) +{ + try { + Exception::tryCatchLog<void>( + boost::bind(f, this), + "Closing connection due to exception" + ); + return; + } catch (...) { + // Exception was already logged by tryCatchLog + closeNoThrow(); + } +} + +// Post the write event. +// Always called inside closeOnException. +// Called by endWrite and send, but only one thread writes at a time. +// +void EventChannelConnection::startWrite() { + FrameQueue::auto_type frame; + { + Monitor::ScopedLock lock(monitor); + // Stop if closed or a write event is already in progress. + if (isClosed || isWriting) + return; + if (writeFrames.empty()) { + isWriting = false; + return; + } + isWriting = true; + frame = writeFrames.pop_front(); + } + // No need to lock here - only one thread can be writing at a time. + out.clear(); + if (isTrace) + cout << "Send on socket " << writeFd << ": " << *frame << endl; + frame->encode(out); + out.flip(); + writeEvent = WriteEvent( + writeFd, out.start(), out.available(), + boost::bind(&EventChannelConnection::closeOnException, + this, &EventChannelConnection::endWrite)); + threads->post(writeEvent); +} + +// ScopedBusy ctor increments busyThreads. +// dtor decrements and calls monitor.notifyAll if it reaches 0. +// +struct EventChannelConnection::ScopedBusy : public AtomicCount::ScopedIncrement +{ + ScopedBusy(EventChannelConnection& ecc) + : AtomicCount::ScopedIncrement( + ecc.busyThreads, boost::bind(&Monitor::notifyAll, &ecc.monitor)) + {} +}; + +// Write event completed. +// Always called by a channel thread inside closeOnException. +// +void EventChannelConnection::endWrite() { + ScopedBusy(*this); + { + Monitor::ScopedLock lock(monitor); + isWriting = false; + if (isClosed) + return; + writeEvent.throwIfException(); + } + // Check if there's more in to write in the write queue. + startWrite(); +} + + +// Post the read event. +// Always called inside closeOnException. +// Called from ctor and end[Init]Read, so only one call at a time +// is possible since we only post one read event at a time. +// +void EventChannelConnection::startRead() { + // Non blocking read, as much as we can swallow. + readEvent = ReadEvent( + readFd, in.start(), in.available(), readCallback,true); + threads->post(readEvent); +} + +// Completion of initial read, expect protocolInit. +// Always called inside closeOnException in channel thread. +// Only called by one thread at a time. +void EventChannelConnection::endInitRead() { + ScopedBusy(*this); + if (!isClosed) { + readEvent.throwIfException(); + in.move(readEvent.getBytesRead()); + in.flip(); + ProtocolInitiation protocolInit; + if(protocolInit.decode(in)){ + handler->initiated(&protocolInit); + readCallback = boost::bind( + &EventChannelConnection::closeOnException, + this, &EventChannelConnection::endRead); + } + in.compact(); + // Continue reading. + startRead(); + } +} + +// Normal reads, expect a frame. +// Always called inside closeOnException in channel thread. +void EventChannelConnection::endRead() { + ScopedBusy(*this); + if (!isClosed) { + readEvent.throwIfException(); + in.move(readEvent.getBytesRead()); + in.flip(); + AMQFrame frame; + while (frame.decode(in)) { + // TODO aconway 2006-11-30: received should take Frame& + if (isTrace) + cout << "Received on socket " << readFd + << ": " << frame << endl; + handler->received(&frame); + } + in.compact(); + startRead(); + } +} + +}} // namespace qpid::sys diff --git a/qpid/cpp-0-9/lib/common/sys/posix/EventChannelConnection.h b/qpid/cpp-0-9/lib/common/sys/posix/EventChannelConnection.h new file mode 100644 index 0000000000..da7b6dca27 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/posix/EventChannelConnection.h @@ -0,0 +1,102 @@ +#ifndef _posix_EventChannelConnection_h +#define _posix_EventChannelConnection_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <boost/ptr_container/ptr_deque.hpp> + +#include "EventChannelThreads.h" +#include "sys/Monitor.h" +#include "sys/ConnectionOutputHandler.h" +#include "sys/ConnectionInputHandler.h" +#include "sys/AtomicCount.h" +#include "framing/AMQFrame.h" + +namespace qpid { +namespace sys { + +class ConnectionInputHandlerFactory; + +/** + * Implements ConnectionOutputHandler and delegates to a ConnectionInputHandler + * for a connection via the EventChannel. + *@param readDescriptor file descriptor for reading. + *@param writeDescriptor file descriptor for writing, + * by default same as readDescriptor + */ +class EventChannelConnection : public ConnectionOutputHandler { + public: + EventChannelConnection( + EventChannelThreads::shared_ptr threads, + ConnectionInputHandlerFactory& factory, + int readDescriptor, + int writeDescriptor = 0, + bool isTrace = false + ); + + // TODO aconway 2006-11-30: ConnectionOutputHandler::send should take auto_ptr + virtual void send(qpid::framing::AMQFrame* frame) { + send(std::auto_ptr<qpid::framing::AMQFrame>(frame)); + } + + virtual void send(std::auto_ptr<qpid::framing::AMQFrame> frame); + + virtual void close(); + + private: + typedef boost::ptr_deque<qpid::framing::AMQFrame> FrameQueue; + typedef void (EventChannelConnection::*MemberFnPtr)(); + struct ScopedBusy; + + void startWrite(); + void endWrite(); + void startRead(); + void endInitRead(); + void endRead(); + void closeNoThrow(); + void closeOnException(MemberFnPtr); + bool shouldContinue(bool& flag); + + static const size_t bufferSize; + + Monitor monitor; + + int readFd, writeFd; + ReadEvent readEvent; + WriteEvent writeEvent; + Event::Callback readCallback; + bool isWriting; + bool isClosed; + AtomicCount busyThreads; + + EventChannelThreads::shared_ptr threads; + std::auto_ptr<ConnectionInputHandler> handler; + qpid::framing::Buffer in, out; + FrameQueue writeFrames; + bool isTrace; + + friend struct ScopedBusy; +}; + + +}} // namespace qpid::sys + + + +#endif /*!_posix_EventChannelConnection_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/posix/EventChannelThreads.cpp b/qpid/cpp-0-9/lib/common/sys/posix/EventChannelThreads.cpp new file mode 100644 index 0000000000..95e699e0b0 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/posix/EventChannelThreads.cpp @@ -0,0 +1,119 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "EventChannelThreads.h" +#include <sys/Runnable.h> +#include <iostream> +using namespace std; +#include <boost/bind.hpp> + +namespace qpid { +namespace sys { + +EventChannelThreads::shared_ptr EventChannelThreads::create( + EventChannel::shared_ptr ec) +{ + return EventChannelThreads::shared_ptr(new EventChannelThreads(ec)); +} + +EventChannelThreads::EventChannelThreads(EventChannel::shared_ptr ec) : + channel(ec), nWaiting(0), state(RUNNING) +{ + // TODO aconway 2006-11-15: Estimate initial threads based on CPUs. + addThread(); +} + +EventChannelThreads::~EventChannelThreads() { + shutdown(); + join(); +} + +void EventChannelThreads::shutdown() +{ + ScopedLock lock(*this); + if (state != RUNNING) // Already shutting down. + return; + for (size_t i = 0; i < workers.size(); ++i) { + channel->postEvent(terminate); + } + state = TERMINATE_SENT; + notify(); // Wake up one join() thread. +} + +void EventChannelThreads::join() +{ + { + ScopedLock lock(*this); + while (state == RUNNING) // Wait for shutdown to start. + wait(); + if (state == SHUTDOWN) // Shutdown is complete + return; + if (state == JOINING) { + // Someone else is doing the join. + while (state != SHUTDOWN) + wait(); + return; + } + // I'm the joining thread + assert(state == TERMINATE_SENT); + state = JOINING; + } // Drop the lock. + + for (size_t i = 0; i < workers.size(); ++i) { + assert(state == JOINING); // Only this thread can change JOINING. + workers[i].join(); + } + state = SHUTDOWN; + notifyAll(); // Notify other join() threaeds. +} + +void EventChannelThreads::addThread() { + ScopedLock l(*this); + workers.push_back(Thread(*this)); +} + +void EventChannelThreads::run() +{ + // Start life waiting. Decrement on exit. + AtomicCount::ScopedIncrement inc(nWaiting); + try { + while (true) { + Event* e = channel->getEvent(); + assert(e != 0); + if (e == &terminate) { + return; + } + AtomicCount::ScopedDecrement dec(nWaiting); + // I'm no longer waiting, make sure someone is. + if (dec == 0) + addThread(); + e->dispatch(); + } + } + catch (const std::exception& e) { + // TODO aconway 2006-11-15: need better logging across the board. + std::cerr << "EventChannelThreads::run() caught: " << e.what() + << std::endl; + } + catch (...) { + std::cerr << "EventChannelThreads::run() caught unknown exception." + << std::endl; + } +} + +}} diff --git a/qpid/cpp-0-9/lib/common/sys/posix/EventChannelThreads.h b/qpid/cpp-0-9/lib/common/sys/posix/EventChannelThreads.h new file mode 100644 index 0000000000..98403c0869 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/posix/EventChannelThreads.h @@ -0,0 +1,92 @@ +#ifndef _posix_EventChannelThreads_h +#define _sys_EventChannelThreads_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include <vector> + +#include <Exception.h> +#include <sys/Time.h> +#include <sys/Monitor.h> +#include <sys/Thread.h> +#include <sys/AtomicCount.h> +#include "EventChannel.h" + +namespace qpid { +namespace sys { + +/** + Dynamic thread pool serving an EventChannel. + + Threads run a loop { e = getEvent(); e->dispatch(); } + The size of the thread pool is automatically adjusted to optimal size. +*/ +class EventChannelThreads : + public qpid::SharedObject<EventChannelThreads>, + public sys::Monitor, private sys::Runnable +{ + public: + /** Create the thread pool and start initial threads. */ + static EventChannelThreads::shared_ptr create( + EventChannel::shared_ptr channel + ); + + ~EventChannelThreads(); + + /** Post event to the underlying channel */ + void postEvent(Event& event) { channel->postEvent(event); } + + /** Post event to the underlying channel Must not be 0. */ + void postEvent(Event* event) { channel->postEvent(event); } + + /** + * Terminate all threads. + * + * Returns immediately, use join() to wait till all threads are + * shut down. + */ + void shutdown(); + + /** Wait for all threads to terminate. */ + void join(); + + private: + typedef std::vector<sys::Thread> Threads; + typedef enum { + RUNNING, TERMINATE_SENT, JOINING, SHUTDOWN + } State; + + EventChannelThreads(EventChannel::shared_ptr underlyingChannel); + void addThread(); + + void run(); + bool keepRunning(); + void adjustThreads(); + + EventChannel::shared_ptr channel; + Threads workers; + sys::AtomicCount nWaiting; + State state; + Event terminate; +}; + + +}} + + +#endif /*!_sys_EventChannelThreads_h*/ diff --git a/qpid/cpp-0-9/lib/common/sys/posix/PosixAcceptor.cpp b/qpid/cpp-0-9/lib/common/sys/posix/PosixAcceptor.cpp new file mode 100644 index 0000000000..a80a6c61f7 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/posix/PosixAcceptor.cpp @@ -0,0 +1,48 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <sys/Acceptor.h> +#include <Exception.h> + +namespace qpid { +namespace sys { + +namespace { +void fail() { throw qpid::Exception("PosixAcceptor not implemented"); } +} + +class PosixAcceptor : public Acceptor { + public: + virtual int16_t getPort() const { fail(); return 0; } + virtual void run(qpid::sys::ConnectionInputHandlerFactory* ) { fail(); } + virtual void shutdown() { fail(); } +}; + +// Define generic Acceptor::create() to return APRAcceptor. + Acceptor::shared_ptr Acceptor::create(int16_t , int, int, bool) +{ + return Acceptor::shared_ptr(new PosixAcceptor()); +} + +// Must define Acceptor virtual dtor. +Acceptor::~Acceptor() {} + +}} diff --git a/qpid/cpp-0-9/lib/common/sys/posix/Socket.cpp b/qpid/cpp-0-9/lib/common/sys/posix/Socket.cpp new file mode 100644 index 0000000000..5bd13742f6 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/posix/Socket.cpp @@ -0,0 +1,118 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <sys/socket.h> +#include <sys/errno.h> +#include <netinet/in.h> +#include <netdb.h> + +#include <boost/format.hpp> + +#include <QpidError.h> +#include <posix/check.h> +#include <sys/Socket.h> + +using namespace qpid::sys; + +Socket Socket::createTcp() +{ + int s = ::socket (PF_INET, SOCK_STREAM, 0); + if (s < 0) throw QPID_POSIX_ERROR(errno); + return s; +} + +Socket::Socket(int descriptor) : socket(descriptor) {} + +void Socket::setTimeout(Time interval) +{ + struct timeval tv; + tv.tv_sec = interval/TIME_SEC; + tv.tv_usec = (interval%TIME_SEC)/TIME_USEC; + setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); +} + +void Socket::connect(const std::string& host, int port) +{ + struct sockaddr_in name; + name.sin_family = AF_INET; + name.sin_port = htons(port); + struct hostent* hp = gethostbyname ( host.c_str() ); + if (hp == 0) throw QPID_POSIX_ERROR(errno); + memcpy(&name.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length); + if (::connect(socket, (struct sockaddr*)(&name), sizeof(name)) < 0) + throw QPID_POSIX_ERROR(errno); +} + +void +Socket::close() +{ + if (socket == 0) return; + if (::close(socket) < 0) throw QPID_POSIX_ERROR(errno); + socket = 0; +} + +ssize_t +Socket::send(const void* data, size_t size) +{ + ssize_t sent = ::send(socket, data, size, 0); + if (sent < 0) { + if (errno == ECONNRESET) return SOCKET_EOF; + if (errno == ETIMEDOUT) return SOCKET_TIMEOUT; + throw QPID_POSIX_ERROR(errno); + } + return sent; +} + +ssize_t +Socket::recv(void* data, size_t size) +{ + ssize_t received = ::recv(socket, data, size, 0); + if (received < 0) { + if (errno == ETIMEDOUT) return SOCKET_TIMEOUT; + throw QPID_POSIX_ERROR(errno); + } + return received; +} + +int Socket::listen(int port, int backlog) +{ + struct sockaddr_in name; + name.sin_family = AF_INET; + name.sin_port = htons(port); + name.sin_addr.s_addr = 0; + if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) < 0) + throw QPID_POSIX_ERROR(errno); + if (::listen(socket, backlog) < 0) + throw QPID_POSIX_ERROR(errno); + + socklen_t namelen = sizeof(name); + if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0) + throw QPID_POSIX_ERROR(errno); + + return ntohs(name.sin_port); +} + + +int Socket::fd() +{ + return socket; +} diff --git a/qpid/cpp-0-9/lib/common/sys/posix/Thread.cpp b/qpid/cpp-0-9/lib/common/sys/posix/Thread.cpp new file mode 100644 index 0000000000..f524799556 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/posix/Thread.cpp @@ -0,0 +1,28 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <sys/Thread.h> + +void* qpid::sys::Thread::runRunnable(void* p) +{ + static_cast<Runnable*>(p)->run(); + return 0; +} diff --git a/qpid/cpp-0-9/lib/common/sys/posix/check.cpp b/qpid/cpp-0-9/lib/common/sys/posix/check.cpp new file mode 100644 index 0000000000..408679caa8 --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/posix/check.cpp @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <cerrno> +#include "check.h" + +namespace qpid { +namespace sys { + +std::string +PosixError::getMessage(int errNo) +{ + char buf[512]; + return std::string(strerror_r(errNo, buf, sizeof(buf))); +} + +PosixError::PosixError(int errNo, const qpid::SrcLine& loc) throw() + : qpid::QpidError(INTERNAL_ERROR + errNo, getMessage(errNo), loc) +{ } + +}} diff --git a/qpid/cpp-0-9/lib/common/sys/posix/check.h b/qpid/cpp-0-9/lib/common/sys/posix/check.h new file mode 100644 index 0000000000..57b5a5757c --- /dev/null +++ b/qpid/cpp-0-9/lib/common/sys/posix/check.h @@ -0,0 +1,62 @@ +#ifndef _posix_check_h +#define _posix_check_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <cerrno> +#include <string> +#include <QpidError.h> + +namespace qpid { +namespace sys { + +/** + * Exception with message from errno. + */ +class PosixError : public qpid::QpidError +{ + public: + static std::string getMessage(int errNo); + + PosixError(int errNo, const qpid::SrcLine& location) throw(); + + ~PosixError() throw() {} + + int getErrNo() { return errNo; } + + Exception* clone() const throw() { return new PosixError(*this); } + + void throwSelf() const { throw *this; } + + private: + int errNo; +}; + +}} + +/** Create a PosixError for the current file/line and errno. */ +#define QPID_POSIX_ERROR(errNo) ::qpid::sys::PosixError(errNo, SRCLINE) + +/** Throw a posix error if errNo is non-zero */ +#define QPID_POSIX_THROW_IF(ERRNO) \ + if ((ERRNO) != 0) throw QPID_POSIX_ERROR((ERRNO)) +#endif /*!_posix_check_h*/ diff --git a/qpid/cpp-0-9/m4/clock_time.m4 b/qpid/cpp-0-9/m4/clock_time.m4 new file mode 100644 index 0000000000..227a5978e5 --- /dev/null +++ b/qpid/cpp-0-9/m4/clock_time.m4 @@ -0,0 +1,30 @@ +# clock_time.m4 serial 8 +dnl Copyright (C) 2002-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Check for clock_gettime and clock_settime, and set LIB_CLOCK_GETTIME. +# For a program named, say foo, you should add a line like the following +# in the corresponding Makefile.am file: +# foo_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) + +AC_DEFUN([gl_CLOCK_TIME], +[ + dnl Persuade glibc and Solaris <time.h> to declare these functions. + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + + # Solaris 2.5.1 needs -lposix4 to get the clock_gettime function. + # Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4. + + # Save and restore LIBS so e.g., -lrt, isn't added to it. Otherwise, *all* + # programs in the package would end up linked with that potentially-shared + # library, inducing unnecessary run-time overhead. + gl_saved_libs=$LIBS + AC_SEARCH_LIBS(clock_gettime, [rt posix4], + [test "$ac_cv_search_clock_gettime" = "none required" || + LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime]) + AC_SUBST([LIB_CLOCK_GETTIME]) + AC_CHECK_FUNCS(clock_gettime clock_settime) + LIBS=$gl_saved_libs +]) diff --git a/qpid/cpp-0-9/m4/compiler-flags.m4 b/qpid/cpp-0-9/m4/compiler-flags.m4 new file mode 100644 index 0000000000..01cb728f02 --- /dev/null +++ b/qpid/cpp-0-9/m4/compiler-flags.m4 @@ -0,0 +1,23 @@ +# serial 3 +# Find valid warning flags for the C Compiler. -*-Autoconf-*- +dnl Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl Written by Jesse Thilo. + +AC_DEFUN([gl_COMPILER_FLAGS], + [AC_MSG_CHECKING(whether compiler accepts $1) + AC_SUBST(COMPILER_FLAGS) + ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $1" + AC_TRY_COMPILE(, + [int x;], + COMPILER_FLAGS="$COMPILER_FLAGS $1" + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) + CFLAGS="$ac_save_CFLAGS" + CXXFLAGS="$ac_save_CXXFLAGS" + ]) diff --git a/qpid/cpp-0-9/m4/cppunit.m4 b/qpid/cpp-0-9/m4/cppunit.m4 new file mode 100644 index 0000000000..f009086f9d --- /dev/null +++ b/qpid/cpp-0-9/m4/cppunit.m4 @@ -0,0 +1,89 @@ +dnl +dnl AM_PATH_CPPUNIT(MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl +AC_DEFUN([AM_PATH_CPPUNIT], +[ + +AC_ARG_WITH(cppunit-prefix,[ --with-cppunit-prefix=PFX Prefix where CppUnit is installed (optional)], + cppunit_config_prefix="$withval", cppunit_config_prefix="") +AC_ARG_WITH(cppunit-exec-prefix,[ --with-cppunit-exec-prefix=PFX Exec prefix where CppUnit is installed (optional)], + cppunit_config_exec_prefix="$withval", cppunit_config_exec_prefix="") + + if test x$cppunit_config_exec_prefix != x ; then + cppunit_config_args="$cppunit_config_args --exec-prefix=$cppunit_config_exec_prefix" + if test x${CPPUNIT_CONFIG+set} != xset ; then + CPPUNIT_CONFIG=$cppunit_config_exec_prefix/bin/cppunit-config + fi + fi + if test x$cppunit_config_prefix != x ; then + cppunit_config_args="$cppunit_config_args --prefix=$cppunit_config_prefix" + if test x${CPPUNIT_CONFIG+set} != xset ; then + CPPUNIT_CONFIG=$cppunit_config_prefix/bin/cppunit-config + fi + fi + + AC_PATH_PROG(CPPUNIT_CONFIG, cppunit-config, no) + cppunit_version_min=$1 + + AC_MSG_CHECKING(for Cppunit - version >= $cppunit_version_min) + no_cppunit="" + if test "$CPPUNIT_CONFIG" = "no" ; then + AC_MSG_RESULT(no) + no_cppunit=yes + else + CPPUNIT_CFLAGS=`$CPPUNIT_CONFIG --cflags` + CPPUNIT_LIBS=`$CPPUNIT_CONFIG --libs` + cppunit_version=`$CPPUNIT_CONFIG --version` + + cppunit_major_version=`echo $cppunit_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + cppunit_minor_version=`echo $cppunit_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + cppunit_micro_version=`echo $cppunit_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + + cppunit_major_min=`echo $cppunit_version_min | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + if test "x${cppunit_major_min}" = "x" ; then + cppunit_major_min=0 + fi + + cppunit_minor_min=`echo $cppunit_version_min | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + if test "x${cppunit_minor_min}" = "x" ; then + cppunit_minor_min=0 + fi + + cppunit_micro_min=`echo $cppunit_version_min | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x${cppunit_micro_min}" = "x" ; then + cppunit_micro_min=0 + fi + + cppunit_version_proper=`expr \ + $cppunit_major_version \> $cppunit_major_min \| \ + $cppunit_major_version \= $cppunit_major_min \& \ + $cppunit_minor_version \> $cppunit_minor_min \| \ + $cppunit_major_version \= $cppunit_major_min \& \ + $cppunit_minor_version \= $cppunit_minor_min \& \ + $cppunit_micro_version \>= $cppunit_micro_min ` + + if test "$cppunit_version_proper" = "1" ; then + AC_MSG_RESULT([$cppunit_major_version.$cppunit_minor_version.$cppunit_micro_version]) + else + AC_MSG_RESULT(no) + no_cppunit=yes + fi + fi + + if test "x$no_cppunit" = x ; then + ifelse([$2], , :, [$2]) + else + CPPUNIT_CFLAGS="" + CPPUNIT_LIBS="" + ifelse([$3], , :, [$3]) + fi + + AC_SUBST(CPPUNIT_CFLAGS) + AC_SUBST(CPPUNIT_LIBS) +]) diff --git a/qpid/cpp-0-9/m4/extensions.m4 b/qpid/cpp-0-9/m4/extensions.m4 new file mode 100644 index 0000000000..143a9e5403 --- /dev/null +++ b/qpid/cpp-0-9/m4/extensions.m4 @@ -0,0 +1,58 @@ +# serial 4 -*- Autoconf -*- +# Enable extensions on systems that normally disable them. + +# Copyright (C) 2003, 2006 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This definition of AC_USE_SYSTEM_EXTENSIONS is stolen from CVS +# Autoconf. Perhaps we can remove this once we can assume Autoconf +# 2.61 or later everywhere, but since CVS Autoconf mutates rapidly +# enough in this area it's likely we'll need to redefine +# AC_USE_SYSTEM_EXTENSIONS for quite some time. + +# AC_USE_SYSTEM_EXTENSIONS +# ------------------------ +# Enable extensions on systems that normally disable them, +# typically due to standards-conformance issues. +AC_DEFUN([AC_USE_SYSTEM_EXTENSIONS], +[ + AC_BEFORE([$0], [AC_COMPILE_IFELSE]) + AC_BEFORE([$0], [AC_RUN_IFELSE]) + + AC_REQUIRE([AC_GNU_SOURCE]) + AC_REQUIRE([AC_AIX]) + AC_REQUIRE([AC_MINIX]) + + AH_VERBATIM([__EXTENSIONS__], +[/* Enable extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif]) + AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__], + [ac_cv_safe_to_define___extensions__], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([ +# define __EXTENSIONS__ 1 + AC_INCLUDES_DEFAULT])], + [ac_cv_safe_to_define___extensions__=yes], + [ac_cv_safe_to_define___extensions__=no])]) + test $ac_cv_safe_to_define___extensions__ = yes && + AC_DEFINE([__EXTENSIONS__]) + AC_DEFINE([_POSIX_PTHREAD_SEMANTICS]) + AC_DEFINE([_TANDEM_SOURCE]) +]) + +# gl_USE_SYSTEM_EXTENSIONS +# ------------------------ +# Enable extensions on systems that normally disable them, +# typically due to standards-conformance issues. +AC_DEFUN([gl_USE_SYSTEM_EXTENSIONS], + [AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])]) diff --git a/qpid/cpp-0-9/make-dist b/qpid/cpp-0-9/make-dist new file mode 100755 index 0000000000..c23cad63a1 --- /dev/null +++ b/qpid/cpp-0-9/make-dist @@ -0,0 +1,83 @@ +#!/bin/bash +# +# Temporary hack for producing a binary dev distribution. +# Includes regular stuff from 'make install' + examples and headers. +# +# TODO: Also include debug libraries. +# + +Usage() { + echo "usage: $0 [release-version] + release-version e.g. 1.0M1 (defaults to the svn revision)" >&2 + exit 2 +} + +if [[ $# -eq 1 ]]; then + [[ $1 == "-?" ]] && Usage + version=$1 +elif [[ $# -ne 0 ]]; then + Usage +else + # Default the version to the svn revision + if which svn >/dev/null 2>&1; then + svnRevision=$(svn info | grep ^Revision: | awk '{print $2}') + version=r${svnRevision} + else + echo "You need to have svn in your PATH or specify a release-version" + exit 2 + fi +fi + +releaseName=qpid-cpp-dev-${version}-$(uname -s)-$(uname -p) +releaseDir=release/$releaseName + +if [[ -d $releaseDir ]]; then + echo "$releaseDir already exists" + exit 2 +fi + +# Copy bin. +mkdir -p $releaseDir/bin +cp -r src/.libs/* ${releaseDir}/bin + +# Copy libs. +mkdir -p $releaseDir/lib +cp lib/broker/.libs/lib* lib/common/.libs/lib* lib/client/.libs/lib* \ + $releaseDir/lib + +# Copy gen include files. +find gen -name \*.h | while read file; do + destFile=${releaseDir}/include/$file + baseDir=$(dirname $destFile) + mkdir -p $baseDir + cp $file $destFile +done + +# Copy in lib include files. +( + cd lib; find . -name \*.h | while read file; do + destFile=../${releaseDir}/include/$file + baseDir=$(dirname $destFile) + mkdir -p $baseDir + cp $file $destFile + done +) + +# Copy non-cppunit tests as examples. +mkdir -p $releaseDir/examples +for file in tests/*.cpp; do + if grep CppUnit $file >/dev/null; then + echo Skipping cppunit file $file + else + cp $file $releaseDir/examples + fi +done + +# Copy Makefile and README for examples. +cp tests/examples.Makefile $releaseDir/examples/Makefile +cp tests/examples.README $releaseDir/examples/README + +cd release +tar=$releaseName.tar +tar cvf $tar $releaseName +bzip2 $tar diff --git a/qpid/cpp-0-9/qpid-autotools-install b/qpid/cpp-0-9/qpid-autotools-install new file mode 100755 index 0000000000..2ed3174903 --- /dev/null +++ b/qpid/cpp-0-9/qpid-autotools-install @@ -0,0 +1,205 @@ +#!/bin/sh +# Written by Jim Meyering + +VERSION='2007-01-22 19:38' # UTC + +prog_name=`basename $0` +die () { echo "$prog_name: $*" >&2; exit 1; } + +tarballs=' + http://pkgconfig.freedesktop.org/releases/pkg-config-0.21.tar.gz + ftp://ftp.gnu.org/gnu/m4/m4-1.4.8.tar.gz + ftp://ftp.gnu.org/gnu/automake/automake-1.10.tar.gz + ftp://ftp.gnu.org/gnu/autoconf/autoconf-2.61.tar.gz + ftp://ftp.gnu.org/gnu/libtool/libtool-1.5.22.tar.gz +' + +usage() { + echo >&2 "\ +Usage: $0 [OPTION]... +Download, build, and install some tools. + +Options: + --prefix=PREFIX install tools under specified directory + --skip-check do not run "make check" (this can save 50+ min) + --help display this help and exit + +For example, to install programs into \$HOME/qpid-tools/bin, run this command: + + $prog_name --prefix=\$HOME/qpid-tools + +If you've already verified that your system/environment can build working +versions of these tools, you can make this script complete in just a +minute or two (rather than about an hour if you let all "make check" +tests run) by invoking it like this: + + $prog_name --prefix=\$HOME/qpid-tools --skip-check + +" +} + +# Get the listed tarballs into the current directory. +get_sources() +{ + case `wget --help` in + *'--no-cache'*) + WGET_COMMAND='wget -nv --no-cache';; + *'--cache=on/off'*) + WGET_COMMAND='wget -nv --cache=off';; + *'--non-verbose'*) + WGET_COMMAND='wget -nv';; + *) + die 'no wget program found; please install it and try again';; + esac + + # Download the each tar-ball along with its signature, if there is one. + pkgs= + for t in $(echo $tarballs); do + base=$(basename $t) + pkgs="$pkgs $base" + test -f $base || $WGET_COMMAND $t + + # pkg-config has no .sig file. + case $base in pkg-config*) continue;; esac + + test -f $base.sig || $WGET_COMMAND $t.sig + # Verify each signature. + gpg --quiet --verify --trust-model=always \ + --trusted-key=32419B785D0CDCFC \ + --trusted-key=3859C03B2E236E47 \ + --trusted-key=B93F60C6B5C4CE13 \ + --trusted-key=F382AE19F4850180 \ + $base.sig > /dev/null 2>&1 \ + || echo "info: not verifying GPG signature for $base" 1>&2 + done + + printf 'verifying package SHA1 checksums...' 1>&2 + sha1sum -c --warn --status <<EOF || die "checksum mismatch" +69f37c509a4757d747b6f4c091d209ab3984d62f autoconf-2.61.tar.gz +69dc02b083b9a609b28fc4db129fef6a83ed2339 automake-1.10.tar.gz +17353e66aeaac80ae188ea0a3a90609550ce3254 libtool-1.5.22.tar.gz +32b5bb526de9315d1a319c2ca8eb881d9b835506 m4-1.4.8.tar.gz +b2508ba8404cad46ec42f6f58cbca43ae59d715f pkg-config-0.21.tar.gz +EOF + printf 'ok\n' 1>&2 + echo $pkgs +} + +################################################################# +set -e + +# Parse options. + +make_check=yes +prefix= + +for option +do + case $option in + --help) usage; exit;; + --skip-check) make_check=no;; + --prefix=*) prefix=`expr "$option" : '--prefix=\(.*\)'`;; + *) die "$option: unknown option";; + esac +done + +test -n "$prefix" \ + || die "you must specify a --prefix" + +case $prefix in + /*) ;; + *) die 'invalid prefix: '"$prefix"': it must be an absolute name';; +esac + +# Don't run as root. +# Make sure id -u succeeds. +my_uid=`id -u` +test $? = 0 || { + echo "$0: cannot run \`id -u'" 1>&2 + (exit 1); exit 1 +} +test $my_uid = 0 && die "please don't run this program as root" + +# Ensure that prefix is not /usr/bin or /bin, /sbin, etc. +case $prefix in + /bin|/sbin|/usr/bin|/usr/sbin) + die "don't set PREFIX to a system directory";; + *) ;; +esac + +# Create a build directory, then cd into it for the rest.... +tmpdir=.build-auto-tools +mkdir -p $tmpdir +cd $tmpdir + +pkgs=$(get_sources) + +for pkg in $pkgs; do + echo building/installing $pkg... + dir=$(basename $pkg .tar.gz) + rm -rf dir + gzip -dc $pkg|tar xf - + cd $dir + ./configure CFLAGS=-O2 LDFLAGS=-s --prefix=$prefix > makerr-config 2>&1 + make -j1 > makerr-build 2>&1 + if test "$make_check" = yes; then + case $pkg in + automake*) expected_duration_minutes=40;; + autoconf*) expected_duration_minutes=15;; + # libtool*) expected_duration_minutes=3;; + *);; + esac + test -n "$expected_duration_minutes" \ + && echo "running 'make check' for $pkg; NB: this can take over" \ + "$expected_duration_minutes minutes" + case $pkg in + # In this package, the check-requires-private test fails. + # Change the Makefile so it skips that test. + pkg-config-0.21.tar.gz) + perl -pi.bak -e 's/check-requires-private //' check/Makefile;; + + esac + make -j1 check > makerr-check 2>&1 + fi + make -j1 install > makerr-install 2>&1 + echo done at $(date +%Y-%m-%d.%T) + cd .. +done + +# Without checks (and with existing tarballs), it takes just one minute. +# Including all checks, it takes nearly an hour on an AMD64/3400+ + +case $PKG_CONFIG_PATH in + $prefix/lib/pkgconfig:/usr/lib/pkgconfig) + echo 'Good! your PKG_CONFIG_PATH envvar is already set';; + *) cat <<EOF;; +************************************************************************** +Be sure that PKG_CONFIG_PATH is set in your environment, e.g., +PKG_CONFIG_PATH=$prefix/lib/pkgconfig:/usr/lib/pkgconfig +************************************************************************** +EOF +esac + +case $PATH in + "$prefix/bin:"*) echo 'Good! your PATH is fine';; + *) cat <<EOF;; +************************************************************************** +Be sure that "$prefix/bin" is earlier in your PATH than /bin, /usr/bin, etc. +************************************************************************** +EOF +esac + +cat <<EOF +************************************************************************** +You may want to remove the tool build directory: +rm -rf $tmpdir +************************************************************************** +EOF + +## Local Variables: +## eval: (add-hook 'write-file-hooks 'time-stamp) +## time-stamp-start: "VERSION='" +## time-stamp-format: "%:y-%02m-%02d %02H:%02M" +## time-stamp-time-zone: "UTC" +## time-stamp-end: "' # UTC" +## End: diff --git a/qpid/cpp-0-9/qpidc.spec.in b/qpid/cpp-0-9/qpidc.spec.in new file mode 100644 index 0000000000..9b7cb4ef91 --- /dev/null +++ b/qpid/cpp-0-9/qpidc.spec.in @@ -0,0 +1,147 @@ +# +# Spec file for Qpid C++ packages: qpidc qpidc-devel, qpidd +# +%define daemon qpidd + +Name: @PACKAGE@ +Version: @VERSION@ +Release: 4%{?dist} +Summary: Libraries for Qpid C++ client applications +Group: System Environment/Libraries +License: Apache Software License +URL: http://rhm.et.redhat.com/qpidc/ +Source0: http://rhm.et.redhat.com/download/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +BuildRequires: libtool +BuildRequires: boost-devel +BuildRequires: cppunit-devel +BuildRequires: doxygen +BuildRequires: graphviz +BuildRequires: help2man +BuildRequires: pkgconfig +BuildRequires: e2fsprogs-devel +BuildRequires: apr-devel + +Requires: boost + +Requires(post):/sbin/chkconfig +Requires(preun):/sbin/chkconfig +Requires(preun):/sbin/service +Requires(postun):/sbin/service + +%description +Run-time libraries for AMQP client applications developed using Qpid +C++. Clients exchange messages with an AMQP message broker using +the AMQP protocol. + +%package devel +Summary: Header files and documentation for developing Qpid C++ clients +Group: Development/System +Requires: %name = %version-%release +Requires: libtool +Requires: apr-devel +Requires: boost-devel +Requires: cppunit-devel + +%description devel +Libraries, header files and documentation for developing AMQP clients +in C++ using Qpid. Qpid implements the AMQP messaging specification. + +%package -n %{daemon} +Summary: An AMQP message broker daemon +Group: System Environment/Daemons +Requires: %name = %version-%release + +%description -n %{daemon} +A message broker daemon that receives stores and routes messages using +the open AMQP messaging protocol. + +%prep +%setup -q + +%build +%configure --disable-static +make %{?_smp_mflags} +# Remove this generated perl file, we don't need it and it upsets rpmlint. +rm docs/api/html/installdox + +%install +rm -rf %{buildroot} +make install DESTDIR=%{buildroot} +install -Dp -m0755 etc/qpidd %{buildroot}%{_initrddir}/qpidd +rm -f %{buildroot}%_libdir/*.a +rm -f %{buildroot}%_libdir/*.la +# There's no qpidd-devel package so no .so for the broker needed. +rm -f %{buildroot}%_libdir/libqpidbroker.so + + +%clean +rm -rf %{buildroot} + +%check +make check + +%files +%defattr(-,root,root,-) +%doc LICENSE NOTICE README +%_libdir/libqpidcommon.so.0 +%_libdir/libqpidcommon.so.0.1.0 +%_libdir/libqpidclient.so.0 +%_libdir/libqpidclient.so.0.1.0 + +%files devel +%defattr(-,root,root,-) +%_includedir/qpidc +%_libdir/libqpidcommon.so +%_libdir/libqpidclient.so +%doc docs/api/html +# We don't need this perl script and it causes rpmlint to complain. +# There is probably a more polite way of calculating the devel docdir. + +%files -n %{daemon} +%_libdir/libqpidbroker.so.0 +%_libdir/libqpidbroker.so.0.1.0 +%_sbindir/%{daemon} +%{_initrddir}/qpidd +%doc %_mandir/man1/%{daemon}.* + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%post -n %{daemon} +# This adds the proper /etc/rc*.d links for the script +/sbin/chkconfig --add qpidd +/sbin/ldconfig + +%preun -n %{daemon} +# Check that this is actual deinstallation, not just removing for upgrade. +if [ $1 = 0 ]; then + /sbin/service qpidd stop >/dev/null 2>&1 || : + /sbin/chkconfig --del qpidd +fi + +%postun -n %{daemon} +if [ "$1" -ge "1" ]; then + /sbin/service qpidd condrestart >/dev/null 2>&1 || : +fi +/sbin/ldconfig + +%changelog + +* Mon Feb 19 2007 Jim Meyering <meyering@redhat.com> - 0.1-4 +- Address http://bugzilla.redhat.com/220630: +- Remove redundant "cppunit" build-requires. +- Add --disable-static. + +* Thu Jan 25 2007 Alan Conway <aconway@redhat.com> - 0.1-3 +- Applied Jim Meyerings fixes from http://mail-archives.apache.org/mod_mbox/incubator-qpid-dev/200701.mbox/%3c87hcugzmyp.fsf@rho.meyering.net%3e + +* Mon Dec 22 2006 Alan Conway <aconway@redhat.com> - 0.1-1 +- Fixed all rpmlint complaints (with help from David Lutterkort) +- Added qpidd --daemon behaviour, fix init.rc scripts + +* Fri Dec 8 2006 David Lutterkort <dlutter@redhat.com> - 0.1-1 +- Initial version based on Jim Meyering's sketch and discussions with Alan + Conway diff --git a/qpid/cpp-0-9/rpm/Makefile.am b/qpid/cpp-0-9/rpm/Makefile.am new file mode 100644 index 0000000000..363a444f4f --- /dev/null +++ b/qpid/cpp-0-9/rpm/Makefile.am @@ -0,0 +1,27 @@ +# +# Build RPMs from the distribution tarball. +# + +# TODO aconway 2006-12-21: use autoconf macros for version, base name etc. + +SPEC=${top_srcdir}/qpidc.spec +RPMOPTS=--define "_sourcedir ${abs_top_srcdir}" --define "_topdir ${abs_builddir}" + +clean-local: + -rm -rf BUILD RPMS SOURCES SPECS SRPMS + +.PHONY: rpm srpm dist + +# Build source and binary RPMs. +rpm: dist + rpmbuild $(RPMOPTS) $(RPMEXTRAOPTS) -ba $(SPEC) + rpmlint RPMS/*/*.rpm + +# Build source RPM only. +srpm: dist + rpmbuild $(RPMOPTS) -bs $(SPEC) + +# Build source distribution and create required subdirs. +dist: + cd .. && $(MAKE) $(AM_MAKEFLAGS) dist + mkdir -p BUILD RPMS SOURCES SPECS SRPMS diff --git a/qpid/cpp-0-9/src/Makefile.am b/qpid/cpp-0-9/src/Makefile.am new file mode 100644 index 0000000000..40398eb2c9 --- /dev/null +++ b/qpid/cpp-0-9/src/Makefile.am @@ -0,0 +1,17 @@ +AM_CXXFLAGS = $(WARNING_CFLAGS) +INCLUDES = \ + -I$(top_srcdir)/gen \ + -I$(top_srcdir)/lib/broker \ + -I$(top_srcdir)/lib/common \ + -I$(top_srcdir)/lib/common/framing \ + -I$(top_srcdir)/lib/common/sys + +LDADD = \ + ../lib/broker/libqpidbroker.la \ + ../lib/common/libqpidcommon.la + +sbin_PROGRAMS = qpidd +qpidd_SOURCES = qpidd.cpp + +# Force build of qpidd during dist phase so help2man will work. +dist-hook: $(sbin_PROGRAMS) diff --git a/qpid/cpp-0-9/src/qpidd.cpp b/qpid/cpp-0-9/src/qpidd.cpp new file mode 100644 index 0000000000..9f658ebf74 --- /dev/null +++ b/qpid/cpp-0-9/src/qpidd.cpp @@ -0,0 +1,80 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <Broker.h> +#include <Configuration.h> +#include <signal.h> +#include <iostream> +#include <memory> +#include <cerrno> +#include <config.h> +#include <unistd.h> + +static char const* programName = "qpidd"; + +using namespace qpid::broker; +using namespace qpid::sys; + +Broker::shared_ptr broker; + +void handle_signal(int /*signal*/){ + std::cerr << "Shutting down..." << std::endl; + broker->shutdown(); +} + +int main(int argc, char** argv) +{ + Configuration config; + try { + config.parse(programName, argc, argv); + + if(config.isHelp()){ + config.usage(); + }else if(config.isVersion()){ + std::cout << programName << " (" << PACKAGE_NAME << ") version " + << PACKAGE_VERSION << std::endl; + }else{ + broker = Broker::create(config); + signal(SIGINT, handle_signal); + if (config.isDaemon()) { + // Detach & run as daemon. + int chdirRoot = 0; // 0 means chdir to root. + int closeStd = 0; // 0 means close stdin/out/err + if (daemon(chdirRoot, closeStd) < 0) { + char buf[512]; + + std::cerr << "Failed to detach as daemon: " + << strerror_r(errno, buf, sizeof(buf)) + << std::endl;; + return 1; + } + } + broker->run(); + } + return 0; + } + catch (const Configuration::BadOptionException& e) { + std::cerr << e.what() << std::endl << std::endl; + config.usage(); + } catch(const std::exception& e) { + std::cerr << e.what() << std::endl; + } + return 1; +} diff --git a/qpid/cpp-0-9/tests/.vg-supp b/qpid/cpp-0-9/tests/.vg-supp new file mode 100644 index 0000000000..e107377aa2 --- /dev/null +++ b/qpid/cpp-0-9/tests/.vg-supp @@ -0,0 +1,4705 @@ +{ + x17984_1 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsmj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_2 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid6broker6BrokerEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid6broker6BrokerEEC1IS3_EEPT_ + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_3 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid6broker15HeadersExchangeEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid6broker8ExchangeEEC1INS2_15HeadersExchangeEEEPT_ + fun:_ZN4qpid6broker16ExchangeRegistry7declareERKSsS3_ + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsmj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_4 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid6broker14FanOutExchangeEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid6broker8ExchangeEEC1INS2_14FanOutExchangeEEEPT_ + fun:_ZN4qpid6broker16ExchangeRegistry7declareERKSsS3_ + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsmj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_5 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid6broker13TopicExchangeEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid6broker8ExchangeEEC1INS2_13TopicExchangeEEEPT_ + fun:_ZN4qpid6broker16ExchangeRegistry7declareERKSsS3_ + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsmj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_6 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid3sys11APRAcceptorEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid3sys8AcceptorEEC1INS2_11APRAcceptorEEEPT_ + fun:_ZN4qpid3sys8Acceptor6createEsiib + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_7 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid3sys7APRBase11getInstanceEv + fun:_ZN4qpid3sys7APRBase9incrementEv + fun:_ZN4qpid3sys7APRPoolC1Ev + fun:_ZN5boost7details4pool17singleton_defaultIN4qpid3sys7APRPoolEE8instanceEv + fun:_ZN4qpid3sys7APRPool3getEv + fun:_Z41__static_initialization_and_destruction_0ii + obj:/home_old/e/work/rh/rhn/messaging-clean/trunk/qpid-help2man/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + obj:/home_old/e/work/rh/rhn/messaging-clean/trunk/qpid-help2man/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_8 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znam + fun:_ZN4qpid3sys11LFProcessorC1EP10apr_pool_tiii + fun:_ZN4qpid3sys11APRAcceptorC1Esiib + fun:_ZN4qpid3sys8Acceptor6createEsiib + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_9 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid7framing5Value12decode_valueERNS0_6BufferE + fun:_ZN4qpid7framing10FieldTable6decodeERNS0_6BufferE + fun:_ZN4qpid7framing6Buffer13getFieldTableERNS0_10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody13decodeContentERNS0_6BufferE + fun:_ZN4qpid7framing13AMQMethodBody6decodeERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid7framing5ValueEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid7framing5ValueEEC1IS3_EEPT_ + fun:_ZN4qpid7framing10FieldTable6decodeERNS0_6BufferE + fun:_ZN4qpid7framing6Buffer13getFieldTableERNS0_10FieldTableE +} +{ + x17984_10 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid6broker14DirectExchangeEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid6broker8ExchangeEEC1INS2_14DirectExchangeEEEPT_ + fun:_ZN4qpid6broker16ExchangeRegistry7declareERKSsS3_ + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsmj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_11 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISsE8allocateEmPKv + fun:_ZNSt12_Vector_baseISsSaISsEE11_M_allocateEm + fun:_ZNSt12_Vector_baseISsSaISsEEC2EmRKS0_ + fun:_ZNSt6vectorISsSaISsEEC2ERKS1_ + fun:_ZN4qpid6broker6TokensC2ERKS1_ + fun:_ZN4qpid6broker12TopicPatternC1ERKS1_ + fun:_ZNSt4pairIKN4qpid6broker12TopicPatternESt6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS8_EEEC1ERKSB_ + fun:_ZN9__gnu_cxx13new_allocatorISt4pairIKN4qpid6broker12TopicPatternESt6vectorIN5boost10shared_ptrINS3_5QueueEEESaISA_EEEE9constructEPSD_RKSD_ + fun:_ZNSt8_Rb_treeIN4qpid6broker12TopicPatternESt4pairIKS2_St6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS9_EEESt10_Select1stISC_ESt4lessIS2_ESaISC_EE14_M_create_nodeERKSC_ + fun:_ZNSt8_Rb_treeIN4qpid6broker12TopicPatternESt4pairIKS2_St6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS9_EEESt10_Select1stISC_ESt4lessIS2_ESaISC_EE9_M_insertEPSt18_Rb_tree_node_baseSK_RKSC_ + fun:_ZNSt8_Rb_treeIN4qpid6broker12TopicPatternESt4pairIKS2_St6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS9_EEESt10_Select1stISC_ESt4lessIS2_ESaISC_EE13insert_uniqueERKSC_ + fun:_ZNSt8_Rb_treeIN4qpid6broker12TopicPatternESt4pairIKS2_St6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS9_EEESt10_Select1stISC_ESt4lessIS2_ESaISC_EE13insert_uniqueESt17_Rb_tree_iteratorISC_ERKSC_ + fun:_ZNSt3mapIN4qpid6broker12TopicPatternESt6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS7_EESt4lessIS2_ESaISt4pairIKS2_S9_EEE6insertESt17_Rb_tree_iteratorISE_ERKSE_ + fun:_ZNSt3mapIN4qpid6broker12TopicPatternESt6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS7_EESt4lessIS2_ESaISt4pairIKS2_S9_EEEixERSD_ + fun:_ZN4qpid6broker13TopicExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone +} +{ + x17984_12 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker16ExchangeRegistry7declareERKSsS3_ + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsmj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_13 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIPN5boost10shared_ptrIN4qpid6broker5QueueEEEE8allocateEmPKv + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE15_M_allocate_mapEm + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE17_M_initialize_mapEm + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EEC2ERKS6_m + fun:_ZNSt5dequeIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EEC1ERKS7_ + fun:_ZNSt5queueIN5boost10shared_ptrIN4qpid6broker5QueueEEESt5dequeIS5_SaIS5_EEEC1ERKS8_ + fun:_ZN4qpid6broker10AutoDeleteC1EPNS0_13QueueRegistryEj + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsmj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_14 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid7framing5Value12decode_valueERNS0_6BufferE + fun:_ZN4qpid7framing10FieldTable6decodeERNS0_6BufferE + fun:_ZN4qpid7framing6Buffer13getFieldTableERNS0_10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody13decodeContentERNS0_6BufferE + fun:_ZN4qpid7framing13AMQMethodBody6decodeERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZNSs4_Rep9_S_createEmmRKSaIcE + fun:_ZNSs9_M_mutateEmmm + fun:_ZNSs15_M_replace_safeEmmPKcm + fun:_ZN4qpid7framing6Buffer13getLongStringERSs +} +{ + x17984_15 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEEEE8allocateEmPKv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE11_M_get_nodeEv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE14_M_create_nodeERKS8_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE9_M_insertEPSt18_Rb_tree_node_baseSG_RKS8_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE13insert_uniqueESt17_Rb_tree_iteratorIS8_ERKS8_ + fun:_ZNSt3mapISsN5boost10shared_ptrIN4qpid6broker5QueueEEESt4lessISsESaISt4pairIKSsS5_EEE6insertESt17_Rb_tree_iteratorISA_ERKSA_ + fun:_ZNSt3mapISsN5boost10shared_ptrIN4qpid6broker5QueueEEESt4lessISsESaISt4pairIKSsS5_EEEixERS9_ + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm +} +{ + x17984_16 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIPN4qpid6broker13Configuration6OptionEE8allocateEmPKv + fun:_ZNSt12_Vector_baseIPN4qpid6broker13Configuration6OptionESaIS4_EE11_M_allocateEm + fun:_ZNSt6vectorIPN4qpid6broker13Configuration6OptionESaIS4_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS4_S6_EERKS4_ + fun:_ZNSt6vectorIPN4qpid6broker13Configuration6OptionESaIS4_EE9push_backERKS4_ + fun:_ZN4qpid6broker13ConfigurationC1Ev + fun:main +} +{ + x17984_17 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid3sys8Acceptor6createEsiib + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_18 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker14FanOutExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__ZdlPv + fun:_ZN9__gnu_cxx13new_allocatorIN5boost10shared_ptrIN4qpid6broker5QueueEEEE10deallocateEPS6_m + fun:_ZNSt12_Vector_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE13_M_deallocateEPS5_m + fun:_ZNSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS5_S7_EERKS5_ + fun:_ZNSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE9push_backERKS5_ + fun:_ZN4qpid6broker14FanOutExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt +} +{ + x17984_19 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker15HeadersExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__ZdlPv + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEEEE10deallocateEPSB_m + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE11_M_put_nodeEPSt13_Rb_tree_nodeIS8_E + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE12destroy_nodeEPSt13_Rb_tree_nodeIS8_E + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE8_M_eraseEPSt13_Rb_tree_nodeIS8_E + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE8_M_eraseEPSt13_Rb_tree_nodeIS8_E + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EED1Ev + fun:_ZNSt3mapISsN5boost10shared_ptrIN4qpid7framing5ValueEEESt4lessISsESaISt4pairIKSsS5_EEED1Ev +} +{ + x17984_20 + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_malloc + fun:apr_allocator_create + fun:apr_pool_initialize + fun:apr_initialize + fun:_ZN4qpid3sys7APRBaseC1Ev + fun:_ZN4qpid3sys7APRBase11getInstanceEv + fun:_ZN4qpid3sys7APRBase9incrementEv + fun:_ZN4qpid3sys7APRPoolC1Ev + fun:_ZN5boost7details4pool17singleton_defaultIN4qpid3sys7APRPoolEE8instanceEv + fun:_ZN4qpid3sys7APRPool3getEv + fun:_Z41__static_initialization_and_destruction_0ii + obj:/home_old/e/work/rh/rhn/messaging-clean/trunk/qpid-help2man/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + obj:/home_old/e/work/rh/rhn/messaging-clean/trunk/qpid-help2man/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_21 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid7framing5ValueEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid7framing5ValueEEC1IS3_EEPT_ + fun:_ZN4qpid7framing10FieldTable6decodeERNS0_6BufferE + fun:_ZN4qpid7framing6Buffer13getFieldTableERNS0_10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody13decodeContentERNS0_6BufferE + fun:_ZN4qpid7framing13AMQMethodBody6decodeERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEEEE8allocateEmPKv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE11_M_get_nodeEv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE14_M_create_nodeERKS8_ +} +{ + x17984_22 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker13TopicExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__ZdlPv + fun:_ZN9__gnu_cxx13new_allocatorISsE10deallocateEPSsm + fun:_ZNSt12_Vector_baseISsSaISsEE13_M_deallocateEPSsm + fun:_ZNSt12_Vector_baseISsSaISsEED2Ev + fun:_ZNSt6vectorISsSaISsEED2Ev + fun:_ZN4qpid6broker6TokensD2Ev + fun:_ZN4qpid6broker12TopicPatternD1Ev + fun:_ZN4qpid6broker13TopicExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE +} +{ + x17984_23 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS2_6broker5QueueEEEEE8allocateEmPKv + fun:_ZNSt12_Vector_baseISt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS1_6broker5QueueEEEESaIS9_EE11_M_allocateEm + fun:_ZNSt6vectorISt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS1_6broker5QueueEEEESaIS9_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS9_SB_EERKS9_ + fun:_ZNSt6vectorISt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS1_6broker5QueueEEEESaIS9_EE9push_backERKS9_ + fun:_ZN4qpid6broker15HeadersExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEEEE8allocateEmPKv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE11_M_get_nodeEv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE14_M_create_nodeERKS8_ +} +{ + x17984_24 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker7Channel8completeERN5boost10shared_ptrINS0_7MessageEEE + fun:_ZN4qpid6broker14MessageBuilder5routeEv + fun:_ZN4qpid6broker14MessageBuilder10addContentERN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker7Channel13handleContentEN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl13handleContentEtN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIPN4qpid6broker4TxOpEE8allocateEmPKv + fun:_ZNSt12_Vector_baseIPN4qpid6broker4TxOpESaIS3_EE11_M_allocateEm + fun:_ZNSt6vectorIPN4qpid6broker4TxOpESaIS3_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS3_S5_EERKS3_ + fun:_ZNSt6vectorIPN4qpid6broker4TxOpESaIS3_EE9push_backERKS3_ + fun:_ZN4qpid6broker8TxBuffer6enlistEPNS0_4TxOpE +} +{ + x17984_25 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_26 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKN4qpid6broker12TopicPatternESt6vectorIN5boost10shared_ptrINS4_5QueueEEESaISB_EEEEE8allocateEmPKv + fun:_ZNSt8_Rb_treeIN4qpid6broker12TopicPatternESt4pairIKS2_St6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS9_EEESt10_Select1stISC_ESt4lessIS2_ESaISC_EE11_M_get_nodeEv + fun:_ZNSt8_Rb_treeIN4qpid6broker12TopicPatternESt4pairIKS2_St6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS9_EEESt10_Select1stISC_ESt4lessIS2_ESaISC_EE14_M_create_nodeERKSC_ + fun:_ZNSt8_Rb_treeIN4qpid6broker12TopicPatternESt4pairIKS2_St6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS9_EEESt10_Select1stISC_ESt4lessIS2_ESaISC_EE9_M_insertEPSt18_Rb_tree_node_baseSK_RKSC_ + fun:_ZNSt8_Rb_treeIN4qpid6broker12TopicPatternESt4pairIKS2_St6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS9_EEESt10_Select1stISC_ESt4lessIS2_ESaISC_EE13insert_uniqueERKSC_ + fun:_ZNSt8_Rb_treeIN4qpid6broker12TopicPatternESt4pairIKS2_St6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS9_EEESt10_Select1stISC_ESt4lessIS2_ESaISC_EE13insert_uniqueESt17_Rb_tree_iteratorISC_ERKSC_ + fun:_ZNSt3mapIN4qpid6broker12TopicPatternESt6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS7_EESt4lessIS2_ESaISt4pairIKS2_S9_EEE6insertESt17_Rb_tree_iteratorISE_ERKSE_ + fun:_ZNSt3mapIN4qpid6broker12TopicPatternESt6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS7_EESt4lessIS2_ESaISt4pairIKS2_S9_EEEixERSD_ + fun:_ZN4qpid6broker13TopicExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_27 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIPN4qpid6broker8ConsumerEE8allocateEmPKv + fun:_ZNSt12_Vector_baseIPN4qpid6broker8ConsumerESaIS3_EE11_M_allocateEm + fun:_ZNSt6vectorIPN4qpid6broker8ConsumerESaIS3_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS3_S5_EERKS3_ + fun:_ZNSt6vectorIPN4qpid6broker8ConsumerESaIS3_EE9push_backERKS3_ + fun:_ZN4qpid6broker5Queue7consumeEPNS0_8ConsumerEb + fun:_ZN4qpid6broker7Channel7consumeERSsN5boost10shared_ptrINS0_5QueueEEEbbPNS0_15ConnectionTokenEPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16BasicHandlerImpl7consumeEttRKSsS4_bbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16BasicConsumeBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKSsPN4qpid6broker7Channel12ConsumerImplEEEE8allocateEmPKv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsPN4qpid6broker7Channel12ConsumerImplEESt10_Select1stIS7_ESt4lessISsESaIS7_EE11_M_get_nodeEv +} +{ + x17984_28 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKSsN5boost10shared_ptrIN4qpid6broker8ExchangeEEEEEE8allocateEmPKv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker8ExchangeEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE11_M_get_nodeEv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker8ExchangeEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE14_M_create_nodeERKS8_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker8ExchangeEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE9_M_insertEPSt18_Rb_tree_node_baseSG_RKS8_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker8ExchangeEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE13insert_uniqueERKS8_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker8ExchangeEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE13insert_uniqueESt17_Rb_tree_iteratorIS8_ERKS8_ + fun:_ZNSt3mapISsN5boost10shared_ptrIN4qpid6broker8ExchangeEEESt4lessISsESaISt4pairIKSsS5_EEE6insertESt17_Rb_tree_iteratorISA_ERKSA_ + fun:_ZNSt3mapISsN5boost10shared_ptrIN4qpid6broker8ExchangeEEESt4lessISsESaISt4pairIKSsS5_EEEixERS9_ + fun:_ZN4qpid6broker16ExchangeRegistry7declareERKSsS3_ + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsmj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_29 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEEEE8allocateEmPKv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE11_M_get_nodeEv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE14_M_create_nodeERKS8_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE13_M_clone_nodeEPKSt13_Rb_tree_nodeIS8_E + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE7_M_copyEPKSt13_Rb_tree_nodeIS8_EPSG_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE7_M_copyEPKSt13_Rb_tree_nodeIS8_EPSG_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EEC1ERKSE_ + fun:_ZNSt3mapISsN5boost10shared_ptrIN4qpid7framing5ValueEEESt4lessISsESaISt4pairIKSsS5_EEEC1ERKSC_ + fun:_ZN4qpid7framing10FieldTableC1ERKS1_ + fun:_ZNSt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS0_6broker5QueueEEEEC1ERKS8_ + fun:_ZSt10_ConstructISt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS1_6broker5QueueEEEES9_EvPT_RKT0_ + fun:_ZSt24__uninitialized_copy_auxIN9__gnu_cxx17__normal_iteratorIPSt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS3_6broker5QueueEEEESt6vectorISB_SaISB_EEEESG_ET0_T_SI_SH_12__false_type + fun:_ZSt18uninitialized_copyIN9__gnu_cxx17__normal_iteratorIPSt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS3_6broker5QueueEEEESt6vectorISB_SaISB_EEEESG_ET0_T_SI_SH_ + fun:_ZSt22__uninitialized_copy_aIN9__gnu_cxx17__normal_iteratorIPSt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS3_6broker5QueueEEEESt6vectorISB_SaISB_EEEESG_SB_ET0_T_SI_SH_SaIT1_E + fun:_ZNSt6vectorISt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS1_6broker5QueueEEEESaIS9_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS9_SB_EERKS9_ + fun:_ZNSt6vectorISt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS1_6broker5QueueEEEESaIS9_EE9push_backERKS9_ + fun:_ZN4qpid6broker15HeadersExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv +} +{ + x17984_30 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIPN4qpid3sys16LFSessionContextEE8allocateEmPKv + fun:_ZNSt12_Vector_baseIPN4qpid3sys16LFSessionContextESaIS3_EE11_M_allocateEm + fun:_ZNSt6vectorIPN4qpid3sys16LFSessionContextESaIS3_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS3_S5_EERKS3_ + fun:_ZNSt6vectorIPN4qpid3sys16LFSessionContextESaIS3_EE9push_backERKS3_ + fun:_ZN4qpid3sys11LFProcessor3addEPK12apr_pollfd_t + fun:_ZN4qpid3sys11APRAcceptor3runEPNS0_21SessionHandlerFactoryE + fun:_ZN4qpid6broker6Broker3runEv + fun:main +} +{ + x17984_31 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZNSs4_Rep9_S_createEmmRKSaIcE + obj:/usr/lib/libstdc++.so.6.0.8 + fun:_ZNSsC1EPKcRKSaIcE + fun:_ZN4qpid6broker7ChannelC1ERNS_7framing15ProtocolVersionEPNS2_13OutputHandlerEijPNS0_12MessageStoreEm + fun:_ZN4qpid6broker18SessionHandlerImpl18ChannelHandlerImpl4openEtRKSs + fun:_ZN4qpid7framing15ChannelOpenBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid7framing16AMQP_ClientProxy7Channel6openOkEt + fun:_ZN4qpid6broker18SessionHandlerImpl18ChannelHandlerImpl4openEtRKSs + fun:_ZN4qpid7framing15ChannelOpenBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE +} +{ + x17984_32 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIN5boost10shared_ptrIN4qpid7framing14AMQContentBodyEEEE8allocateEmPKv + fun:_ZNSt12_Vector_baseIN5boost10shared_ptrIN4qpid7framing14AMQContentBodyEEESaIS5_EE11_M_allocateEm + fun:_ZNSt6vectorIN5boost10shared_ptrIN4qpid7framing14AMQContentBodyEEESaIS5_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS5_S7_EERKS5_ + fun:_ZNSt6vectorIN5boost10shared_ptrIN4qpid7framing14AMQContentBodyEEESaIS5_EE9push_backERKS5_ + fun:_ZN4qpid6broker15InMemoryContent3addEN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker7Message10addContentEN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker14MessageBuilder10addContentERN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker7Channel13handleContentEN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl13handleContentEtN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZNSs4_Rep9_S_createEmmRKSaIcE +} +{ + x17984_33 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid7framing14AMQContentBodyEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid7framing7AMQBodyEEC1INS2_14AMQContentBodyEEEPT_ + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone +} +{ + x17984_34 + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_calloc + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_2.2.5 + fun:_ZN4qpid3sys6ThreadC1EPNS0_8RunnableE + fun:_ZN4qpid6broker10AutoDelete5startEv + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsmj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_35 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid7framing14AMQContentBodyEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid7framing7AMQBodyEEC1INS2_14AMQContentBodyEEEPT_ + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZNSs4_Rep9_S_createEmmRKSaIcE + fun:_ZNSs9_M_mutateEmmm + fun:_ZNSs15_M_replace_safeEmmPKcm + fun:_ZN4qpid7framing6Buffer10getRawDataERSsj + fun:_ZN4qpid7framing14AMQContentBody6decodeERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE +} +{ + x17984_36 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid7framing13AMQHeaderBodyEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid7framing7AMQBodyEEC1INS2_13AMQHeaderBodyEEEPT_ + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__ZdlPv + fun:_ZN4qpid7framing16BasicPublishBodyD0Ev + fun:_ZN5boost14checked_deleteIN4qpid7framing13AMQMethodBodyEEEvPT_ + fun:_ZN5boost6detail17sp_counted_impl_pIN4qpid7framing13AMQMethodBodyEE7disposeEv + fun:_ZN5boost6detail15sp_counted_base7releaseEv + fun:_ZN5boost6detail12shared_countaSERKS1_ + fun:_ZN5boost10shared_ptrIN4qpid7framing7AMQBodyEEaSERKS4_ + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj +} +{ + x17984_37 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid6broker7MessageEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid6broker7MessageEEC1IS3_EEPT_ + fun:_ZN4qpid6broker7Channel13handlePublishEPNS0_7MessageEN5boost10shared_ptrINS0_8ExchangeEEE + fun:_ZN4qpid6broker18SessionHandlerImpl16BasicHandlerImpl7publishEttRKSsS4_bb + fun:_ZN4qpid7framing16BasicPublishBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_38 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker14MessageBuilder9setHeaderERN5boost10shared_ptrINS_7framing13AMQHeaderBodyEEE + fun:_ZN4qpid6broker7Channel12handleHeaderEN5boost10shared_ptrINS_7framing13AMQHeaderBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl12handleHeaderEtN5boost10shared_ptrINS_7framing13AMQHeaderBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_39 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_40 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN5boost6detail12shared_countC1IN4qpid6broker5QueueEEEPT_ + fun:_ZN5boost10shared_ptrIN4qpid6broker5QueueEEC1IS3_EEPT_ + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEEEE8allocateEmPKv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE11_M_get_nodeEv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE14_M_create_nodeERKS8_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE9_M_insertEPSt18_Rb_tree_node_baseSG_RKS8_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE13insert_uniqueERKS8_ +} +{ + x17984_41 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker5Queue9configureERKNS_7framing10FieldTableE + fun:_ZN4qpid6broker5Queue6createERKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIN5boost10shared_ptrIN4qpid6broker5QueueEEEE8allocateEmPKv + fun:_ZNSt12_Vector_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE11_M_allocateEm + fun:_ZNSt12_Vector_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EEC2EmRKS6_ + fun:_ZNSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EEC1ERKS7_ + fun:_ZNSt4pairIKSsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS7_EEEC1ERS0_RKS9_ + fun:_ZNSt3mapISsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS6_EESt4lessISsESaISt4pairIKSsS8_EEEixERSC_ +} +{ + x17984_42 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIN5boost10shared_ptrIN4qpid6broker5QueueEEEE8allocateEmPKv + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE16_M_allocate_nodeEv + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE15_M_create_nodesEPPS5_S9_ + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE17_M_initialize_mapEm + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EEC2ERKS6_m + fun:_ZNSt5dequeIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EEC1ERKS7_ + fun:_ZNSt5queueIN5boost10shared_ptrIN4qpid6broker5QueueEEESt5dequeIS5_SaIS5_EEEC1ERKS8_ + fun:_ZN4qpid6broker10AutoDeleteC1EPNS0_13QueueRegistryEj + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsmj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x17984_43 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKSsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaISA_EEEEE8allocateEmPKv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS8_EEESt10_Select1stISB_ESt4lessISsESaISB_EE11_M_get_nodeEv + fun:_ZNSt8_Rb_treeISsSt4pairIKSsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS8_EEESt10_Select1stISB_ESt4lessISsESaISB_EE14_M_create_nodeERKSB_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS8_EEESt10_Select1stISB_ESt4lessISsESaISB_EE9_M_insertEPSt18_Rb_tree_node_baseSJ_RKSB_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS8_EEESt10_Select1stISB_ESt4lessISsESaISB_EE13insert_uniqueERKSB_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS8_EEESt10_Select1stISB_ESt4lessISsESaISB_EE13insert_uniqueESt17_Rb_tree_iteratorISB_ERKSB_ + fun:_ZNSt3mapISsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS6_EESt4lessISsESaISt4pairIKSsS8_EEE6insertESt17_Rb_tree_iteratorISD_ERKSD_ + fun:_ZNSt3mapISsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS6_EESt4lessISsESaISt4pairIKSsS8_EEEixERSC_ + fun:_ZN4qpid6broker14DirectExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_44 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker18SessionHandlerImpl16BasicHandlerImpl7publishEttRKSsS4_bb + fun:_ZN4qpid7framing16BasicPublishBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_45 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker14DirectExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_46 + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_malloc + fun:__new_exitfn + fun:__cxa_atexit + fun:_Z41__static_initialization_and_destruction_0ii + fun:_GLOBAL__I__ZN4qpid6broker9TxPublishC2EN5boost10shared_ptrINS0_7MessageEEEPKSs + obj:/home_old/e/work/rh/rhn/messaging-clean/trunk/qpid-help2man/cpp/lib/broker/.libs/libqpidbroker.so.0.1.0 + obj:/home_old/e/work/rh/rhn/messaging-clean/trunk/qpid-help2man/cpp/lib/broker/.libs/libqpidbroker.so.0.1.0 + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_47 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIPN5boost10shared_ptrIN4qpid6broker7MessageEEEE8allocateEmPKv + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker7MessageEEESaIS5_EE15_M_allocate_mapEm + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker7MessageEEESaIS5_EE17_M_initialize_mapEm + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker7MessageEEESaIS5_EEC2ERKS6_m + fun:_ZNSt5dequeIN5boost10shared_ptrIN4qpid6broker7MessageEEESaIS5_EEC1ERKS7_ + fun:_ZNSt5queueIN5boost10shared_ptrIN4qpid6broker7MessageEEESt5dequeIS5_SaIS5_EEEC1ERKS8_ + fun:_ZN4qpid6broker5QueueC1ERKSsjPNS0_12MessageStoreEPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm +} +{ + x17984_48 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIPPN4qpid6broker7BindingEE8allocateEmPKv + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EE15_M_allocate_mapEm + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EE17_M_initialize_mapEm + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EEC2ERKS4_m + fun:_ZNSt5dequeIPN4qpid6broker7BindingESaIS3_EEC1ERKS5_ + fun:_ZNSt5queueIPN4qpid6broker7BindingESt5dequeIS3_SaIS3_EEEC1ERKS6_ + fun:_ZN4qpid6broker5QueueC1ERKSsjPNS0_12MessageStoreEPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm +} +{ + x17984_49 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKmPFPN4qpid7framing13AMQMethodBodyEhhEEEE8allocateEmPKv + fun:_ZNSt8_Rb_treeImSt4pairIKmPFPN4qpid7framing13AMQMethodBodyEhhEESt10_Select1stIS8_ESt4lessImESaIS8_EE11_M_get_nodeEv + fun:_ZNSt8_Rb_treeImSt4pairIKmPFPN4qpid7framing13AMQMethodBodyEhhEESt10_Select1stIS8_ESt4lessImESaIS8_EE14_M_create_nodeERKS8_ + fun:_ZNSt8_Rb_treeImSt4pairIKmPFPN4qpid7framing13AMQMethodBodyEhhEESt10_Select1stIS8_ESt4lessImESaIS8_EE9_M_insertEPSt18_Rb_tree_node_baseSG_RKS8_ + fun:_ZNSt8_Rb_treeImSt4pairIKmPFPN4qpid7framing13AMQMethodBodyEhhEESt10_Select1stIS8_ESt4lessImESaIS8_EE13insert_uniqueERKS8_ + fun:_ZNSt3mapImPFPN4qpid7framing13AMQMethodBodyEhhESt4lessImESaISt4pairIKmS5_EEE6insertERKSA_ + fun:_ZN4qpid7framing21AMQP_MethodVersionMapC1Ev + fun:_Z41__static_initialization_and_destruction_0ii + fun:_GLOBAL__I__ZN4qpid7framing8AMQFrame10versionMapE + obj:/home_old/e/work/rh/rhn/messaging-clean/trunk/qpid-help2man/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + obj:/home_old/e/work/rh/rhn/messaging-clean/trunk/qpid-help2man/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKmPFPN4qpid7framing13AMQMethodBodyEhhEEEE8allocateEmPKv + fun:_ZNSt8_Rb_treeImSt4pairIKmPFPN4qpid7framing13AMQMethodBodyEhhEESt10_Select1stIS8_ESt4lessImESaIS8_EE11_M_get_nodeEv + fun:_ZNSt8_Rb_treeImSt4pairIKmPFPN4qpid7framing13AMQMethodBodyEhhEESt10_Select1stIS8_ESt4lessImESaIS8_EE14_M_create_nodeERKS8_ + fun:_ZNSt8_Rb_treeImSt4pairIKmPFPN4qpid7framing13AMQMethodBodyEhhEESt10_Select1stIS8_ESt4lessImESaIS8_EE9_M_insertEPSt18_Rb_tree_node_baseSG_RKS8_ + fun:_ZNSt8_Rb_treeImSt4pairIKmPFPN4qpid7framing13AMQMethodBodyEhhEESt10_Select1stIS8_ESt4lessImESaIS8_EE13insert_uniqueERKS8_ +} +{ + x17984_50 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid7framing13AMQHeaderBody16createPropertiesEi + fun:_ZN4qpid7framing13AMQHeaderBody6decodeERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_51 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker18SessionHandlerImpl18ChannelHandlerImpl4openEtRKSs + fun:_ZN4qpid7framing15ChannelOpenBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZNSs4_Rep9_S_createEmmRKSaIcE + obj:/usr/lib/libstdc++.so.6.0.8 + fun:_ZNSsC1EPKcRKSaIcE + fun:_ZN4qpid6broker7ChannelC1ERNS_7framing15ProtocolVersionEPNS2_13OutputHandlerEijPNS0_12MessageStoreEm + fun:_ZN4qpid6broker18SessionHandlerImpl18ChannelHandlerImpl4openEtRKSs + fun:_ZN4qpid7framing15ChannelOpenBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv +} +{ + x17984_52 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZNSs4_Rep9_S_createEmmRKSaIcE + obj:/usr/lib/libstdc++.so.6.0.8 + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z41__static_initialization_and_destruction_0ii + fun:_GLOBAL__I__ZN4qpid6broker6TokensaSERKSs + obj:/home_old/e/work/rh/rhn/messaging-clean/trunk/qpid-help2man/cpp/lib/broker/.libs/libqpidbroker.so.0.1.0 + obj:/home_old/e/work/rh/rhn/messaging-clean/trunk/qpid-help2man/cpp/lib/broker/.libs/libqpidbroker.so.0.1.0 + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_53 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIPPN4qpid6broker7BindingEE8allocateEmPKv + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EE15_M_allocate_mapEm + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EE17_M_initialize_mapEm + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EEC2ERKS4_m + fun:_ZNSt5dequeIPN4qpid6broker7BindingESaIS3_EEC1ERKS4_ + fun:_ZN4qpid6broker5QueueC1ERKSsjPNS0_12MessageStoreEPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE +} +{ + x17984_54 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIN5boost10shared_ptrIN4qpid6broker7MessageEEEE8allocateEmPKv + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker7MessageEEESaIS5_EE16_M_allocate_nodeEv + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker7MessageEEESaIS5_EE15_M_create_nodesEPPS5_S9_ + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker7MessageEEESaIS5_EE17_M_initialize_mapEm + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker7MessageEEESaIS5_EEC2ERKS6_m + fun:_ZNSt5dequeIN5boost10shared_ptrIN4qpid6broker7MessageEEESaIS5_EEC1ERKS7_ + fun:_ZNSt5queueIN5boost10shared_ptrIN4qpid6broker7MessageEEESt5dequeIS5_SaIS5_EEEC1ERKS8_ + fun:_ZN4qpid6broker5QueueC1ERKSsjPNS0_12MessageStoreEPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_55 + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwm + fun:_ZN9__gnu_cxx13new_allocatorIPN4qpid6broker7BindingEE8allocateEmPKv + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EE16_M_allocate_nodeEv + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EE15_M_create_nodesEPPS3_S7_ + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EE17_M_initialize_mapEm + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EEC2ERKS4_m + fun:_ZNSt5dequeIPN4qpid6broker7BindingESaIS3_EEC1ERKS5_ + fun:_ZNSt5queueIPN4qpid6broker7BindingESt5dequeIS3_SaIS3_EEEC1ERKS6_ + fun:_ZN4qpid6broker5QueueC1ERKSsjPNS0_12MessageStoreEPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_56 + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_malloc + fun:apr_pool_create_ex + fun:apr_pool_initialize + fun:apr_initialize + fun:_ZN4qpid3sys7APRBaseC1Ev + fun:_ZN4qpid3sys7APRBase11getInstanceEv + fun:_ZN4qpid3sys7APRBase9incrementEv + fun:_ZN4qpid3sys7APRPoolC1Ev + fun:_ZN5boost7details4pool17singleton_defaultIN4qpid3sys7APRPoolEE8instanceEv + fun:_ZN4qpid3sys7APRPool3getEv + fun:_Z41__static_initialization_and_destruction_0ii + obj:/home_old/e/work/rh/rhn/messaging-clean/trunk/qpid-help2man/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + obj:/home_old/e/work/rh/rhn/messaging-clean/trunk/qpid-help2man/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + obj:* + obj:* + obj:* + obj:* +} +{ + x17984_57 + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_malloc + fun:apr_palloc + fun:apr_pollset_create + fun:_ZN4qpid3sys11LFProcessorC1EP10apr_pool_tiii + fun:_ZN4qpid3sys11APRAcceptorC1Esiib + fun:_ZN4qpid3sys8Acceptor6createEsiib + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} + +{ + x7393_1 + Memcheck:Leak + fun:_Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_2 + Memcheck:Leak + fun:_Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs +} +{ + x7393_3 + Memcheck:Leak + fun:_Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_4 + Memcheck:Leak + fun:_Znwj + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_5 + Memcheck:Leak + fun:_Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + fun:_Z8runTestsRK17CommandLineParser +} +{ + x7393_6 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE15_M_create_nodesEPPS5_S9_ + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE17_M_initialize_mapEj + fun:_ZN4qpid6broker10AutoDeleteC1EPNS0_13QueueRegistryEj + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsyj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x7393_7 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_8 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker14MessageBuilder9setHeaderERN5boost10shared_ptrINS_7framing13AMQHeaderBodyEEE + fun:_ZN4qpid6broker7Channel12handleHeaderEN5boost10shared_ptrINS_7framing13AMQHeaderBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl12handleHeaderEtN5boost10shared_ptrINS_7framing13AMQHeaderBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_9 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker7Channel13handlePublishEPNS0_7MessageEN5boost10shared_ptrINS0_8ExchangeEEE + fun:_ZN4qpid6broker18SessionHandlerImpl16BasicHandlerImpl7publishEttRKSsS4_bb + fun:_ZN4qpid7framing16BasicPublishBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_10 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker18SessionHandlerImplC1EPNS_3sys14SessionContextEPNS0_13QueueRegistryEPNS0_16ExchangeRegistryEPNS0_10AutoDeleteERKNS0_8SettingsE + fun:_ZN4qpid6broker25SessionHandlerFactoryImpl6createEPNS_3sys14SessionContextE + fun:_ZN4qpid3sys11APRAcceptor3runEPNS0_21SessionHandlerFactoryE + fun:_ZN4qpid6broker6Broker3runEv + fun:main +} +{ + x7393_11 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE9_M_insertEPSt18_Rb_tree_node_baseSG_RKS8_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE13insert_uniqueERKS8_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker5QueueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE13insert_uniqueESt17_Rb_tree_iteratorIS8_ERKS8_ + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_12 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS5_S7_EERKS5_ + fun:_ZN4qpid6broker14DirectExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_13 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt8_Rb_treeItSt4pairIKtPN4qpid6broker7ChannelEESt10_Select1stIS6_ESt4lessItESaIS6_EE9_M_insertEPSt18_Rb_tree_node_baseSE_RKS6_ + fun:_ZNSt8_Rb_treeItSt4pairIKtPN4qpid6broker7ChannelEESt10_Select1stIS6_ESt4lessItESaIS6_EE13insert_uniqueERKS6_ + fun:_ZNSt8_Rb_treeItSt4pairIKtPN4qpid6broker7ChannelEESt10_Select1stIS6_ESt4lessItESaIS6_EE13insert_uniqueESt17_Rb_tree_iteratorIS6_ERKS6_ + fun:_ZN4qpid6broker18SessionHandlerImpl18ChannelHandlerImpl4openEtRKSs + fun:_ZN4qpid7framing15ChannelOpenBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_14 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_15 + Memcheck:Leak + fun:calloc + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_2.1 + fun:apr_thread_create + fun:_ZN4qpid6broker10AutoDelete5startEv + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsyj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x7393_16 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt8_Rb_treeISsSt4pairIKSsPN4qpid6broker7Channel12ConsumerImplEESt10_Select1stIS7_ESt4lessISsESaIS7_EE9_M_insertEPSt18_Rb_tree_node_baseSF_RKS7_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsPN4qpid6broker7Channel12ConsumerImplEESt10_Select1stIS7_ESt4lessISsESaIS7_EE13insert_uniqueERKS7_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsPN4qpid6broker7Channel12ConsumerImplEESt10_Select1stIS7_ESt4lessISsESaIS7_EE13insert_uniqueESt17_Rb_tree_iteratorIS7_ERKS7_ + fun:_ZN4qpid6broker7Channel7consumeERSsN5boost10shared_ptrINS0_5QueueEEEbbPNS0_15ConnectionTokenEPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16BasicHandlerImpl7consumeEttRKSsS4_bbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16BasicConsumeBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_17 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker7Channel7consumeERSsN5boost10shared_ptrINS0_5QueueEEEbbPNS0_15ConnectionTokenEPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16BasicHandlerImpl7consumeEttRKSsS4_bbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16BasicConsumeBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_18 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker5Queue9configureERKNS_7framing10FieldTableE + fun:_ZN4qpid6broker5Queue6createERKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_19 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker7Channel7deliverERN5boost10shared_ptrINS0_7MessageEEERKSsRNS3_INS0_5QueueEEEb + fun:_ZN4qpid6broker7Channel12ConsumerImpl7deliverERN5boost10shared_ptrINS0_7MessageEEE + fun:_ZN4qpid6broker5Queue8dispatchERN5boost10shared_ptrINS0_7MessageEEE + fun:_ZN4qpid6broker5Queue8dispatchEv + fun:_ZN4qpid6broker18SessionHandlerImpl16BasicHandlerImpl7consumeEttRKSsS4_bbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16BasicConsumeBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_20 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt11_Deque_baseIPN4qpid7framing8AMQFrameESaIS3_EE17_M_initialize_mapEj + fun:_ZN4qpid3sys16LFSessionContextC1EP10apr_pool_tP12apr_socket_tPNS0_11LFProcessorEb + fun:_ZN4qpid3sys11APRAcceptor3runEPNS0_21SessionHandlerFactoryE + fun:_ZN4qpid6broker6Broker3runEv + fun:main +} +{ + x7393_21 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt8_Rb_treeISsSt4pairIKSsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS8_EEESt10_Select1stISB_ESt4lessISsESaISB_EE9_M_insertEPSt18_Rb_tree_node_baseSJ_RKSB_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS8_EEESt10_Select1stISB_ESt4lessISsESaISB_EE13insert_uniqueERKSB_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS8_EEESt10_Select1stISB_ESt4lessISsESaISB_EE13insert_uniqueESt17_Rb_tree_iteratorISB_ERKSB_ + fun:_ZNSt3mapISsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS6_EESt4lessISsESaISt4pairIKSsS8_EEEixERSC_ + fun:_ZN4qpid6broker14DirectExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_22 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker14DirectExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_23 + Memcheck:Leak + fun:calloc + fun:__new_exitfn + fun:__cxa_atexit + fun:_Z41__static_initialization_and_destruction_0ii + obj:/home/gordon/qpid/trunk/qpid/cpp/lib/broker/.libs/libqpidbroker.so.0.1.0 + obj:/home/gordon/qpid/trunk/qpid/cpp/lib/broker/.libs/libqpidbroker.so.0.1.0 + fun:call_init + fun:_dl_init + obj:/lib/ld-2.4.so +} +{ + x7393_24 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker7MessageEEESaIS5_EE17_M_initialize_mapEj + fun:_ZN4qpid6broker5QueueC1ERKSsjPNS0_12MessageStoreEPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_25 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EE17_M_initialize_mapEj + fun:_ZN4qpid6broker5QueueC1ERKSsjPNS0_12MessageStoreEPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_26 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker18SessionHandlerImpl16BasicHandlerImpl7publishEttRKSsS4_bb + fun:_ZN4qpid7framing16BasicPublishBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_27 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt8_Rb_treeIySt4pairIKyPFPN4qpid7framing13AMQMethodBodyEhhEESt10_Select1stIS8_ESt4lessIyESaIS8_EE9_M_insertEPSt18_Rb_tree_node_baseSG_RKS8_ + fun:_ZNSt8_Rb_treeIySt4pairIKyPFPN4qpid7framing13AMQMethodBodyEhhEESt10_Select1stIS8_ESt4lessIyESaIS8_EE13insert_uniqueERKS8_ + fun:_ZN4qpid7framing21AMQP_MethodVersionMapC1Ev + fun:_Z41__static_initialization_and_destruction_0ii + obj:/home/gordon/qpid/trunk/qpid/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + obj:/home/gordon/qpid/trunk/qpid/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + fun:call_init + fun:_dl_init + obj:/lib/ld-2.4.so +} +{ + x7393_28 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid7framing13AMQHeaderBody16createPropertiesEi + fun:_ZN4qpid7framing13AMQHeaderBody6decodeERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_29 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker18SessionHandlerImpl18ChannelHandlerImpl4openEtRKSs + fun:_ZN4qpid7framing15ChannelOpenBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_30 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker25SessionHandlerFactoryImpl6createEPNS_3sys14SessionContextE + fun:_ZN4qpid3sys11APRAcceptor3runEPNS0_21SessionHandlerFactoryE + fun:_ZN4qpid6broker6Broker3runEv + fun:main +} +{ + x7393_31 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid3sys11APRAcceptor3runEPNS0_21SessionHandlerFactoryE + fun:_ZN4qpid6broker6Broker3runEv + fun:main +} +{ + x7393_32 + Memcheck:Leak + fun:_Znwj + fun:_ZNSs4_Rep9_S_createEjjRKSaIcE + obj:/usr/lib/libstdc++.so.6.0.8 + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z41__static_initialization_and_destruction_0ii + obj:/home/gordon/qpid/trunk/qpid/cpp/lib/broker/.libs/libqpidbroker.so.0.1.0 + obj:/home/gordon/qpid/trunk/qpid/cpp/lib/broker/.libs/libqpidbroker.so.0.1.0 + fun:call_init + fun:_dl_init + obj:/lib/ld-2.4.so +} +{ + x7393_33 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker18SessionHandlerImpl9initiatedEPNS_7framing18ProtocolInitiationE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_34 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt11_Deque_baseIPN4qpid7framing8AMQFrameESaIS3_EE15_M_create_nodesEPPS3_S7_ + fun:_ZNSt11_Deque_baseIPN4qpid7framing8AMQFrameESaIS3_EE17_M_initialize_mapEj + fun:_ZN4qpid3sys16LFSessionContextC1EP10apr_pool_tP12apr_socket_tPNS0_11LFProcessorEb + fun:_ZN4qpid3sys11APRAcceptor3runEPNS0_21SessionHandlerFactoryE + fun:_ZN4qpid6broker6Broker3runEv + fun:main +} +{ + x7393_35 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker7MessageEEESaIS5_EE15_M_create_nodesEPPS5_S9_ + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker7MessageEEESaIS5_EE17_M_initialize_mapEj + fun:_ZN4qpid6broker5QueueC1ERKSsjPNS0_12MessageStoreEPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_36 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EE15_M_create_nodesEPPS3_S7_ + fun:_ZNSt11_Deque_baseIPN4qpid6broker7BindingESaIS3_EE17_M_initialize_mapEj + fun:_ZN4qpid6broker5QueueC1ERKSsjPNS0_12MessageStoreEPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker13QueueRegistry7declareERKSsbjPKNS0_15ConnectionTokenE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl7declareEttRKSsbbbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16QueueDeclareBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_37 + Memcheck:Leak + fun:malloc + fun:apr_palloc + fun:apr_pollset_create + fun:_ZN4qpid3sys11LFProcessorC1EP10apr_pool_tiii + fun:_ZN4qpid3sys11APRAcceptorC1Esiib + fun:_ZN4qpid3sys8Acceptor6createEsiib + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x7393_38 + Memcheck:Leak + fun:malloc + fun:apr_pool_create_ex + fun:apr_pool_initialize + fun:apr_initialize + fun:_ZN4qpid3sys7APRBaseC1Ev + fun:_ZN4qpid3sys7APRBase11getInstanceEv + fun:_ZN4qpid3sys7APRBase9incrementEv + fun:_ZN4qpid3sys7APRPoolC1Ev + fun:_ZN4qpid3sys7APRPool3getEv + fun:_Z41__static_initialization_and_destruction_0ii + obj:/home/gordon/qpid/trunk/qpid/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + obj:/home/gordon/qpid/trunk/qpid/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + fun:call_init + fun:_dl_init + obj:/lib/ld-2.4.so +} +{ + x7393_39 + Memcheck:Leak + fun:_Znaj + fun:_ZN4qpid7framing6BufferC1Ej + fun:_ZN4qpid3sys16LFSessionContextC1EP10apr_pool_tP12apr_socket_tPNS0_11LFProcessorEb + fun:_ZN4qpid3sys11APRAcceptor3runEPNS0_21SessionHandlerFactoryE + fun:_ZN4qpid6broker6Broker3runEv + fun:main +} +{ + x7393_40 + Memcheck:Leak + fun:_Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_41 + Memcheck:Leak + fun:malloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object + fun:openaux + fun:_dl_catch_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_42 + Memcheck:Leak + fun:malloc + fun:_dl_map_object + fun:openaux + fun:_dl_catch_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_43 + Memcheck:Leak + fun:malloc + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_44 + Memcheck:Leak + fun:_Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_45 + Memcheck:Leak + fun:realloc + fun:add_to_global + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_46 + Memcheck:Leak + fun:realloc + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_47 + Memcheck:Leak + fun:calloc + fun:_dl_check_map_versions + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_48 + Memcheck:Leak + fun:_Znwj + fun:_ZNSs4_Rep9_S_createEjjRKSaIcE + obj:/usr/lib/libstdc++.so.6.0.8 + fun:_ZNSsC1EPKcRKSaIcE + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_49 + Memcheck:Leak + fun:calloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object + fun:openaux + fun:_dl_catch_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + fun:_Z8runTestsRK17CommandLineParser + fun:main +} +{ + x7393_50 + Memcheck:Leak + fun:_Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE +} +{ + x7393_51 + Memcheck:Param + epoll_ctl(event) + fun:epoll_ctl + fun:_ZN4qpid3sys11LFProcessor3addEPK12apr_pollfd_t + fun:_ZN4qpid3sys16LFSessionContext4initEPNS0_14SessionHandlerE + fun:_ZN4qpid3sys11APRAcceptor3runEPNS0_21SessionHandlerFactoryE + fun:_ZN4qpid6broker6Broker3runEv + fun:main +} +{ + x7393_52 + Memcheck:Param + epoll_ctl(event) + fun:epoll_ctl + fun:_ZN4qpid3sys11LFProcessor10reactivateEPK12apr_pollfd_t + fun:_ZN4qpid3sys16LFSessionContext14stopProcessingEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_53 + Memcheck:Param + epoll_ctl(event) + fun:epoll_ctl + fun:_ZN4qpid3sys11LFProcessor6updateEPK12apr_pollfd_t + fun:_ZN4qpid3sys16LFSessionContext4sendEPNS_7framing8AMQFrameE + fun:_ZN4qpid6broker7Message7deliverEPNS_7framing13OutputHandlerEiRKSsyjPNS2_15ProtocolVersionE + fun:_ZN4qpid6broker7Channel7deliverERN5boost10shared_ptrINS0_7MessageEEERKSsRNS3_INS0_5QueueEEEb + fun:_ZN4qpid6broker7Channel12ConsumerImpl7deliverERN5boost10shared_ptrINS0_7MessageEEE + fun:_ZN4qpid6broker5Queue8dispatchERN5boost10shared_ptrINS0_7MessageEEE + fun:_ZN4qpid6broker5Queue7processERN5boost10shared_ptrINS0_7MessageEEE + fun:_ZN4qpid6broker5Queue7deliverERN5boost10shared_ptrINS0_7MessageEEE + fun:_ZN4qpid6broker18DeliverableMessage9deliverToERN5boost10shared_ptrINS0_5QueueEEE + fun:_ZN4qpid6broker15HeadersExchange5routeERNS0_11DeliverableERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker7Channel8completeERN5boost10shared_ptrINS0_7MessageEEE + fun:_ZN4qpid6broker14MessageBuilder5routeEv + fun:_ZN4qpid6broker14MessageBuilder10addContentERN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker7Channel13handleContentEN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl13handleContentEtN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_54 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt8_Rb_treeISsSt4pairIKSsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS8_EEESt10_Select1stISB_ESt4lessISsESaISB_EE9_M_insertEPSt18_Rb_tree_node_baseSJ_RKSB_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS8_EEESt10_Select1stISB_ESt4lessISsESaISB_EE13insert_uniqueESt17_Rb_tree_iteratorISB_ERKSB_ + fun:_ZNSt3mapISsSt6vectorIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS6_EESt4lessISsESaISt4pairIKSsS8_EEEixERSC_ + fun:_ZN4qpid6broker14DirectExchange5routeERNS0_11DeliverableERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker7Channel8completeERN5boost10shared_ptrINS0_7MessageEEE + fun:_ZN4qpid6broker14MessageBuilder5routeEv + fun:_ZN4qpid6broker14MessageBuilder10addContentERN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker7Channel13handleContentEN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl13handleContentEtN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_55 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsyj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x7393_56 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid3sys7APRBase11getInstanceEv + fun:_ZN4qpid3sys7APRBase9incrementEv + fun:_ZN4qpid3sys7APRPoolC1Ev + fun:_ZN4qpid3sys7APRPool3getEv + fun:_Z41__static_initialization_and_destruction_0ii + obj:/home/gordon/qpid/trunk/qpid/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + obj:/home/gordon/qpid/trunk/qpid/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + fun:call_init + fun:_dl_init + obj:/lib/ld-2.4.so +} +{ + x7393_57 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x7393_58 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker16ExchangeRegistry7declareERKSsS3_ + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsyj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x7393_59 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid3sys8Acceptor6createEsiib + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x7393_60 + Memcheck:Leak + fun:_Znaj + fun:_ZN4qpid3sys11LFProcessorC1EP10apr_pool_tiii + fun:_ZN4qpid3sys11APRAcceptorC1Esiib + fun:_ZN4qpid3sys8Acceptor6createEsiib + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x7393_61 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid7framing5Value12decode_valueERNS0_6BufferE + fun:_ZN4qpid7framing10FieldTable6decodeERNS0_6BufferE + fun:_ZN4qpid7framing6Buffer13getFieldTableERNS0_10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody13decodeContentERNS0_6BufferE + fun:_ZN4qpid7framing13AMQMethodBody6decodeERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_62 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker7Channel8completeERN5boost10shared_ptrINS0_7MessageEEE + fun:_ZN4qpid6broker14MessageBuilder5routeEv + fun:_ZN4qpid6broker14MessageBuilder10addContentERN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker7Channel13handleContentEN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl13handleContentEtN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_63 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt8_Rb_treeIN4qpid6broker12TopicPatternESt4pairIKS2_St6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS9_EEESt10_Select1stISC_ESt4lessIS2_ESaISC_EE9_M_insertEPSt18_Rb_tree_node_baseSK_RKSC_ + fun:_ZNSt8_Rb_treeIN4qpid6broker12TopicPatternESt4pairIKS2_St6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS9_EEESt10_Select1stISC_ESt4lessIS2_ESaISC_EE13insert_uniqueERKSC_ + fun:_ZNSt8_Rb_treeIN4qpid6broker12TopicPatternESt4pairIKS2_St6vectorIN5boost10shared_ptrINS1_5QueueEEESaIS9_EEESt10_Select1stISC_ESt4lessIS2_ESaISC_EE13insert_uniqueESt17_Rb_tree_iteratorISC_ERKSC_ + fun:_ZN4qpid6broker13TopicExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_64 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt11_Deque_baseIN5boost10shared_ptrIN4qpid6broker5QueueEEESaIS5_EE17_M_initialize_mapEj + fun:_ZN4qpid6broker10AutoDeleteC1EPNS0_13QueueRegistryEj + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsyj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x7393_65 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt6vectorIPN4qpid6broker13Configuration6OptionESaIS4_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS4_S6_EERKS4_ + fun:_ZN4qpid6broker13ConfigurationC1Ev + fun:main +} +{ + x7393_66 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid7framing5ValueEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE7_M_copyEPKSt13_Rb_tree_nodeIS8_EPSG_ + fun:_ZNSt6vectorISt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS1_6broker5QueueEEEESaIS9_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS9_SB_EERKS9_ + fun:_ZN4qpid6broker15HeadersExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_67 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker14FanOutExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_68 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker15HeadersExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_69 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt6vectorIPN4qpid6broker4TxOpESaIS3_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS3_S5_EERKS3_ + fun:_ZN4qpid6broker8TxBuffer6enlistEPNS0_4TxOpE + fun:_ZN4qpid6broker7Channel8completeERN5boost10shared_ptrINS0_7MessageEEE + fun:_ZN4qpid6broker14MessageBuilder5routeEv + fun:_ZN4qpid6broker14MessageBuilder10addContentERN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker7Channel13handleContentEN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl13handleContentEtN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_70 + Memcheck:Leak + fun:malloc + fun:apr_allocator_create + fun:apr_pool_initialize + fun:apr_initialize + fun:_ZN4qpid3sys7APRBaseC1Ev + fun:_ZN4qpid3sys7APRBase11getInstanceEv + fun:_ZN4qpid3sys7APRBase9incrementEv + fun:_ZN4qpid3sys7APRPoolC1Ev + fun:_ZN4qpid3sys7APRPool3getEv + fun:_Z41__static_initialization_and_destruction_0ii + obj:/home/gordon/qpid/trunk/qpid/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + obj:/home/gordon/qpid/trunk/qpid/cpp/lib/common/.libs/libqpidcommon.so.0.1.0 + fun:call_init + fun:_dl_init + obj:/lib/ld-2.4.so +} +{ + x7393_71 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid6broker13TopicExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_72 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt6vectorISt4pairIN4qpid7framing10FieldTableEN5boost10shared_ptrINS1_6broker5QueueEEEESaIS9_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS9_SB_EERKS9_ + fun:_ZN4qpid6broker15HeadersExchange4bindEN5boost10shared_ptrINS0_5QueueEEERKSsPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16QueueHandlerImpl4bindEttRKSsS4_S4_bRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_73 + Memcheck:Leak + fun:_Znwj + fun:_ZN4qpid7framing10FieldTable6decodeERNS0_6BufferE + fun:_ZN4qpid7framing6Buffer13getFieldTableERNS0_10FieldTableE + fun:_ZN4qpid7framing13QueueBindBody13decodeContentERNS0_6BufferE + fun:_ZN4qpid7framing13AMQMethodBody6decodeERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame10decodeBodyERNS0_6BufferEj + fun:_ZN4qpid7framing8AMQFrame6decodeERNS0_6BufferE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_74 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt6vectorIPN4qpid6broker8ConsumerESaIS3_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS3_S5_EERKS3_ + fun:_ZN4qpid6broker5Queue7consumeEPNS0_8ConsumerEb + fun:_ZN4qpid6broker7Channel7consumeERSsN5boost10shared_ptrINS0_5QueueEEEbbPNS0_15ConnectionTokenEPKNS_7framing10FieldTableE + fun:_ZN4qpid6broker18SessionHandlerImpl16BasicHandlerImpl7consumeEttRKSsS4_bbbbRKNS_7framing10FieldTableE + fun:_ZN4qpid7framing16BasicConsumeBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_75 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker8ExchangeEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE9_M_insertEPSt18_Rb_tree_node_baseSG_RKS8_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker8ExchangeEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE13insert_uniqueERKS8_ + fun:_ZNSt8_Rb_treeISsSt4pairIKSsN5boost10shared_ptrIN4qpid6broker8ExchangeEEEESt10_Select1stIS8_ESt4lessISsESaIS8_EE13insert_uniqueESt17_Rb_tree_iteratorIS8_ERKS8_ + fun:_ZNSt3mapISsN5boost10shared_ptrIN4qpid6broker8ExchangeEEESt4lessISsESaISt4pairIKSsS5_EEEixERS9_ + fun:_ZN4qpid6broker16ExchangeRegistry7declareERKSsS3_ + fun:_ZN4qpid6broker25SessionHandlerFactoryImplC1ERKSsyj + fun:_ZN4qpid6broker6BrokerC1ERKNS0_13ConfigurationE + fun:_ZN4qpid6broker6Broker6createERKNS0_13ConfigurationE + fun:main +} +{ + x7393_76 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt6vectorIPN4qpid3sys16LFSessionContextESaIS3_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS3_S5_EERKS3_ + fun:_ZN4qpid3sys11LFProcessor3addEPK12apr_pollfd_t + fun:_ZN4qpid3sys16LFSessionContext4initEPNS0_14SessionHandlerE + fun:_ZN4qpid3sys11APRAcceptor3runEPNS0_21SessionHandlerFactoryE + fun:_ZN4qpid6broker6Broker3runEv + fun:main +} +{ + x7393_77 + Memcheck:Leak + fun:_Znwj + fun:_ZNSt6vectorIN5boost10shared_ptrIN4qpid7framing14AMQContentBodyEEESaIS5_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS5_S7_EERKS5_ + fun:_ZN4qpid6broker15InMemoryContent3addEN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker7Message10addContentEN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker14MessageBuilder10addContentERN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker7Channel13handleContentEN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl13handleContentEtN5boost10shared_ptrINS_7framing14AMQContentBodyEEE + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + x7393_78 + Memcheck:Leak + fun:_Znwj + fun:_ZNSs4_Rep9_S_createEjjRKSaIcE + obj:/usr/lib/libstdc++.so.6.0.8 + fun:_ZNSsC1EPKcRKSaIcE + fun:_ZN4qpid6broker7ChannelC1ERNS_7framing15ProtocolVersionEPNS2_13OutputHandlerEijPNS0_12MessageStoreEy + fun:_ZN4qpid6broker18SessionHandlerImpl18ChannelHandlerImpl4openEtRKSs + fun:_ZN4qpid7framing15ChannelOpenBody6invokeERNS0_21AMQP_ServerOperationsEt + fun:_ZN4qpid6broker18SessionHandlerImpl8receivedEPNS_7framing8AMQFrameE + fun:_ZN4qpid3sys16LFSessionContext4readEv + fun:_ZN4qpid3sys11LFProcessor3runEv + fun:_ZN4qpid3sys6Thread11runRunnableEP12apr_thread_tPv + fun:dummy_worker + fun:start_thread + fun:clone +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + fun:_ZNSs4_Rep9_S_createEjjRKSaIcE + obj:/usr/lib/libstdc++.so.6.0.8 + fun:_ZNSsC1EPKcRKSaIcE + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_malloc + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:do_dlopen + fun:_dl_catch_error + fun:__libc_dlopen_mode + fun:pthread_cancel_init + fun:_Unwind_ForcedUnwind + fun:__pthread_unwind + fun:pthread_exit + fun:pthread_exit + obj:* + obj:* + obj:* + fun:start_thread + fun:clone + obj:* + obj:* + obj:* + obj:* +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_malloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object + fun:openaux + fun:_dl_catch_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_malloc + fun:_dl_map_object + fun:openaux + fun:_dl_catch_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_malloc + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_realloc + fun:add_to_global + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_realloc + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_calloc + fun:_dl_check_map_versions + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libcZdsoZa_calloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object + fun:openaux + fun:_dl_catch_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + fun:_ZNSs4_Rep9_S_createEjjRKSaIcE + obj:/usr/lib/libstdc++.so.6.0.8 + fun:_ZNSsC1EPKcRKSaIcE + obj:* + obj:* + obj:* + obj:* + fun:call_init + fun:_dl_init + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@GLIBC_2.0 + fun:_ZN7CppUnit21DynamicLibraryManager13doLoadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManager11loadLibraryERKSs + fun:_ZN7CppUnit21DynamicLibraryManagerC1ERKSs + fun:_ZN7CppUnit13PlugInManager4loadERKSsRKNS_16PlugInParametersE + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* + fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE + fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit27TestSuiteBuilderContextBase15makeTestFixtureEv + obj:* + obj:* + obj:* + obj:* +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + fun:_ZNK7CppUnit21TestCaseMethodFunctorclEv + fun:_ZN7CppUnit16DefaultProtector7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZNK7CppUnit14ProtectorChain14ProtectFunctorclEv + fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE + fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKSs + fun:_ZN7CppUnit8TestCase3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite15doRunChildTestsEPNS_10TestResultE + fun:_ZN7CppUnit13TestComposite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestRunner13WrappingSuite3runEPNS_10TestResultE + fun:_ZN7CppUnit10TestResult7runTestEPNS_4TestE + fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKSs + obj:/usr/bin/DllPlugInTester + obj:/usr/bin/DllPlugInTester + fun:__libc_start_main +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* +} +{ + == NOT YET INVESTIGATED == + Memcheck:Leak + fun:_vgrZU_libstdcZpZpZa__Znwj + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* +} diff --git a/qpid/cpp-0-9/tests/APRBaseTest.cpp b/qpid/cpp-0-9/tests/APRBaseTest.cpp new file mode 100644 index 0000000000..7d95c3bf52 --- /dev/null +++ b/qpid/cpp-0-9/tests/APRBaseTest.cpp @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <apr/APRBase.h> +#include <qpid_test_plugin.h> +#include <iostream> + +using namespace qpid::sys; + +class APRBaseTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(APRBaseTest); + CPPUNIT_TEST(testMe); + CPPUNIT_TEST_SUITE_END(); + + public: + + void testMe() + { + APRBase::increment(); + APRBase::increment(); + APRBase::decrement(); + APRBase::decrement(); + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(APRBaseTest); + diff --git a/qpid/cpp-0-9/tests/AcceptorTest.cpp b/qpid/cpp-0-9/tests/AcceptorTest.cpp new file mode 100644 index 0000000000..34a51888d4 --- /dev/null +++ b/qpid/cpp-0-9/tests/AcceptorTest.cpp @@ -0,0 +1,95 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <iostream> +#include <boost/bind.hpp> + +#include "sys/Thread.h" +#include "sys/Acceptor.h" +#include "sys/Socket.h" +#include "framing/Buffer.h" +#include "qpid_test_plugin.h" + +#include "MockConnectionInputHandler.h" + +using namespace qpid::sys; +using namespace qpid::framing; +using namespace std; + +const char hello[] = "hello"; +const size_t size = sizeof(hello); + + +class AcceptorTest : public CppUnit::TestCase, private Runnable +{ + CPPUNIT_TEST_SUITE(AcceptorTest); + CPPUNIT_TEST(testAccept); + CPPUNIT_TEST_SUITE_END(); + + private: + MockConnectionInputHandlerFactory factory; + Acceptor::shared_ptr acceptor; + + public: + + void run() { + acceptor->run(factory); + } + + void setUp() { + acceptor = Acceptor::create(0, 10, 3); + } + + void tearDown() { + acceptor.reset(); + } + + void testAccept() + { + int port = acceptor->getPort(); + CPPUNIT_ASSERT(port > 0); + Thread runThread(*this); + // Connect to the acceptor + Socket client = Socket::createTcp(); + client.connect("localhost", port); + factory.waitForHandler(); + CPPUNIT_ASSERT(factory.handler != 0); + // Send a protocol initiation. + Buffer buf(1024); + ProtocolInitiation(4,2).encode(buf); + buf.flip(); + client.send(buf.start(), buf.available()); + + // Verify session handler got the protocol init. + ProtocolInitiation init = factory.handler->waitForProtocolInit(); + CPPUNIT_ASSERT_EQUAL(int(4), int(init.getMajor())); + CPPUNIT_ASSERT_EQUAL(int(2), int(init.getMinor())); + + acceptor->shutdown(); + runThread.join(); + factory.handler->waitForClosed(); + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(AcceptorTest); + diff --git a/qpid/cpp-0-9/tests/AccumulatedAckTest.cpp b/qpid/cpp-0-9/tests/AccumulatedAckTest.cpp new file mode 100644 index 0000000000..30554f808e --- /dev/null +++ b/qpid/cpp-0-9/tests/AccumulatedAckTest.cpp @@ -0,0 +1,107 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <AccumulatedAck.h> +#include <qpid_test_plugin.h> +#include <iostream> +#include <list> + +using std::list; +using namespace qpid::broker; + +class AccumulatedAckTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(AccumulatedAckTest); + CPPUNIT_TEST(testGeneral); + CPPUNIT_TEST(testCovers); + CPPUNIT_TEST(testUpdateAndConsolidate); + CPPUNIT_TEST_SUITE_END(); + + public: + void testGeneral() + { + AccumulatedAck ack(0); + ack.clear(); + ack.update(3,3); + ack.update(7,7); + ack.update(9,9); + ack.update(1,2); + ack.update(4,5); + ack.update(6,6); + + for(int i = 1; i <= 7; i++) CPPUNIT_ASSERT(ack.covers(i)); + CPPUNIT_ASSERT(ack.covers(9)); + + CPPUNIT_ASSERT(!ack.covers(8)); + CPPUNIT_ASSERT(!ack.covers(10)); + + ack.consolidate(); + + for(int i = 1; i <= 7; i++) CPPUNIT_ASSERT(ack.covers(i)); + CPPUNIT_ASSERT(ack.covers(9)); + + CPPUNIT_ASSERT(!ack.covers(8)); + CPPUNIT_ASSERT(!ack.covers(10)); + } + + void testCovers() + { + AccumulatedAck ack(5); + ack.individual.push_back(7); + ack.individual.push_back(9); + + CPPUNIT_ASSERT(ack.covers(1)); + CPPUNIT_ASSERT(ack.covers(2)); + CPPUNIT_ASSERT(ack.covers(3)); + CPPUNIT_ASSERT(ack.covers(4)); + CPPUNIT_ASSERT(ack.covers(5)); + CPPUNIT_ASSERT(ack.covers(7)); + CPPUNIT_ASSERT(ack.covers(9)); + + CPPUNIT_ASSERT(!ack.covers(6)); + CPPUNIT_ASSERT(!ack.covers(8)); + CPPUNIT_ASSERT(!ack.covers(10)); + } + + void testUpdateAndConsolidate() + { + AccumulatedAck ack(0); + ack.update(1, 1); + ack.update(3, 3); + ack.update(10, 10); + ack.update(8, 8); + ack.update(6, 6); + ack.update(3, 3); + ack.update(2, 2); + ack.update(0, 5); + ack.consolidate(); + CPPUNIT_ASSERT_EQUAL((uint64_t) 6, ack.range); + CPPUNIT_ASSERT_EQUAL((size_t) 2, ack.individual.size()); + list<uint64_t>::iterator i = ack.individual.begin(); + CPPUNIT_ASSERT_EQUAL((uint64_t) 8, *i); + i++; + CPPUNIT_ASSERT_EQUAL((uint64_t) 10, *i); + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(AccumulatedAckTest); + diff --git a/qpid/cpp-0-9/tests/BrokerChannelTest.cpp b/qpid/cpp-0-9/tests/BrokerChannelTest.cpp new file mode 100644 index 0000000000..9216ae4672 --- /dev/null +++ b/qpid/cpp-0-9/tests/BrokerChannelTest.cpp @@ -0,0 +1,356 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <BrokerChannel.h> +#include <BrokerMessage.h> +#include <BrokerQueue.h> +#include <FanOutExchange.h> +#include <NullMessageStore.h> +#include <qpid_test_plugin.h> +#include <iostream> +#include <memory> +#include <AMQP_HighestVersion.h> +#include "AMQFrame.h" +#include "MockChannel.h" +#include "broker/Connection.h" +#include "ProtocolInitiation.h" + +using namespace boost; +using namespace qpid::broker; +using namespace qpid::framing; +using namespace qpid::sys; +using std::string; +using std::queue; + +struct MockHandler : ConnectionOutputHandler{ + std::vector<AMQFrame*> frames; + + void send(AMQFrame* frame){ frames.push_back(frame); } + + void close() {}; +}; + + +class BrokerChannelTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(BrokerChannelTest); + CPPUNIT_TEST(testConsumerMgmt); + CPPUNIT_TEST(testDeliveryNoAck); + CPPUNIT_TEST(testDeliveryAndRecovery); + CPPUNIT_TEST(testStaging); + CPPUNIT_TEST(testQueuePolicy); + CPPUNIT_TEST_SUITE_END(); + + Broker::shared_ptr broker; + Connection connection; + MockHandler handler; + + class MockMessageStore : public NullMessageStore + { + struct MethodCall + { + const string name; + Message* const msg; + const string data;//only needed for appendContent + + void check(const MethodCall& other) const + { + CPPUNIT_ASSERT_EQUAL(name, other.name); + CPPUNIT_ASSERT_EQUAL(msg, other.msg); + CPPUNIT_ASSERT_EQUAL(data, other.data); + } + }; + + queue<MethodCall> expected; + bool expectMode;//true when setting up expected calls + + void handle(const MethodCall& call) + { + if (expectMode) { + expected.push(call); + } else { + call.check(expected.front()); + expected.pop(); + } + } + + void handle(const string& name, Message* msg, const string& data) + { + MethodCall call = {name, msg, data}; + handle(call); + } + + public: + + MockMessageStore() : expectMode(false) {} + + void stage(Message* const msg) + { + if(!expectMode) msg->setPersistenceId(1); + MethodCall call = {"stage", msg, ""}; + handle(call); + } + + void appendContent(Message* msg, const string& data) + { + MethodCall call = {"appendContent", msg, data}; + handle(call); + } + + // Don't hide overloads. + using NullMessageStore::destroy; + + void destroy(Message* msg) + { + MethodCall call = {"destroy", msg, ""}; + handle(call); + } + + void expect() + { + expectMode = true; + } + + void test() + { + expectMode = false; + } + + void check() + { + CPPUNIT_ASSERT(expected.empty()); + } + }; + + + public: + + BrokerChannelTest() : + broker(Broker::create()), + connection(&handler, *broker) + { + connection.initiated(new ProtocolInitiation()); + } + + + void testConsumerMgmt(){ + Queue::shared_ptr queue(new Queue("my_queue")); + Channel channel(connection, 0, 0, 0); + channel.open(); + CPPUNIT_ASSERT(!channel.exists("my_consumer")); + + ConnectionToken* owner = 0; + string tag("my_consumer"); + channel.consume(tag, queue, false, false, owner); + string tagA; + string tagB; + channel.consume(tagA, queue, false, false, owner); + channel.consume(tagB, queue, false, false, owner); + CPPUNIT_ASSERT_EQUAL((uint32_t) 3, queue->getConsumerCount()); + CPPUNIT_ASSERT(channel.exists("my_consumer")); + CPPUNIT_ASSERT(channel.exists(tagA)); + CPPUNIT_ASSERT(channel.exists(tagB)); + channel.cancel(tagA); + CPPUNIT_ASSERT_EQUAL((uint32_t) 2, queue->getConsumerCount()); + CPPUNIT_ASSERT(channel.exists("my_consumer")); + CPPUNIT_ASSERT(!channel.exists(tagA)); + CPPUNIT_ASSERT(channel.exists(tagB)); + channel.close(); + CPPUNIT_ASSERT_EQUAL((uint32_t) 0, queue->getConsumerCount()); + } + + void testDeliveryNoAck(){ + Channel channel(connection, 7, 10000); + channel.open(); + const string data("abcdefghijklmn"); + Message::shared_ptr msg( + createMessage("test", "my_routing_key", "my_message_id", 14)); + addContent(msg, data); + Queue::shared_ptr queue(new Queue("my_queue")); + ConnectionToken* owner(0); + string tag("no_ack"); + channel.consume(tag, queue, false, false, owner); + + queue->deliver(msg); + CPPUNIT_ASSERT_EQUAL((size_t) 4, handler.frames.size()); + CPPUNIT_ASSERT_EQUAL(ChannelId(0), handler.frames[0]->getChannel()); + CPPUNIT_ASSERT_EQUAL(ChannelId(7), handler.frames[1]->getChannel()); + CPPUNIT_ASSERT_EQUAL(ChannelId(7), handler.frames[2]->getChannel()); + CPPUNIT_ASSERT_EQUAL(ChannelId(7), handler.frames[3]->getChannel()); + CPPUNIT_ASSERT(dynamic_cast<ConnectionStartBody*>( + handler.frames[0]->getBody().get())); + CPPUNIT_ASSERT(dynamic_cast<BasicDeliverBody*>( + handler.frames[1]->getBody().get())); + CPPUNIT_ASSERT(dynamic_cast<AMQHeaderBody*>( + handler.frames[2]->getBody().get())); + AMQContentBody* contentBody = dynamic_cast<AMQContentBody*>( + handler.frames[3]->getBody().get()); + CPPUNIT_ASSERT(contentBody); + CPPUNIT_ASSERT_EQUAL(data, contentBody->getData()); + } + + void testDeliveryAndRecovery(){ + Channel channel(connection, 7, 10000); + channel.open(); + const string data("abcdefghijklmn"); + + Message::shared_ptr msg(createMessage("test", "my_routing_key", "my_message_id", 14)); + addContent(msg, data); + + Queue::shared_ptr queue(new Queue("my_queue")); + ConnectionToken* owner(0); + string tag("ack"); + channel.consume(tag, queue, true, false, owner); + + queue->deliver(msg); + CPPUNIT_ASSERT_EQUAL((size_t) 4, handler.frames.size()); + CPPUNIT_ASSERT_EQUAL(ChannelId(0), handler.frames[0]->getChannel()); + CPPUNIT_ASSERT_EQUAL(ChannelId(7), handler.frames[1]->getChannel()); + CPPUNIT_ASSERT_EQUAL(ChannelId(7), handler.frames[2]->getChannel()); + CPPUNIT_ASSERT_EQUAL(ChannelId(7), handler.frames[3]->getChannel()); + CPPUNIT_ASSERT(dynamic_cast<ConnectionStartBody*>( + handler.frames[0]->getBody().get())); + CPPUNIT_ASSERT(dynamic_cast<BasicDeliverBody*>( + handler.frames[1]->getBody().get())); + CPPUNIT_ASSERT(dynamic_cast<AMQHeaderBody*>( + handler.frames[2]->getBody().get())); + AMQContentBody* contentBody = dynamic_cast<AMQContentBody*>( + handler.frames[3]->getBody().get()); + CPPUNIT_ASSERT(contentBody); + CPPUNIT_ASSERT_EQUAL(data, contentBody->getData()); + } + + void testStaging(){ + MockMessageStore store; + Channel channel( + connection, 1, 1000/*framesize*/, &store, 10/*staging threshold*/); + const string data[] = {"abcde", "fghij", "klmno"}; + + Message* msg = new BasicMessage( + 0, "my_exchange", "my_routing_key", false, false, + MockChannel::basicGetBody()); + + store.expect(); + store.stage(msg); + for (int i = 0; i < 3; i++) { + store.appendContent(msg, data[i]); + } + store.destroy(msg); + store.test(); + + Exchange::shared_ptr exchange = + broker->getExchanges().declare("my_exchange", "fanout").first; + Queue::shared_ptr queue(new Queue("my_queue")); + exchange->bind(queue, "", 0); + + AMQHeaderBody::shared_ptr header(new AMQHeaderBody(BASIC)); + uint64_t contentSize(0); + for (int i = 0; i < 3; i++) { + contentSize += data[i].size(); + } + header->setContentSize(contentSize); + channel.handlePublish(msg); + channel.handleHeader(header); + + for (int i = 0; i < 3; i++) { + AMQContentBody::shared_ptr body(new AMQContentBody(data[i])); + channel.handleContent(body); + } + Message::shared_ptr msg2 = queue->dequeue(); + CPPUNIT_ASSERT_EQUAL(msg, msg2.get()); + msg2.reset();//should trigger destroy call + + store.check(); + } + + + //NOTE: strictly speaking this should/could be part of QueueTest, + //but as it can usefully use the same utility classes as this + //class it is defined here for simpllicity + void testQueuePolicy() + { + MockMessageStore store; + {//must ensure that store is last thing deleted as it is needed by destructor of lazy loaded content + const string data1("abcd"); + const string data2("efghijk"); + const string data3("lmnopqrstuvwxyz"); + Message::shared_ptr msg1(createMessage("e", "A", "MsgA", data1.size())); + Message::shared_ptr msg2(createMessage("e", "B", "MsgB", data2.size())); + Message::shared_ptr msg3(createMessage("e", "C", "MsgC", data3.size())); + addContent(msg1, data1); + addContent(msg2, data2); + addContent(msg3, data3); + + QueuePolicy policy(2, 0);//third message should be stored on disk and lazy loaded + FieldTable settings; + policy.update(settings); + + store.expect(); + store.stage(msg3.get()); + store.destroy(msg3.get()); + store.test(); + + Queue::shared_ptr queue(new Queue("my_queue", false, &store, 0)); + queue->configure(settings);//set policy + queue->deliver(msg1); + queue->deliver(msg2); + queue->deliver(msg3); + + Message::shared_ptr next = queue->dequeue(); + CPPUNIT_ASSERT_EQUAL(msg1, next); + CPPUNIT_ASSERT_EQUAL((uint32_t) data1.size(), next->encodedContentSize()); + next = queue->dequeue(); + CPPUNIT_ASSERT_EQUAL(msg2, next); + CPPUNIT_ASSERT_EQUAL((uint32_t) data2.size(), next->encodedContentSize()); + next = queue->dequeue(); + CPPUNIT_ASSERT_EQUAL(msg3, next); + CPPUNIT_ASSERT_EQUAL((uint32_t) 0, next->encodedContentSize()); + + next.reset(); + msg1.reset(); + msg2.reset(); + msg3.reset();//must clear all references to messages to allow them to be destroyed + + } + store.check(); + } + + Message* createMessage(const string& exchange, const string& routingKey, const string& messageId, uint64_t contentSize) + { + BasicMessage* msg = new BasicMessage( + 0, exchange, routingKey, false, false, + MockChannel::basicGetBody()); + AMQHeaderBody::shared_ptr header(new AMQHeaderBody(BASIC)); + header->setContentSize(contentSize); + msg->setHeader(header); + msg->getHeaderProperties()->setMessageId(messageId); + return msg; + } + + void addContent(Message::shared_ptr msg, const string& data) + { + AMQContentBody::shared_ptr body(new AMQContentBody(data)); + msg->addContent(body); + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(BrokerChannelTest); diff --git a/qpid/cpp-0-9/tests/ClientChannelTest.cpp b/qpid/cpp-0-9/tests/ClientChannelTest.cpp new file mode 100644 index 0000000000..7b0bc363fe --- /dev/null +++ b/qpid/cpp-0-9/tests/ClientChannelTest.cpp @@ -0,0 +1,164 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <vector> +#include "qpid_test_plugin.h" +#include "InProcessBroker.h" +#include "ClientChannel.h" +#include "ClientMessage.h" +#include "ClientQueue.h" +#include "ClientExchange.h" + +using namespace std; +using namespace boost; +using namespace qpid::client; +using namespace qpid::sys; +using namespace qpid::framing; + +/** + * Test client API using an in-process broker. + */ +class ClientChannelTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(ClientChannelTest); + CPPUNIT_TEST(testPublishGet); + CPPUNIT_TEST(testGetNoContent); + CPPUNIT_TEST(testConsumeCancel); + CPPUNIT_TEST(testConsumePublished); + CPPUNIT_TEST_SUITE_END(); + + struct Listener: public qpid::client::MessageListener { + vector<Message> messages; + Monitor monitor; + void received(Message& msg) { + Mutex::ScopedLock l(monitor); + messages.push_back(msg); + monitor.notifyAll(); + } + }; + + InProcessBrokerClient connection; // client::connection + local broker + Channel channel; + const std::string qname; + const std::string data; + Queue queue; + Exchange exchange; + Listener listener; + + public: + + ClientChannelTest() + : qname("testq"), data("hello"), + queue(qname, true), exchange("", Exchange::DIRECT_EXCHANGE) + { + connection.openChannel(channel); + CPPUNIT_ASSERT(channel.getId() != 0); + channel.declareQueue(queue); + } + + void testPublishGet() { + Message pubMsg(data); + pubMsg.getHeaders().setString("hello", "world"); + channel.getBasic().publish(pubMsg, exchange, qname); + Message getMsg; + CPPUNIT_ASSERT(channel.getBasic().get(getMsg, queue)); + CPPUNIT_ASSERT_EQUAL(data, getMsg.getData()); + CPPUNIT_ASSERT_EQUAL(string("world"), + getMsg.getHeaders().getString("hello")); + CPPUNIT_ASSERT(!channel.getBasic().get(getMsg, queue)); // Empty queue + } + + void testGetNoContent() { + Message pubMsg; + pubMsg.getHeaders().setString("hello", "world"); + channel.getBasic().publish(pubMsg, exchange, qname); + Message getMsg; + CPPUNIT_ASSERT(channel.getBasic().get(getMsg, queue)); + CPPUNIT_ASSERT(getMsg.getData().empty()); + CPPUNIT_ASSERT_EQUAL(string("world"), + getMsg.getHeaders().getString("hello")); + } + + void testConsumeCancel() { + string tag; // Broker assigned + channel.getBasic().consume(queue, tag, &listener); + channel.start(); + CPPUNIT_ASSERT_EQUAL(size_t(0), listener.messages.size()); + channel.getBasic().publish(Message("a"), exchange, qname); + { + Mutex::ScopedLock l(listener.monitor); + Time deadline(now() + 1*TIME_SEC); + while (listener.messages.size() != 1) { + CPPUNIT_ASSERT(listener.monitor.wait(deadline)); + } + } + CPPUNIT_ASSERT_EQUAL(size_t(1), listener.messages.size()); + CPPUNIT_ASSERT_EQUAL(string("a"), listener.messages[0].getData()); + + channel.getBasic().publish(Message("b"), exchange, qname); + channel.getBasic().publish(Message("c"), exchange, qname); + { + Mutex::ScopedLock l(listener.monitor); + while (listener.messages.size() != 3) { + CPPUNIT_ASSERT(listener.monitor.wait(1*TIME_SEC)); + } + } + CPPUNIT_ASSERT_EQUAL(size_t(3), listener.messages.size()); + CPPUNIT_ASSERT_EQUAL(string("b"), listener.messages[1].getData()); + CPPUNIT_ASSERT_EQUAL(string("c"), listener.messages[2].getData()); + + channel.getBasic().cancel(tag); + channel.getBasic().publish(Message("d"), exchange, qname); + CPPUNIT_ASSERT_EQUAL(size_t(3), listener.messages.size()); + { + Mutex::ScopedLock l(listener.monitor); + CPPUNIT_ASSERT(!listener.monitor.wait(TIME_SEC/2)); + } + Message msg; + CPPUNIT_ASSERT(channel.getBasic().get(msg, queue)); + CPPUNIT_ASSERT_EQUAL(string("d"), msg.getData()); + } + + // Consume already-published messages + void testConsumePublished() { + Message pubMsg("x"); + pubMsg.getHeaders().setString("y", "z"); + channel.getBasic().publish(pubMsg, exchange, qname); + string tag; + channel.getBasic().consume(queue, tag, &listener); + CPPUNIT_ASSERT_EQUAL(size_t(0), listener.messages.size()); + channel.start(); + { + Mutex::ScopedLock l(listener.monitor); + while (listener.messages.size() != 1) + CPPUNIT_ASSERT(listener.monitor.wait(1*TIME_SEC)); + } + CPPUNIT_ASSERT_EQUAL(string("x"), listener.messages[0].getData()); + CPPUNIT_ASSERT_EQUAL(string("z"), + listener.messages[0].getHeaders().getString("y")); + } + + + +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(ClientChannelTest); diff --git a/qpid/cpp-0-9/tests/ConfigurationTest.cpp b/qpid/cpp-0-9/tests/ConfigurationTest.cpp new file mode 100644 index 0000000000..3a1d5ba85d --- /dev/null +++ b/qpid/cpp-0-9/tests/ConfigurationTest.cpp @@ -0,0 +1,98 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <Configuration.h> +#include <qpid_test_plugin.h> +#include <iostream> + +using namespace std; +using namespace qpid::broker; + +class ConfigurationTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(ConfigurationTest); + CPPUNIT_TEST(testIsHelp); + CPPUNIT_TEST(testPortLongForm); + CPPUNIT_TEST(testPortShortForm); + CPPUNIT_TEST(testStore); + CPPUNIT_TEST(testStagingThreshold); + CPPUNIT_TEST(testVarious); + CPPUNIT_TEST_SUITE_END(); + + public: + + void testIsHelp() + { + Configuration conf; + char* argv[] = {"ignore", "--help"}; + conf.parse("ignore", 2, argv); + CPPUNIT_ASSERT(conf.isHelp()); + } + + void testPortLongForm() + { + Configuration conf; + char* argv[] = {"ignore", "--port", "6789"}; + conf.parse("ignore", 3, argv); + CPPUNIT_ASSERT_EQUAL(6789, conf.getPort()); + } + + void testPortShortForm() + { + Configuration conf; + char* argv[] = {"ignore", "-p", "6789"}; + conf.parse("ignore", 3, argv); + CPPUNIT_ASSERT_EQUAL(6789, conf.getPort()); + } + + void testStore() + { + Configuration conf; + char* argv[] = {"ignore", "--store", "my-store-module.so"}; + conf.parse("ignore", 3, argv); + std::string expected("my-store-module.so"); + CPPUNIT_ASSERT_EQUAL(expected, conf.getStore()); + } + + void testStagingThreshold() + { + Configuration conf; + char* argv[] = {"ignore", "--staging-threshold", "123456789"}; + conf.parse("ignore", 3, argv); + long expected = 123456789; + CPPUNIT_ASSERT_EQUAL(expected, conf.getStagingThreshold()); + } + + void testVarious() + { + Configuration conf; + char* argv[] = {"ignore", "-t", "--worker-threads", "10"}; + conf.parse("ignore", 4, argv); + CPPUNIT_ASSERT_EQUAL(5672, conf.getPort());//default + CPPUNIT_ASSERT_EQUAL(10, conf.getWorkerThreads()); + CPPUNIT_ASSERT(conf.isTrace()); + CPPUNIT_ASSERT(!conf.isHelp()); + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(ConfigurationTest); + diff --git a/qpid/cpp-0-9/tests/EventChannelConnectionTest.cpp b/qpid/cpp-0-9/tests/EventChannelConnectionTest.cpp new file mode 100644 index 0000000000..66561daf83 --- /dev/null +++ b/qpid/cpp-0-9/tests/EventChannelConnectionTest.cpp @@ -0,0 +1,109 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <iostream> +#include <boost/bind.hpp> +#include "framing/AMQHeartbeatBody.h" +#include "framing/AMQFrame.h" +#include "sys/posix/EventChannelConnection.h" +#include "sys/ConnectionInputHandler.h" +#include "sys/ConnectionInputHandlerFactory.h" +#include "sys/Socket.h" +#include "qpid_test_plugin.h" +#include "MockConnectionInputHandler.h" + +using namespace qpid::sys; +using namespace qpid::framing; +using namespace std; + +class EventChannelConnectionTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(EventChannelConnectionTest); + CPPUNIT_TEST(testSendReceive); + CPPUNIT_TEST(testCloseExternal); + CPPUNIT_TEST(testCloseException); + CPPUNIT_TEST_SUITE_END(); + + public: + + void setUp() { + threads = EventChannelThreads::create(); + CPPUNIT_ASSERT_EQUAL(0, ::pipe(pipe)); + connection.reset( + new EventChannelConnection(threads, factory, pipe[0], pipe[1])); + CPPUNIT_ASSERT(factory.handler != 0); + } + + void tearDown() { + threads->shutdown(); + threads->join(); + } + + void testSendReceive() + { + // Send a protocol initiation. + Buffer buf(1024); + ProtocolInitiation(4,2).encode(buf); + buf.flip(); + ssize_t n = write(pipe[1], buf.start(), buf.available()); + CPPUNIT_ASSERT_EQUAL(ssize_t(buf.available()), n); + + // Verify session handler got the protocol init. + ProtocolInitiation init = factory.handler->waitForProtocolInit(); + CPPUNIT_ASSERT_EQUAL(int(4), int(init.getMajor())); + CPPUNIT_ASSERT_EQUAL(int(2), int(init.getMinor())); + + // Send a heartbeat frame, verify connection got it. + connection->send(new AMQFrame(42, new AMQHeartbeatBody())); + AMQFrame frame = factory.handler->waitForFrame(); + CPPUNIT_ASSERT_EQUAL(uint16_t(42), frame.getChannel()); + CPPUNIT_ASSERT_EQUAL(uint8_t(HEARTBEAT_BODY), + frame.getBody()->type()); + threads->shutdown(); + } + + // Make sure the handler is closed if the connection is closed. + void testCloseExternal() { + connection->close(); + factory.handler->waitForClosed(); + } + + // Make sure the handler is closed if the connection closes or fails. + // TODO aconway 2006-12-18: logs exception message in test output. + void testCloseException() { + ::close(pipe[0]); + ::close(pipe[1]); + // TODO aconway 2006-12-18: Shouldn't this be failing? + connection->send(new AMQFrame(42, new AMQHeartbeatBody())); + factory.handler->waitForClosed(); + } + + private: + EventChannelThreads::shared_ptr threads; + int pipe[2]; + std::auto_ptr<EventChannelConnection> connection; + MockConnectionInputHandlerFactory factory; +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(EventChannelConnectionTest); + diff --git a/qpid/cpp-0-9/tests/EventChannelTest.cpp b/qpid/cpp-0-9/tests/EventChannelTest.cpp new file mode 100644 index 0000000000..8e5c724a15 --- /dev/null +++ b/qpid/cpp-0-9/tests/EventChannelTest.cpp @@ -0,0 +1,187 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <posix/EventChannel.h> +#include <posix/check.h> +#include <sys/Runnable.h> +#include <sys/Socket.h> +#include <sys/Thread.h> +#include <qpid_test_plugin.h> + +#include <sys/socket.h> +#include <signal.h> +#include <netinet/in.h> +#include <netdb.h> +#include <iostream> + +using namespace qpid::sys; + + +const char hello[] = "hello"; +const size_t size = sizeof(hello); + +struct RunMe : public Runnable +{ + bool ran; + RunMe() : ran(false) {} + void run() { ran = true; } +}; + +class EventChannelTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(EventChannelTest); + CPPUNIT_TEST(testEvent); + CPPUNIT_TEST(testRead); + CPPUNIT_TEST(testFailedRead); + CPPUNIT_TEST(testWrite); + CPPUNIT_TEST(testFailedWrite); + CPPUNIT_TEST(testReadWrite); + CPPUNIT_TEST(testAccept); + CPPUNIT_TEST_SUITE_END(); + + private: + EventChannel::shared_ptr ec; + int pipe[2]; + char readBuf[size]; + + public: + + void setUp() + { + memset(readBuf, size, 0); + ec = EventChannel::create(); + if (::pipe(pipe) != 0) throw QPID_POSIX_ERROR(errno); + // Ignore SIGPIPE, otherwise we will crash writing to broken pipe. + signal(SIGPIPE, SIG_IGN); + } + + // Verify that calling getEvent returns event. + template <class T> bool isNextEvent(T& event) + { + return &event == dynamic_cast<T*>(ec->getEvent()); + } + + template <class T> bool isNextEventOk(T& event) + { + Event* next = ec->getEvent(); + if (next) next->throwIfError(); + return &event == next; + } + + void testEvent() + { + RunMe runMe; + CPPUNIT_ASSERT(!runMe.ran); + // Instances of Event just pass thru the channel immediately. + Event e(runMe.functor()); + ec->postEvent(e); + CPPUNIT_ASSERT(isNextEventOk(e)); + e.dispatch(); + CPPUNIT_ASSERT(runMe.ran); + } + + void testRead() { + ReadEvent re(pipe[0], readBuf, size); + ec->postEvent(re); + CPPUNIT_ASSERT_EQUAL(ssize_t(size), ::write(pipe[1], hello, size)); + CPPUNIT_ASSERT(isNextEventOk(re)); + CPPUNIT_ASSERT_EQUAL(size, re.getSize()); + CPPUNIT_ASSERT_EQUAL(std::string(hello), std::string(readBuf)); + } + + void testFailedRead() + { + ReadEvent re(pipe[0], readBuf, size); + ec->postEvent(re); + + // EOF before all data read. + ::close(pipe[1]); + CPPUNIT_ASSERT(isNextEvent(re)); + CPPUNIT_ASSERT(re.hasError()); + try { + re.throwIfError(); + CPPUNIT_FAIL("Expected QpidError."); + } + catch (const qpid::QpidError&) { } + + // Bad file descriptor. Note in this case we fail + // in postEvent and throw immediately. + try { + ReadEvent bad; + ec->postEvent(bad); + CPPUNIT_FAIL("Expected QpidError."); + } + catch (const qpid::QpidError&) { } + } + + void testWrite() { + WriteEvent wr(pipe[1], hello, size); + ec->postEvent(wr); + CPPUNIT_ASSERT(isNextEventOk(wr)); + CPPUNIT_ASSERT_EQUAL(ssize_t(size), ::read(pipe[0], readBuf, size));; + CPPUNIT_ASSERT_EQUAL(std::string(hello), std::string(readBuf)); + } + + void testFailedWrite() { + WriteEvent wr(pipe[1], hello, size); + ::close(pipe[0]); + ec->postEvent(wr); + CPPUNIT_ASSERT(isNextEvent(wr)); + CPPUNIT_ASSERT(wr.hasError()); + } + + void testReadWrite() + { + ReadEvent re(pipe[0], readBuf, size); + WriteEvent wr(pipe[1], hello, size); + ec->postEvent(re); + ec->postEvent(wr); + ec->getEvent(); + ec->getEvent(); + CPPUNIT_ASSERT_EQUAL(std::string(hello), std::string(readBuf)); + } + + void testAccept() { + Socket s = Socket::createTcp(); + int port = s.listen(0, 10); + CPPUNIT_ASSERT(port != 0); + + AcceptEvent ae(s.fd()); + ec->postEvent(ae); + Socket client = Socket::createTcp(); + client.connect("localhost", port); + CPPUNIT_ASSERT(isNextEvent(ae)); + ae.dispatch(); + + // Verify client writes are read by the accepted descriptor. + char readBuf[size]; + ReadEvent re(ae.getAcceptedDesscriptor(), readBuf, size); + ec->postEvent(re); + CPPUNIT_ASSERT_EQUAL(ssize_t(size), client.send(hello, sizeof(hello))); + CPPUNIT_ASSERT(isNextEvent(re)); + re.dispatch(); + CPPUNIT_ASSERT_EQUAL(std::string(hello), std::string(readBuf)); + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(EventChannelTest); + diff --git a/qpid/cpp-0-9/tests/EventChannelThreadsTest.cpp b/qpid/cpp-0-9/tests/EventChannelThreadsTest.cpp new file mode 100644 index 0000000000..285ed29518 --- /dev/null +++ b/qpid/cpp-0-9/tests/EventChannelThreadsTest.cpp @@ -0,0 +1,247 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <boost/bind.hpp> + +#include <sys/Socket.h> +#include <posix/EventChannelThreads.h> +#include <qpid_test_plugin.h> + + +using namespace std; + +using namespace qpid::sys; + +const int nConnections = 5; +const int nMessages = 10; // Messages read/written per connection. + + +// Accepts + reads + writes. +const int totalEvents = nConnections+2*nConnections*nMessages; + +/** + * Messages are numbered 0..nMessages. + * We count the total number of events, and the + * number of reads and writes for each message number. + */ +class TestResults : public Monitor { + public: + TestResults() : isShutdown(false), nEventsRemaining(totalEvents) {} + + void countEvent() { + if (--nEventsRemaining == 0) + shutdown(); + } + + void countRead(int messageNo) { + ++reads[messageNo]; + countEvent(); + } + + void countWrite(int messageNo) { + ++writes[messageNo]; + countEvent(); + } + + void shutdown(const std::string& exceptionMsg = std::string()) { + ScopedLock lock(*this); + exception = exceptionMsg; + isShutdown = true; + notifyAll(); + } + + void wait() { + ScopedLock lock(*this); + Time deadline = now() + 10*TIME_SEC; + while (!isShutdown) { + CPPUNIT_ASSERT(Monitor::wait(deadline)); + } + } + + bool isShutdown; + std::string exception; + AtomicCount reads[nMessages]; + AtomicCount writes[nMessages]; + AtomicCount nEventsRemaining; +}; + +TestResults results; + +EventChannelThreads::shared_ptr threads; + +// Functor to wrap callbacks in try/catch. +class SafeCallback { + public: + SafeCallback(Runnable& r) : callback(r.functor()) {} + SafeCallback(Event::Callback cb) : callback(cb) {} + + void operator()() { + std::string exception; + try { + callback(); + return; + } + catch (const std::exception& e) { + exception = e.what(); + } + catch (...) { + exception = "Unknown exception."; + } + results.shutdown(exception); + } + + private: + Event::Callback callback; +}; + +/** Repost an event N times. */ +class Repost { + public: + Repost(int n) : count (n) {} + virtual ~Repost() {} + + void repost(Event* event) { + if (--count==0) { + delete event; + } else { + threads->postEvent(event); + } + } + private: + int count; +}; + + + +/** Repeating read event. */ +class TestReadEvent : public ReadEvent, public Runnable, private Repost { + public: + explicit TestReadEvent(int fd=-1) : + ReadEvent(fd, &value, sizeof(value), SafeCallback(*this)), + Repost(nMessages) + {} + + void run() { + CPPUNIT_ASSERT_EQUAL(sizeof(value), getSize()); + CPPUNIT_ASSERT(0 <= value); + CPPUNIT_ASSERT(value < nMessages); + results.countRead(value); + repost(this); + } + + private: + int value; + ReadEvent original; +}; + + +/** Fire and forget write event */ +class TestWriteEvent : public WriteEvent, public Runnable, private Repost { + public: + TestWriteEvent(int fd=-1) : + WriteEvent(fd, &value, sizeof(value), SafeCallback(*this)), + Repost(nMessages), + value(0) + {} + + void run() { + CPPUNIT_ASSERT_EQUAL(sizeof(int), getSize()); + results.countWrite(value++); + repost(this); + } + + private: + int value; +}; + +/** Fire-and-forget Accept event, posts reads on the accepted connection. */ +class TestAcceptEvent : public AcceptEvent, public Runnable, private Repost { + public: + TestAcceptEvent(int fd=-1) : + AcceptEvent(fd, SafeCallback(*this)), + Repost(nConnections) + {} + + void run() { + threads->postEvent(new TestReadEvent(getAcceptedDesscriptor())); + results.countEvent(); + repost(this); + } +}; + +class EventChannelThreadsTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(EventChannelThreadsTest); + CPPUNIT_TEST(testThreads); + CPPUNIT_TEST_SUITE_END(); + + public: + + void setUp() { + threads = EventChannelThreads::create(EventChannel::create()); + } + + void tearDown() { + threads.reset(); + } + + void testThreads() + { + Socket listener = Socket::createTcp(); + int port = listener.listen(); + + // Post looping accept events, will repost nConnections times. + // The accept event will automatically post read events. + threads->postEvent(new TestAcceptEvent(listener.fd())); + + // Make connections. + Socket connections[nConnections]; + for (int i = 0; i < nConnections; ++i) { + connections[i] = Socket::createTcp(); + connections[i].connect("localhost", port); + } + + // Post looping write events. + for (int i = 0; i < nConnections; ++i) { + threads->postEvent(new TestWriteEvent(connections[i].fd())); + } + + // Wait for all events to be dispatched. + results.wait(); + + if (!results.exception.empty()) CPPUNIT_FAIL(results.exception); + CPPUNIT_ASSERT_EQUAL(0, int(results.nEventsRemaining)); + + // Expect a read and write for each messageNo from each connection. + for (int messageNo = 0; messageNo < nMessages; ++messageNo) { + CPPUNIT_ASSERT_EQUAL(nConnections, int(results.reads[messageNo])); + CPPUNIT_ASSERT_EQUAL(nConnections, int(results.writes[messageNo])); + } + + threads->shutdown(); + threads->join(); + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(EventChannelThreadsTest); + diff --git a/qpid/cpp-0-9/tests/ExceptionTest.cpp b/qpid/cpp-0-9/tests/ExceptionTest.cpp new file mode 100644 index 0000000000..6cea863168 --- /dev/null +++ b/qpid/cpp-0-9/tests/ExceptionTest.cpp @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include <Exception.h> +#include <qpid_test_plugin.h> + +using namespace qpid; + +struct CountDestroyedException : public Exception { + int& count; + static int staticCount; + CountDestroyedException() : count(staticCount) { } + CountDestroyedException(int& n) : count(n) {} + ~CountDestroyedException() throw() { count++; } + void throwSelf() const { throw *this; } +}; + +int CountDestroyedException::staticCount = 0; + + +class ExceptionTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(ExceptionTest); + CPPUNIT_TEST(testHeapException); + CPPUNIT_TEST_SUITE_END(); + public: + // Verify proper memory management for heap-allocated exceptions. + void testHeapException() { + int count = 0; + try { + std::auto_ptr<Exception> p( + new CountDestroyedException(count)); + p.release()->throwSelf(); + CPPUNIT_FAIL("Expected CountDestroyedException."); + } catch (const CountDestroyedException& e) { + CPPUNIT_ASSERT(&e.count == &count); + } + CPPUNIT_ASSERT_EQUAL(1, count); + } +}; + + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(ExceptionTest); + diff --git a/qpid/cpp-0-9/tests/ExchangeTest.cpp b/qpid/cpp-0-9/tests/ExchangeTest.cpp new file mode 100644 index 0000000000..cccec92024 --- /dev/null +++ b/qpid/cpp-0-9/tests/ExchangeTest.cpp @@ -0,0 +1,73 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <DeliverableMessage.h> +#include <DirectExchange.h> +#include <BrokerExchange.h> +#include <BrokerQueue.h> +#include <TopicExchange.h> +#include <qpid_test_plugin.h> +#include <iostream> +#include "BasicGetBody.h" + +using namespace qpid::broker; +using namespace qpid::framing; +using namespace qpid::sys; + +class ExchangeTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(ExchangeTest); + CPPUNIT_TEST(testMe); + CPPUNIT_TEST_SUITE_END(); + + public: + + void testMe() + { + Queue::shared_ptr queue(new Queue("queue", true)); + Queue::shared_ptr queue2(new Queue("queue2", 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 msgPtr( + new BasicMessage( + 0, "e", "A", true, true, + AMQMethodBody::shared_ptr( + new BasicGetBody(ProtocolVersion())))); + DeliverableMessage msg(msgPtr); + topic.route(msg, "abc", 0); + direct.route(msg, "abc", 0); + + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(ExchangeTest); diff --git a/qpid/cpp-0-9/tests/FieldTableTest.cpp b/qpid/cpp-0-9/tests/FieldTableTest.cpp new file mode 100644 index 0000000000..8d9285bf4b --- /dev/null +++ b/qpid/cpp-0-9/tests/FieldTableTest.cpp @@ -0,0 +1,55 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <amqp_framing.h> +#include <qpid_test_plugin.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/qpid/cpp-0-9/tests/FramingTest.cpp b/qpid/cpp-0-9/tests/FramingTest.cpp new file mode 100644 index 0000000000..f8754337c8 --- /dev/null +++ b/qpid/cpp-0-9/tests/FramingTest.cpp @@ -0,0 +1,381 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <memory> +#include <boost/lexical_cast.hpp> + +#include <ConnectionRedirectBody.h> +#include <ProtocolVersion.h> +#include <amqp_framing.h> +#include <iostream> +#include <qpid_test_plugin.h> +#include <sstream> +#include <typeinfo> +#include <QpidError.h> +#include <AMQP_HighestVersion.h> +#include "AMQRequestBody.h" +#include "AMQResponseBody.h" +#include "Requester.h" +#include "Responder.h" +#include "InProcessBroker.h" +#include "client/Connection.h" +#include "client/ClientExchange.h" +#include "client/ClientQueue.h" + +using namespace qpid; +using namespace qpid::framing; +using namespace std; + +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(testConnectionRedirectBodyFrame); + CPPUNIT_TEST(testBasicConsumeOkBodyFrame); + CPPUNIT_TEST(testRequestBodyFrame); + CPPUNIT_TEST(testResponseBodyFrame); + CPPUNIT_TEST(testRequester); + CPPUNIT_TEST(testResponder); + CPPUNIT_TEST(testInlineContent); + CPPUNIT_TEST(testContentReference); + CPPUNIT_TEST(testContentValidation); + CPPUNIT_TEST(testRequestResponseRoundtrip); + CPPUNIT_TEST_SUITE_END(); + + private: + Buffer buffer; + ProtocolVersion version; + AMQP_MethodVersionMap versionMap; + + public: + + FramingTest() : buffer(1024), version(highestProtocolVersion) {} + + void testBasicQosBody() + { + BasicQosBody in(version, 0xCAFEBABE, 0xABBA, true); + in.encodeContent(buffer); + buffer.flip(); + BasicQosBody out(version); + out.decodeContent(buffer); + CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out)); + } + + void testConnectionSecureBody() + { + std::string s = "security credential"; + ConnectionSecureBody in(version, s); + in.encodeContent(buffer); + buffer.flip(); + ConnectionSecureBody out(version); + out.decodeContent(buffer); + CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out)); + } + + void testConnectionRedirectBody() + { + std::string a = "hostA"; + std::string b = "hostB"; + ConnectionRedirectBody in(version, 0, a, b); + in.encodeContent(buffer); + buffer.flip(); + ConnectionRedirectBody out(version); + out.decodeContent(buffer); + CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out)); + } + + void testAccessRequestBody() + { + std::string s = "text"; + AccessRequestBody in(version, s, true, false, true, false, true); + in.encodeContent(buffer); + buffer.flip(); + AccessRequestBody out(version); + out.decodeContent(buffer); + CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out)); + } + + void testBasicConsumeBody() + { + std::string q = "queue"; + std::string t = "tag"; + BasicConsumeBody in(version, 0, q, t, false, true, false, false, + FieldTable()); + in.encodeContent(buffer); + buffer.flip(); + BasicConsumeBody out(version); + out.decodeContent(buffer); + CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out)); + } + + + void testConnectionRedirectBodyFrame() + { + std::string a = "hostA"; + std::string b = "hostB"; + AMQFrame in(version, 999, + new ConnectionRedirectBody(version, 0, a, b)); + in.encode(buffer); + buffer.flip(); + AMQFrame out; + out.decode(buffer); + CPPUNIT_ASSERT_EQUAL(tostring(in), tostring(out)); + } + + void testBasicConsumeOkBodyFrame() + { + std::string s = "hostA"; + AMQFrame in(version, 999, new BasicConsumeOkBody(version, 0, 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)); + } + } + + void testRequestBodyFrame() { + std::string testing("testing"); + AMQBody::shared_ptr request(new ChannelOpenBody(version, testing)); + AMQFrame in(version, 999, request); + in.encode(buffer); + buffer.flip(); + AMQFrame out; + out.decode(buffer); + ChannelOpenBody* decoded = + dynamic_cast<ChannelOpenBody*>(out.getBody().get()); + CPPUNIT_ASSERT(decoded); + CPPUNIT_ASSERT_EQUAL(testing, decoded->getOutOfBand()); + } + + void testResponseBodyFrame() { + AMQBody::shared_ptr response(new ChannelOkBody(version)); + AMQFrame in(version, 999, response); + in.encode(buffer); + buffer.flip(); + AMQFrame out; + out.decode(buffer); + ChannelOkBody* decoded = + dynamic_cast<ChannelOkBody*>(out.getBody().get()); + CPPUNIT_ASSERT(decoded); + } + + void testInlineContent() { + Content content(INLINE, "MyData"); + CPPUNIT_ASSERT(content.isInline()); + content.encode(buffer); + buffer.flip(); + Content recovered; + recovered.decode(buffer); + CPPUNIT_ASSERT(recovered.isInline()); + CPPUNIT_ASSERT_EQUAL(content.getValue(), recovered.getValue()); + } + + void testContentReference() { + Content content(REFERENCE, "MyRef"); + CPPUNIT_ASSERT(content.isReference()); + content.encode(buffer); + buffer.flip(); + Content recovered; + recovered.decode(buffer); + CPPUNIT_ASSERT(recovered.isReference()); + CPPUNIT_ASSERT_EQUAL(content.getValue(), recovered.getValue()); + } + + void testContentValidation() { + try { + Content content(REFERENCE, ""); + CPPUNIT_ASSERT(false);//fail, expected exception + } catch (QpidError& e) { + CPPUNIT_ASSERT_EQUAL(FRAMING_ERROR, e.code); + CPPUNIT_ASSERT_EQUAL(string("Reference cannot be empty"), e.msg); + } + + try { + Content content(2, "Blah"); + CPPUNIT_ASSERT(false);//fail, expected exception + } catch (QpidError& e) { + CPPUNIT_ASSERT_EQUAL(FRAMING_ERROR, e.code); + CPPUNIT_ASSERT_EQUAL(string("Invalid discriminator: 2"), e.msg); + } + + try { + buffer.putOctet(2); + buffer.putLongString("blah, blah"); + buffer.flip(); + Content content; + content.decode(buffer); + CPPUNIT_ASSERT(false);//fail, expected exception + } catch (QpidError& e) { + CPPUNIT_ASSERT_EQUAL(FRAMING_ERROR, e.code); + CPPUNIT_ASSERT_EQUAL(string("Invalid discriminator: 2"), e.msg); + } + + } + + void testRequester() { + Requester r; + AMQRequestBody::Data q; + AMQResponseBody::Data p; + + r.sending(q); + CPPUNIT_ASSERT_EQUAL(1ULL, q.requestId); + CPPUNIT_ASSERT_EQUAL(0ULL, q.responseMark); + + r.sending(q); + CPPUNIT_ASSERT_EQUAL(2ULL, q.requestId); + CPPUNIT_ASSERT_EQUAL(0ULL, q.responseMark); + + // Now process a response + p.responseId = 1; + p.requestId = 2; + r.processed(AMQResponseBody::Data(1, 2)); + + r.sending(q); + CPPUNIT_ASSERT_EQUAL(3ULL, q.requestId); + CPPUNIT_ASSERT_EQUAL(1ULL, q.responseMark); + + try { + r.processed(p); // Already processed this response. + CPPUNIT_FAIL("Expected exception"); + } catch (...) {} + + try { + p.requestId = 50; + r.processed(p); // No such request + CPPUNIT_FAIL("Expected exception"); + } catch (...) {} + + r.sending(q); // reqId=4 + r.sending(q); // reqId=5 + r.sending(q); // reqId=6 + p.responseId++; + p.requestId = 4; + p.batchOffset = 2; + r.processed(p); + r.sending(q); + CPPUNIT_ASSERT_EQUAL(7ULL, q.requestId); + CPPUNIT_ASSERT_EQUAL(2ULL, q.responseMark); + + p.responseId++; + p.requestId = 1; // Out of order + p.batchOffset = 0; + r.processed(p); + r.sending(q); + CPPUNIT_ASSERT_EQUAL(8ULL, q.requestId); + CPPUNIT_ASSERT_EQUAL(3ULL, q.responseMark); + } + + void testResponder() { + Responder r; + AMQRequestBody::Data q; + AMQResponseBody::Data p; + + q.requestId = 1; + q.responseMark = 0; + r.received(q); + p.requestId = q.requestId; + r.sending(p); + CPPUNIT_ASSERT_EQUAL(1ULL, p.responseId); + CPPUNIT_ASSERT_EQUAL(1ULL, p.requestId); + CPPUNIT_ASSERT_EQUAL(0U, p.batchOffset); + CPPUNIT_ASSERT_EQUAL(0ULL, r.getResponseMark()); + + q.requestId++; + q.responseMark = 1; + r.received(q); + r.sending(p); + CPPUNIT_ASSERT_EQUAL(2ULL, p.responseId); + CPPUNIT_ASSERT_EQUAL(0U, p.batchOffset); + CPPUNIT_ASSERT_EQUAL(1ULL, r.getResponseMark()); + + try { + // Response mark higher any request ID sent. + q.responseMark = 3; + r.received(q); + } catch(...) {} + + try { + // Response mark lower than previous response mark. + q.responseMark = 0; + r.received(q); + } catch(...) {} + + // TODO aconway 2007-01-14: Test for batching when supported. + + } + + // expect may contain null chars so use string(ptr,size) constructor + // Use sizeof(expect)-1 to strip the trailing null. +#define ASSERT_FRAME(expect, frame) \ + CPPUNIT_ASSERT_EQUAL(string(expect, sizeof(expect)-1), boost::lexical_cast<string>(frame)) + + void testRequestResponseRoundtrip() { + broker::InProcessBroker ibroker(version); + client::Connection clientConnection; + clientConnection.setConnector(ibroker); + clientConnection.open(""); + client::Channel c; + clientConnection.openChannel(c); + + client::Exchange exchange( + "MyExchange", client::Exchange::TOPIC_EXCHANGE); + client::Queue queue("MyQueue", true); + c.declareExchange(exchange); + c.declareQueue(queue); + c.bind(exchange, queue, "MyTopic", framing::FieldTable()); + broker::InProcessBroker::Conversation::const_iterator i = ibroker.conversation.begin(); + ASSERT_FRAME("BROKER: Frame[channel=0; request(id=1,mark=0): ConnectionStart: versionMajor=0; versionMinor=9; serverProperties={}; mechanisms=PLAIN; locales=en_US]", *i++); + ASSERT_FRAME("CLIENT: Frame[channel=0; response(id=1,request=1,batch=0): ConnectionStartOk: clientProperties={}; mechanism=PLAIN; response=\000guest\000guest; locale=en_US]", *i++); + ASSERT_FRAME("BROKER: Frame[channel=0; request(id=2,mark=1): ConnectionTune: channelMax=100; frameMax=65536; heartbeat=0]", *i++); + ASSERT_FRAME("CLIENT: Frame[channel=0; response(id=2,request=2,batch=0): ConnectionTuneOk: channelMax=100; frameMax=65536; heartbeat=0]", *i++); + ASSERT_FRAME("CLIENT: Frame[channel=0; request(id=1,mark=0): ConnectionOpen: virtualHost=/; capabilities=; insist=1]", *i++); + ASSERT_FRAME("BROKER: Frame[channel=0; response(id=1,request=1,batch=0): ConnectionOpenOk: knownHosts=]", *i++); + ASSERT_FRAME("CLIENT: Frame[channel=1; request(id=1,mark=0): ChannelOpen: outOfBand=]", *i++); + ASSERT_FRAME("BROKER: Frame[channel=1; response(id=1,request=1,batch=0): ChannelOpenOk: channelId=]", *i++); + ASSERT_FRAME("CLIENT: Frame[channel=1; request(id=2,mark=1): ExchangeDeclare: ticket=0; exchange=MyExchange; type=topic; passive=0; durable=0; autoDelete=0; internal=0; nowait=0; arguments={}]", *i++); + ASSERT_FRAME("BROKER: Frame[channel=1; response(id=2,request=2,batch=0): ExchangeDeclareOk: ]", *i++); + ASSERT_FRAME("CLIENT: Frame[channel=1; request(id=3,mark=2): QueueDeclare: ticket=0; queue=MyQueue; passive=0; durable=0; exclusive=1; autoDelete=1; nowait=0; arguments={}]", *i++); + ASSERT_FRAME("BROKER: Frame[channel=1; response(id=3,request=3,batch=0): QueueDeclareOk: queue=MyQueue; messageCount=0; consumerCount=0]", *i++); + ASSERT_FRAME("CLIENT: Frame[channel=1; request(id=4,mark=3): QueueBind: ticket=0; queue=MyQueue; exchange=MyExchange; routingKey=MyTopic; nowait=0; arguments={}]", *i++); + ASSERT_FRAME("BROKER: Frame[channel=1; response(id=4,request=4,batch=0): QueueBindOk: ]", *i++); + } + }; + + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(FramingTest); + + + diff --git a/qpid/cpp-0-9/tests/HeaderTest.cpp b/qpid/cpp-0-9/tests/HeaderTest.cpp new file mode 100644 index 0000000000..f77aaaedb4 --- /dev/null +++ b/qpid/cpp-0-9/tests/HeaderTest.cpp @@ -0,0 +1,141 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <amqp_framing.h> +#include <qpid_test_plugin.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: + + 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"); + uint8_t deliveryMode(2); + uint8_t priority(3); + string correlationId("abc"); + string replyTo("no-address"); + string expiration("why is this a string?"); + string messageId("xyz"); + uint64_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"); + uint8_t deliveryMode(5); + uint8_t priority(6); + string expiration("Z"); + uint64_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/qpid/cpp-0-9/tests/HeadersExchangeTest.cpp b/qpid/cpp-0-9/tests/HeadersExchangeTest.cpp new file mode 100644 index 0000000000..6cd51c55a9 --- /dev/null +++ b/qpid/cpp-0-9/tests/HeadersExchangeTest.cpp @@ -0,0 +1,115 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <HeadersExchange.h> +#include <FieldTable.h> +#include <Value.h> +#include <qpid_test_plugin.h> + +using namespace qpid::broker; +using namespace qpid::framing; + +class HeadersExchangeTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(HeadersExchangeTest); + CPPUNIT_TEST(testMatchAll); + CPPUNIT_TEST(testMatchAny); + CPPUNIT_TEST(testMatchEmptyValue); + CPPUNIT_TEST(testMatchEmptyArgs); + CPPUNIT_TEST(testMatchNoXMatch); + CPPUNIT_TEST_SUITE_END(); + + public: + + void testMatchAll() + { + FieldTable b, m; + b.setString("x-match", "all"); + b.setString("foo", "FOO"); + b.setInt("n", 42); + m.setString("foo", "FOO"); + m.setInt("n", 42); + CPPUNIT_ASSERT(HeadersExchange::match(b, m)); + + // Ignore extras. + m.setString("extra", "x"); + CPPUNIT_ASSERT(HeadersExchange::match(b, m)); + + // Fail mismatch, wrong value. + m.setString("foo", "NotFoo"); + CPPUNIT_ASSERT(!HeadersExchange::match(b, m)); + + // Fail mismatch, missing value + m.erase("foo"); + CPPUNIT_ASSERT(!HeadersExchange::match(b, m)); + } + + void testMatchAny() + { + FieldTable b, m; + b.setString("x-match", "any"); + b.setString("foo", "FOO"); + b.setInt("n", 42); + m.setString("foo", "FOO"); + CPPUNIT_ASSERT(HeadersExchange::match(b, m)); + m.erase("foo"); + CPPUNIT_ASSERT(!HeadersExchange::match(b, m)); + m.setInt("n", 42); + CPPUNIT_ASSERT(HeadersExchange::match(b, m)); + } + + void testMatchEmptyValue() + { + FieldTable b, m; + b.setString("x-match", "all"); + b.getMap()["foo"] = FieldTable::ValuePtr(new EmptyValue()); + b.getMap()["n"] = FieldTable::ValuePtr(new EmptyValue()); + CPPUNIT_ASSERT(!HeadersExchange::match(b, m)); + m.setString("foo", "blah"); + m.setInt("n", 123); + } + + void testMatchEmptyArgs() + { + FieldTable b, m; + m.setString("foo", "FOO"); + + b.setString("x-match", "all"); + CPPUNIT_ASSERT(HeadersExchange::match(b, m)); + b.setString("x-match", "any"); + CPPUNIT_ASSERT(!HeadersExchange::match(b, m)); + } + + + void testMatchNoXMatch() + { + FieldTable b, m; + b.setString("foo", "FOO"); + m.setString("foo", "FOO"); + CPPUNIT_ASSERT(!HeadersExchange::match(b, m)); + } + + +}; + +// make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(HeadersExchangeTest); diff --git a/qpid/cpp-0-9/tests/InMemoryContentTest.cpp b/qpid/cpp-0-9/tests/InMemoryContentTest.cpp new file mode 100644 index 0000000000..d02cc56a7b --- /dev/null +++ b/qpid/cpp-0-9/tests/InMemoryContentTest.cpp @@ -0,0 +1,92 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <InMemoryContent.h> +#include <qpid_test_plugin.h> +#include <AMQP_HighestVersion.h> +#include <iostream> +#include <list> +#include "AMQFrame.h" +#include "MockChannel.h" + +using std::list; +using std::string; +using boost::dynamic_pointer_cast; +using namespace qpid::broker; +using namespace qpid::framing; + + +class InMemoryContentTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(InMemoryContentTest); + CPPUNIT_TEST(testRefragmentation); + CPPUNIT_TEST_SUITE_END(); + +public: + void testRefragmentation() + { + {//no remainder + string out[] = {"abcde", "fghij", "klmno", "pqrst"}; + string in[] = {out[0] + out[1], out[2] + out[3]}; + refragment(2, in, 4, out); + } + {//remainder for last frame + string out[] = {"abcde", "fghij", "klmno", "pqrst", "uvw"}; + string in[] = {out[0] + out[1], out[2] + out[3] + out[4]}; + refragment(2, in, 5, out); + } + } + + + void refragment(size_t inCount, string* in, size_t outCount, string* out, uint32_t framesize = 5) + { + InMemoryContent content; + MockChannel channel(3); + + addframes(content, inCount, in); + content.send(channel, framesize); + CPPUNIT_ASSERT_EQUAL(outCount, channel.out.frames.size()); + + for (unsigned int i = 0; i < outCount; i++) { + AMQContentBody::shared_ptr chunk( + dynamic_pointer_cast<AMQContentBody>( + channel.out.frames[i]->getBody())); + CPPUNIT_ASSERT(chunk); + CPPUNIT_ASSERT_EQUAL(out[i], chunk->getData()); + CPPUNIT_ASSERT_EQUAL( + ChannelId(3), channel.out.frames[i]->getChannel()); + } + } + + void addframes(InMemoryContent& content, size_t frameCount, string* frameData) + { + for (unsigned int i = 0; i < frameCount; i++) { + AMQContentBody::shared_ptr frame(new AMQContentBody(frameData[i])); + content.add(frame); + } + } + + +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(InMemoryContentTest); + diff --git a/qpid/cpp-0-9/tests/InProcessBroker.h b/qpid/cpp-0-9/tests/InProcessBroker.h new file mode 100644 index 0000000000..709ca9b953 --- /dev/null +++ b/qpid/cpp-0-9/tests/InProcessBroker.h @@ -0,0 +1,169 @@ +#ifndef _tests_InProcessBroker_h +#define _tests_InProcessBroker_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include <vector> +#include <iostream> +#include <algorithm> + +#include "AMQP_HighestVersion.h" +#include "framing/AMQFrame.h" +#include "broker/Broker.h" +#include "broker/Connection.h" +#include "client/Connector.h" +#include "client/Connection.h" + +namespace qpid { +namespace broker { + +/** Make a copy of a frame body. Inefficient, only intended for tests. */ +// TODO aconway 2007-01-29: from should be const, need to fix +// AMQPFrame::encode as const. +framing::AMQFrame copy(framing::AMQFrame& from) { + framing::Buffer buffer(from.size()); + from.encode(buffer); + buffer.flip(); + framing::AMQFrame result; + result.decode(buffer); + return result; +} + +/** + * A broker that implements client::Connector allowing direct + * in-process connection of client to broker. Used to write round-trip + * tests without requiring an external broker process. + * + * Also allows you to "snoop" on frames exchanged between client & broker. + * + * see FramingTest::testRequestResponseRoundtrip() for example of use. + */ +class InProcessBroker : public client::Connector { + public: + enum Sender {CLIENT,BROKER}; + + struct Frame : public framing::AMQFrame { + Frame(Sender e, const AMQFrame& f) : AMQFrame(f), from(e) {} + bool fromBroker() const { return from == BROKER; } + bool fromClient() const { return from == CLIENT; } + + template <class MethodType> + MethodType* asMethod() { + return dynamic_cast<MethodType*>(getBody().get()); + } + + Sender from; + }; + typedef std::vector<Frame> Conversation; + + InProcessBroker(framing::ProtocolVersion ver= + framing::highestProtocolVersion + ) : + Connector(ver), + protocolInit(ver), + broker(broker::Broker::create()), + brokerOut(BROKER, conversation), + brokerConnection(&brokerOut, *broker), + clientOut(CLIENT, conversation, &brokerConnection) + {} + + ~InProcessBroker() { broker->shutdown(); } + + void connect(const std::string& /*host*/, int /*port*/) {} + void init() { brokerConnection.initiated(&protocolInit); } + void close() {} + + /** Client's input handler. */ + void setInputHandler(framing::InputHandler* handler) { + brokerOut.in = handler; + } + + /** Called by client to send a frame */ + void send(framing::AMQFrame* frame) { + clientOut.send(frame); + } + + /** Entire client-broker conversation is recorded here */ + Conversation conversation; + + private: + /** OutputHandler that forwards data to an InputHandler */ + struct OutputToInputHandler : public sys::ConnectionOutputHandler { + OutputToInputHandler( + Sender from_, Conversation& conversation_, + framing::InputHandler* ih=0 + ) : from(from_), conversation(conversation_), in(ih) {} + + void send(framing::AMQFrame* frame) { + conversation.push_back(Frame(from, copy(*frame))); + in->received(frame); + } + + void close() {} + + Sender from; + Conversation& conversation; + framing::InputHandler* in; + }; + + framing::ProtocolInitiation protocolInit; + Broker::shared_ptr broker; + OutputToInputHandler brokerOut; + broker::Connection brokerConnection; + OutputToInputHandler clientOut; +}; + +std::ostream& operator<<( + std::ostream& out, const InProcessBroker::Frame& frame) +{ + return out << (frame.fromBroker()? "BROKER: ":"CLIENT: ") << + static_cast<const framing::AMQFrame&>(frame); +} +std::ostream& operator<<( + std::ostream& out, const InProcessBroker::Conversation& conv) +{ + for (InProcessBroker::Conversation::const_iterator i = conv.begin(); + i != conv.end(); ++i) + { + out << *i << std::endl; + } + return out; +} + + +}} // namespace qpid::broker + +/** An in-process client+broker all in one. */ +class InProcessBrokerClient : public qpid::client::Connection { + public: + qpid::broker::InProcessBroker broker; + qpid::broker::InProcessBroker::Conversation& conversation; + + /** Constructor creates broker and opens client connection. */ + InProcessBrokerClient(qpid::framing::ProtocolVersion version= + qpid::framing::highestProtocolVersion + ) : broker(version), conversation(broker.conversation) + { + setConnector(broker); + open(""); + } + + ~InProcessBrokerClient() {} +}; + +#endif // _tests_InProcessBroker_h diff --git a/qpid/cpp-0-9/tests/LazyLoadedContentTest.cpp b/qpid/cpp-0-9/tests/LazyLoadedContentTest.cpp new file mode 100644 index 0000000000..b24cd5a84a --- /dev/null +++ b/qpid/cpp-0-9/tests/LazyLoadedContentTest.cpp @@ -0,0 +1,112 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <LazyLoadedContent.h> +#include <AMQP_HighestVersion.h> +#include <NullMessageStore.h> +#include <qpid_test_plugin.h> +#include <iostream> +#include <list> +#include <sstream> +#include "AMQFrame.h" +#include "MockChannel.h" +using std::list; +using std::string; +using boost::dynamic_pointer_cast; +using namespace qpid::broker; +using namespace qpid::framing; + + + +class LazyLoadedContentTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(LazyLoadedContentTest); + CPPUNIT_TEST(testFragmented); + CPPUNIT_TEST(testWhole); + CPPUNIT_TEST(testHalved); + CPPUNIT_TEST_SUITE_END(); + + class TestMessageStore : public NullMessageStore + { + const string content; + + public: + TestMessageStore(const string& _content) : content(_content) {} + + void loadContent(Message* const, string& data, uint64_t offset, uint32_t length) + { + if (offset + length <= content.size()) { + data = content.substr(offset, length); + } else{ + std::stringstream error; + error << "Invalid segment: offset=" << offset << ", length=" << length << ", content_length=" << content.size(); + throw qpid::Exception(error.str()); + } + } + }; + + +public: + void testFragmented() + { + string data = "abcdefghijklmnopqrstuvwxyz"; + uint32_t framesize = 5; + string out[] = {"abcde", "fghij", "klmno", "pqrst", "uvwxy", "z"}; + load(data, 6, out, framesize); + } + + void testWhole() + { + string data = "abcdefghijklmnopqrstuvwxyz"; + uint32_t framesize = 50; + string out[] = {data}; + load(data, 1, out, framesize); + } + + void testHalved() + { + string data = "abcdefghijklmnopqrstuvwxyz"; + uint32_t framesize = 13; + string out[] = {"abcdefghijklm", "nopqrstuvwxyz"}; + load(data, 2, out, framesize); + } + + void load(string& in, size_t outCount, string* out, uint32_t framesize) + { + TestMessageStore store(in); + LazyLoadedContent content(&store, 0, in.size()); + MockChannel channel(3); + content.send(channel, framesize); + CPPUNIT_ASSERT_EQUAL(outCount, channel.out.frames.size()); + + for (unsigned int i = 0; i < outCount; i++) { + AMQContentBody::shared_ptr chunk(dynamic_pointer_cast<AMQContentBody, AMQBody>(channel.out.frames[i]->getBody())); + CPPUNIT_ASSERT(chunk); + CPPUNIT_ASSERT_EQUAL(out[i], chunk->getData()); + CPPUNIT_ASSERT_EQUAL( + ChannelId(3), channel.out.frames[i]->getChannel()); + } + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(LazyLoadedContentTest); + diff --git a/qpid/cpp-0-9/tests/Makefile.am b/qpid/cpp-0-9/tests/Makefile.am new file mode 100644 index 0000000000..edad0945f3 --- /dev/null +++ b/qpid/cpp-0-9/tests/Makefile.am @@ -0,0 +1,118 @@ +AM_CXXFLAGS = $(WARNING_CFLAGS) $(CPPUNIT_CXXFLAGS) +INCLUDES = \ + -I$(top_srcdir)/gen \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/lib/client \ + -I$(top_srcdir)/lib/broker \ + -I$(top_srcdir)/lib/common \ + -I$(top_srcdir)/lib/common/sys \ + -I$(top_srcdir)/lib/common/framing \ + $(APR_CXXFLAGS) + +# Unit tests +broker_tests = \ + AccumulatedAckTest \ + BrokerChannelTest \ + ConfigurationTest \ + ExchangeTest \ + HeadersExchangeTest \ + InMemoryContentTest \ + LazyLoadedContentTest \ + MessageBuilderTest \ + MessageTest \ + ReferenceTest \ + QueueRegistryTest \ + QueueTest \ + QueuePolicyTest \ + TopicExchangeTest \ + TxAckTest \ + TxBufferTest \ + TxPublishTest \ + ValueTest \ + MessageHandlerTest + +client_tests = \ + ClientChannelTest + +framing_tests = \ + FieldTableTest \ + FramingTest \ + HeaderTest + +misc_tests = \ + ExceptionTest \ + ProducerConsumerTest + +posix_tests = \ + EventChannelTest \ + EventChannelThreadsTest + +unit_tests = \ + $(broker_tests) \ + $(client_tests) \ + $(framing_tests) \ + $(misc_tests) + +# Executable client tests + +client_exe_tests = \ + client_test \ + echo_service \ + topic_listener \ + topic_publisher + +noinst_PROGRAMS = $(client_exe_tests) + +TESTS_ENVIRONMENT = \ + VALGRIND=$(VALGRIND) \ + abs_builddir='$(abs_builddir)' \ + PATH="$(abs_builddir)/../src$(PATH_SEPARATOR)$$PATH" \ + abs_srcdir='$(abs_srcdir)' + +CLIENT_TESTS = client_test quick_topictest +TESTS = run-unit-tests start_broker $(CLIENT_TESTS) python_tests kill_broker + +EXTRA_DIST = \ + $(TESTS) \ + .vg-supp \ + InProcessBroker.h \ + MockChannel.h \ + MockConnectionInputHandler.h \ + qpid_test_plugin.h \ + setup \ + topicall \ + topictest \ + APRBaseTest.cpp + +CLEANFILES=qpidd.log +DISTCLEANFILES=gen.mk + +include gen.mk + +abs_builddir = @abs_builddir@ +extra_libs = $(CPPUNIT_LIBS) +lib_client = $(abs_builddir)/../lib/client/libqpidclient.la +lib_common = $(abs_builddir)/../lib/common/libqpidcommon.la +lib_broker = $(abs_builddir)/../lib/broker/libqpidbroker.la + +gen.mk: Makefile.am + ( \ + for i in $(client_exe_tests); do \ + echo $${i}_SOURCES = $$i.cpp; \ + echo $${i}_LDADD = '$$(lib_client) $$(lib_common) $$(extra_libs)'; \ + done; \ + libs=; \ + for i in $(unit_tests); do \ + libs="$$libs $${i}.la"; \ + echo $${i}_la_SOURCES = $$i.cpp; \ + echo $${i}_la_LIBADD = '$$(lib_common) $$(lib_client)'; \ + echo $${i}_la_LIBADD += '$$(lib_broker) $$(extra_libs)'; \ + echo $${i}_la_LDFLAGS = "-module -rpath `pwd`"; \ + done; \ + echo "check_LTLIBRARIES =$$libs"; \ + ) \ + > $@-t + mv $@-t $@ + + +check: $(check_LTLIBRARIES) $(lib_common) $(lib_client) $(lib_broker) diff --git a/qpid/cpp-0-9/tests/MessageBuilderTest.cpp b/qpid/cpp-0-9/tests/MessageBuilderTest.cpp new file mode 100644 index 0000000000..d3b3902e97 --- /dev/null +++ b/qpid/cpp-0-9/tests/MessageBuilderTest.cpp @@ -0,0 +1,226 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <Exception.h> +#include <BrokerMessage.h> +#include <MessageBuilder.h> +#include <NullMessageStore.h> +#include <Buffer.h> +#include <qpid_test_plugin.h> +#include <iostream> +#include <memory> +#include "MockChannel.h" + +using namespace boost; +using namespace qpid::broker; +using namespace qpid::framing; +using namespace qpid::sys; + +class MessageBuilderTest : public CppUnit::TestCase +{ + struct MockHandler : CompletionHandler { + Message::shared_ptr msg; + + virtual void complete(Message::shared_ptr _msg){ + msg = _msg; + } + }; + + class TestMessageStore : public NullMessageStore + { + Buffer* header; + Buffer* content; + const uint32_t contentBufferSize; + + public: + + void stage(Message* const msg) + { + if (msg->getPersistenceId() == 0) { + header = new Buffer(msg->encodedHeaderSize()); + msg->encodeHeader(*header); + content = new Buffer(contentBufferSize); + msg->setPersistenceId(1); + } else { + throw qpid::Exception("Message already staged!"); + } + } + + void appendContent(Message* msg, const string& data) + { + if (msg) { + content->putRawData(data); + } else { + throw qpid::Exception("Invalid message id!"); + } + } + + // Don't hide overloads. + using NullMessageStore::destroy; + + void destroy(BasicMessage* msg) + { + CPPUNIT_ASSERT(msg->getPersistenceId()); + } + + BasicMessage::shared_ptr getRestoredMessage() + { + BasicMessage::shared_ptr msg(new BasicMessage()); + if (header) { + header->flip(); + msg->decodeHeader(*header); + delete header; + header = 0; + if (content) { + content->flip(); + msg->decodeContent(*content); + delete content; + content = 0; + } + } + return msg; + } + + //dont care about any of the other methods: + TestMessageStore(uint32_t _contentBufferSize) : NullMessageStore(), header(0), content(0), + contentBufferSize(_contentBufferSize) {} + ~TestMessageStore(){} + }; + + CPPUNIT_TEST_SUITE(MessageBuilderTest); + CPPUNIT_TEST(testHeaderOnly); + CPPUNIT_TEST(test1ContentFrame); + CPPUNIT_TEST(test2ContentFrames); + CPPUNIT_TEST(testStaging); + CPPUNIT_TEST_SUITE_END(); + + public: + + void testHeaderOnly(){ + MockHandler handler; + MessageBuilder builder(&handler); + + Message::shared_ptr message( + new BasicMessage( + 0, "test", "my_routing_key", false, false, + MockChannel::basicGetBody())); + AMQHeaderBody::shared_ptr header(new AMQHeaderBody(BASIC)); + header->setContentSize(0); + + builder.initialise(message); + CPPUNIT_ASSERT(!handler.msg); + builder.setHeader(header); + CPPUNIT_ASSERT(handler.msg); + CPPUNIT_ASSERT_EQUAL(message, handler.msg); + } + + void test1ContentFrame(){ + MockHandler handler; + MessageBuilder builder(&handler); + + string data1("abcdefg"); + + Message::shared_ptr message( + new BasicMessage(0, "test", "my_routing_key", false, false, + MockChannel::basicGetBody())); + AMQHeaderBody::shared_ptr header(new AMQHeaderBody(BASIC)); + header->setContentSize(7); + AMQContentBody::shared_ptr part1(new AMQContentBody(data1)); + + builder.initialise(message); + CPPUNIT_ASSERT(!handler.msg); + builder.setHeader(header); + CPPUNIT_ASSERT(!handler.msg); + builder.addContent(part1); + CPPUNIT_ASSERT(handler.msg); + CPPUNIT_ASSERT_EQUAL(message, handler.msg); + } + + void test2ContentFrames(){ + MockHandler handler; + MessageBuilder builder(&handler); + + string data1("abcdefg"); + string data2("hijklmn"); + + Message::shared_ptr message( + new BasicMessage(0, "test", "my_routing_key", false, false, + MockChannel::basicGetBody())); + AMQHeaderBody::shared_ptr header(new AMQHeaderBody(BASIC)); + header->setContentSize(14); + AMQContentBody::shared_ptr part1(new AMQContentBody(data1)); + AMQContentBody::shared_ptr part2(new AMQContentBody(data2)); + + builder.initialise(message); + CPPUNIT_ASSERT(!handler.msg); + builder.setHeader(header); + CPPUNIT_ASSERT(!handler.msg); + builder.addContent(part1); + CPPUNIT_ASSERT(!handler.msg); + builder.addContent(part2); + CPPUNIT_ASSERT(handler.msg); + CPPUNIT_ASSERT_EQUAL(message, handler.msg); + } + + void testStaging(){ + //store must be the last thing to be destroyed or destructor + //of Message fails (it uses the store to call destroy if lazy + //loaded content is in use) + TestMessageStore store(14); + { + MockHandler handler; + MessageBuilder builder(&handler, &store, 5); + + string data1("abcdefg"); + string data2("hijklmn"); + + Message::shared_ptr message( + new BasicMessage(0, "test", "my_routing_key", false, false, + MockChannel::basicGetBody())); + AMQHeaderBody::shared_ptr header(new AMQHeaderBody(BASIC)); + header->setContentSize(14); + BasicHeaderProperties* properties = dynamic_cast<BasicHeaderProperties*>(header->getProperties()); + properties->setMessageId("MyMessage"); + properties->getHeaders().setString("abc", "xyz"); + + AMQContentBody::shared_ptr part1(new AMQContentBody(data1)); + AMQContentBody::shared_ptr part2(new AMQContentBody(data2)); + + builder.initialise(message); + builder.setHeader(header); + builder.addContent(part1); + builder.addContent(part2); + CPPUNIT_ASSERT(handler.msg); + CPPUNIT_ASSERT_EQUAL(message, handler.msg); + + BasicMessage::shared_ptr restored = store.getRestoredMessage(); + CPPUNIT_ASSERT_EQUAL(message->getExchange(), restored->getExchange()); + CPPUNIT_ASSERT_EQUAL(message->getRoutingKey(), restored->getRoutingKey()); + CPPUNIT_ASSERT_EQUAL(message->getHeaderProperties()->getMessageId(), restored->getHeaderProperties()->getMessageId()); + CPPUNIT_ASSERT_EQUAL(message->getHeaderProperties()->getHeaders().getString("abc"), + restored->getHeaderProperties()->getHeaders().getString("abc")); + CPPUNIT_ASSERT_EQUAL((uint64_t) 14, restored->contentSize()); + } + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(MessageBuilderTest); diff --git a/qpid/cpp-0-9/tests/MessageHandlerTest.cpp b/qpid/cpp-0-9/tests/MessageHandlerTest.cpp new file mode 100644 index 0000000000..55971355f6 --- /dev/null +++ b/qpid/cpp-0-9/tests/MessageHandlerTest.cpp @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +//#include <iostream> +//#include <AMQP_HighestVersion.h> +#include <amqp_framing.h> +#include <qpid_test_plugin.h> + +#include <BrokerAdapter.h> + +using namespace qpid::framing; +using namespace qpid::broker; + +class MessageHandlerTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(MessageHandlerTest); + CPPUNIT_TEST(testOpenMethod); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + + MessageHandlerTest() + { + } + + void testOpenMethod() + { + //AMQFrame frame(highestProtocolVersion, 0, method); + //TestBodyHandler handler(method); + //handler.handleBody(frame.getBody()); + } + +}; + + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(MessageHandlerTest); + diff --git a/qpid/cpp-0-9/tests/MessageTest.cpp b/qpid/cpp-0-9/tests/MessageTest.cpp new file mode 100644 index 0000000000..a3bbfe4afc --- /dev/null +++ b/qpid/cpp-0-9/tests/MessageTest.cpp @@ -0,0 +1,89 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <BrokerMessage.h> +#include <qpid_test_plugin.h> +#include <iostream> +#include <AMQP_HighestVersion.h> +#include "AMQFrame.h" +#include "MockChannel.h" + +using namespace boost; +using namespace qpid::broker; +using namespace qpid::framing; + +class MessageTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(MessageTest); + CPPUNIT_TEST(testEncodeDecode); + CPPUNIT_TEST_SUITE_END(); + + public: + + void testEncodeDecode() + { + string exchange = "MyExchange"; + string routingKey = "MyRoutingKey"; + string messageId = "MyMessage"; + string data1("abcdefg"); + string data2("hijklmn"); + + BasicMessage::shared_ptr msg( + new BasicMessage(0, exchange, routingKey, false, false, + MockChannel::basicGetBody())); + AMQHeaderBody::shared_ptr header(new AMQHeaderBody(BASIC)); + header->setContentSize(14); + AMQContentBody::shared_ptr part1(new AMQContentBody(data1)); + AMQContentBody::shared_ptr part2(new AMQContentBody(data2)); + msg->setHeader(header); + msg->addContent(part1); + msg->addContent(part2); + + msg->getHeaderProperties()->setMessageId(messageId); + msg->getHeaderProperties()->setDeliveryMode(PERSISTENT); + msg->getHeaderProperties()->getHeaders().setString("abc", "xyz"); + + Buffer buffer(msg->encodedSize()); + msg->encode(buffer); + buffer.flip(); + + msg.reset(new BasicMessage()); + msg->decode(buffer); + CPPUNIT_ASSERT_EQUAL(exchange, msg->getExchange()); + CPPUNIT_ASSERT_EQUAL(routingKey, msg->getRoutingKey()); + CPPUNIT_ASSERT_EQUAL(messageId, msg->getHeaderProperties()->getMessageId()); + CPPUNIT_ASSERT_EQUAL((uint8_t) PERSISTENT, msg->getHeaderProperties()->getDeliveryMode()); + CPPUNIT_ASSERT_EQUAL(string("xyz"), msg->getHeaderProperties()->getHeaders().getString("abc")); + CPPUNIT_ASSERT_EQUAL((uint64_t) 14, msg->contentSize()); + + MockChannel channel(1); + // FIXME aconway 2007-02-02: deliver should take ProtocolVersion + msg->deliver(channel, "ignore", 0, 100); + CPPUNIT_ASSERT_EQUAL((size_t) 3, channel.out.frames.size()); + AMQContentBody::shared_ptr contentBody(dynamic_pointer_cast<AMQContentBody, AMQBody>(channel.out.frames[2]->getBody())); + CPPUNIT_ASSERT(contentBody); + CPPUNIT_ASSERT_EQUAL(data1 + data2, contentBody->getData()); + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(MessageTest); + diff --git a/qpid/cpp-0-9/tests/MockChannel.h b/qpid/cpp-0-9/tests/MockChannel.h new file mode 100644 index 0000000000..10fcb56969 --- /dev/null +++ b/qpid/cpp-0-9/tests/MockChannel.h @@ -0,0 +1,69 @@ +#ifndef _tests_MockChannel_h +#define _tests_MockChannel_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <boost/shared_ptr.hpp> +#include "framing/MethodContext.h" +#include "framing/ChannelAdapter.h" +#include "framing/OutputHandler.h" +#include "framing/AMQFrame.h" +#include "BasicGetBody.h" + +/** Mock output handler to collect frames */ +struct MockOutputHandler : public qpid::framing::OutputHandler { + std::vector<qpid::framing::AMQFrame*> frames; + void send(qpid::framing::AMQFrame* frame){ frames.push_back(frame); } +}; + +/** + * Combination mock OutputHandler and ChannelAdapter for tests. + */ +struct MockChannel : public qpid::framing::ChannelAdapter +{ + typedef qpid::framing::BasicGetBody Body; + static Body::shared_ptr basicGetBody() { + return Body::shared_ptr( + new Body(qpid::framing::ProtocolVersion())); + } + + MockOutputHandler out; + + MockChannel(qpid::framing::ChannelId id) { + init(id, out, qpid::framing::ProtocolVersion()); + } + + bool isOpen() const { return true; } + + void handleHeader( + boost::shared_ptr<qpid::framing::AMQHeaderBody> b) { send(b); } + void handleContent( + boost::shared_ptr<qpid::framing::AMQContentBody> b) { send(b); } + void handleHeartbeat( + boost::shared_ptr<qpid::framing::AMQHeartbeatBody> b) { send(b); } + void handleMethodInContext( + boost::shared_ptr<qpid::framing::AMQMethodBody> method, + const qpid::framing::MethodContext& context) + { + context.channel->send(method); + }; + +}; + +#endif /*!_tests_MockChannel_h*/ diff --git a/qpid/cpp-0-9/tests/MockConnectionInputHandler.h b/qpid/cpp-0-9/tests/MockConnectionInputHandler.h new file mode 100644 index 0000000000..b039e244d9 --- /dev/null +++ b/qpid/cpp-0-9/tests/MockConnectionInputHandler.h @@ -0,0 +1,113 @@ +#ifndef _tests_MockConnectionInputHandler_h +#define _tests_MockConnectionInputHandler_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "sys/ConnectionInputHandler.h" +#include "sys/ConnectionInputHandlerFactory.h" +#include "sys/Monitor.h" +#include "framing/ProtocolInitiation.h" + +struct MockConnectionInputHandler : public qpid::sys::ConnectionInputHandler { + + MockConnectionInputHandler() : state(START) {} + + ~MockConnectionInputHandler() {} + + void initiated(qpid::framing::ProtocolInitiation* pi) { + qpid::sys::Monitor::ScopedLock l(monitor); + init = *pi; + setState(GOT_INIT); + } + + void received(qpid::framing::AMQFrame* framep) { + qpid::sys::Monitor::ScopedLock l(monitor); + frame = *framep; + setState(GOT_FRAME); + } + + qpid::framing::ProtocolInitiation waitForProtocolInit() { + waitFor(GOT_INIT); + return init; + } + + qpid::framing::AMQFrame waitForFrame() { + waitFor(GOT_FRAME); + return frame; + } + + void waitForClosed() { + waitFor(CLOSED); + } + + void closed() { + qpid::sys::Monitor::ScopedLock l(monitor); + setState(CLOSED); + } + + void idleOut() {} + void idleIn() {} + + private: + typedef enum { START, GOT_INIT, GOT_FRAME, CLOSED } State; + + void setState(State s) { + state = s; + monitor.notify(); + } + + void waitFor(State s) { + qpid::sys::Monitor::ScopedLock l(monitor); + qpid::sys::Time deadline = qpid::sys::now() + 10*qpid::sys::TIME_SEC; + while (state != s) + CPPUNIT_ASSERT(monitor.wait(deadline)); + } + + qpid::sys::Monitor monitor; + State state; + qpid::framing::ProtocolInitiation init; + qpid::framing::AMQFrame frame; +}; + + +struct MockConnectionInputHandlerFactory : public qpid::sys::ConnectionInputHandlerFactory { + MockConnectionInputHandlerFactory() : handler(0) {} + + qpid::sys::ConnectionInputHandler* create(qpid::sys::ConnectionOutputHandler*) { + qpid::sys::Monitor::ScopedLock lock(monitor); + handler = new MockConnectionInputHandler(); + monitor.notifyAll(); + return handler; + } + + void waitForHandler() { + qpid::sys::Monitor::ScopedLock lock(monitor); + qpid::sys::Time deadline = + qpid::sys::now() + 500 * qpid::sys::TIME_SEC; + while (handler == 0) + CPPUNIT_ASSERT(monitor.wait(deadline)); + } + + MockConnectionInputHandler* handler; + qpid::sys::Monitor monitor; +}; + + + +#endif /*!_tests_MockConnectionInputHandler_h*/ diff --git a/qpid/cpp-0-9/tests/ProducerConsumerTest.cpp b/qpid/cpp-0-9/tests/ProducerConsumerTest.cpp new file mode 100644 index 0000000000..e6d4090596 --- /dev/null +++ b/qpid/cpp-0-9/tests/ProducerConsumerTest.cpp @@ -0,0 +1,283 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <vector> +#include <iostream> + +#include <boost/bind.hpp> + +#include <qpid_test_plugin.h> +#include "InProcessBroker.h" +#include "sys/ProducerConsumer.h" +#include "sys/Thread.h" +#include "AMQP_HighestVersion.h" +#include "sys/AtomicCount.h" + +using namespace qpid::sys; +using namespace qpid::framing; +using namespace boost; +using namespace std; + +/** A counter that notifies a monitor when changed */ +class WatchedCounter : public Monitor { + public: + WatchedCounter(int i=0) : count(i) {} + WatchedCounter(const WatchedCounter& c) : Monitor(), count(int(c)) {} + + WatchedCounter& operator=(const WatchedCounter& x) { + return *this = int(x); + } + + WatchedCounter& operator=(int i) { + Lock l(*this); + count = i; + return *this; + } + + int operator++() { + Lock l(*this); + notifyAll(); + return ++count; + } + + int operator++(int) { + Lock l(*this); + notifyAll(); + return count++; + } + + bool operator==(int i) const { + Lock l(const_cast<WatchedCounter&>(*this)); + return i == count; + } + + operator int() const { + Lock l(const_cast<WatchedCounter&>(*this)); + return count; + } + + bool waitFor(int i, Time timeout=TIME_SEC) { + Lock l(*this); + Time deadline = timeout+now(); + while (count != i) { + if (!wait(deadline)) + return false; + } + assert(count == i); + return true; + } + + private: + typedef Mutex::ScopedLock Lock; + int count; +}; + +class ProducerConsumerTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(ProducerConsumerTest); + CPPUNIT_TEST(testProduceConsume); + CPPUNIT_TEST(testTimeout); + CPPUNIT_TEST(testStop); + CPPUNIT_TEST(testCancel); + CPPUNIT_TEST_SUITE_END(); + + public: + InProcessBrokerClient client; + ProducerConsumer pc; + + WatchedCounter stopped; + WatchedCounter timeout; + WatchedCounter consumed; + WatchedCounter produced; + + struct ConsumeRunnable : public Runnable { + ProducerConsumerTest& test; + ConsumeRunnable(ProducerConsumerTest& test_) : test(test_) {} + void run() { test.consume(); } + }; + + struct ConsumeTimeoutRunnable : public Runnable { + ProducerConsumerTest& test; + Time timeout; + ConsumeTimeoutRunnable(ProducerConsumerTest& test_, const Time& t) + : test(test_), timeout(t) {} + void run() { test.consumeTimeout(timeout); } + }; + + + void consumeInternal(ProducerConsumer::ConsumerLock& consumer) { + if (pc.isStopped()) { + ++stopped; + return; + } + if (consumer.isTimedOut()) { + ++timeout; + return; + } + CPPUNIT_ASSERT(consumer.isOk()); + CPPUNIT_ASSERT(pc.available() > 0); + consumer.confirm(); + consumed++; + } + + void consume() { + ProducerConsumer::ConsumerLock consumer(pc); + consumeInternal(consumer); + }; + + void consumeTimeout(const Time& timeout) { + ProducerConsumer::ConsumerLock consumer(pc, timeout); + consumeInternal(consumer); + }; + + void produce() { + ProducerConsumer::ProducerLock producer(pc); + CPPUNIT_ASSERT(producer.isOk()); + producer.confirm(); + produced++; + } + + void join(vector<Thread>& threads) { + for_each(threads.begin(), threads.end(), bind(&Thread::join,_1)); + } + + vector<Thread> startThreads(size_t n, Runnable& runnable) { + vector<Thread> threads(n); + while (n > 0) + threads[--n] = Thread(runnable); + return threads; + } + +public: + ProducerConsumerTest() : client(highestProtocolVersion) {} + + void testProduceConsume() { + ConsumeRunnable runMe(*this); + produce(); + produce(); + CPPUNIT_ASSERT(produced.waitFor(2)); + vector<Thread> threads = startThreads(1, runMe); + CPPUNIT_ASSERT(consumed.waitFor(1)); + join(threads); + + threads = startThreads(1, runMe); + CPPUNIT_ASSERT(consumed.waitFor(2)); + join(threads); + + threads = startThreads(3, runMe); + produce(); + produce(); + CPPUNIT_ASSERT(consumed.waitFor(4)); + produce(); + CPPUNIT_ASSERT(consumed.waitFor(5)); + join(threads); + CPPUNIT_ASSERT_EQUAL(0, int(stopped)); + } + + void testTimeout() { + try { + // 0 timeout no items available throws exception + ProducerConsumer::ConsumerLock consumer(pc, 0); + CPPUNIT_FAIL("Expected exception"); + } catch(...){} + + produce(); + CPPUNIT_ASSERT(produced.waitFor(1)); + CPPUNIT_ASSERT_EQUAL(1, int(pc.available())); + { + // 0 timeout succeeds if there's an item available. + ProducerConsumer::ConsumerLock consume(pc, 0); + CPPUNIT_ASSERT(consume.isOk()); + consume.confirm(); + } + CPPUNIT_ASSERT_EQUAL(0, int(pc.available())); + + // Produce an item within the timeout. + ConsumeTimeoutRunnable runMe(*this, 2*TIME_SEC); + vector<Thread> threads = startThreads(1, runMe); + produce(); + CPPUNIT_ASSERT(consumed.waitFor(1)); + join(threads); + } + + + void testStop() { + ConsumeRunnable runMe(*this); + vector<Thread> threads = startThreads(2, runMe); + while (pc.consumers() != 2) + Thread::yield(); + pc.stop(); + CPPUNIT_ASSERT(stopped.waitFor(2)); + join(threads); + + threads = startThreads(1, runMe); // Should stop immediately. + CPPUNIT_ASSERT(stopped.waitFor(3)); + join(threads); + + // Produce/consume while stopped should return isStopped and + // throw on confirm. + try { + ProducerConsumer::ProducerLock p(pc); + CPPUNIT_ASSERT(pc.isStopped()); + CPPUNIT_FAIL("Expected exception"); + } + catch (...) {} // Expected + try { + ProducerConsumer::ConsumerLock c(pc); + CPPUNIT_ASSERT(pc.isStopped()); + CPPUNIT_FAIL("Expected exception"); + } + catch (...) {} // Expected + } + + void testCancel() { + CPPUNIT_ASSERT_EQUAL(size_t(0), pc.available()); + { + ProducerConsumer::ProducerLock p(pc); + CPPUNIT_ASSERT(p.isOk()); + p.cancel(); + } + // Nothing was produced. + CPPUNIT_ASSERT_EQUAL(size_t(0), pc.available()); + { + ProducerConsumer::ConsumerLock c(pc, 0); + CPPUNIT_ASSERT(c.isTimedOut()); + } + // Now produce but cancel the consume + { + ProducerConsumer::ProducerLock p(pc); + CPPUNIT_ASSERT(p.isOk()); + p.confirm(); + } + CPPUNIT_ASSERT_EQUAL(size_t(1), pc.available()); + { + ProducerConsumer::ConsumerLock c(pc); + CPPUNIT_ASSERT(c.isOk()); + c.cancel(); + } + CPPUNIT_ASSERT_EQUAL(size_t(1), pc.available()); + } +}; + + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(ProducerConsumerTest); + diff --git a/qpid/cpp-0-9/tests/QueuePolicyTest.cpp b/qpid/cpp-0-9/tests/QueuePolicyTest.cpp new file mode 100644 index 0000000000..20917dcd6a --- /dev/null +++ b/qpid/cpp-0-9/tests/QueuePolicyTest.cpp @@ -0,0 +1,89 @@ + /* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <QueuePolicy.h> +#include <qpid_test_plugin.h> + +using namespace qpid::broker; +using namespace qpid::framing; + +class QueuePolicyTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(QueuePolicyTest); + CPPUNIT_TEST(testCount); + CPPUNIT_TEST(testSize); + CPPUNIT_TEST(testBoth); + CPPUNIT_TEST(testSettings); + CPPUNIT_TEST_SUITE_END(); + + public: + void testCount(){ + QueuePolicy policy(5, 0); + CPPUNIT_ASSERT(!policy.limitExceeded()); + for (int i = 0; i < 5; i++) policy.enqueued(10); + CPPUNIT_ASSERT_EQUAL((uint64_t) 0, policy.getMaxSize()); + CPPUNIT_ASSERT_EQUAL((uint32_t) 5, policy.getMaxCount()); + CPPUNIT_ASSERT(!policy.limitExceeded()); + policy.enqueued(10); + CPPUNIT_ASSERT(policy.limitExceeded()); + policy.dequeued(10); + CPPUNIT_ASSERT(!policy.limitExceeded()); + policy.enqueued(10); + CPPUNIT_ASSERT(policy.limitExceeded()); + } + + void testSize(){ + QueuePolicy policy(0, 50); + for (int i = 0; i < 5; i++) policy.enqueued(10); + CPPUNIT_ASSERT(!policy.limitExceeded()); + policy.enqueued(10); + CPPUNIT_ASSERT(policy.limitExceeded()); + policy.dequeued(10); + CPPUNIT_ASSERT(!policy.limitExceeded()); + policy.enqueued(10); + CPPUNIT_ASSERT(policy.limitExceeded()); + } + + void testBoth(){ + QueuePolicy policy(5, 50); + for (int i = 0; i < 5; i++) policy.enqueued(11); + CPPUNIT_ASSERT(policy.limitExceeded()); + policy.dequeued(20); + CPPUNIT_ASSERT(!policy.limitExceeded());//fails + policy.enqueued(5); + policy.enqueued(10); + CPPUNIT_ASSERT(policy.limitExceeded()); + } + + void testSettings(){ + //test reading and writing the policy from/to field table + FieldTable settings; + QueuePolicy a(101, 303); + a.update(settings); + QueuePolicy b(settings); + CPPUNIT_ASSERT_EQUAL(a.getMaxCount(), b.getMaxCount()); + CPPUNIT_ASSERT_EQUAL(a.getMaxSize(), b.getMaxSize()); + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(QueuePolicyTest); + diff --git a/qpid/cpp-0-9/tests/QueueRegistryTest.cpp b/qpid/cpp-0-9/tests/QueueRegistryTest.cpp new file mode 100644 index 0000000000..3926d56292 --- /dev/null +++ b/qpid/cpp-0-9/tests/QueueRegistryTest.cpp @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <QueueRegistry.h> +#include <qpid_test_plugin.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/qpid/cpp-0-9/tests/QueueTest.cpp b/qpid/cpp-0-9/tests/QueueTest.cpp new file mode 100644 index 0000000000..fa38029de1 --- /dev/null +++ b/qpid/cpp-0-9/tests/QueueTest.cpp @@ -0,0 +1,185 @@ + /* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <BrokerQueue.h> +#include <QueueRegistry.h> +#include <qpid_test_plugin.h> +#include <iostream> +#include "MockChannel.h" + +using namespace qpid::broker; +using namespace qpid::sys; + + +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(testConsumers); + CPPUNIT_TEST(testBinding); + CPPUNIT_TEST(testRegistry); + CPPUNIT_TEST(testDequeue); + CPPUNIT_TEST_SUITE_END(); + + public: + Message::shared_ptr message(std::string exchange, std::string routingKey) { + return Message::shared_ptr( + new BasicMessage(0, exchange, routingKey, true, true, + MockChannel::basicGetBody())); + } + + void testConsumers(){ + Queue::shared_ptr queue(new Queue("my_queue", true)); + + //Test adding consumers: + TestConsumer c1; + TestConsumer c2; + queue->consume(&c1); + queue->consume(&c2); + + CPPUNIT_ASSERT_EQUAL(uint32_t(2), queue->getConsumerCount()); + + //Test basic delivery: + Message::shared_ptr msg1 = message("e", "A"); + Message::shared_ptr msg2 = message("e", "B"); + Message::shared_ptr msg3 = message("e", "C"); + + 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(uint32_t(1), queue->getConsumerCount()); + queue->cancel(&c2); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), queue->getConsumerCount()); + } + + void testBinding(){ + Queue::shared_ptr queue(new Queue("my_queue", true)); + //Test bindings: + TestBinding a; + TestBinding b; + queue->bound(&a); + queue->bound(&b); + + queue.reset(); + + CPPUNIT_ASSERT(a.isCancelled()); + CPPUNIT_ASSERT(b.isCancelled()); + } + + void testRegistry(){ + //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")); + } + + void testDequeue(){ + Queue::shared_ptr queue(new Queue("my_queue", true)); + Message::shared_ptr msg1 = message("e", "A"); + Message::shared_ptr msg2 = message("e", "B"); + Message::shared_ptr msg3 = message("e", "C"); + Message::shared_ptr received; + + queue->deliver(msg1); + queue->deliver(msg2); + queue->deliver(msg3); + + CPPUNIT_ASSERT_EQUAL(uint32_t(3), queue->getMessageCount()); + + received = queue->dequeue(); + CPPUNIT_ASSERT_EQUAL(msg1.get(), received.get()); + CPPUNIT_ASSERT_EQUAL(uint32_t(2), queue->getMessageCount()); + + received = queue->dequeue(); + CPPUNIT_ASSERT_EQUAL(msg2.get(), received.get()); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), queue->getMessageCount()); + + TestConsumer consumer; + queue->consume(&consumer); + queue->dispatch(); + CPPUNIT_ASSERT_EQUAL(msg3.get(), consumer.last.get()); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), queue->getMessageCount()); + + received = queue->dequeue(); + CPPUNIT_ASSERT(!received); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), queue->getMessageCount()); + + } +}; + +// 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/qpid/cpp-0-9/tests/ReferenceTest.cpp b/qpid/cpp-0-9/tests/ReferenceTest.cpp new file mode 100644 index 0000000000..753f68ee75 --- /dev/null +++ b/qpid/cpp-0-9/tests/ReferenceTest.cpp @@ -0,0 +1,102 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <memory> +#include "qpid_test_plugin.h" +#include "Reference.h" +#include "BrokerMessageMessage.h" +#include "MessageTransferBody.h" +#include "MessageAppendBody.h" +#include "CompletionHandler.h" + +using namespace boost; +using namespace qpid::broker; +using namespace qpid::framing; +using namespace std; + +class ReferenceTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(ReferenceTest); + CPPUNIT_TEST(testRegistry); + CPPUNIT_TEST(testReference); + CPPUNIT_TEST_SUITE_END(); + + ProtocolVersion v; + ReferenceRegistry registry; + Reference::shared_ptr r1; + MessageTransferBody::shared_ptr t1, t2; + MessageMessage::shared_ptr m1, m2; + MessageAppendBody::shared_ptr a1, a2; + public: + + ReferenceTest() : + r1(registry.open("bar")), + t1(new MessageTransferBody(v)), + t2(new MessageTransferBody(v)), + m1(new MessageMessage(0, 1, t1, r1)), + m2(new MessageMessage(0, 2, t2, r1)), + a1(new MessageAppendBody(v)), + a2(new MessageAppendBody(v)) + {} + + void testRegistry() { + Reference::shared_ptr ref = registry.open("foo"); + CPPUNIT_ASSERT_EQUAL(string("foo"), ref->getId()); + CPPUNIT_ASSERT(ref == registry.get("foo")); + try { + registry.get("none"); + CPPUNIT_FAIL("Expected exception"); + } catch (...) {} + try { + registry.open("foo"); + CPPUNIT_FAIL("Expected exception"); + } catch(...) {} + } + + void testReference() { + r1->addMessage(m1); + r1->addMessage(m2); + CPPUNIT_ASSERT_EQUAL(size_t(2), r1->getMessages().size()); + r1->append(a1); + r1->append(a2); + CPPUNIT_ASSERT_EQUAL(size_t(2), r1->getAppends().size()); + const vector<MessageMessage::shared_ptr> messages = r1->getMessages(); + r1->close(); + try { + registry.open("bar"); + CPPUNIT_FAIL("Expected exception"); + } catch(...) {} + + CPPUNIT_ASSERT_EQUAL(messages[0], m1); + CPPUNIT_ASSERT_EQUAL(messages[0]->getReference()->getAppends()[0], a1); + CPPUNIT_ASSERT_EQUAL(messages[0]->getReference()->getAppends()[1], a2); + + CPPUNIT_ASSERT_EQUAL(messages[1], m2); + CPPUNIT_ASSERT_EQUAL(messages[1]->getReference()->getAppends()[0], a1); + CPPUNIT_ASSERT_EQUAL(messages[1]->getReference()->getAppends()[1], a2); + } + + +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(ReferenceTest); diff --git a/qpid/cpp-0-9/tests/TopicExchangeTest.cpp b/qpid/cpp-0-9/tests/TopicExchangeTest.cpp new file mode 100644 index 0000000000..4ba9cdd6e5 --- /dev/null +++ b/qpid/cpp-0-9/tests/TopicExchangeTest.cpp @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include <TopicExchange.h> +#include <qpid_test_plugin.h> + +using namespace qpid::broker; + +Tokens makeTokens(char** begin, char** end) +{ + Tokens t; + t.insert(t.end(), begin, end); + return t; +} + +// Calculate size of an array. +#define LEN(a) (sizeof(a)/sizeof(a[0])) + +// Convert array to token vector +#define TOKENS(a) makeTokens(a, a + LEN(a)) + +// Allow CPPUNIT_EQUALS to print a Tokens. +CppUnit::OStringStream& operator <<(CppUnit::OStringStream& out, const Tokens& v) +{ + out << "[ "; + for (Tokens::const_iterator i = v.begin(); + i != v.end(); ++i) + { + out << '"' << *i << '"' << (i+1 == v.end() ? "]" : ", "); + } + return out; +} + + +class TokensTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(TokensTest); + CPPUNIT_TEST(testTokens); + CPPUNIT_TEST_SUITE_END(); + + public: + void testTokens() + { + Tokens tokens("hello.world"); + char* expect[] = {"hello", "world"}; + CPPUNIT_ASSERT_EQUAL(TOKENS(expect), tokens); + + tokens = "a.b.c"; + char* expect2[] = { "a", "b", "c" }; + CPPUNIT_ASSERT_EQUAL(TOKENS(expect2), tokens); + + tokens = ""; + CPPUNIT_ASSERT(tokens.empty()); + + tokens = "x"; + char* expect3[] = { "x" }; + CPPUNIT_ASSERT_EQUAL(TOKENS(expect3), tokens); + + tokens = (".x"); + char* expect4[] = { "", "x" }; + CPPUNIT_ASSERT_EQUAL(TOKENS(expect4), tokens); + + tokens = ("x."); + char* expect5[] = { "x", "" }; + CPPUNIT_ASSERT_EQUAL(TOKENS(expect5), tokens); + + tokens = ("."); + char* expect6[] = { "", "" }; + CPPUNIT_ASSERT_EQUAL(TOKENS(expect6), tokens); + + tokens = (".."); + char* expect7[] = { "", "", "" }; + CPPUNIT_ASSERT_EQUAL(TOKENS(expect7), tokens); + } + +}; + +#define ASSERT_NORMALIZED(expect, pattern) \ + CPPUNIT_ASSERT_EQUAL(Tokens(expect), static_cast<Tokens>(TopicPattern(pattern))) +class TopicPatternTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(TopicPatternTest); + CPPUNIT_TEST(testNormalize); + CPPUNIT_TEST(testPlain); + CPPUNIT_TEST(testStar); + CPPUNIT_TEST(testHash); + CPPUNIT_TEST(testMixed); + CPPUNIT_TEST(testCombo); + CPPUNIT_TEST_SUITE_END(); + + public: + + void testNormalize() + { + CPPUNIT_ASSERT(TopicPattern("").empty()); + ASSERT_NORMALIZED("a.b.c", "a.b.c"); + ASSERT_NORMALIZED("a.*.c", "a.*.c"); + ASSERT_NORMALIZED("#", "#"); + ASSERT_NORMALIZED("#", "#.#.#.#"); + ASSERT_NORMALIZED("*.*.*.#", "#.*.#.*.#.#.*"); + ASSERT_NORMALIZED("a.*.*.*.#", "a.*.#.*.#.*.#"); + ASSERT_NORMALIZED("a.*.*.*.#", "a.*.#.*.#.*"); + } + + void testPlain() { + TopicPattern p("ab.cd.e"); + CPPUNIT_ASSERT(p.match("ab.cd.e")); + CPPUNIT_ASSERT(!p.match("abx.cd.e")); + CPPUNIT_ASSERT(!p.match("ab.cd")); + CPPUNIT_ASSERT(!p.match("ab.cd..e.")); + CPPUNIT_ASSERT(!p.match("ab.cd.e.")); + CPPUNIT_ASSERT(!p.match(".ab.cd.e")); + + p = ""; + CPPUNIT_ASSERT(p.match("")); + + p = "."; + CPPUNIT_ASSERT(p.match(".")); + } + + + void testStar() + { + TopicPattern p("a.*.b"); + CPPUNIT_ASSERT(p.match("a.xx.b")); + CPPUNIT_ASSERT(!p.match("a.b")); + + p = "*.x"; + CPPUNIT_ASSERT(p.match("y.x")); + CPPUNIT_ASSERT(p.match(".x")); + CPPUNIT_ASSERT(!p.match("x")); + + p = "x.x.*"; + CPPUNIT_ASSERT(p.match("x.x.y")); + CPPUNIT_ASSERT(p.match("x.x.")); + CPPUNIT_ASSERT(!p.match("x.x")); + CPPUNIT_ASSERT(!p.match("q.x.y")); + } + + void testHash() + { + TopicPattern p("a.#.b"); + CPPUNIT_ASSERT(p.match("a.b")); + CPPUNIT_ASSERT(p.match("a.x.b")); + CPPUNIT_ASSERT(p.match("a..x.y.zz.b")); + CPPUNIT_ASSERT(!p.match("a.b.")); + CPPUNIT_ASSERT(!p.match("q.x.b")); + + p = "a.#"; + CPPUNIT_ASSERT(p.match("a")); + CPPUNIT_ASSERT(p.match("a.b")); + CPPUNIT_ASSERT(p.match("a.b.c")); + + p = "#.a"; + CPPUNIT_ASSERT(p.match("a")); + CPPUNIT_ASSERT(p.match("x.y.a")); + } + + void testMixed() + { + TopicPattern p("*.x.#.y"); + CPPUNIT_ASSERT(p.match("a.x.y")); + CPPUNIT_ASSERT(p.match("a.x.p.qq.y")); + CPPUNIT_ASSERT(!p.match("a.a.x.y")); + CPPUNIT_ASSERT(!p.match("aa.x.b.c")); + + p = "a.#.b.*"; + CPPUNIT_ASSERT(p.match("a.b.x")); + CPPUNIT_ASSERT(p.match("a.x.x.x.b.x")); + } + + void testCombo() { + TopicPattern p("*.#.#.*.*.#"); + CPPUNIT_ASSERT(p.match("x.y.z")); + CPPUNIT_ASSERT(p.match("x.y.z.a.b.c")); + CPPUNIT_ASSERT(!p.match("x.y")); + CPPUNIT_ASSERT(!p.match("x")); + } +}; + + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(TopicPatternTest); +CPPUNIT_TEST_SUITE_REGISTRATION(TokensTest); diff --git a/qpid/cpp-0-9/tests/TxAckTest.cpp b/qpid/cpp-0-9/tests/TxAckTest.cpp new file mode 100644 index 0000000000..c189533ea9 --- /dev/null +++ b/qpid/cpp-0-9/tests/TxAckTest.cpp @@ -0,0 +1,125 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <NullMessageStore.h> +#include <RecoveryManager.h> +#include <TxAck.h> +#include <qpid_test_plugin.h> +#include <iostream> +#include <list> +#include <vector> +#include "MockChannel.h" + +using std::list; +using std::vector; +using namespace qpid::broker; +using namespace qpid::framing; + +class TxAckTest : public CppUnit::TestCase +{ + + class TestMessageStore : public NullMessageStore + { + public: + vector< std::pair<Message*, const string*> > dequeued; + + void dequeue(TransactionContext*, Message* const msg, const Queue& /*queue*/, const string * const xid) + { + dequeued.push_back(std::pair<Message*, const string*>(msg, xid)); + } + + TestMessageStore() : NullMessageStore() {} + ~TestMessageStore(){} + }; + + CPPUNIT_TEST_SUITE(TxAckTest); + CPPUNIT_TEST(testPrepare2pc); + CPPUNIT_TEST(testPrepare); + CPPUNIT_TEST(testCommit); + CPPUNIT_TEST_SUITE_END(); + + + AccumulatedAck acked; + TestMessageStore store; + Queue::shared_ptr queue; + vector<Message::shared_ptr> messages; + list<DeliveryRecord> deliveries; + TxAck op; + std::string xid; + + +public: + + TxAckTest() : acked(0), queue(new Queue("my_queue", false, &store, 0)), op(acked, deliveries, &xid) + { + for(int i = 0; i < 10; i++){ + Message::shared_ptr msg( + new BasicMessage(0, "exchange", "routing_key", false, false, + MockChannel::basicGetBody())); + msg->setHeader(AMQHeaderBody::shared_ptr(new AMQHeaderBody(BASIC))); + msg->getHeaderProperties()->setDeliveryMode(PERSISTENT); + messages.push_back(msg); + deliveries.push_back(DeliveryRecord(msg, queue, "xyz", (i+1))); + } + + //assume msgs 1-5, 7 and 9 are all acked (i.e. 6, 8 & 10 are not) + acked.range = 5; + acked.individual.push_back(7); + acked.individual.push_back(9); + } + + void testPrepare() + { + //ensure acked messages are discarded, i.e. dequeued from store + op.prepare(0); + CPPUNIT_ASSERT_EQUAL((size_t) 7, store.dequeued.size()); + CPPUNIT_ASSERT_EQUAL((size_t) 10, deliveries.size()); + int dequeued[] = {0, 1, 2, 3, 4, 6, 8}; + for (int i = 0; i < 7; i++) { + CPPUNIT_ASSERT_EQUAL(messages[dequeued[i]].get(), store.dequeued[i].first); + } + } + + void testPrepare2pc() + { + xid = "abcdefg"; + testPrepare(); + const string expected(xid); + for (int i = 0; i < 7; i++) { + CPPUNIT_ASSERT_EQUAL(expected, *store.dequeued[i].second); + } + } + + void testCommit() + { + //emsure acked messages are removed from list + op.commit(); + CPPUNIT_ASSERT_EQUAL((size_t) 3, deliveries.size()); + list<DeliveryRecord>::iterator i = deliveries.begin(); + CPPUNIT_ASSERT(i->matches(6));//msg 6 + CPPUNIT_ASSERT((++i)->matches(8));//msg 8 + CPPUNIT_ASSERT((++i)->matches(10));//msg 10 + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(TxAckTest); + diff --git a/qpid/cpp-0-9/tests/TxBufferTest.cpp b/qpid/cpp-0-9/tests/TxBufferTest.cpp new file mode 100644 index 0000000000..8a9b233eb9 --- /dev/null +++ b/qpid/cpp-0-9/tests/TxBufferTest.cpp @@ -0,0 +1,266 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <TxBuffer.h> +#include <qpid_test_plugin.h> +#include <iostream> +#include <vector> + +using namespace qpid::broker; + +template <class T> void assertEqualVector(std::vector<T>& expected, std::vector<T>& actual){ + unsigned int i = 0; + while(i < expected.size() && i < actual.size()){ + CPPUNIT_ASSERT_EQUAL(expected[i], actual[i]); + i++; + } + CPPUNIT_ASSERT(i == expected.size()); + CPPUNIT_ASSERT(i == actual.size()); +} + +class TxBufferTest : public CppUnit::TestCase +{ + class MockTxOp : public TxOp{ + enum op_codes {PREPARE=2, COMMIT=4, ROLLBACK=8}; + std::vector<int> expected; + std::vector<int> actual; + bool failOnPrepare; + public: + MockTxOp() : failOnPrepare(false) {} + MockTxOp(bool _failOnPrepare) : failOnPrepare(_failOnPrepare) {} + + bool prepare(TransactionContext*) throw(){ + actual.push_back(PREPARE); + return !failOnPrepare; + } + void commit() throw(){ + actual.push_back(COMMIT); + } + void rollback() throw(){ + actual.push_back(ROLLBACK); + } + MockTxOp& expectPrepare(){ + expected.push_back(PREPARE); + return *this; + } + MockTxOp& expectCommit(){ + expected.push_back(COMMIT); + return *this; + } + MockTxOp& expectRollback(){ + expected.push_back(ROLLBACK); + return *this; + } + void check(){ + assertEqualVector(expected, actual); + } + ~MockTxOp(){} + }; + + class MockTransactionalStore : public TransactionalStore{ + enum op_codes {BEGIN=2, COMMIT=4, ABORT=8}; + std::vector<int> expected; + std::vector<int> actual; + + enum states {OPEN = 1, COMMITTED = 2, ABORTED = 3}; + int state; + + class TestTransactionContext : public TransactionContext{ + MockTransactionalStore* store; + public: + TestTransactionContext(MockTransactionalStore* _store) : store(_store) {} + void commit(){ + if(store->state != OPEN) throw "txn already completed"; + store->state = COMMITTED; + } + + void abort(){ + if(store->state != OPEN) throw "txn already completed"; + store->state = ABORTED; + } + ~TestTransactionContext(){} + }; + + + public: + MockTransactionalStore() : state(OPEN){} + + std::auto_ptr<TransactionContext> begin(){ + actual.push_back(BEGIN); + std::auto_ptr<TransactionContext> txn(new TestTransactionContext(this)); + return txn; + } + void commit(TransactionContext* ctxt){ + actual.push_back(COMMIT); + TestTransactionContext* txn(dynamic_cast<TestTransactionContext*>(ctxt)); + CPPUNIT_ASSERT(txn); + txn->commit(); + } + void abort(TransactionContext* ctxt){ + actual.push_back(ABORT); + TestTransactionContext* txn(dynamic_cast<TestTransactionContext*>(ctxt)); + CPPUNIT_ASSERT(txn); + txn->abort(); + } + MockTransactionalStore& expectBegin(){ + expected.push_back(BEGIN); + return *this; + } + MockTransactionalStore& expectCommit(){ + expected.push_back(COMMIT); + return *this; + } + MockTransactionalStore& expectAbort(){ + expected.push_back(ABORT); + return *this; + } + void check(){ + assertEqualVector(expected, actual); + } + + bool isCommitted(){ + return state == COMMITTED; + } + + bool isAborted(){ + return state == ABORTED; + } + + bool isOpen() const{ + return state == OPEN; + } + ~MockTransactionalStore(){} + }; + + CPPUNIT_TEST_SUITE(TxBufferTest); + CPPUNIT_TEST(testPrepareAndCommit); + CPPUNIT_TEST(testFailOnPrepare); + CPPUNIT_TEST(testRollback); + CPPUNIT_TEST(testBufferIsClearedAfterRollback); + CPPUNIT_TEST(testBufferIsClearedAfterCommit); + CPPUNIT_TEST_SUITE_END(); + + public: + + void testPrepareAndCommit(){ + MockTransactionalStore store; + store.expectBegin().expectCommit(); + + MockTxOp opA; + opA.expectPrepare().expectCommit(); + MockTxOp opB; + opB.expectPrepare().expectPrepare().expectCommit().expectCommit();//opB enlisted twice to test reative order + MockTxOp opC; + opC.expectPrepare().expectCommit(); + + TxBuffer buffer; + buffer.enlist(&opA); + buffer.enlist(&opB); + buffer.enlist(&opB);//opB enlisted twice + buffer.enlist(&opC); + + CPPUNIT_ASSERT(buffer.prepare(&store)); + buffer.commit(); + store.check(); + CPPUNIT_ASSERT(store.isCommitted()); + opA.check(); + opB.check(); + opC.check(); + } + + void testFailOnPrepare(){ + MockTransactionalStore store; + store.expectBegin().expectAbort(); + + MockTxOp opA; + opA.expectPrepare(); + MockTxOp opB(true); + opB.expectPrepare(); + MockTxOp opC;//will never get prepare as b will fail + + TxBuffer buffer; + buffer.enlist(&opA); + buffer.enlist(&opB); + buffer.enlist(&opC); + + CPPUNIT_ASSERT(!buffer.prepare(&store)); + store.check(); + CPPUNIT_ASSERT(store.isAborted()); + opA.check(); + opB.check(); + opC.check(); + } + + void testRollback(){ + MockTxOp opA; + opA.expectRollback(); + MockTxOp opB(true); + opB.expectRollback(); + MockTxOp opC; + opC.expectRollback(); + + TxBuffer buffer; + buffer.enlist(&opA); + buffer.enlist(&opB); + buffer.enlist(&opC); + + buffer.rollback(); + opA.check(); + opB.check(); + opC.check(); + } + + void testBufferIsClearedAfterRollback(){ + MockTxOp opA; + opA.expectRollback(); + MockTxOp opB; + opB.expectRollback(); + + TxBuffer buffer; + buffer.enlist(&opA); + buffer.enlist(&opB); + + buffer.rollback(); + buffer.commit();//second call should not reach ops + opA.check(); + opB.check(); + } + + void testBufferIsClearedAfterCommit(){ + MockTxOp opA; + opA.expectCommit(); + MockTxOp opB; + opB.expectCommit(); + + TxBuffer buffer; + buffer.enlist(&opA); + buffer.enlist(&opB); + + buffer.commit(); + buffer.rollback();//second call should not reach ops + opA.check(); + opB.check(); + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(TxBufferTest); + diff --git a/qpid/cpp-0-9/tests/TxPublishTest.cpp b/qpid/cpp-0-9/tests/TxPublishTest.cpp new file mode 100644 index 0000000000..d9d5607c06 --- /dev/null +++ b/qpid/cpp-0-9/tests/TxPublishTest.cpp @@ -0,0 +1,125 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <NullMessageStore.h> +#include <RecoveryManager.h> +#include <TxPublish.h> +#include <qpid_test_plugin.h> +#include <iostream> +#include <list> +#include <vector> +#include "MockChannel.h" + +using std::list; +using std::pair; +using std::vector; +using namespace qpid::broker; +using namespace qpid::framing; + +class TxPublishTest : public CppUnit::TestCase +{ + struct Triple + { + string first; + Message* second; + const string* third; + }; + + class TestMessageStore : public NullMessageStore + { + public: + vector<Triple> enqueued; + + void enqueue(TransactionContext*, Message* const msg, const Queue& queue, const string * const xid) + { + Triple args = {queue.getName(), msg, xid}; + enqueued.push_back(args); + } + + //dont care about any of the other methods: + TestMessageStore() : NullMessageStore(false) {} + ~TestMessageStore(){} + }; + + CPPUNIT_TEST_SUITE(TxPublishTest); + CPPUNIT_TEST(testPrepare); + CPPUNIT_TEST(testPrepare2pc); + CPPUNIT_TEST(testCommit); + CPPUNIT_TEST_SUITE_END(); + + + TestMessageStore store; + Queue::shared_ptr queue1; + Queue::shared_ptr queue2; + Message::shared_ptr const msg; + TxPublish op; + string xid; + +public: + + TxPublishTest() : + queue1(new Queue("queue1", false, &store, 0)), + queue2(new Queue("queue2", false, &store, 0)), + msg(new BasicMessage(0, "exchange", "routing_key", false, false, + MockChannel::basicGetBody())), + op(msg, &xid) + { + msg->setHeader(AMQHeaderBody::shared_ptr(new AMQHeaderBody(BASIC))); + msg->getHeaderProperties()->setDeliveryMode(PERSISTENT); + op.deliverTo(queue1); + op.deliverTo(queue2); + } + + void testPrepare() + { + //ensure messages are enqueued in store + op.prepare(0); + CPPUNIT_ASSERT_EQUAL((size_t) 2, store.enqueued.size()); + CPPUNIT_ASSERT_EQUAL(string("queue1"), store.enqueued[0].first); + CPPUNIT_ASSERT_EQUAL(msg.get(), store.enqueued[0].second); + CPPUNIT_ASSERT_EQUAL(string("queue2"), store.enqueued[1].first); + CPPUNIT_ASSERT_EQUAL(msg.get(), store.enqueued[1].second); + } + + void testPrepare2pc() + { + xid = "abcde"; + const string expected(xid); + testPrepare(); + CPPUNIT_ASSERT_EQUAL(expected, *store.enqueued[0].third); + CPPUNIT_ASSERT_EQUAL(expected, *store.enqueued[1].third); + } + + void testCommit() + { + //ensure messages are delivered to queue + op.commit(); + CPPUNIT_ASSERT_EQUAL((uint32_t) 1, queue1->getMessageCount()); + CPPUNIT_ASSERT_EQUAL(msg, queue1->dequeue()); + + CPPUNIT_ASSERT_EQUAL((uint32_t) 1, queue2->getMessageCount()); + CPPUNIT_ASSERT_EQUAL(msg, queue2->dequeue()); + } +}; + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(TxPublishTest); + diff --git a/qpid/cpp-0-9/tests/ValueTest.cpp b/qpid/cpp-0-9/tests/ValueTest.cpp new file mode 100644 index 0000000000..a3f9ec2541 --- /dev/null +++ b/qpid/cpp-0-9/tests/ValueTest.cpp @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include <Value.h> +#include <qpid_test_plugin.h> + +using namespace qpid::framing; + + +class ValueTest : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(ValueTest); + CPPUNIT_TEST(testStringValueEquals); + CPPUNIT_TEST(testIntegerValueEquals); + CPPUNIT_TEST(testDecimalValueEquals); + CPPUNIT_TEST(testFieldTableValueEquals); + CPPUNIT_TEST_SUITE_END(); + + StringValue s; + IntegerValue i; + DecimalValue d; + FieldTableValue ft; + EmptyValue e; + + public: + ValueTest() : + s("abc"), + i(42), + d(1234,2) + + { + ft.getValue().setString("foo", "FOO"); + ft.getValue().setInt("magic", 7); + } + + void testStringValueEquals() + { + + CPPUNIT_ASSERT(StringValue("abc") == s); + CPPUNIT_ASSERT(s != StringValue("foo")); + CPPUNIT_ASSERT(s != e); + CPPUNIT_ASSERT(e != d); + CPPUNIT_ASSERT(e != ft); + } + + void testIntegerValueEquals() + { + CPPUNIT_ASSERT(IntegerValue(42) == i); + CPPUNIT_ASSERT(IntegerValue(5) != i); + CPPUNIT_ASSERT(i != e); + CPPUNIT_ASSERT(i != d); + } + + void testDecimalValueEquals() + { + CPPUNIT_ASSERT(DecimalValue(1234, 2) == d); + CPPUNIT_ASSERT(DecimalValue(12345, 2) != d); + CPPUNIT_ASSERT(DecimalValue(1234, 3) != d); + CPPUNIT_ASSERT(d != s); + } + + + void testFieldTableValueEquals() + { + CPPUNIT_ASSERT_EQUAL(std::string("FOO"), + ft.getValue().getString("foo")); + CPPUNIT_ASSERT_EQUAL(7, ft.getValue().getInt("magic")); + + FieldTableValue f2; + CPPUNIT_ASSERT(ft != f2); + f2.getValue().setString("foo", "FOO"); + CPPUNIT_ASSERT(ft != f2); + f2.getValue().setInt("magic", 7); + CPPUNIT_ASSERT_EQUAL(ft,f2); + CPPUNIT_ASSERT(ft == f2); + f2.getValue().setString("foo", "BAR"); + CPPUNIT_ASSERT(ft != f2); + CPPUNIT_ASSERT(ft != i); + } + +}; + + +// Make this test suite a plugin. +CPPUNIT_PLUGIN_IMPLEMENT(); +CPPUNIT_TEST_SUITE_REGISTRATION(ValueTest); + diff --git a/qpid/cpp-0-9/tests/client_test.cpp b/qpid/cpp-0-9/tests/client_test.cpp new file mode 100644 index 0000000000..413523a6a7 --- /dev/null +++ b/qpid/cpp-0-9/tests/client_test.cpp @@ -0,0 +1,138 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** + * This file provides a simple test (and example) of basic + * functionality including declaring an exchange and a queue, binding + * these together, publishing a message and receiving that message + * asynchronously. + */ + +#include <iostream> + +#include <QpidError.h> +#include <ClientChannel.h> +#include <Connection.h> +#include <ClientMessage.h> +#include <MessageListener.h> +#include <sys/Monitor.h> +#include <FieldTable.h> + +using namespace qpid::client; +using namespace qpid::sys; +using std::string; + +bool verbose = false; + +/** + * A simple message listener implementation that prints out the + * message content then notifies a montitor allowing the test to + * complete. + */ +class SimpleListener : public virtual MessageListener{ + Monitor* monitor; + +public: + inline SimpleListener(Monitor* _monitor) : monitor(_monitor){} + + inline virtual void received(Message& msg){ + if (verbose) + std::cout << "Received message " << msg.getData() << std::endl; + monitor->notify(); + } +}; + +int main(int argc, char**) +{ + verbose = argc > 1; + try { + //Use a custom exchange + Exchange exchange("MyExchange", Exchange::TOPIC_EXCHANGE); + //Use a named, temporary queue + Queue queue("MyQueue", true); + + + Connection con(verbose); + string host("localhost"); + con.open(host, 5672, "guest", "guest", "/test"); + if (verbose) + std::cout << "Opened connection." << std::endl; + + //Create and open a channel on the connection through which + //most functionality is exposed + Channel channel; + con.openChannel(channel); + if (verbose) std::cout << "Opened channel." << std::endl; + + //'declare' the exchange and the queue, which will create them + //as they don't exist + channel.declareExchange(exchange); + if (verbose) std::cout << "Declared exchange." << std::endl; + channel.declareQueue(queue); + if (verbose) std::cout << "Declared queue." << std::endl; + + //now bind the queue to the exchange + qpid::framing::FieldTable args; + channel.bind(exchange, queue, "MyTopic", args); + if (verbose) std::cout << "Bound queue to exchange." << std::endl; + + //Set up a message listener to receive any messages that + //arrive in our queue on the broker. We only expect one, and + //as it will be received on another thread, we create a + //montior to use to notify the main thread when that message + //is received. + Monitor monitor; + SimpleListener listener(&monitor); + string tag("MyTag"); + channel.getBasic().consume(queue, tag, &listener); + if (verbose) std::cout << "Registered consumer." << std::endl; + + //we need to enable the message dispatching for this channel + //and we want that to occur on another thread so we call + //start(). + channel.start(); + + //Now we create and publish a message to our exchange with a + //routing key that will cause it to be routed to our queue + Message msg; + string data("MyMessage"); + msg.setData(data); + channel.getBasic().publish(msg, exchange, "MyTopic"); + if (verbose) std::cout << "Published message: " << data << std::endl; + + { + Monitor::ScopedLock l(monitor); + //now we wait until we receive notification that the + //message was received + monitor.wait(); + } + + //close the channel & connection + channel.close(); + if (verbose) std::cout << "Closed channel." << std::endl; + con.close(); + if (verbose) std::cout << "Closed connection." << std::endl; + return 0; + } catch(const std::exception& e) { + std::cout << e.what() << std::endl; + } + return 1; +} diff --git a/qpid/cpp-0-9/tests/echo_service.cpp b/qpid/cpp-0-9/tests/echo_service.cpp new file mode 100644 index 0000000000..412ffbeb58 --- /dev/null +++ b/qpid/cpp-0-9/tests/echo_service.cpp @@ -0,0 +1,230 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** + * This class provides an example of using AMQP for a request-response + * style system. 'Requests' are messages sent to a well known + * destination. A 'service' process consumes these message and + * responds by echoing the message back to the sender on a + * sender-specified private queue. + */ + +#include <QpidError.h> +#include <ClientChannel.h> +#include <Connection.h> +#include <ClientExchange.h> +#include <MessageListener.h> +#include <ClientQueue.h> +#include <sys/Time.h> +#include <iostream> +#include <sstream> + +using namespace qpid::client; +using namespace qpid::sys; +using std::string; + + +/** + * A message listener implementation representing the 'service', this + * will 'echo' any requests received. + */ +class EchoServer : public MessageListener{ + Channel* const channel; +public: + EchoServer(Channel* channel); + virtual void received(Message& msg); +}; + +/** + * A message listener implementation that merely prints received + * messages to the console. Used to report on 'echo' responses. + */ +class LoggingListener : public MessageListener{ +public: + virtual void received(Message& msg); +}; + +/** + * A utility class that manages the command line options needed to run + * the example confirgurably. + */ +class Args{ + string host; + int port; + bool trace; + bool help; + bool client; +public: + inline Args() : host("localhost"), port(5672), trace(false), help(false), client(false){} + void parse(int argc, char** argv); + void usage(); + + inline const string& getHost() const { return host;} + inline int getPort() const { return port; } + inline bool getTrace() const { return trace; } + inline bool getHelp() const { return help; } + inline bool getClient() const { return client; } +}; + +/** + * The main test path. There are two basic modes: 'client' and + * 'service'. First one or more services are started, then one or more + * clients are started and messages can be sent. + */ +int main(int argc, char** argv){ + const std::string echo_service("echo_service"); + Args args; + args.parse(argc, argv); + if (args.getHelp()) { + args.usage(); + } else if (args.getClient()) { + //we have been started in 'client' mode, i.e. we will send an + //echo requests and print responses received. + try { + //Create connection & open a channel + Connection connection(args.getTrace()); + connection.open(args.getHost(), args.getPort()); + Channel channel; + connection.openChannel(channel); + + //Setup: declare the private 'response' queue and bind it + //to the direct exchange by its name which will be + //generated by the server + Queue response; + channel.declareQueue(response); + qpid::framing::FieldTable emptyArgs; + channel.bind(Exchange::STANDARD_DIRECT_EXCHANGE, response, response.getName(), emptyArgs); + + //Consume from the response queue, logging all echoed message to console: + LoggingListener listener; + std::string tag; + channel.getBasic().consume(response, tag, &listener); + + //Process incoming requests on a new thread + channel.start(); + + //get messages from console and send them: + std::string text; + std::cout << "Enter text to send:" << std::endl; + while (std::getline(std::cin, text)) { + std::cout << "Sending " << text << " to echo server." << std::endl; + Message msg; + msg.getHeaders().setString("RESPONSE_QUEUE", response.getName()); + msg.setData(text); + channel.getBasic().publish(msg, Exchange::STANDARD_DIRECT_EXCHANGE, echo_service); + + std::cout << "Enter text to send:" << std::endl; + } + + connection.close(); + } catch(qpid::QpidError error) { + std::cout << error.what() << std::endl; + } + } else { + // we are in 'service' mode, i.e. we will consume messages + // from the request queue and echo each request back to the + // senders own private response queue. + try { + //Create connection & open a channel + Connection connection(args.getTrace()); + connection.open(args.getHost(), args.getPort()); + Channel channel; + connection.openChannel(channel); + + //Setup: declare the 'request' queue and bind it to the direct exchange with a 'well known' name + Queue request("request"); + channel.declareQueue(request); + qpid::framing::FieldTable emptyArgs; + channel.bind(Exchange::STANDARD_DIRECT_EXCHANGE, request, echo_service, emptyArgs); + + //Consume from the request queue, echoing back all messages received to the client that sent them + EchoServer server(&channel); + std::string tag = "server_tag"; + channel.getBasic().consume(request, tag, &server); + + //Process incoming requests on the main thread + channel.getBasic().run(); + + connection.close(); + } catch(qpid::QpidError error) { + std::cout << error.what() << std::endl; + } + } +} + +EchoServer::EchoServer(Channel* _channel) : channel(_channel){} + +void EchoServer::received(Message& message) +{ + //get name of response queues binding to the default direct exchange: + const std::string name = message.getHeaders().getString("RESPONSE_QUEUE"); + + if (name.empty()) { + std::cout << "Cannot echo " << message.getData() << ", no response queue specified." << std::endl; + } else { + //print message to console: + std::cout << "Echoing " << message.getData() << " back to " << name << std::endl; + + //'echo' the message back: + channel->getBasic().publish(message, Exchange::STANDARD_DIRECT_EXCHANGE, name); + } +} + +void LoggingListener::received(Message& message) +{ + //print message to console: + std::cout << "Received echo: " << message.getData() << std::endl; +} + + +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("-trace" == name){ + trace = true; + }else if("-client" == name){ + client = 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 << " -trace" << std::endl; + std::cout << " Indicates that the frames sent and received should be logged" << std::endl; + std::cout << " -client" << std::endl; + std::cout << " Run as a client (else will run as a server)" << std::endl; +} diff --git a/qpid/cpp-0-9/tests/examples.Makefile b/qpid/cpp-0-9/tests/examples.Makefile new file mode 100644 index 0000000000..45999f7852 --- /dev/null +++ b/qpid/cpp-0-9/tests/examples.Makefile @@ -0,0 +1,66 @@ +# +# XXX: Edit these locations to suit. +# +BOOST_LOCATION := $(HOME)/local/boost-1.33.1 +APR_LOCATION := $(HOME)/local/apr-1.2.7 + +CXXFLAGS := -DNDEBUG -DUSE_APR -MMD -fpic + +# +# Configure Boost. +# +BOOST_CFLAGS := -I$(BOOST_LOCATION)/include/boost-1_33_1 +CXXFLAGS := $(CXXFLAGS) $(BOOST_CFLAGS) + +# +# Configure APR. +# +APR_CFLAGS := -I$(APR_LOCATION)/include/apr-1 +APR_LDFLAGS := $(shell $(APR_LOCATION)/bin/apr-1-config --libs) -L$(APR_LOCATION)/lib -lapr-1 +CXXFLAGS := $(CXXFLAGS) $(APR_CFLAGS) +LDFLAGS := $(LDFLAGS) $(APR_LDFLAGS) + +# +# Configure Qpid cpp client. +# +QPID_CLIENT_LDFLAGS := ../lib/libcommon.so ../lib/libclient.so +includeDir := ../include +QPID_CLIENT_CFLAGS := \ + -I$(includeDir)/gen \ + -I$(includeDir)/client \ + -I$(includeDir)/broker \ + -I$(includeDir)/common \ + -I$(includeDir)/common/sys \ + -I$(includeDir)/common/framing + +CXXFLAGS := $(CXXFLAGS) $(QPID_CLIENT_CFLAGS) +LDFLAGS := $(LDFLAGS) $(QPID_CLIENT_LDFLAGS) + +CXX := g++ + +# +# Add rule to build examples. +# +.SUFFIX: .cpp +%: %.cpp + $(CXX) $(CXXFLAGS) $(LDFLAGS) $< -o $@ + +# +# Define targets. +# + +EXAMPLES := client_test topic_listener topic_publisher echo_service + +cppFiles := $(wildcard *.cpp) +programs = $(foreach cppFile, $(cppFiles), $(subst .cpp, ,$(cppFile))) + +.PHONY: +all: $(programs) + +debug: + @echo cppFiles = $(cppFiles) + @echo programs = $(programs) + +.PHONY: +clean: + -rm $(EXAMPLES) diff --git a/qpid/cpp-0-9/tests/examples.README b/qpid/cpp-0-9/tests/examples.README new file mode 100644 index 0000000000..65f908c249 --- /dev/null +++ b/qpid/cpp-0-9/tests/examples.README @@ -0,0 +1,18 @@ +Building the examples +--------------------- + +You had better edit the Makefile and provide the locations for APR and boost. + +Then just type 'make'. + + +Running the examples +-------------------- + +Before running the examples ensure that you have setup your LD_LIBRARY_PATH. + +Most of the examples take the following connection parameters for your +AMQP broker: + + -host host + -port port diff --git a/qpid/cpp-0-9/tests/kill_broker b/qpid/cpp-0-9/tests/kill_broker new file mode 100755 index 0000000000..b71ca22ffd --- /dev/null +++ b/qpid/cpp-0-9/tests/kill_broker @@ -0,0 +1,3 @@ +#!/bin/sh +PID=qpidd.pid +if [ -f $PID ] ; then kill -9 `cat $PID` ; rm -f $PID ; fi diff --git a/qpid/cpp-0-9/tests/python_tests b/qpid/cpp-0-9/tests/python_tests new file mode 100755 index 0000000000..4ee177ce6a --- /dev/null +++ b/qpid/cpp-0-9/tests/python_tests @@ -0,0 +1,8 @@ +#!/bin/sh +# Run the python tests. +if test -d ../../python ; then + cd ../../python && ./run-tests -v -s "0-9" -I cpp_failing_0-9.txt +else + echo Warning: python tests not found. +fi + diff --git a/qpid/cpp-0-9/tests/qpid_test_plugin.h b/qpid/cpp-0-9/tests/qpid_test_plugin.h new file mode 100644 index 0000000000..b2f4a8ffed --- /dev/null +++ b/qpid/cpp-0-9/tests/qpid_test_plugin.h @@ -0,0 +1,43 @@ +#ifndef _qpid_test_plugin_ +#define _qpid_test_plugin_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** + * Convenience to include cppunit headers needed by qpid test plugins and + * workaround for warning from superfluous main() declaration + * in cppunit/TestPlugIn.h + */ + +#include <cppunit/TestCase.h> +#include <cppunit/TextTestRunner.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +// Redefine CPPUNIT_PLUGIN_IMPLEMENT_MAIN to a dummy typedef to avoid warnings. +// +#if defined(CPPUNIT_HAVE_UNIX_DLL_LOADER) || defined(CPPUNIT_HAVE_UNIX_SHL_LOADER) +#undef CPPUNIT_PLUGIN_IMPLEMENT_MAIN +#define CPPUNIT_PLUGIN_IMPLEMENT_MAIN() typedef char __CppUnitPlugInImplementMainDummyTypeDef +#endif + +#endif /*!_qpid_test_plugin_*/ diff --git a/qpid/cpp-0-9/tests/quick_topictest b/qpid/cpp-0-9/tests/quick_topictest new file mode 100755 index 0000000000..9df5b5c84c --- /dev/null +++ b/qpid/cpp-0-9/tests/quick_topictest @@ -0,0 +1,7 @@ +#!/bin/sh +# Quick and quiet topic test for make check. +./topictest -s2 -m2 -b1 > topictest.log 2>&1 || { + echo See topictest.log. + exit 1 +} +rm topictest.log diff --git a/qpid/cpp-0-9/tests/run-python-tests b/qpid/cpp-0-9/tests/run-python-tests new file mode 100755 index 0000000000..e69de29bb2 --- /dev/null +++ b/qpid/cpp-0-9/tests/run-python-tests diff --git a/qpid/cpp-0-9/tests/run-unit-tests b/qpid/cpp-0-9/tests/run-unit-tests new file mode 100755 index 0000000000..0ab01f05c5 --- /dev/null +++ b/qpid/cpp-0-9/tests/run-unit-tests @@ -0,0 +1,9 @@ +#!/bin/sh + +. $srcdir/setup + +fail=0 +$vg DllPlugInTester -c -b $pwd/.libs/*.so 2> out || fail=1 +vg_check out || fail=1 + +exit $fail diff --git a/qpid/cpp-0-9/tests/setup b/qpid/cpp-0-9/tests/setup new file mode 100644 index 0000000000..9dde4758b1 --- /dev/null +++ b/qpid/cpp-0-9/tests/setup @@ -0,0 +1,74 @@ +# -*- sh -*- + +test "$VERBOSE" = yes && set -x + +pwd=`pwd` +t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$ +pid=0 +test -z "$TEST_DEBUG" && +trap 's=$?;test $pid = 0||kill -2 $pid;cd "$pwd" && rm -rf $t0 && exit $s' 0 +test -z "$TEST_DEBUG" && trap '(exit $?); exit $?' 1 2 13 15 + +framework_failure=0 +mkdir -p $tmp || framework_failure=1 +cd $tmp || framework_failure=1 + +gen_supp=--gen-suppressions=all +# This option makes valgrind significantly slower. +full_leak_check=--leak-check=full + +vg_options=" + --suppressions=$abs_srcdir/.vg-supp + --num-callers=25 + --demangle=no + --track-fds=yes + $full_leak_check + $gen_supp + " +# configure tests for the existence of valgrind. +# If it's not available, then make $vg and vg_check no-ops. +if test x$VALGRIND = x; then + vg= +else + vg="libtool --mode=execute valgrind `echo $vg_options` --" +fi + +vg_leak_check() +{ + local file=$1 + local fail + # If we detect a leak, dump all output to stderr. + grep -E '^==[0-9]+== +definitely lost: [^0]' $file \ + && { fail=1; cat $file 1>&2; + echo "found memory leaks (see log file, $file); see above" 1>&2; } + test "$fail" = '' +} + + +# Ensure 1) that there is an ERROR SUMMARY line, and +# 2) that the number of errors is 0. +# An offending line looks like this: +# ==29302== ERROR SUMMARY: 4 errors from 2 contexts (suppressed: 16 from 5) +vg_error_check() +{ + local file=$1 + local fail + # If we detect a leak, dump all output to stderr. + grep -E '^==[0-9]+== ERROR SUMMARY:' $file > /dev/null \ + || { fail=1; cat $file 1>&2; + echo "no valgrind ERROR SUMMARY line in $file" 1>&2; } + if test "$fail" = ''; then + grep -E '^==[0-9]+== ERROR SUMMARY: [^0] ' $file \ + && { fail=1; cat $file 1>&2; + echo "valgrind reported errors in $file; see above" 1>&2; } + fi + test "$fail" = '' +} + +vg_check() +{ + local file=$1 + if test x$VALGRIND != x; then + vg_error_check $file && vg_leak_check $file + fi +} diff --git a/qpid/cpp-0-9/tests/start_broker b/qpid/cpp-0-9/tests/start_broker new file mode 100755 index 0000000000..fe30458463 --- /dev/null +++ b/qpid/cpp-0-9/tests/start_broker @@ -0,0 +1,14 @@ +#!/bin/sh +set -e + +LOG=`pwd`/qpidd.log +PID=`pwd`/qpidd.pid + +rm -rf $LOG $PID + +# Start the daemon, recording its PID. +../src/qpidd > $LOG 2>&1 & echo $! > $PID + +# FIXME aconway 2007-01-18: qpidd should not return till it is accepting +# connections, remove arbitrary sleep. +sleep 5 diff --git a/qpid/cpp-0-9/tests/topic_listener.cpp b/qpid/cpp-0-9/tests/topic_listener.cpp new file mode 100644 index 0000000000..5f5500f7b9 --- /dev/null +++ b/qpid/cpp-0-9/tests/topic_listener.cpp @@ -0,0 +1,217 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** + * This file provides one half of a test and example of a pub-sub + * style of interaction. See topic_publisher.cpp for the other half, + * in which the logic for publishing is defined. + * + * This file contains the listener logic. A listener will subscribe to + * a logical 'topic'. It will count the number of messages it receives + * and the time elapsed between the first one and the last one. It + * recognises two types of 'special' message that tell it to (a) send + * a report containing this information, (b) shutdown (i.e. stop + * listening). + */ + +#include <QpidError.h> +#include <ClientChannel.h> +#include <Connection.h> +#include <ClientExchange.h> +#include <MessageListener.h> +#include <ClientQueue.h> +#include <sys/Time.h> +#include <iostream> +#include <sstream> + +using namespace qpid::client; +using namespace qpid::sys; +using namespace std; + +/** + * A message listener implementation in which the runtime logic is + * defined. + */ +class Listener : public MessageListener{ + Channel* const channel; + const string responseQueue; + const bool transactional; + bool init; + int count; + Time start; + + void shutdown(); + void report(); +public: + Listener(Channel* channel, const string& reponseQueue, bool tx); + virtual void received(Message& msg); +}; + +/** + * A utility class for managing the options passed in. + */ +class Args{ + string host; + int port; + AckMode 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(); + + const string& getHost() const { return host;} + int getPort() const { return port; } + AckMode getAckMode(){ return ackMode; } + bool getTransactional() const { return transactional; } + int getPrefetch(){ return prefetch; } + bool getTrace() const { return trace; } + bool getHelp() const { return help; } +}; + +/** + * The main routine creates a Listener instance and sets it up to + * consume from a private queue bound to the exchange with the + * appropriate topic name. + */ +int main(int argc, char** argv){ + Args args; + args.parse(argc, argv); + if(args.getHelp()){ + args.usage(); + }else{ + try{ + cout << "topic_listener: Started." << endl; + Connection connection(args.getTrace()); + connection.open(args.getHost(), args.getPort(), "guest", "guest", "/test"); + 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::STANDARD_TOPIC_EXCHANGE, control, "topic_control", bindArgs); + //set up listener + Listener listener(&channel, response.getName(), args.getTransactional()); + string tag; + channel.getBasic().consume(control, tag, &listener, args.getAckMode()); + cout << "topic_listener: Consuming." << endl; + channel.getBasic().run(); + connection.close(); + cout << "topic_listener: normal exit" << endl; + return 0; + }catch(qpid::QpidError error){ + cout << "topic_listener: " << error.what() << endl; + } + } + return 1; +} + +Listener::Listener(Channel* _channel, const string& _responseq, bool tx) : + channel(_channel), responseQueue(_responseq), transactional(tx), init(false), count(0){} + +void Listener::received(Message& message){ + if(!init){ + start = now(); + count = 0; + init = true; + } + 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){ + cout <<"Received " << count << " messages." << endl; + } +} + +void Listener::shutdown(){ + channel->close(); +} + +void Listener::report(){ + Time finish = now(); + Time time = finish - start; + stringstream reportstr; + reportstr << "Received " << count << " messages in " + << time/TIME_MSEC << " ms."; + Message msg(reportstr.str()); + msg.getHeaders().setString("TYPE", "REPORT"); + channel->getBasic().publish(msg, string(), 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 = 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{ + cout << "Warning: unrecognised option " << name << endl; + } + } +} + +void Args::usage(){ + cout << "Options:" << endl; + cout << " -help" << endl; + cout << " Prints this usage message" << endl; + cout << " -host <host>" << endl; + cout << " Specifies host to connect to (default is localhost)" << endl; + cout << " -port <port>" << endl; + cout << " Specifies port to conect to (default is 5762)" << endl; + cout << " -ack_mode <mode>" << endl; + cout << " Sets the acknowledgement mode" << endl; + cout << " 0=NO_ACK (default), 1=AUTO_ACK, 2=LAZY_ACK" << endl; + cout << " -transactional" << endl; + cout << " Indicates the client should use transactions" << endl; + cout << " -prefetch <count>" << endl; + cout << " Specifies the prefetch count (default is 1000)" << endl; + cout << " -trace" << endl; + cout << " Indicates that the frames sent and received should be logged" << endl; +} diff --git a/qpid/cpp-0-9/tests/topic_publisher.cpp b/qpid/cpp-0-9/tests/topic_publisher.cpp new file mode 100644 index 0000000000..0e6c63ab35 --- /dev/null +++ b/qpid/cpp-0-9/tests/topic_publisher.cpp @@ -0,0 +1,286 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/** + * This file provides one half of a test and example of a pub-sub + * style of interaction. See topic_listener.cpp for the other half, in + * which the logic for subscribers is defined. + * + * This file contains the publisher logic. The publisher will send a + * number of messages to the exchange with the appropriate routing key + * for the logical 'topic'. Once it has done this it will then send a + * request that each subscriber report back with the number of message + * it has received and the time that elapsed between receiving the + * first one and receiving the report request. Once the expected + * number of reports are received, it sends out a request that each + * subscriber shutdown. + */ + +#include <QpidError.h> +#include <ClientChannel.h> +#include <Connection.h> +#include <ClientExchange.h> +#include <MessageListener.h> +#include <ClientQueue.h> +#include <sys/Monitor.h> +#include "unistd.h" +#include <sys/Time.h> +#include <cstdlib> +#include <iostream> + +using namespace qpid::client; +using namespace qpid::sys; +using std::string; + +/** + * The publishing logic is defined in this class. It implements + * message listener and can therfore be used to receive messages sent + * back by the subscribers. + */ +class Publisher : public MessageListener{ + Channel* const channel; + const std::string controlTopic; + const bool transactional; + Monitor 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); + int64_t publish(int msgs, int listeners, int size); + void terminate(); +}; + +/** + * A utility class for managing the options passed in to the test + */ +class Args{ + string host; + int port; + int messages; + int subscribers; + AckMode 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(); + + const string& getHost() const { return host;} + int getPort() const { return port; } + int getMessages() const { return messages; } + int getSubscribers() const { return subscribers; } + AckMode getAckMode(){ return ackMode; } + bool getTransactional() const { return transactional; } + int getPrefetch(){ return prefetch; } + int getBatches(){ return batches; } + int getDelay(){ return delay; } + int getSize(){ return size; } + bool getTrace() const { return trace; } + 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(), "guest", "guest", "/test"); + 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.getBasic().consume(response, tag, &publisher, args.getAckMode()); + channel.start(); + + int batchSize(args.getBatches()); + int64_t max(0); + int64_t min(0); + int64_t sum(0); + for(int i = 0; i < batchSize; i++){ + if(i > 0 && args.getDelay()) sleep(args.getDelay()); + int64_t msecs = + publisher.publish(args.getMessages(), + args.getSubscribers(), + args.getSize()) / TIME_MSEC; + if(!max || msecs > max) max = msecs; + if(!min || msecs < min) min = msecs; + sum += msecs; + std::cout << "Completed " << (i+1) << " of " << batchSize + << " in " << msecs << "ms" << std::endl; + } + publisher.terminate(); + int64_t avg = sum / batchSize; + if(batchSize > 1){ + std::cout << batchSize << " batches completed. avg=" << avg << + ", max=" << max << ", min=" << min << std::endl; + } + channel.close(); + connection.close(); + return 0; + }catch(qpid::QpidError error) { + std::cout << error.what() << std::endl; + } + } + return 1; +} + +Publisher::Publisher(Channel* _channel, const std::string& _controlTopic, bool tx) : + channel(_channel), controlTopic(_controlTopic), transactional(tx){} + +void Publisher::received(Message& ){ + //count responses and when all are received end the current batch + Monitor::ScopedLock l(monitor); + if(--count == 0){ + monitor.notify(); + } +} + +void Publisher::waitForCompletion(int msgs){ + count = msgs; + monitor.wait(); +} + +int64_t Publisher::publish(int msgs, int listeners, int size){ + Message msg; + msg.setData(generateData(size)); + Time start = now(); + { + Monitor::ScopedLock l(monitor); + for(int i = 0; i < msgs; i++){ + channel->getBasic().publish(msg, Exchange::STANDARD_TOPIC_EXCHANGE, controlTopic); + } + //send report request + Message reportRequest; + reportRequest.getHeaders().setString("TYPE", "REPORT_REQUEST"); + channel->getBasic().publish(reportRequest, Exchange::STANDARD_TOPIC_EXCHANGE, controlTopic); + if(transactional){ + channel->commit(); + } + + waitForCompletion(listeners); + } + + Time finish = 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->getBasic().publish(terminationRequest, Exchange::STANDARD_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 = 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/qpid/cpp-0-9/tests/topictest b/qpid/cpp-0-9/tests/topictest new file mode 100755 index 0000000000..76807b82bd --- /dev/null +++ b/qpid/cpp-0-9/tests/topictest @@ -0,0 +1,38 @@ +#!/bin/bash +# Run the C++ topic test + +# Clean up old log files +rm -f subscriber_*.log + +# Defaults values +SUBSCRIBERS=10 +MESSAGES=2000 +BATCHES=10 + +while getopts "s:m:b:" opt ; do + case $opt in + s) SUBSCRIBERS=$OPTARG ;; + m) MESSAGES=$OPTARG ;; + b) BATCHES=$OPTARG ;; + ?) + echo "Usage: %0 [-s <subscribers>] [-m <messages.] [-b <batches>]" + exit 1 + ;; + esac +done + +subscribe() { + echo Start subscriber $1 + LOG="subscriber_$1.log" + ./topic_listener > $LOG 2>&1 && rm -f $LOG +} + +publish() { + ./topic_publisher -messages $MESSAGES -batches $BATCHES -subscribers $SUBSCRIBERS +} + +for ((i=$SUBSCRIBERS ; i--; )); do + subscribe $i & +done + +publish 2>&1 || exit 1 diff --git a/qpid/cpp-0-9/versions b/qpid/cpp-0-9/versions new file mode 100755 index 0000000000..2c82e3fd80 --- /dev/null +++ b/qpid/cpp-0-9/versions @@ -0,0 +1,12 @@ +#!/bin/sh +# Utility to print out currently installed versions of qpid developer +# dependencies. Assumes that some dependencies are installed with RPM. +# + +for p in pkg-config doxygen help2man autoconf automake libtool ; do + echo `which $p` `$p --version | head -n1` +done + +for r in apr boost boost-devel cppunit cppunit-devel graphviz; do + rpm -q $r +done diff --git a/qpid/python/cpp_failing_0-9.txt b/qpid/python/cpp_failing_0-9.txt index 69c7cf3f5a..5d74874d52 100644 --- a/qpid/python/cpp_failing_0-9.txt +++ b/qpid/python/cpp_failing_0-9.txt @@ -1,4 +1,4 @@ tests.message.MessageTests.test_checkpoint -tests.message.MessageTests.test_reference_large tests.message.MessageTests.test_reject tests.basic.BasicTests.test_get + diff --git a/qpid/python/qpid/testlib.py b/qpid/python/qpid/testlib.py index 05641bce7e..ba2dbe9fc3 100644 --- a/qpid/python/qpid/testlib.py +++ b/qpid/python/qpid/testlib.py @@ -125,7 +125,7 @@ Options: if self.use08spec(): self.tests=findmodules("tests_0-8") else: - self.tests=findmodules("tests") + self.tests=findmodules("tests_0-9") def testSuite(self): class IgnoringTestSuite(unittest.TestSuite): @@ -142,16 +142,14 @@ Options: self._parseargs(args) runner = unittest.TextTestRunner(descriptions=False, verbosity=self.verbose) - try: - result = runner.run(self.testSuite()) - except: - print "Unhandled error in test:", sys.exc_info() + result = runner.run(self.testSuite()) if (self.ignore): print "=======================================" print "NOTE: the following tests were ignored:" for t in self.ignore: print t print "=======================================" + return result.wasSuccessful() def connect(self, host=None, port=None, spec=None, user=None, password=None, tune_params=None): diff --git a/qpid/python/tests_0-9/__init__.py b/qpid/python/tests_0-9/__init__.py new file mode 100644 index 0000000000..9a09d2d04f --- /dev/null +++ b/qpid/python/tests_0-9/__init__.py @@ -0,0 +1,20 @@ +# Do not delete - marks this directory as a python package. + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# diff --git a/qpid/python/tests_0-9/basic.py b/qpid/python/tests_0-9/basic.py new file mode 100644 index 0000000000..140576540a --- /dev/null +++ b/qpid/python/tests_0-9/basic.py @@ -0,0 +1,394 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +from qpid.client import Client, Closed +from qpid.queue import Empty +from qpid.content import Content +from qpid.testlib import testrunner, TestBase + +class BasicTests(TestBase): + """Tests for 'methods' on the amqp basic 'class'""" + + def test_consume_no_local(self): + """ + Test that the no_local flag is honoured in the consume method + """ + channel = self.channel + #setup, declare two queues: + channel.queue_declare(queue="test-queue-1a", exclusive=True) + channel.queue_declare(queue="test-queue-1b", exclusive=True) + #establish two consumers one of which excludes delivery of locally sent messages + channel.basic_consume(consumer_tag="local_included", queue="test-queue-1a") + channel.basic_consume(consumer_tag="local_excluded", queue="test-queue-1b", no_local=True) + + #send a message + channel.basic_publish(routing_key="test-queue-1a", content=Content("consume_no_local")) + channel.basic_publish(routing_key="test-queue-1b", content=Content("consume_no_local")) + + #check the queues of the two consumers + excluded = self.client.queue("local_excluded") + included = self.client.queue("local_included") + msg = included.get(timeout=1) + self.assertEqual("consume_no_local", msg.content.body) + try: + excluded.get(timeout=1) + self.fail("Received locally published message though no_local=true") + except Empty: None + + + def test_consume_exclusive(self): + """ + Test that the exclusive flag is honoured in the consume method + """ + channel = self.channel + #setup, declare a queue: + channel.queue_declare(queue="test-queue-2", exclusive=True) + + #check that an exclusive consumer prevents other consumer being created: + channel.basic_consume(consumer_tag="first", queue="test-queue-2", exclusive=True) + try: + channel.basic_consume(consumer_tag="second", queue="test-queue-2") + self.fail("Expected consume request to fail due to previous exclusive consumer") + except Closed, e: + self.assertChannelException(403, e.args[0]) + + #open new channel and cleanup last consumer: + channel = self.client.channel(2) + channel.channel_open() + + #check that an exclusive consumer cannot be created if a consumer already exists: + channel.basic_consume(consumer_tag="first", queue="test-queue-2") + try: + channel.basic_consume(consumer_tag="second", queue="test-queue-2", exclusive=True) + self.fail("Expected exclusive consume request to fail due to previous consumer") + except Closed, e: + self.assertChannelException(403, e.args[0]) + + def test_consume_queue_errors(self): + """ + Test error conditions associated with the queue field of the consume method: + """ + channel = self.channel + try: + #queue specified but doesn't exist: + channel.basic_consume(queue="invalid-queue") + self.fail("Expected failure when consuming from non-existent queue") + except Closed, e: + self.assertChannelException(404, e.args[0]) + + channel = self.client.channel(2) + channel.channel_open() + try: + #queue not specified and none previously declared for channel: + channel.basic_consume(queue="") + self.fail("Expected failure when consuming from unspecified queue") + except Closed, e: + self.assertConnectionException(530, e.args[0]) + + def test_consume_unique_consumers(self): + """ + Ensure unique consumer tags are enforced + """ + channel = self.channel + #setup, declare a queue: + channel.queue_declare(queue="test-queue-3", exclusive=True) + + #check that attempts to use duplicate tags are detected and prevented: + channel.basic_consume(consumer_tag="first", queue="test-queue-3") + try: + channel.basic_consume(consumer_tag="first", queue="test-queue-3") + self.fail("Expected consume request to fail due to non-unique tag") + except Closed, e: + self.assertConnectionException(530, e.args[0]) + + def test_cancel(self): + """ + Test compliance of the basic.cancel method + """ + channel = self.channel + #setup, declare a queue: + channel.queue_declare(queue="test-queue-4", exclusive=True) + channel.basic_consume(consumer_tag="my-consumer", queue="test-queue-4") + channel.basic_publish(routing_key="test-queue-4", content=Content("One")) + + #cancel should stop messages being delivered + channel.basic_cancel(consumer_tag="my-consumer") + channel.basic_publish(routing_key="test-queue-4", content=Content("Two")) + myqueue = self.client.queue("my-consumer") + msg = myqueue.get(timeout=1) + self.assertEqual("One", msg.content.body) + try: + msg = myqueue.get(timeout=1) + self.fail("Got message after cancellation: " + msg) + except Empty: None + + #cancellation of non-existant consumers should be handled without error + channel.basic_cancel(consumer_tag="my-consumer") + channel.basic_cancel(consumer_tag="this-never-existed") + + + def test_ack(self): + """ + Test basic ack/recover behaviour + """ + channel = self.channel + channel.queue_declare(queue="test-ack-queue", exclusive=True) + + reply = channel.basic_consume(queue="test-ack-queue", no_ack=False) + queue = self.client.queue(reply.consumer_tag) + + channel.basic_publish(routing_key="test-ack-queue", content=Content("One")) + channel.basic_publish(routing_key="test-ack-queue", content=Content("Two")) + channel.basic_publish(routing_key="test-ack-queue", content=Content("Three")) + channel.basic_publish(routing_key="test-ack-queue", content=Content("Four")) + channel.basic_publish(routing_key="test-ack-queue", content=Content("Five")) + + msg1 = queue.get(timeout=1) + msg2 = queue.get(timeout=1) + msg3 = queue.get(timeout=1) + msg4 = queue.get(timeout=1) + msg5 = queue.get(timeout=1) + + self.assertEqual("One", msg1.content.body) + self.assertEqual("Two", msg2.content.body) + self.assertEqual("Three", msg3.content.body) + self.assertEqual("Four", msg4.content.body) + self.assertEqual("Five", msg5.content.body) + + channel.basic_ack(delivery_tag=msg2.delivery_tag, multiple=True) #One & Two + channel.basic_ack(delivery_tag=msg4.delivery_tag, multiple=False) #Four + + channel.basic_recover(requeue=False) + + msg3b = queue.get(timeout=1) + msg5b = queue.get(timeout=1) + + self.assertEqual("Three", msg3b.content.body) + self.assertEqual("Five", msg5b.content.body) + + try: + extra = queue.get(timeout=1) + self.fail("Got unexpected message: " + extra.content.body) + except Empty: None + + def test_recover_requeue(self): + """ + Test requeing on recovery + """ + channel = self.channel + channel.queue_declare(queue="test-requeue", exclusive=True) + + subscription = channel.basic_consume(queue="test-requeue", no_ack=False) + queue = self.client.queue(subscription.consumer_tag) + + channel.basic_publish(routing_key="test-requeue", content=Content("One")) + channel.basic_publish(routing_key="test-requeue", content=Content("Two")) + channel.basic_publish(routing_key="test-requeue", content=Content("Three")) + channel.basic_publish(routing_key="test-requeue", content=Content("Four")) + channel.basic_publish(routing_key="test-requeue", content=Content("Five")) + + msg1 = queue.get(timeout=1) + msg2 = queue.get(timeout=1) + msg3 = queue.get(timeout=1) + msg4 = queue.get(timeout=1) + msg5 = queue.get(timeout=1) + + self.assertEqual("One", msg1.content.body) + self.assertEqual("Two", msg2.content.body) + self.assertEqual("Three", msg3.content.body) + self.assertEqual("Four", msg4.content.body) + self.assertEqual("Five", msg5.content.body) + + channel.basic_ack(delivery_tag=msg2.delivery_tag, multiple=True) #One & Two + channel.basic_ack(delivery_tag=msg4.delivery_tag, multiple=False) #Four + + channel.basic_cancel(consumer_tag=subscription.consumer_tag) + subscription2 = channel.basic_consume(queue="test-requeue") + queue2 = self.client.queue(subscription2.consumer_tag) + + channel.basic_recover(requeue=True) + + msg3b = queue2.get(timeout=1) + msg5b = queue2.get(timeout=1) + + self.assertEqual("Three", msg3b.content.body) + self.assertEqual("Five", msg5b.content.body) + + self.assertEqual(True, msg3b.redelivered) + self.assertEqual(True, msg5b.redelivered) + + try: + extra = queue2.get(timeout=1) + self.fail("Got unexpected message in second queue: " + extra.content.body) + except Empty: None + try: + extra = queue.get(timeout=1) + self.fail("Got unexpected message in original queue: " + extra.content.body) + except Empty: None + + + def test_qos_prefetch_count(self): + """ + Test that the prefetch count specified is honoured + """ + #setup: declare queue and subscribe + channel = self.channel + channel.queue_declare(queue="test-prefetch-count", exclusive=True) + subscription = channel.basic_consume(queue="test-prefetch-count", no_ack=False) + queue = self.client.queue(subscription.consumer_tag) + + #set prefetch to 5: + channel.basic_qos(prefetch_count=5) + + #publish 10 messages: + for i in range(1, 11): + channel.basic_publish(routing_key="test-prefetch-count", content=Content("Message %d" % i)) + + #only 5 messages should have been delivered: + for i in range(1, 6): + msg = queue.get(timeout=1) + self.assertEqual("Message %d" % i, msg.content.body) + try: + extra = queue.get(timeout=1) + self.fail("Got unexpected 6th message in original queue: " + extra.content.body) + except Empty: None + + #ack messages and check that the next set arrive ok: + channel.basic_ack(delivery_tag=msg.delivery_tag, multiple=True) + + for i in range(6, 11): + msg = queue.get(timeout=1) + self.assertEqual("Message %d" % i, msg.content.body) + + channel.basic_ack(delivery_tag=msg.delivery_tag, multiple=True) + + try: + extra = queue.get(timeout=1) + self.fail("Got unexpected 11th message in original queue: " + extra.content.body) + except Empty: None + + + + def test_qos_prefetch_size(self): + """ + Test that the prefetch size specified is honoured + """ + #setup: declare queue and subscribe + channel = self.channel + channel.queue_declare(queue="test-prefetch-size", exclusive=True) + subscription = channel.basic_consume(queue="test-prefetch-size", no_ack=False) + queue = self.client.queue(subscription.consumer_tag) + + #set prefetch to 50 bytes (each message is 9 or 10 bytes): + channel.basic_qos(prefetch_size=50) + + #publish 10 messages: + for i in range(1, 11): + channel.basic_publish(routing_key="test-prefetch-size", content=Content("Message %d" % i)) + + #only 5 messages should have been delivered (i.e. 45 bytes worth): + for i in range(1, 6): + msg = queue.get(timeout=1) + self.assertEqual("Message %d" % i, msg.content.body) + + try: + extra = queue.get(timeout=1) + self.fail("Got unexpected 6th message in original queue: " + extra.content.body) + except Empty: None + + #ack messages and check that the next set arrive ok: + channel.basic_ack(delivery_tag=msg.delivery_tag, multiple=True) + + for i in range(6, 11): + msg = queue.get(timeout=1) + self.assertEqual("Message %d" % i, msg.content.body) + + channel.basic_ack(delivery_tag=msg.delivery_tag, multiple=True) + + try: + extra = queue.get(timeout=1) + self.fail("Got unexpected 11th message in original queue: " + extra.content.body) + except Empty: None + + #make sure that a single oversized message still gets delivered + large = "abcdefghijklmnopqrstuvwxyz" + large = large + "-" + large; + channel.basic_publish(routing_key="test-prefetch-size", content=Content(large)) + msg = queue.get(timeout=1) + self.assertEqual(large, msg.content.body) + + def test_get(self): + """ + Test basic_get method + """ + channel = self.channel + channel.queue_declare(queue="test-get", exclusive=True) + + #publish some messages (no_ack=True) + for i in range(1, 11): + channel.basic_publish(routing_key="test-get", content=Content("Message %d" % i)) + + #use basic_get to read back the messages, and check that we get an empty at the end + for i in range(1, 11): + reply = channel.basic_get(no_ack=True) + self.assertEqual(reply.method.klass.name, "basic") + self.assertEqual(reply.method.name, "get_ok") + self.assertEqual("Message %d" % i, reply.content.body) + + reply = channel.basic_get(no_ack=True) + self.assertEqual(reply.method.klass.name, "basic") + self.assertEqual(reply.method.name, "get_empty") + + #repeat for no_ack=False + for i in range(11, 21): + channel.basic_publish(routing_key="test-get", content=Content("Message %d" % i)) + + for i in range(11, 21): + reply = channel.basic_get(no_ack=False) + self.assertEqual(reply.method.klass.name, "basic") + self.assertEqual(reply.method.name, "get_ok") + self.assertEqual("Message %d" % i, reply.content.body) + if(i == 13): + channel.basic_ack(delivery_tag=reply.delivery_tag, multiple=True) + if(i in [15, 17, 19]): + channel.basic_ack(delivery_tag=reply.delivery_tag) + + reply = channel.basic_get(no_ack=True) + self.assertEqual(reply.method.klass.name, "basic") + self.assertEqual(reply.method.name, "get_empty") + + #recover(requeue=True) + channel.basic_recover(requeue=True) + + #get the unacked messages again (14, 16, 18, 20) + for i in [14, 16, 18, 20]: + reply = channel.basic_get(no_ack=False) + self.assertEqual(reply.method.klass.name, "basic") + self.assertEqual(reply.method.name, "get_ok") + self.assertEqual("Message %d" % i, reply.content.body) + channel.basic_ack(delivery_tag=reply.delivery_tag) + + reply = channel.basic_get(no_ack=True) + self.assertEqual(reply.method.klass.name, "basic") + self.assertEqual(reply.method.name, "get_empty") + + channel.basic_recover(requeue=True) + + reply = channel.basic_get(no_ack=True) + self.assertEqual(reply.method.klass.name, "basic") + self.assertEqual(reply.method.name, "get_empty") diff --git a/qpid/python/tests_0-9/broker.py b/qpid/python/tests_0-9/broker.py new file mode 100644 index 0000000000..a978993891 --- /dev/null +++ b/qpid/python/tests_0-9/broker.py @@ -0,0 +1,116 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +from qpid.client import Closed +from qpid.queue import Empty +from qpid.content import Content +from qpid.testlib import testrunner, TestBase + +class BrokerTests(TestBase): + """Tests for basic Broker functionality""" + + def test_ack_and_no_ack(self): + """ + First, this test tries to receive a message with a no-ack + consumer. Second, this test tries to explicitely receive and + acknowledge a message with an acknowledging consumer. + """ + ch = self.channel + self.queue_declare(ch, queue = "myqueue") + + # No ack consumer + ctag = "tag1" + ch.message_consume(queue = "myqueue", destination = ctag, no_ack = True) + body = "test no-ack" + ch.message_transfer(routing_key = "myqueue", body = body) + msg = self.client.queue(ctag).get(timeout = 5) + self.assert_(msg.body == body) + + # Acknowledging consumer + self.queue_declare(ch, queue = "otherqueue") + ctag = "tag2" + ch.message_consume(queue = "otherqueue", destination = ctag, no_ack = False) + body = "test ack" + ch.message_transfer(routing_key = "otherqueue", body = body) + msg = self.client.queue(ctag).get(timeout = 5) + msg.ok() + self.assert_(msg.body == body) + + def test_simple_delivery_immediate(self): + """ + Test simple message delivery where consume is issued before publish + """ + channel = self.channel + self.exchange_declare(channel, exchange="test-exchange", type="direct") + self.queue_declare(channel, queue="test-queue") + channel.queue_bind(queue="test-queue", exchange="test-exchange", routing_key="key") + consumer_tag = "tag1" + channel.message_consume(queue="test-queue", destination=consumer_tag, no_ack=True) + queue = self.client.queue(consumer_tag) + + body = "Immediate Delivery" + channel.message_transfer(destination="test-exchange", routing_key="key", body=body, immediate=True) + msg = queue.get(timeout=5) + self.assert_(msg.body == body) + + # TODO: Ensure we fail if immediate=True and there's no consumer. + + + def test_simple_delivery_queued(self): + """ + Test basic message delivery where publish is issued before consume + (i.e. requires queueing of the message) + """ + channel = self.channel + self.exchange_declare(channel, exchange="test-exchange", type="direct") + self.queue_declare(channel, queue="test-queue") + channel.queue_bind(queue="test-queue", exchange="test-exchange", routing_key="key") + body = "Queued Delivery" + channel.message_transfer(destination="test-exchange", routing_key="key", body=body) + + consumer_tag = "tag1" + channel.message_consume(queue="test-queue", destination=consumer_tag, no_ack=True) + queue = self.client.queue(consumer_tag) + msg = queue.get(timeout=5) + self.assert_(msg.body == body) + + def test_invalid_channel(self): + channel = self.client.channel(200) + try: + channel.queue_declare(exclusive=True) + self.fail("Expected error on queue_declare for invalid channel") + except Closed, e: + self.assertConnectionException(504, e.args[0]) + + def test_closed_channel(self): + channel = self.client.channel(200) + channel.channel_open() + channel.channel_close() + try: + channel.queue_declare(exclusive=True) + self.fail("Expected error on queue_declare for closed channel") + except Closed, e: + if isinstance(e.args[0], str): self.fail(e) + self.assertConnectionException(504, e.args[0]) + + def test_ping_pong(self): + channel = self.channel + reply = channel.channel_ping() + self.assertEqual(reply.method.klass.name, "channel") + self.assertEqual(reply.method.name, "ok") + #todo: provide a way to get notified of incoming pongs... diff --git a/qpid/python/tests_0-9/example.py b/qpid/python/tests_0-9/example.py new file mode 100644 index 0000000000..7ab4cc7d0a --- /dev/null +++ b/qpid/python/tests_0-9/example.py @@ -0,0 +1,94 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from qpid.content import Content +from qpid.testlib import testrunner, TestBase + +class ExampleTest (TestBase): + """ + An example Qpid test, illustrating the unittest frameowkr and the + python Qpid client. The test class must inherit TestCase. The + test code uses the Qpid client to interact with a qpid broker and + verify it behaves as expected. + """ + + def test_example(self): + """ + An example test. Note that test functions must start with 'test_' + to be recognized by the test framework. + """ + + # By inheriting TestBase, self.client is automatically connected + # and self.channel is automatically opened as channel(1) + # Other channel methods mimic the protocol. + channel = self.channel + + # Now we can send regular commands. If you want to see what the method + # arguments mean or what other commands are available, you can use the + # python builtin help() method. For example: + #help(chan) + #help(chan.exchange_declare) + + # If you want browse the available protocol methods without being + # connected to a live server you can use the amqp-doc utility: + # + # Usage amqp-doc [<options>] <spec> [<pattern_1> ... <pattern_n>] + # + # Options: + # -e, --regexp use regex instead of glob when matching + + # Now that we know what commands are available we can use them to + # interact with the server. + + # Here we use ordinal arguments. + self.exchange_declare(channel, 0, "test", "direct") + + # Here we use keyword arguments. + self.queue_declare(channel, queue="test-queue") + channel.queue_bind(queue="test-queue", exchange="test", routing_key="key") + + # Call Channel.basic_consume to register as a consumer. + # All the protocol methods return a message object. The message object + # has fields corresponding to the reply method fields, plus a content + # field that is filled if the reply includes content. In this case the + # interesting field is the consumer_tag. + channel.message_consume(queue="test-queue", destination="consumer_tag") + + # We can use the Client.queue(...) method to access the queue + # corresponding to our consumer_tag. + queue = self.client.queue("consumer_tag") + + # Now lets publish a message and see if our consumer gets it. To do + # this we need to import the Content class. + body = "Hello World!" + channel.message_transfer(destination="test", + routing_key="key", + body = body) + + # Now we'll wait for the message to arrive. We can use the timeout + # argument in case the server hangs. By default queue.get() will wait + # until a message arrives or the connection to the server dies. + msg = queue.get(timeout=10) + + # And check that we got the right response with assertEqual + self.assertEqual(body, msg.body) + + # Now acknowledge the message. + msg.ok() + diff --git a/qpid/python/tests_0-9/exchange.py b/qpid/python/tests_0-9/exchange.py new file mode 100644 index 0000000000..3a47ffff8c --- /dev/null +++ b/qpid/python/tests_0-9/exchange.py @@ -0,0 +1,327 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +""" +Tests for exchange behaviour. + +Test classes ending in 'RuleTests' are derived from rules in amqp.xml. +""" + +import Queue, logging +from qpid.testlib import TestBase +from qpid.content import Content +from qpid.client import Closed + + +class StandardExchangeVerifier: + """Verifies standard exchange behavior. + + Used as base class for classes that test standard exchanges.""" + + def verifyDirectExchange(self, ex): + """Verify that ex behaves like a direct exchange.""" + self.queue_declare(queue="q") + self.channel.queue_bind(queue="q", exchange=ex, routing_key="k") + self.assertPublishConsume(exchange=ex, queue="q", routing_key="k") + try: + self.assertPublishConsume(exchange=ex, queue="q", routing_key="kk") + self.fail("Expected Empty exception") + except Queue.Empty: None # Expected + + def verifyFanOutExchange(self, ex): + """Verify that ex behaves like a fanout exchange.""" + self.queue_declare(queue="q") + self.channel.queue_bind(queue="q", exchange=ex) + self.queue_declare(queue="p") + self.channel.queue_bind(queue="p", exchange=ex) + for qname in ["q", "p"]: self.assertPublishGet(self.consume(qname), ex) + + def verifyTopicExchange(self, ex): + """Verify that ex behaves like a topic exchange""" + self.queue_declare(queue="a") + self.channel.queue_bind(queue="a", exchange=ex, routing_key="a.#.b.*") + q = self.consume("a") + self.assertPublishGet(q, ex, "a.b.x") + self.assertPublishGet(q, ex, "a.x.b.x") + self.assertPublishGet(q, ex, "a.x.x.b.x") + # Shouldn't match + self.channel.message_transfer(destination=ex, routing_key="a.b", body="") + self.channel.message_transfer(destination=ex, routing_key="a.b.x.y", body="") + self.channel.message_transfer(destination=ex, routing_key="x.a.b.x", body="") + self.channel.message_transfer(destination=ex, routing_key="a.b", body="") + self.assert_(q.empty()) + + def verifyHeadersExchange(self, ex): + """Verify that ex is a headers exchange""" + self.queue_declare(queue="q") + self.channel.queue_bind(queue="q", exchange=ex, arguments={ "x-match":"all", "name":"fred" , "age":3} ) + q = self.consume("q") + headers = {"name":"fred", "age":3} + self.assertPublishGet(q, exchange=ex, properties=headers) + self.channel.message_transfer(destination=ex, body="") # No headers, won't deliver + self.assertEmpty(q); + + +class RecommendedTypesRuleTests(TestBase, StandardExchangeVerifier): + """ + The server SHOULD implement these standard exchange types: topic, headers. + + Client attempts to declare an exchange with each of these standard types. + """ + + def testDirect(self): + """Declare and test a direct exchange""" + self.exchange_declare(0, exchange="d", type="direct") + self.verifyDirectExchange("d") + + def testFanout(self): + """Declare and test a fanout exchange""" + self.exchange_declare(0, exchange="f", type="fanout") + self.verifyFanOutExchange("f") + + def testTopic(self): + """Declare and test a topic exchange""" + self.exchange_declare(0, exchange="t", type="topic") + self.verifyTopicExchange("t") + + def testHeaders(self): + """Declare and test a headers exchange""" + self.exchange_declare(0, exchange="h", type="headers") + self.verifyHeadersExchange("h") + + +class RequiredInstancesRuleTests(TestBase, StandardExchangeVerifier): + """ + The server MUST, in each virtual host, pre-declare an exchange instance + for each standard exchange type that it implements, where the name of the + exchange instance is amq. followed by the exchange type name. + + Client creates a temporary queue and attempts to bind to each required + exchange instance (amq.fanout, amq.direct, and amq.topic, amq.match if + those types are defined). + """ + def testAmqDirect(self): self.verifyDirectExchange("amq.direct") + + def testAmqFanOut(self): self.verifyFanOutExchange("amq.fanout") + + def testAmqTopic(self): self.verifyTopicExchange("amq.topic") + + def testAmqMatch(self): self.verifyHeadersExchange("amq.match") + +class DefaultExchangeRuleTests(TestBase, StandardExchangeVerifier): + """ + The server MUST predeclare a direct exchange to act as the default exchange + for content Publish methods and for default queue bindings. + + Client checks that the default exchange is active by specifying a queue + binding with no exchange name, and publishing a message with a suitable + routing key but without specifying the exchange name, then ensuring that + the message arrives in the queue correctly. + """ + def testDefaultExchange(self): + # Test automatic binding by queue name. + self.queue_declare(queue="d") + self.assertPublishConsume(queue="d", routing_key="d") + # Test explicit bind to default queue + self.verifyDirectExchange("") + + +# TODO aconway 2006-09-27: Fill in empty tests: + +class DefaultAccessRuleTests(TestBase): + """ + The server MUST NOT allow clients to access the default exchange except + by specifying an empty exchange name in the Queue.Bind and content Publish + methods. + """ + +class ExtensionsRuleTests(TestBase): + """ + The server MAY implement other exchange types as wanted. + """ + + +class DeclareMethodMinimumRuleTests(TestBase): + """ + The server SHOULD support a minimum of 16 exchanges per virtual host and + ideally, impose no limit except as defined by available resources. + + The client creates as many exchanges as it can until the server reports + an error; the number of exchanges successfuly created must be at least + sixteen. + """ + + +class DeclareMethodTicketFieldValidityRuleTests(TestBase): + """ + The client MUST provide a valid access ticket giving "active" access to + the realm in which the exchange exists or will be created, or "passive" + access if the if-exists flag is set. + + Client creates access ticket with wrong access rights and attempts to use + in this method. + """ + + +class DeclareMethodExchangeFieldReservedRuleTests(TestBase): + """ + Exchange names starting with "amq." are reserved for predeclared and + standardised exchanges. The client MUST NOT attempt to create an exchange + starting with "amq.". + + + """ + + +class DeclareMethodTypeFieldTypedRuleTests(TestBase): + """ + Exchanges cannot be redeclared with different types. The client MUST not + attempt to redeclare an existing exchange with a different type than used + in the original Exchange.Declare method. + + + """ + + +class DeclareMethodTypeFieldSupportRuleTests(TestBase): + """ + The client MUST NOT attempt to create an exchange with a type that the + server does not support. + + + """ + + +class DeclareMethodPassiveFieldNotFoundRuleTests(TestBase): + """ + If set, and the exchange does not already exist, the server MUST raise a + channel exception with reply code 404 (not found). + """ + def test(self): + try: + self.channel.exchange_declare(exchange="humpty_dumpty", passive=True) + self.fail("Expected 404 for passive declaration of unknown exchange.") + except Closed, e: + self.assertChannelException(404, e.args[0]) + + +class DeclareMethodDurableFieldSupportRuleTests(TestBase): + """ + The server MUST support both durable and transient exchanges. + + + """ + + +class DeclareMethodDurableFieldStickyRuleTests(TestBase): + """ + The server MUST ignore the durable field if the exchange already exists. + + + """ + + +class DeclareMethodAutoDeleteFieldStickyRuleTests(TestBase): + """ + The server MUST ignore the auto-delete field if the exchange already + exists. + + + """ + + +class DeleteMethodTicketFieldValidityRuleTests(TestBase): + """ + The client MUST provide a valid access ticket giving "active" access + rights to the exchange's access realm. + + Client creates access ticket with wrong access rights and attempts to use + in this method. + """ + + +class DeleteMethodExchangeFieldExistsRuleTests(TestBase): + """ + The client MUST NOT attempt to delete an exchange that does not exist. + """ + + +class HeadersExchangeTests(TestBase): + """ + Tests for headers exchange functionality. + """ + def setUp(self): + TestBase.setUp(self) + self.queue_declare(queue="q") + self.q = self.consume("q") + + def myAssertPublishGet(self, headers): + self.assertPublishGet(self.q, exchange="amq.match", properties=headers) + + def myBasicPublish(self, headers): + self.channel.message_transfer(destination="amq.match", body="foobar", application_headers=headers) + + def testMatchAll(self): + self.channel.queue_bind(queue="q", exchange="amq.match", arguments={ 'x-match':'all', "name":"fred", "age":3}) + self.myAssertPublishGet({"name":"fred", "age":3}) + self.myAssertPublishGet({"name":"fred", "age":3, "extra":"ignoreme"}) + + # None of these should match + self.myBasicPublish({}) + self.myBasicPublish({"name":"barney"}) + self.myBasicPublish({"name":10}) + self.myBasicPublish({"name":"fred", "age":2}) + self.assertEmpty(self.q) + + def testMatchAny(self): + self.channel.queue_bind(queue="q", exchange="amq.match", arguments={ 'x-match':'any', "name":"fred", "age":3}) + self.myAssertPublishGet({"name":"fred"}) + self.myAssertPublishGet({"name":"fred", "ignoreme":10}) + self.myAssertPublishGet({"ignoreme":10, "age":3}) + + # Wont match + self.myBasicPublish({}) + self.myBasicPublish({"irrelevant":0}) + self.assertEmpty(self.q) + + +class MiscellaneousErrorsTests(TestBase): + """ + Test some miscellaneous error conditions + """ + def testTypeNotKnown(self): + try: + self.channel.exchange_declare(exchange="test_type_not_known_exchange", type="invalid_type") + self.fail("Expected 503 for declaration of unknown exchange type.") + except Closed, e: + self.assertConnectionException(503, e.args[0]) + + def testDifferentDeclaredType(self): + self.channel.exchange_declare(exchange="test_different_declared_type_exchange", type="direct") + try: + self.channel.exchange_declare(exchange="test_different_declared_type_exchange", type="topic") + self.fail("Expected 530 for redeclaration of exchange with different type.") + except Closed, e: + self.assertConnectionException(530, e.args[0]) + #cleanup + other = self.connect() + c2 = other.channel(1) + c2.channel_open() + c2.exchange_delete(exchange="test_different_declared_type_exchange") + diff --git a/qpid/python/tests_0-9/message.py b/qpid/python/tests_0-9/message.py new file mode 100644 index 0000000000..8da9978792 --- /dev/null +++ b/qpid/python/tests_0-9/message.py @@ -0,0 +1,651 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +from qpid.client import Client, Closed +from qpid.queue import Empty +from qpid.content import Content +from qpid.testlib import testrunner, TestBase +from qpid.reference import Reference, ReferenceId + +class MessageTests(TestBase): + """Tests for 'methods' on the amqp message 'class'""" + + def test_consume_no_local(self): + """ + Test that the no_local flag is honoured in the consume method + """ + channel = self.channel + #setup, declare two queues: + channel.queue_declare(queue="test-queue-1a", exclusive=True) + channel.queue_declare(queue="test-queue-1b", exclusive=True) + #establish two consumers one of which excludes delivery of locally sent messages + channel.message_consume(destination="local_included", queue="test-queue-1a") + channel.message_consume(destination="local_excluded", queue="test-queue-1b", no_local=True) + + #send a message + channel.message_transfer(routing_key="test-queue-1a", body="consume_no_local") + channel.message_transfer(routing_key="test-queue-1b", body="consume_no_local") + + #check the queues of the two consumers + excluded = self.client.queue("local_excluded") + included = self.client.queue("local_included") + msg = included.get(timeout=1) + self.assertEqual("consume_no_local", msg.body) + try: + excluded.get(timeout=1) + self.fail("Received locally published message though no_local=true") + except Empty: None + + + def test_consume_exclusive(self): + """ + Test that the exclusive flag is honoured in the consume method + """ + channel = self.channel + #setup, declare a queue: + channel.queue_declare(queue="test-queue-2", exclusive=True) + + #check that an exclusive consumer prevents other consumer being created: + channel.message_consume(destination="first", queue="test-queue-2", exclusive=True) + try: + channel.message_consume(destination="second", queue="test-queue-2") + self.fail("Expected consume request to fail due to previous exclusive consumer") + except Closed, e: + self.assertChannelException(403, e.args[0]) + + #open new channel and cleanup last consumer: + channel = self.client.channel(2) + channel.channel_open() + + #check that an exclusive consumer cannot be created if a consumer already exists: + channel.message_consume(destination="first", queue="test-queue-2") + try: + channel.message_consume(destination="second", queue="test-queue-2", exclusive=True) + self.fail("Expected exclusive consume request to fail due to previous consumer") + except Closed, e: + self.assertChannelException(403, e.args[0]) + + def test_consume_queue_errors(self): + """ + Test error conditions associated with the queue field of the consume method: + """ + channel = self.channel + try: + #queue specified but doesn't exist: + channel.message_consume(queue="invalid-queue") + self.fail("Expected failure when consuming from non-existent queue") + except Closed, e: + self.assertChannelException(404, e.args[0]) + + channel = self.client.channel(2) + channel.channel_open() + try: + #queue not specified and none previously declared for channel: + channel.message_consume(queue="") + self.fail("Expected failure when consuming from unspecified queue") + except Closed, e: + self.assertConnectionException(530, e.args[0]) + + def test_consume_unique_consumers(self): + """ + Ensure unique consumer tags are enforced + """ + channel = self.channel + #setup, declare a queue: + channel.queue_declare(queue="test-queue-3", exclusive=True) + + #check that attempts to use duplicate tags are detected and prevented: + channel.message_consume(destination="first", queue="test-queue-3") + try: + channel.message_consume(destination="first", queue="test-queue-3") + self.fail("Expected consume request to fail due to non-unique tag") + except Closed, e: + self.assertConnectionException(530, e.args[0]) + + def test_cancel(self): + """ + Test compliance of the basic.cancel method + """ + channel = self.channel + #setup, declare a queue: + channel.queue_declare(queue="test-queue-4", exclusive=True) + channel.message_consume(destination="my-consumer", queue="test-queue-4") + channel.message_transfer(routing_key="test-queue-4", body="One") + + #cancel should stop messages being delivered + channel.message_cancel(destination="my-consumer") + channel.message_transfer(routing_key="test-queue-4", body="Two") + myqueue = self.client.queue("my-consumer") + msg = myqueue.get(timeout=1) + self.assertEqual("One", msg.body) + try: + msg = myqueue.get(timeout=1) + self.fail("Got message after cancellation: " + msg) + except Empty: None + + #cancellation of non-existant consumers should be handled without error + channel.message_cancel(destination="my-consumer") + channel.message_cancel(destination="this-never-existed") + + + def test_ack(self): + """ + Test basic ack/recover behaviour + """ + channel = self.channel + channel.queue_declare(queue="test-ack-queue", exclusive=True) + + channel.message_consume(queue="test-ack-queue", destination="consumer_tag", no_ack=False) + queue = self.client.queue("consumer_tag") + + channel.message_transfer(routing_key="test-ack-queue", body="One") + channel.message_transfer(routing_key="test-ack-queue", body="Two") + channel.message_transfer(routing_key="test-ack-queue", body="Three") + channel.message_transfer(routing_key="test-ack-queue", body="Four") + channel.message_transfer(routing_key="test-ack-queue", body="Five") + + msg1 = queue.get(timeout=1) + msg2 = queue.get(timeout=1) + msg3 = queue.get(timeout=1) + msg4 = queue.get(timeout=1) + msg5 = queue.get(timeout=1) + + self.assertEqual("One", msg1.body) + self.assertEqual("Two", msg2.body) + self.assertEqual("Three", msg3.body) + self.assertEqual("Four", msg4.body) + self.assertEqual("Five", msg5.body) + + msg1.ok(batchoffset=1)#One and Two + msg4.ok() + + channel.message_recover(requeue=False) + + msg3b = queue.get(timeout=1) + msg5b = queue.get(timeout=1) + + self.assertEqual("Three", msg3b.body) + self.assertEqual("Five", msg5b.body) + + try: + extra = queue.get(timeout=1) + self.fail("Got unexpected message: " + extra.body) + except Empty: None + + def test_recover_requeue(self): + """ + Test requeing on recovery + """ + channel = self.channel + channel.queue_declare(queue="test-requeue", exclusive=True) + + channel.message_consume(queue="test-requeue", destination="consumer_tag", no_ack=False) + queue = self.client.queue("consumer_tag") + + channel.message_transfer(routing_key="test-requeue", body="One") + channel.message_transfer(routing_key="test-requeue", body="Two") + channel.message_transfer(routing_key="test-requeue", body="Three") + channel.message_transfer(routing_key="test-requeue", body="Four") + channel.message_transfer(routing_key="test-requeue", body="Five") + + msg1 = queue.get(timeout=1) + msg2 = queue.get(timeout=1) + msg3 = queue.get(timeout=1) + msg4 = queue.get(timeout=1) + msg5 = queue.get(timeout=1) + + self.assertEqual("One", msg1.body) + self.assertEqual("Two", msg2.body) + self.assertEqual("Three", msg3.body) + self.assertEqual("Four", msg4.body) + self.assertEqual("Five", msg5.body) + + msg1.ok(batchoffset=1) #One and Two + msg4.ok() #Four + + channel.message_cancel(destination="consumer_tag") + channel.message_consume(queue="test-requeue", destination="consumer_tag") + queue2 = self.client.queue("consumer_tag") + + channel.message_recover(requeue=True) + + msg3b = queue2.get(timeout=1) + msg5b = queue2.get(timeout=1) + + self.assertEqual("Three", msg3b.body) + self.assertEqual("Five", msg5b.body) + + self.assertEqual(True, msg3b.redelivered) + self.assertEqual(True, msg5b.redelivered) + + try: + extra = queue2.get(timeout=1) + self.fail("Got unexpected message in second queue: " + extra.body) + except Empty: None + try: + extra = queue.get(timeout=1) + self.fail("Got unexpected message in original queue: " + extra.body) + except Empty: None + + + def test_qos_prefetch_count(self): + """ + Test that the prefetch count specified is honoured + """ + #setup: declare queue and subscribe + channel = self.channel + channel.queue_declare(queue="test-prefetch-count", exclusive=True) + subscription = channel.message_consume(queue="test-prefetch-count", destination="consumer_tag", no_ack=False) + queue = self.client.queue("consumer_tag") + + #set prefetch to 5: + channel.message_qos(prefetch_count=5) + + #publish 10 messages: + for i in range(1, 11): + channel.message_transfer(routing_key="test-prefetch-count", body="Message %d" % i) + + #only 5 messages should have been delivered: + for i in range(1, 6): + msg = queue.get(timeout=1) + self.assertEqual("Message %d" % i, msg.body) + try: + extra = queue.get(timeout=1) + self.fail("Got unexpected 6th message in original queue: " + extra.body) + except Empty: None + + #ack messages and check that the next set arrive ok: + #todo: once batching is implmented, send a single response for all messages + msg.ok(batchoffset=-4)#1-5 + + for i in range(6, 11): + msg = queue.get(timeout=1) + self.assertEqual("Message %d" % i, msg.body) + + msg.ok(batchoffset=-4)#6-10 + + try: + extra = queue.get(timeout=1) + self.fail("Got unexpected 11th message in original queue: " + extra.body) + except Empty: None + + + + def test_qos_prefetch_size(self): + """ + Test that the prefetch size specified is honoured + """ + #setup: declare queue and subscribe + channel = self.channel + channel.queue_declare(queue="test-prefetch-size", exclusive=True) + subscription = channel.message_consume(queue="test-prefetch-size", destination="consumer_tag", no_ack=False) + queue = self.client.queue("consumer_tag") + + #set prefetch to 50 bytes (each message is 9 or 10 bytes): + channel.message_qos(prefetch_size=50) + + #publish 10 messages: + for i in range(1, 11): + channel.message_transfer(routing_key="test-prefetch-size", body="Message %d" % i) + + #only 5 messages should have been delivered (i.e. 45 bytes worth): + for i in range(1, 6): + msg = queue.get(timeout=1) + self.assertEqual("Message %d" % i, msg.body) + + try: + extra = queue.get(timeout=1) + self.fail("Got unexpected 6th message in original queue: " + extra.body) + except Empty: None + + #ack messages and check that the next set arrive ok: + msg.ok(batchoffset=-4)#1-5 + + for i in range(6, 11): + msg = queue.get(timeout=1) + self.assertEqual("Message %d" % i, msg.body) + + msg.ok(batchoffset=-4)#6-10 + + try: + extra = queue.get(timeout=1) + self.fail("Got unexpected 11th message in original queue: " + extra.body) + except Empty: None + + #make sure that a single oversized message still gets delivered + large = "abcdefghijklmnopqrstuvwxyz" + large = large + "-" + large; + channel.message_transfer(routing_key="test-prefetch-size", body=large) + msg = queue.get(timeout=1) + self.assertEqual(large, msg.body) + + def test_get(self): + """ + Test message_get method + """ + channel = self.channel + channel.queue_declare(queue="test-get", exclusive=True) + + #publish some messages (no_ack=True) + for i in range(1, 11): + channel.message_transfer(routing_key="test-get", body="Message %d" % i) + + #use message_get to read back the messages, and check that we get an empty at the end + for i in range(1, 11): + tag = "queue %d" % i + reply = channel.message_get(no_ack=True, queue="test-get", destination=tag) + self.assertEqual(reply.method.klass.name, "message") + self.assertEqual(reply.method.name, "ok") + self.assertEqual("Message %d" % i, self.client.queue(tag).get(timeout=1).body) + + reply = channel.message_get(no_ack=True, queue="test-get") + self.assertEqual(reply.method.klass.name, "message") + self.assertEqual(reply.method.name, "empty") + + #repeat for no_ack=False + for i in range(11, 21): + channel.message_transfer(routing_key="test-get", body="Message %d" % i) + + for i in range(11, 21): + tag = "queue %d" % i + reply = channel.message_get(no_ack=False, queue="test-get", destination=tag) + self.assertEqual(reply.method.klass.name, "message") + self.assertEqual(reply.method.name, "ok") + msg = self.client.queue(tag).get(timeout=1) + self.assertEqual("Message %d" % i, msg.body) + + if (i==13): + msg.ok(batchoffset=-2)#11, 12 & 13 + if(i in [15, 17, 19]): + msg.ok() + + reply = channel.message_get(no_ack=True, queue="test-get") + self.assertEqual(reply.method.klass.name, "message") + self.assertEqual(reply.method.name, "empty") + + #recover(requeue=True) + channel.message_recover(requeue=True) + + #get the unacked messages again (14, 16, 18, 20) + for i in [14, 16, 18, 20]: + tag = "queue %d" % i + reply = channel.message_get(no_ack=False, queue="test-get", destination=tag) + self.assertEqual(reply.method.klass.name, "message") + self.assertEqual(reply.method.name, "ok") + msg = self.client.queue(tag).get(timeout=1) + self.assertEqual("Message %d" % i, msg.body) + msg.ok() + #channel.message_ack(delivery_tag=reply.delivery_tag) + + reply = channel.message_get(no_ack=True, queue="test-get") + self.assertEqual(reply.method.klass.name, "message") + self.assertEqual(reply.method.name, "empty") + + channel.message_recover(requeue=True) + + reply = channel.message_get(no_ack=True, queue="test-get") + self.assertEqual(reply.method.klass.name, "message") + self.assertEqual(reply.method.name, "empty") + + def test_reference_simple(self): + """ + Test basic ability to handle references + """ + channel = self.channel + channel.queue_declare(queue="ref_queue", exclusive=True) + channel.message_consume(queue="ref_queue", destination="c1") + queue = self.client.queue("c1") + + refId = "myref" + channel.message_open(reference=refId) + channel.message_append(reference=refId, bytes="abcd") + channel.synchronous = False + ack = channel.message_transfer(routing_key="ref_queue", body=ReferenceId(refId)) + channel.synchronous = True + + channel.message_append(reference=refId, bytes="efgh") + channel.message_append(reference=refId, bytes="ijkl") + channel.message_close(reference=refId) + + #first, wait for the ok for the transfer + ack.get_response(timeout=1) + + self.assertDataEquals(channel, queue.get(timeout=1), "abcdefghijkl") + + + def test_reference_large(self): + """ + Test basic ability to handle references whose content exceeds max frame size + """ + channel = self.channel + self.queue_declare(queue="ref_queue") + + #generate a big data string (> max frame size of consumer): + data = "0123456789" + for i in range(0, 10): + data += data + #send it inline + channel.synchronous = False + ack = channel.message_transfer(routing_key="ref_queue", body=data) + channel.synchronous = True + #first, wait for the ok for the transfer + ack.get_response(timeout=1) + + #create a new connection for consumer, with specific max frame size (< data) + other = self.connect(tune_params={"channel_max":10, "frame_max":5120, "heartbeat":0}) + ch2 = other.channel(1) + ch2.channel_open() + ch2.message_consume(queue="ref_queue", destination="c1") + queue = other.queue("c1") + + msg = queue.get(timeout=1) + self.assertTrue(isinstance(msg.body, ReferenceId)) + self.assertTrue(msg.reference) + self.assertEquals(data, msg.reference.get_complete()) + + def test_reference_completion(self): + """ + Test that reference transfer are not deemed complete until + closed (therefore are not acked or routed until that point) + """ + channel = self.channel + channel.queue_declare(queue="ref_queue", exclusive=True) + channel.message_consume(queue="ref_queue", destination="c1") + queue = self.client.queue("c1") + + refId = "myref" + channel.message_open(reference=refId) + channel.message_append(reference=refId, bytes="abcd") + channel.synchronous = False + ack = channel.message_transfer(routing_key="ref_queue", body=ReferenceId(refId)) + channel.synchronous = True + + try: + msg = queue.get(timeout=1) + self.fail("Got unexpected message on queue: " + msg) + except Empty: None + + self.assertTrue(not ack.is_complete()) + + channel.message_close(reference=refId) + + #first, wait for the ok for the transfer + ack.get_response(timeout=1) + + self.assertDataEquals(channel, queue.get(timeout=1), "abcd") + + def test_reference_multi_transfer(self): + """ + Test that multiple transfer requests for the same reference are + correctly handled. + """ + channel = self.channel + #declare and consume from two queues + channel.queue_declare(queue="q-one", exclusive=True) + channel.queue_declare(queue="q-two", exclusive=True) + channel.message_consume(queue="q-one", destination="q-one") + channel.message_consume(queue="q-two", destination="q-two") + queue1 = self.client.queue("q-one") + queue2 = self.client.queue("q-two") + + #transfer a single ref to both queues (in separate commands) + channel.message_open(reference="my-ref") + channel.synchronous = False + ack1 = channel.message_transfer(routing_key="q-one", body=ReferenceId("my-ref")) + channel.message_append(reference="my-ref", bytes="my data") + ack2 = channel.message_transfer(routing_key="q-two", body=ReferenceId("my-ref")) + channel.synchronous = True + channel.message_close(reference="my-ref") + + #check that both queues have the message + self.assertDataEquals(channel, queue1.get(timeout=1), "my data") + self.assertDataEquals(channel, queue2.get(timeout=1), "my data") + self.assertEmpty(queue1) + self.assertEmpty(queue2) + + #transfer a single ref to the same queue twice (in separate commands) + channel.message_open(reference="my-ref") + channel.synchronous = False + ack1 = channel.message_transfer(routing_key="q-one", message_id="abc", body=ReferenceId("my-ref")) + channel.message_append(reference="my-ref", bytes="second message") + ack2 = channel.message_transfer(routing_key="q-one", message_id="xyz", body=ReferenceId("my-ref")) + channel.synchronous = True + channel.message_close(reference="my-ref") + + msg1 = queue1.get(timeout=1) + msg2 = queue1.get(timeout=1) + #order is undefined + if msg1.message_id == "abc": + self.assertEquals(msg2.message_id, "xyz") + else: + self.assertEquals(msg1.message_id, "xyz") + self.assertEquals(msg2.message_id, "abc") + + #would be legal for the incoming messages to be transfered + #inline or by reference in any combination + + if isinstance(msg1.body, ReferenceId): + self.assertEquals("second message", msg1.reference.get_complete()) + if isinstance(msg2.body, ReferenceId): + if msg1.body != msg2.body: + self.assertEquals("second message", msg2.reference.get_complete()) + #else ok, as same ref as msg1 + else: + self.assertEquals("second message", msg1.body) + if isinstance(msg2.body, ReferenceId): + self.assertEquals("second message", msg2.reference.get_complete()) + else: + self.assertEquals("second message", msg2.body) + + self.assertEmpty(queue1) + + def test_reference_unopened_on_append_error(self): + channel = self.channel + try: + channel.message_append(reference="unopened") + except Closed, e: + self.assertConnectionException(503, e.args[0]) + + def test_reference_unopened_on_close_error(self): + channel = self.channel + try: + channel.message_close(reference="unopened") + except Closed, e: + self.assertConnectionException(503, e.args[0]) + + def test_reference_unopened_on_transfer_error(self): + channel = self.channel + try: + channel.message_transfer(body=ReferenceId("unopened")) + except Closed, e: + self.assertConnectionException(503, e.args[0]) + + def test_reference_already_opened_error(self): + channel = self.channel + channel.message_open(reference="a") + try: + channel.message_open(reference="a") + except Closed, e: + self.assertConnectionException(503, e.args[0]) + + def test_empty_reference(self): + channel = self.channel + channel.queue_declare(queue="ref_queue", exclusive=True) + channel.message_consume(queue="ref_queue", destination="c1") + queue = self.client.queue("c1") + + refId = "myref" + channel.message_open(reference=refId) + channel.synchronous = False + ack = channel.message_transfer(routing_key="ref_queue", message_id="empty-msg", body=ReferenceId(refId)) + channel.synchronous = True + channel.message_close(reference=refId) + + #first, wait for the ok for the transfer + ack.get_response(timeout=1) + + msg = queue.get(timeout=1) + self.assertEquals(msg.message_id, "empty-msg") + self.assertDataEquals(channel, msg, "") + + def test_reject(self): + channel = self.channel + channel.queue_declare(queue = "q", exclusive=True) + + channel.message_consume(queue = "q", destination = "consumer") + channel.message_transfer(routing_key = "q", body="blah, blah") + msg = self.client.queue("consumer").get(timeout = 1) + self.assertEquals(msg.body, "blah, blah") + channel.message_cancel(destination = "consumer") + msg.reject() + + channel.message_consume(queue = "q", destination = "checker") + msg = self.client.queue("checker").get(timeout = 1) + self.assertEquals(msg.body, "blah, blah") + + def test_checkpoint(self): + channel = self.channel + channel.queue_declare(queue = "q", exclusive=True) + + channel.message_open(reference="my-ref") + channel.message_append(reference="my-ref", bytes="abcdefgh") + channel.message_append(reference="my-ref", bytes="ijklmnop") + channel.message_checkpoint(reference="my-ref", identifier="my-checkpoint") + channel.channel_close() + + channel = self.client.channel(2) + channel.channel_open() + channel.message_consume(queue = "q", destination = "consumer") + offset = channel.message_resume(reference="my-ref", identifier="my-checkpoint").value + self.assertTrue(offset<=16) + channel.message_append(reference="my-ref", bytes="qrstuvwxyz") + channel.synchronous = False + channel.message_transfer(routing_key="q-one", message_id="abcd", body=ReferenceId("my-ref")) + channel.synchronous = True + channel.message_close(reference="my-ref") + + self.assertDataEquals(channel, self.client.queue("consumer").get(timeout = 1), "abcdefghijklmnopqrstuvwxyz") + self.assertEmpty(self.client.queue("consumer")) + + + def assertDataEquals(self, channel, msg, expected): + if isinstance(msg.body, ReferenceId): + data = msg.reference.get_complete() + else: + data = msg.body + self.assertEquals(expected, data) diff --git a/qpid/python/tests_0-9/queue.py b/qpid/python/tests_0-9/queue.py new file mode 100644 index 0000000000..b94b8b7739 --- /dev/null +++ b/qpid/python/tests_0-9/queue.py @@ -0,0 +1,306 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +from qpid.client import Client, Closed +from qpid.queue import Empty +from qpid.content import Content +from qpid.testlib import testrunner, TestBase + +class QueueTests(TestBase): + """Tests for 'methods' on the amqp queue 'class'""" + + def test_purge(self): + """ + Test that the purge method removes messages from the queue + """ + channel = self.channel + #setup, declare a queue and add some messages to it: + channel.exchange_declare(exchange="test-exchange", type="direct") + channel.queue_declare(queue="test-queue", exclusive=True) + channel.queue_bind(queue="test-queue", exchange="test-exchange", routing_key="key") + channel.message_transfer(destination="test-exchange", routing_key="key", body="one") + channel.message_transfer(destination="test-exchange", routing_key="key", body="two") + channel.message_transfer(destination="test-exchange", routing_key="key", body="three") + + #check that the queue now reports 3 messages: + reply = channel.queue_declare(queue="test-queue") + self.assertEqual(3, reply.message_count) + + #now do the purge, then test that three messages are purged and the count drops to 0 + reply = channel.queue_purge(queue="test-queue"); + self.assertEqual(3, reply.message_count) + reply = channel.queue_declare(queue="test-queue") + self.assertEqual(0, reply.message_count) + + #send a further message and consume it, ensuring that the other messages are really gone + channel.message_transfer(destination="test-exchange", routing_key="key", body="four") + channel.message_consume(queue="test-queue", destination="tag", no_ack=True) + queue = self.client.queue("tag") + msg = queue.get(timeout=1) + self.assertEqual("four", msg.body) + + #check error conditions (use new channels): + channel = self.client.channel(2) + channel.channel_open() + try: + #queue specified but doesn't exist: + channel.queue_purge(queue="invalid-queue") + self.fail("Expected failure when purging non-existent queue") + except Closed, e: + self.assertChannelException(404, e.args[0]) + + channel = self.client.channel(3) + channel.channel_open() + try: + #queue not specified and none previously declared for channel: + channel.queue_purge() + self.fail("Expected failure when purging unspecified queue") + except Closed, e: + self.assertConnectionException(530, e.args[0]) + + #cleanup + other = self.connect() + channel = other.channel(1) + channel.channel_open() + channel.exchange_delete(exchange="test-exchange") + + def test_declare_exclusive(self): + """ + Test that the exclusive field is honoured in queue.declare + """ + # TestBase.setUp has already opened channel(1) + c1 = self.channel + # Here we open a second separate connection: + other = self.connect() + c2 = other.channel(1) + c2.channel_open() + + #declare an exclusive queue: + c1.queue_declare(queue="exclusive-queue", exclusive="True") + try: + #other connection should not be allowed to declare this: + c2.queue_declare(queue="exclusive-queue", exclusive="True") + self.fail("Expected second exclusive queue_declare to raise a channel exception") + except Closed, e: + self.assertChannelException(405, e.args[0]) + + + def test_declare_passive(self): + """ + Test that the passive field is honoured in queue.declare + """ + channel = self.channel + #declare an exclusive queue: + channel.queue_declare(queue="passive-queue-1", exclusive="True") + channel.queue_declare(queue="passive-queue-1", passive="True") + try: + #other connection should not be allowed to declare this: + channel.queue_declare(queue="passive-queue-2", passive="True") + self.fail("Expected passive declaration of non-existant queue to raise a channel exception") + except Closed, e: + self.assertChannelException(404, e.args[0]) + + + def test_bind(self): + """ + Test various permutations of the queue.bind method + """ + channel = self.channel + channel.queue_declare(queue="queue-1", exclusive="True") + + #straightforward case, both exchange & queue exist so no errors expected: + channel.queue_bind(queue="queue-1", exchange="amq.direct", routing_key="key1") + + #bind the default queue for the channel (i.e. last one declared): + channel.queue_bind(exchange="amq.direct", routing_key="key2") + + #use the queue name where neither routing key nor queue are specified: + channel.queue_bind(exchange="amq.direct") + + #try and bind to non-existant exchange + try: + channel.queue_bind(queue="queue-1", exchange="an-invalid-exchange", routing_key="key1") + self.fail("Expected bind to non-existant exchange to fail") + except Closed, e: + self.assertChannelException(404, e.args[0]) + + #need to reopen a channel: + channel = self.client.channel(2) + channel.channel_open() + + #try and bind non-existant queue: + try: + channel.queue_bind(queue="queue-2", exchange="amq.direct", routing_key="key1") + self.fail("Expected bind of non-existant queue to fail") + except Closed, e: + self.assertChannelException(404, e.args[0]) + + def test_unbind_direct(self): + self.unbind_test(exchange="amq.direct", routing_key="key") + + def test_unbind_topic(self): + self.unbind_test(exchange="amq.topic", routing_key="key") + + def test_unbind_fanout(self): + self.unbind_test(exchange="amq.fanout") + + def test_unbind_headers(self): + self.unbind_test(exchange="amq.match", args={ "x-match":"all", "a":"b"}, headers={"a":"b"}) + + def unbind_test(self, exchange, routing_key="", args=None, headers={}): + #bind two queues and consume from them + channel = self.channel + + channel.queue_declare(queue="queue-1", exclusive="True") + channel.queue_declare(queue="queue-2", exclusive="True") + + channel.message_consume(queue="queue-1", destination="queue-1", no_ack=True) + channel.message_consume(queue="queue-2", destination="queue-2", no_ack=True) + + queue1 = self.client.queue("queue-1") + queue2 = self.client.queue("queue-2") + + channel.queue_bind(exchange=exchange, queue="queue-1", routing_key=routing_key, arguments=args) + channel.queue_bind(exchange=exchange, queue="queue-2", routing_key=routing_key, arguments=args) + + #send a message that will match both bindings + channel.message_transfer(destination=exchange, routing_key=routing_key, application_headers=headers, body="one") + + #unbind first queue + channel.queue_unbind(exchange=exchange, queue="queue-1", routing_key=routing_key, arguments=args) + + #send another message + channel.message_transfer(destination=exchange, routing_key=routing_key, application_headers=headers, body="two") + + #check one queue has both messages and the other has only one + self.assertEquals("one", queue1.get(timeout=1).body) + try: + msg = queue1.get(timeout=1) + self.fail("Got extra message: %s" % msg.body) + except Empty: pass + + self.assertEquals("one", queue2.get(timeout=1).body) + self.assertEquals("two", queue2.get(timeout=1).body) + try: + msg = queue2.get(timeout=1) + self.fail("Got extra message: " + msg) + except Empty: pass + + + def test_delete_simple(self): + """ + Test core queue deletion behaviour + """ + channel = self.channel + + #straight-forward case: + channel.queue_declare(queue="delete-me") + channel.message_transfer(routing_key="delete-me", body="a") + channel.message_transfer(routing_key="delete-me", body="b") + channel.message_transfer(routing_key="delete-me", body="c") + reply = channel.queue_delete(queue="delete-me") + self.assertEqual(3, reply.message_count) + #check that it has gone be declaring passively + try: + channel.queue_declare(queue="delete-me", passive="True") + self.fail("Queue has not been deleted") + except Closed, e: + self.assertChannelException(404, e.args[0]) + + #check attempted deletion of non-existant queue is handled correctly: + channel = self.client.channel(2) + channel.channel_open() + try: + channel.queue_delete(queue="i-dont-exist", if_empty="True") + self.fail("Expected delete of non-existant queue to fail") + except Closed, e: + self.assertChannelException(404, e.args[0]) + + + + def test_delete_ifempty(self): + """ + Test that if_empty field of queue_delete is honoured + """ + channel = self.channel + + #create a queue and add a message to it (use default binding): + channel.queue_declare(queue="delete-me-2") + channel.queue_declare(queue="delete-me-2", passive="True") + channel.message_transfer(routing_key="delete-me-2", body="message") + + #try to delete, but only if empty: + try: + channel.queue_delete(queue="delete-me-2", if_empty="True") + self.fail("Expected delete if_empty to fail for non-empty queue") + except Closed, e: + self.assertChannelException(406, e.args[0]) + + #need new channel now: + channel = self.client.channel(2) + channel.channel_open() + + #empty queue: + channel.message_consume(destination="consumer_tag", queue="delete-me-2", no_ack=True) + queue = self.client.queue("consumer_tag") + msg = queue.get(timeout=1) + self.assertEqual("message", msg.body) + channel.message_cancel(destination="consumer_tag") + + #retry deletion on empty queue: + channel.queue_delete(queue="delete-me-2", if_empty="True") + + #check that it has gone by declaring passively: + try: + channel.queue_declare(queue="delete-me-2", passive="True") + self.fail("Queue has not been deleted") + except Closed, e: + self.assertChannelException(404, e.args[0]) + + def test_delete_ifunused(self): + """ + Test that if_unused field of queue_delete is honoured + """ + channel = self.channel + + #create a queue and register a consumer: + channel.queue_declare(queue="delete-me-3") + channel.queue_declare(queue="delete-me-3", passive="True") + channel.message_consume(destination="consumer_tag", queue="delete-me-3", no_ack=True) + + #need new channel now: + channel2 = self.client.channel(2) + channel2.channel_open() + #try to delete, but only if empty: + try: + channel2.queue_delete(queue="delete-me-3", if_unused="True") + self.fail("Expected delete if_unused to fail for queue with existing consumer") + except Closed, e: + self.assertChannelException(406, e.args[0]) + + + channel.message_cancel(destination="consumer_tag") + channel.queue_delete(queue="delete-me-3", if_unused="True") + #check that it has gone by declaring passively: + try: + channel.queue_declare(queue="delete-me-3", passive="True") + self.fail("Queue has not been deleted") + except Closed, e: + self.assertChannelException(404, e.args[0]) + + diff --git a/qpid/python/tests_0-9/testlib.py b/qpid/python/tests_0-9/testlib.py new file mode 100644 index 0000000000..f345fbbd80 --- /dev/null +++ b/qpid/python/tests_0-9/testlib.py @@ -0,0 +1,66 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# +# Tests for the testlib itself. +# + +from qpid.content import Content +from qpid.testlib import testrunner, TestBase +from Queue import Empty + +import sys +from traceback import * + +def mytrace(frame, event, arg): + print_stack(frame); + print "====" + return mytrace + +class TestBaseTest(TestBase): + """Verify TestBase functions work as expected""" + + def testAssertEmptyPass(self): + """Test assert empty works""" + self.queue_declare(queue="empty") + q = self.consume("empty") + self.assertEmpty(q) + try: + q.get(timeout=1) + self.fail("Queue is not empty.") + except Empty: None # Ignore + + def testAssertEmptyFail(self): + self.queue_declare(queue="full") + q = self.consume("full") + self.channel.message_transfer(routing_key="full", body="") + try: + self.assertEmpty(q); + self.fail("assertEmpty did not assert on non-empty queue") + except AssertionError: None # Ignore + + def testMessageProperties(self): + """Verify properties are passed with message""" + props={"x":1, "y":2} + self.queue_declare(queue="q") + q = self.consume("q") + self.assertPublishGet(q, routing_key="q", properties=props) + + + diff --git a/qpid/python/tests_0-9/tx.py b/qpid/python/tests_0-9/tx.py new file mode 100644 index 0000000000..0f6b4f5cd1 --- /dev/null +++ b/qpid/python/tests_0-9/tx.py @@ -0,0 +1,188 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +from qpid.client import Client, Closed +from qpid.queue import Empty +from qpid.content import Content +from qpid.testlib import testrunner, TestBase + +class TxTests(TestBase): + """ + Tests for 'methods' on the amqp tx 'class' + """ + + def test_commit(self): + """ + Test that commited publishes are delivered and commited acks are not re-delivered + """ + channel = self.channel + queue_a, queue_b, queue_c = self.perform_txn_work(channel, "tx-commit-a", "tx-commit-b", "tx-commit-c") + channel.tx_commit() + + #check results + for i in range(1, 5): + msg = queue_c.get(timeout=1) + self.assertEqual("TxMessage %d" % i, msg.body) + msg.ok() + + msg = queue_b.get(timeout=1) + self.assertEqual("TxMessage 6", msg.body) + msg.ok() + + msg = queue_a.get(timeout=1) + self.assertEqual("TxMessage 7", msg.body) + msg.ok() + + for q in [queue_a, queue_b, queue_c]: + try: + extra = q.get(timeout=1) + self.fail("Got unexpected message: " + extra.body) + except Empty: None + + #cleanup + channel.tx_commit() + + def test_auto_rollback(self): + """ + Test that a channel closed with an open transaction is effectively rolled back + """ + channel = self.channel + queue_a, queue_b, queue_c = self.perform_txn_work(channel, "tx-autorollback-a", "tx-autorollback-b", "tx-autorollback-c") + + for q in [queue_a, queue_b, queue_c]: + try: + extra = q.get(timeout=1) + self.fail("Got unexpected message: " + extra.body) + except Empty: None + + channel.tx_rollback() + + #check results + for i in range(1, 5): + msg = queue_a.get(timeout=1) + self.assertEqual("Message %d" % i, msg.body) + msg.ok() + + msg = queue_b.get(timeout=1) + self.assertEqual("Message 6", msg.body) + msg.ok() + + msg = queue_c.get(timeout=1) + self.assertEqual("Message 7", msg.body) + msg.ok() + + for q in [queue_a, queue_b, queue_c]: + try: + extra = q.get(timeout=1) + self.fail("Got unexpected message: " + extra.body) + except Empty: None + + #cleanup + channel.tx_commit() + + def test_rollback(self): + """ + Test that rolled back publishes are not delivered and rolled back acks are re-delivered + """ + channel = self.channel + queue_a, queue_b, queue_c = self.perform_txn_work(channel, "tx-rollback-a", "tx-rollback-b", "tx-rollback-c") + + for q in [queue_a, queue_b, queue_c]: + try: + extra = q.get(timeout=1) + self.fail("Got unexpected message: " + extra.body) + except Empty: None + + channel.tx_rollback() + + #check results + for i in range(1, 5): + msg = queue_a.get(timeout=1) + self.assertEqual("Message %d" % i, msg.body) + msg.ok() + + msg = queue_b.get(timeout=1) + self.assertEqual("Message 6", msg.body) + msg.ok() + + msg = queue_c.get(timeout=1) + self.assertEqual("Message 7", msg.body) + msg.ok() + + for q in [queue_a, queue_b, queue_c]: + try: + extra = q.get(timeout=1) + self.fail("Got unexpected message: " + extra.body) + except Empty: None + + #cleanup + channel.tx_commit() + + def perform_txn_work(self, channel, name_a, name_b, name_c): + """ + Utility method that does some setup and some work under a transaction. Used for testing both + commit and rollback + """ + #setup: + channel.queue_declare(queue=name_a, exclusive=True) + channel.queue_declare(queue=name_b, exclusive=True) + channel.queue_declare(queue=name_c, exclusive=True) + + key = "my_key_" + name_b + topic = "my_topic_" + name_c + + channel.queue_bind(queue=name_b, exchange="amq.direct", routing_key=key) + channel.queue_bind(queue=name_c, exchange="amq.topic", routing_key=topic) + + for i in range(1, 5): + channel.message_transfer(routing_key=name_a, body="Message %d" % i) + + channel.message_transfer(routing_key=key, destination="amq.direct", body="Message 6") + channel.message_transfer(routing_key=topic, destination="amq.topic", body="Message 7") + + channel.tx_select() + + #consume and ack messages + channel.message_consume(queue=name_a, destination="sub_a", no_ack=False) + queue_a = self.client.queue("sub_a") + for i in range(1, 5): + msg = queue_a.get(timeout=1) + self.assertEqual("Message %d" % i, msg.body) + + msg.ok(batchoffset=-3) + + channel.message_consume(queue=name_b, destination="sub_b", no_ack=False) + queue_b = self.client.queue("sub_b") + msg = queue_b.get(timeout=1) + self.assertEqual("Message 6", msg.body) + msg.ok() + + sub_c = channel.message_consume(queue=name_c, destination="sub_c", no_ack=False) + queue_c = self.client.queue("sub_c") + msg = queue_c.get(timeout=1) + self.assertEqual("Message 7", msg.body) + msg.ok() + + #publish messages + for i in range(1, 5): + channel.message_transfer(routing_key=topic, destination="amq.topic", body="TxMessage %d" % i) + + channel.message_transfer(routing_key=key, destination="amq.direct", body="TxMessage 6") + channel.message_transfer(routing_key=name_a, body="TxMessage 7") + + return queue_a, queue_b, queue_c |